1 /***
2 * Copyright (C) 2003 Jean-Daniel Fekete and INRIA, France
3 * -------------------------------------------------------------------------
4 * This software is published under the terms of the QPL Software License
5 * a copy of which has been included with this distribution in the
6 * license-infovis.txt file.
7 */
8 package edu.psu.geovista.ui;
9
10 import javax.swing.event.*;
11 import javax.swing.event.ChangeEvent;
12 import javax.swing.event.EventListenerList;
13
14 import java.awt.Shape;
15 import java.awt.geom.*;
16 import java.awt.geom.Point2D;
17 import java.awt.geom.Rectangle2D;
18
19
20 /***
21 * Fisheyes manage space deformation to maintain focus+context views by
22 * applying a space deformation. See Sheelagh Carpendale's PhD for full
23 * details.
24 *
25 * @author Jean-Daniel Fekete
26 * @version $Revision: 1.1 $
27 */
28 public class Fisheyes {
29 /*** constant value for setDistanceMetric to use a L1 distance */
30 public static final short DISTANCE_L1 = 0;
31 /*** constant value for setDistanceMetric to use a L2 distance */
32 public static final short DISTANCE_L2 = 1;
33 /*** constant value for setDistanceMetric to use a L infinity distance */
34 public static final short DISTANCE_LINF = 2;
35 /*** constant value for setLensType to use a gaussian lens types */
36 public static final short LENS_GAUSSIAN = 0;
37 /*** constant value for setLensType to use a cosine lens types */
38 public static final short LENS_COSINE = 1;
39 /*** constant value for setLensType to use a hemisphere lens types */
40 public static final short LENS_HEMISPHERE = 2;
41 /*** constant value for setLensType to use a linear lens types */
42 public static final short LENS_LINEAR = 3;
43 /*** constant value for setLensType to use an inverse cosine lens types */
44 public static final short LENS_INVERSE_COSINE = 4;
45 /*** The virtual camera height is 10.0f */
46 public static final float referenceHeight = 10.0f;
47 /*** The virtual viewplane is located at this distance from the camera */
48 public static final float distanceViewplance = 1.0f;
49 transient Rectangle2D.Float bounds = new Rectangle2D.Float();
50 float focusX;
51 float focusY;
52 float lensRadius;
53 float focusRadius;
54 float focalHeight;
55 float tolerance = 1;
56 short distanceMetric;
57 Metric metric;
58 short lensType;
59 LensProfile lensProfile;
60
61 /***
62 * Constructor for Fisheyes.
63 */
64 public Fisheyes() {
65 this(100, 0, 9);
66 }
67
68 /***
69 * Creates a new Fisheye object.
70 *
71 * @param lensRadius the lens radius.
72 * @param focusRadius DOCUMENT ME!
73 * @param focalHeight the focal heigt (0 <= 9)
74 */
75 public Fisheyes(float lensRadius, float focusRadius, float focalHeight) {
76 setLensRadius(lensRadius);
77 setFocusRadius(focusRadius);
78 setFocalHeight(focalHeight);
79 setDistanceMetric(DISTANCE_L2);
80 setLensType(LENS_LINEAR);
81 }
82
83 public Rectangle2D getBounds() {
84 if (bounds == null) {
85 bounds = new Rectangle2D.Float(focusX - focusRadius,
86 focusY - focusRadius,
87 2 * focusRadius, 2 * focusRadius);
88 }
89 return bounds;
90 }
91
92 /***
93 * Returns true of point is transformed.
94 *
95 * @param x X coordinate
96 * @param y Y coordinate
97 *
98 * @return true of point is transformed.
99 */
100 public boolean isTransformed(float x, float y) {
101 return metric.compare(lensRadius, x - focusX, y - focusY) > 0;
102 }
103
104 /***
105 * Returns true of point is transformed.
106 *
107 * @param x X coordinate
108 * @param y Y coordinate
109 *
110 * @return true of point is transformed.
111 */
112 public boolean isTransformed(double x, double y) {
113 return isTransformed((float)x, (float)y);
114 }
115
116 /***
117 * Returns true of point is transformed.
118 *
119 * @param p the point
120 *
121 * @return true of point is transformed.
122 */
123 public boolean isTransformed(Point2D p) {
124 return isTransformed(p.getX(), p.getY());
125 }
126
127 /***
128 * DOCUMENT ME!
129 *
130 * @param bounds DOCUMENT ME!
131 *
132 * @return DOCUMENT ME!
133 */
134 public boolean isTransformed(Rectangle2D bounds) {
135 return bounds.intersects(getBounds());
136 }
137
138 /***
139 * DOCUMENT ME!
140 *
141 * @param s DOCUMENT ME!
142 *
143 * @return DOCUMENT ME!
144 */
145 public boolean isTransformed(Shape s) {
146 return getBounds().intersects(s.getBounds2D());
147 }
148
149 /***
150 * DOCUMENT ME!
151 *
152 * @param s DOCUMENT ME!
153 *
154 * @return DOCUMENT ME!
155 */
156 public Shape transform(Shape s) {
157 if (!isTransformed(s))
158 return s;
159
160 GeneralPath p = new GeneralPath();
161 float[] coords = { 0, 0, 0, 0, 0, 0 };
162 float first_x = 0;
163 float first_y = 0;
164 float first_tx = 0;
165 float first_ty = 0;
166 float prev_x = 0;
167 float prev_y = 0;
168 float prev_tx = 0;
169 float prev_ty = 0;
170 for (PathIterator iter = s.getPathIterator(null); !iter.isDone();
171 iter.next()) {
172 switch (iter.currentSegment(coords)) {
173 case PathIterator.SEG_MOVETO:
174 prev_x = coords[0];
175 prev_y = coords[1];
176 first_x = prev_x;
177 first_y = prev_y;
178 transform(coords, 1);
179 prev_tx = coords[0];
180 prev_ty = coords[1];
181 first_tx = prev_tx;
182 first_ty = prev_ty;
183 p.moveTo(coords[0], coords[1]);
184 break;
185 case PathIterator.SEG_LINETO: {
186 float x = coords[0];
187 float y = coords[1];
188 transform(coords, 1);
189 subdivide(prev_x, prev_y, prev_tx, prev_ty,
190 x, y, coords[0], coords[1], p);
191 prev_x = x;
192 prev_y = y;
193 prev_tx = coords[0];
194 prev_ty = coords[1];
195 break;
196 }
197 case PathIterator.SEG_QUADTO: {
198 float x1 = coords[0];
199 float y1 = coords[1];
200 float x2 = coords[2];
201 float y2 = coords[3];
202 transform(coords, 2);
203 subdivide(prev_x, prev_y, prev_tx, prev_ty,
204 x1, y1, coords[0], coords[1],
205 x2, y2, coords[2], coords[3],
206 p);
207 prev_x = x2;
208 prev_y = y2;
209 prev_tx = coords[2];
210 prev_ty = coords[3];
211 break;
212 }
213 case PathIterator.SEG_CUBICTO: {
214 float x1 = coords[0];
215 float y1 = coords[1];
216 float x2 = coords[2];
217 float y2 = coords[3];
218 float x3 = coords[4];
219 float y3 = coords[5];
220 transform(coords, 3);
221 subdivide(prev_x, prev_y, prev_tx, prev_ty,
222 x1, y1, coords[0], coords[1],
223 x2, y2, coords[2], coords[3],
224 x3, y3, coords[4], coords[5],
225 p);
226 prev_x = x3;
227 prev_y = y3;
228 prev_tx = coords[4];
229 prev_ty = coords[5];
230 break;
231 }
232 case PathIterator.SEG_CLOSE: {
233 subdivide(prev_x, prev_y, prev_tx, prev_ty,
234 first_x, first_y, first_tx, first_ty, p);
235 break;
236 }
237 }
238 }
239 return p;
240 }
241
242 void addTransformed(float x, float y, GeneralPath p) {
243 float scale = getScale(x, y);
244 float tx;
245 float ty;
246 if (scale == 1) {
247 return;
248 }
249 tx = transformX(x, scale);
250 ty = transformY(y, scale);
251 p.lineTo(tx, ty);
252 }
253
254 static float dist2(float dx, float dy) {
255 return dx * dx + dy * dy;
256 }
257
258 /***
259 * Subdivide a line segment.
260 *
261 * @param x1 X coordinate of first point
262 * @param y1 Y coordinate of first point
263 * @param tx1 Y coordinate of first point
264 * @param ty1 transformed Y coordinate of first point
265 * @param x2 X coordinate of second point
266 * @param y2 Y coordinate of second point
267 * @param tx2 Y coordinate of second point
268 * @param ty2 transformed Y coordinate of second point
269 * @param p GeneralPath to fill
270 */
271 public void subdivide(float x1, float y1, float tx1, float ty1,
272 float x2, float y2, float tx2, float ty2,
273 GeneralPath p) {
274 float xm = (x1 + x2) / 2;
275 float ym = (y1 + y2) / 2;
276 float scale = getScale(xm, ym);
277 float txm = transformX(xm, scale);
278 float tym = transformY(ym, scale);
279
280 if (dist2(txm - (tx1 + tx2) / 2, tym - (ty1 + ty2) / 2) > tolerance) {
281 subdivide(x1, y1, tx1, ty2, xm, ym, txm, tym, p);
282 p.lineTo(txm, tym);
283 subdivide(xm, ym, txm, tym, x2, y2, tx2, ty2, p);
284 }
285 else {
286 p.lineTo(tx2, ty2);
287 }
288 }
289
290 private QuadCurve2D.Float leftQuad = new QuadCurve2D.Float();
291 private QuadCurve2D.Float rightQuad = new QuadCurve2D.Float();
292 /***
293 * Subdivide a quad segment.
294 *
295 * @param x1 X coordinate of first point
296 * @param y1 Y coordinate of first point
297 * @param tx1 Y coordinate of first point
298 * @param ty1 transformed Y coordinate of first point
299 * @param x2 X coordinate of second point
300 * @param y2 Y coordinate of second point
301 * @param tx2 Y coordinate of second point
302 * @param ty2 transformed Y coordinate of second point
303 * @param x3 X coordinate of third point
304 * @param y3 Y coordinate of third point
305 * @param tx3 Y coordinate of third point
306 * @param ty3 transformed Y coordinate of third point
307 * @param p GeneralPath to fill
308 */
309 public void subdivide(float x1, float y1, float tx1, float ty1,
310 float x2, float y2, float tx2, float ty2,
311 float x3, float y3, float tx3, float ty3,
312 GeneralPath p) {
313 leftQuad.setCurve(tx1, ty1, tx2, ty2, tx3, ty3);
314 if (leftQuad.getFlatnessSq() <= tolerance) {
315 p.lineTo(tx3, ty3);
316 return;
317 }
318 leftQuad.setCurve(x1, y1, x2, y2, x3, y3);
319 leftQuad.subdivide(leftQuad, rightQuad);
320 float scaleLeft = getScale(leftQuad.ctrlx, leftQuad.ctrly);
321 float txLeft = transformX(leftQuad.ctrlx, scaleLeft);
322 float tyLeft = transformY(leftQuad.ctrly, scaleLeft);
323 float scaleM = getScale(leftQuad.x2, leftQuad.y2);
324 float txm = transformX(leftQuad.x2, scaleM);
325 float tym = transformY(leftQuad.y2, scaleM);
326 subdivide(x1, y1, tx1, ty1,
327 leftQuad.ctrlx, leftQuad.ctrly, txLeft, tyLeft,
328 leftQuad.x2, leftQuad.y2, txm, tym,
329 p);
330 p.lineTo(txm, tym);
331 float scaleRight = getScale(rightQuad.ctrlx, rightQuad.ctrly);
332 float txRight = transformX(rightQuad.ctrlx, scaleRight);
333 float tyRight = transformY(rightQuad.ctrly, scaleRight);
334 subdivide(rightQuad.x1, rightQuad.y1, txm, tym,
335 rightQuad.ctrlx, rightQuad.ctrly, txRight, tyRight,
336 x3, y3, tx3, ty3,
337 p);
338 }
339
340 private CubicCurve2D.Float leftCubic = new CubicCurve2D.Float();
341 private CubicCurve2D.Float rightCubic = new CubicCurve2D.Float();
342 /***
343 * Subdivide a quad segment.
344 *
345 * @param x1 X coordinate of first point
346 * @param y1 Y coordinate of first point
347 * @param tx1 Y coordinate of first point
348 * @param ty1 transformed Y coordinate of first point
349 * @param x2 X coordinate of second point
350 * @param y2 Y coordinate of second point
351 * @param tx2 Y coordinate of second point
352 * @param ty2 transformed Y coordinate of second point
353 * @param x3 X coordinate of third point
354 * @param y3 Y coordinate of third point
355 * @param tx3 Y coordinate of third point
356 * @param ty3 transformed Y coordinate of third point
357 * @param x3 X coordinate of fourth point
358 * @param y3 Y coordinate of fourth point
359 * @param tx3 Y coordinate of fourth point
360 * @param ty3 transformed Y coordinate of fourth point
361 * @param p GeneralPath to fill
362 */
363 public void subdivide(float x1, float y1, float tx1, float ty1,
364 float x2, float y2, float tx2, float ty2,
365 float x3, float y3, float tx3, float ty3,
366 float x4, float y4, float tx4, float ty4,
367 GeneralPath p) {
368 leftCubic.setCurve(tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4);
369 if (leftCubic.getFlatnessSq() <= tolerance) {
370 p.lineTo(tx4, ty4);
371 return;
372 }
373 leftCubic.setCurve(x1, y1, x2, y2, x3, y3, x4, y4);
374 leftCubic.subdivide(leftCubic, rightCubic);
375 float scale = getScale(leftCubic.ctrlx1, leftCubic.ctrly1);
376 float tctrlx1 = transformX(leftCubic.ctrlx1, scale);
377 float tctrly1 = transformY(leftCubic.ctrly1, scale);
378 scale = getScale(leftCubic.ctrlx2, leftCubic.ctrly2);
379 float tctrlx2 = transformX(leftCubic.ctrlx2, scale);
380 float tctrly2 = transformY(leftCubic.ctrly2, scale);
381 scale = getScale(leftCubic.x2, leftCubic.y2);
382 float txm = transformX(leftCubic.x2, scale);
383 float tym = transformY(leftCubic.y2, scale);
384 subdivide(x1, y1, tx1, ty1,
385 leftCubic.ctrlx1, leftCubic.ctrly1, tctrlx1, tctrly1,
386 leftCubic.ctrlx2, leftCubic.ctrly2, tctrlx2, tctrly2,
387 leftCubic.x2, leftCubic.y2, txm, tym,
388 p);
389 p.lineTo(txm, tym);
390 scale = getScale(rightCubic.ctrlx1, rightCubic.ctrly1);
391 tctrlx1 = transformX(rightCubic.ctrlx1, scale);
392 tctrly1 = transformY(rightCubic.ctrly1, scale);
393 scale = getScale(rightCubic.ctrlx2, rightCubic.ctrly2);
394 tctrlx2 = transformX(rightCubic.ctrlx2, scale);
395 tctrly2 = transformY(rightCubic.ctrly2, scale);
396 subdivide(rightCubic.x1, rightCubic.y1, txm, tym,
397 rightCubic.ctrlx1, rightCubic.ctrly1, tctrlx1, tctrly1,
398 rightCubic.ctrlx2, rightCubic.ctrly2, tctrlx2, tctrly2,
399 x3, y3, tx3, ty3,
400 p);
401 }
402
403
404 /***
405 * Returns the height of a specified point.
406 *
407 * @param x X coordinate of the point
408 * @param y Y coordinate of the point
409 *
410 * @return the height of the specified point.
411 */
412 public float pointHeight(float x, float y) {
413 return height(distance(x, y));
414 }
415
416 /***
417 * Sets for focus position
418 *
419 * @param x X coordinate of the position
420 * @param y X coordinate of the position
421 */
422 public void setFocus(float x, float y) {
423 focusX = x;
424 focusY = y;
425 bounds.x = x - lensRadius;
426 bounds.y = y - lensRadius;
427 }
428
429 /***
430 * Returns the distance of the specified point from the focus.
431 *
432 * @param x X coordinate of the point
433 * @param y Y coordinate of the point
434 *
435 * @return the distance of the specified point from the focus.
436 */
437 public float distance(float x, float y) {
438 return metric.distance(x - focusX, y - focusY);
439 }
440
441 /***
442 * Returns the height at the specified distance from the focus
443 *
444 * @param dist the distance
445 *
446 * @return the height at the specified distance from the focus
447 */
448 public float height(float dist) {
449 if (focalHeight == 0) {
450 return 0;
451 }
452
453 float realFocus = focusRadius / getMaximumScale();
454 if (dist > lensRadius) {
455 return 0;
456 } else if (dist <= realFocus) {
457 return focalHeight;
458 } else {
459 float t = (dist - realFocus) / (lensRadius - realFocus);
460 return Math.min(focalHeight * lens(t), focalHeight);
461 }
462 }
463
464 /***
465 * Returns the height at the specified normalized distance from the focus
466 *
467 * @param t the normalized distance from the focus
468 *
469 * @return the height at the specified normalized distance from the focus
470 */
471 public float lens(float t) {
472 return lensProfile.profile(t);
473 }
474
475 /***
476 * Returns the focusX.
477 *
478 * @return float
479 */
480 public float getFocusX() {
481 return focusX;
482 }
483
484 /***
485 * Returns the focusY.
486 *
487 * @return float
488 */
489 public float getFocusY() {
490 return focusY;
491 }
492
493 /***
494 * Sets the focusX.
495 *
496 * @param focusX The focusX to set
497 */
498 public void setFocusX(float focusX) {
499 this.focusX = focusX;
500 bounds.x = focusX - lensRadius;
501 }
502
503 /***
504 * Returns the lensRadius.
505 *
506 * @return float
507 */
508 public float getLensRadius() {
509 return lensRadius;
510 }
511
512 /***
513 * Sets the focusY.
514 *
515 * @param focusY The focusY to set
516 */
517 public void setFocusY(float focusY) {
518 this.focusY = focusY;
519 bounds.y = focusY - lensRadius;
520 }
521
522 /***
523 * Sets the lensRadius.
524 *
525 * @param radius The lensRadius to set
526 */
527 public void setLensRadius(float radius) {
528 this.lensRadius = radius;
529 if (this.focusRadius > radius)
530 this.focusRadius = radius;
531 bounds.width = 2 * radius;
532 bounds.height = 2 * radius;
533 bounds.x = focusX - lensRadius;
534 bounds.y = focusY - lensRadius;
535 }
536
537 /***
538 * Returns the focusRadius.
539 *
540 * @return float
541 */
542 public float getFocusRadius() {
543 return focusRadius;
544 }
545
546 /***
547 * Sets the focusRadius.
548 *
549 * @param focusRadius The focusRadius to set
550 */
551 public void setFocusRadius(float focusRadius) {
552 this.focusRadius = focusRadius;
553 }
554
555 /***
556 * DOCUMENT ME!
557 *
558 * @param focus DOCUMENT ME!
559 * @param lens DOCUMENT ME!
560 */
561 public void setRadii(float focus, float lens) {
562 if (lens < focus) {
563 focus = lens;
564 }
565 focusRadius = focus;
566 lensRadius = lens;
567 bounds.width = 2 * lensRadius;
568 bounds.height = 2 * lensRadius;
569 bounds.x = focusX - lensRadius;
570 bounds.y = focusY - lensRadius;
571 }
572
573 /***
574 * Returns the focal height.
575 *
576 * @return float
577 */
578 public float getFocalHeight() {
579 return focalHeight;
580 }
581
582 /***
583 * Sets the focal height.
584 *
585 * @param focalHeight The focal height to set
586 */
587 public void setFocalHeight(float focalHeight) {
588 if (focalHeight < 0) {
589 focalHeight = 0;
590 } else if (focalHeight > 9) {
591 focalHeight = 9;
592 }
593
594 this.focalHeight = focalHeight;
595 }
596
597 /***
598 * Change the maximum scale
599 *
600 * @param scale the new maximum scale
601 */
602 public void setMaximumScale(float scale) {
603 if (scale == 0) {
604 setFocalHeight(0);
605 } else {
606 setFocalHeight(10 - (10 / scale));
607 }
608 }
609
610 /***
611 * Returns the maximum scale
612 *
613 * @return the maximum scale
614 */
615 public float getMaximumScale() {
616 return 10f / (10f - focalHeight);
617 }
618
619 /***
620 * DOCUMENT ME!
621 *
622 * @param x DOCUMENT ME!
623 * @param y DOCUMENT ME!
624 *
625 * @return DOCUMENT ME!
626 */
627 public float getScale(float x, float y) {
628 float height = pointHeight(x, y);
629 return 10f / (10f - height);
630 }
631
632 /***
633 * DOCUMENT ME!
634 *
635 * @param x DOCUMENT ME!
636 * @param scale DOCUMENT ME!
637 *
638 * @return DOCUMENT ME!
639 */
640 public float transformX(float x, float scale) {
641 return (x - focusX) * scale + focusX;
642 }
643
644 /***
645 * DOCUMENT ME!
646 *
647 * @param y DOCUMENT ME!
648 * @param scale DOCUMENT ME!
649 *
650 * @return DOCUMENT ME!
651 */
652 public float transformY(float y, float scale) {
653 return (y - focusY) * scale + focusY;
654 }
655
656 /***
657 * DOCUMENT ME!
658 *
659 * @param coords DOCUMENT ME!
660 */
661 public void transform(float[] coords, int npoints) {
662 for (int i = 0; i < npoints; i++) {
663 float scale = getScale(coords[2*i], coords[2*i+1]);
664 if (scale != 1) {
665 coords[2*i] = transformX(coords[2*i], scale);
666 coords[2*i+1] = transformY(coords[2*i+1], scale);
667 }
668 }
669 }
670
671 /***
672 * DOCUMENT ME!
673 *
674 * @param src DOCUMENT ME!
675 * @param dst DOCUMENT ME!
676 */
677 public void transform(Point2D.Float src, Point2D.Float dst) {
678 float scale = getScale(src.x, src.y);
679 if (scale != 1) {
680 dst.x = transformX(src.x, scale);
681 dst.y = transformY(src.y, scale);
682 } else if (dst != src) {
683 dst.x = src.x;
684 dst.y = src.y;
685 }
686 }
687
688 /***
689 * Returns the distanceMetric.
690 *
691 * @return short the distanceMetric
692 */
693 public short getDistanceMetric() {
694 return distanceMetric;
695 }
696
697 /***
698 * Returns the lensType.
699 *
700 * @return short
701 */
702 public short getLensType() {
703 return lensType;
704 }
705
706 /***
707 * Sets the distanceMetric.
708 *
709 * @param distanceMetrics The distanceMetric to set
710 */
711 public void setDistanceMetric(short distanceMetrics) {
712 this.distanceMetric = distanceMetrics;
713
714 switch (distanceMetrics) {
715 case DISTANCE_L1:
716 metric = new DistanceL1();
717 break;
718 case DISTANCE_L2:
719 metric = new DistanceL2();
720 break;
721 case DISTANCE_LINF:
722 metric = new DistanceLInf();
723 break;
724 }
725 }
726
727 /***
728 * Sets the lensType.
729 *
730 * @param lensType The lensType to set
731 */
732 public void setLensType(short lensType) {
733 this.lensType = lensType;
734
735 switch (lensType) {
736 case LENS_GAUSSIAN:
737 lensProfile = new ProfileGuassian();
738 break;
739 case LENS_COSINE:
740 lensProfile = new ProfileCos();
741 break;
742 case LENS_HEMISPHERE:
743 lensProfile = new ProfileCos();
744 break;
745 case LENS_INVERSE_COSINE:
746 lensProfile = new ProfileInverse(new ProfileCos());
747 break;
748 case LENS_LINEAR:
749 lensProfile = new ProfileLinear();
750 break;
751 }
752 }
753
754
755 public interface Metric {
756 public float distance(float dx, float dy);
757 public int compare(float dist, float dx, float dy);
758 }
759
760 public interface LensProfile {
761 public float profile(float t);
762 }
763
764 public static class ProfileCos implements LensProfile {
765 public float profile(float t) {
766 return (float)Math.cos(t * Math.PI / 2);
767 }
768 }
769
770 static class ProfileGuassian implements LensProfile {
771 static final double ro = 0.1;
772 static final double denom = 1 / (ro * Math.sqrt(2 * Math.PI));
773
774 public float profile(float t) {
775 return (float)Math.exp((-t * t) / ro);
776 }
777 }
778
779 static class ProfileOneMinusSin implements LensProfile {
780 public float profile(float t) {
781 return 1 - (float)Math.sin(t);
782 }
783 }
784
785 static class ProfileLinear implements LensProfile {
786 public float profile(float t) {
787 return 1 - t;
788 }
789 }
790
791 static class ProfileInverse implements LensProfile {
792 LensProfile profile;
793
794 public ProfileInverse(LensProfile profile) {
795 this.profile = profile;
796 }
797
798 public float profile(float t) {
799 return 1 - profile.profile(1 - t);
800 }
801 }
802
803 static class DistanceL1 implements Metric {
804 public float distance(float dx, float dy) {
805 return Math.abs(dx) + Math.abs(dy);
806 }
807 public int compare(float dist, float dx, float dy) {
808 float d = dist - distance(dx, dy);
809 if (d < 0) return -1;
810 else if (d == 0) return 0;
811 else return 1;
812 }
813
814 }
815
816 static class DistanceL2 implements Metric {
817 public float distance(float dx, float dy) {
818
819 return (float)Math.sqrt((dx * dx) + (dy * dy));
820 }
821 public int compare(float dist, float dx, float dy) {
822 float d = dist*dist - (dx * dx) + (dy * dy);
823 if (d < 0) return -1;
824 else if (d == 0) return 0;
825 else return 1;
826 }
827 }
828
829 static class DistanceLInf implements Metric {
830 public float distance(float dx, float dy) {
831 return Math.max(Math.abs(dx), Math.abs(dy));
832 }
833
834 public int compare(float dist, float dx, float dy) {
835 float d = dist - distance(dx, dy);
836 if (d < 0) return -1;
837 else if (d == 0) return 0;
838 else return 1;
839 }
840 }
841
842 /***
843 * Returns the tolerance.
844 *
845 * @return float
846 */
847 public float getTolerance() {
848 return tolerance;
849 }
850
851 /***
852 * Sets the tolerance.
853 *
854 * @param tolerance The tolerance to set
855 */
856 public void setTolerance(float tolerance) {
857 if (tolerance < 1)
858 tolerance = 1;
859 this.tolerance = tolerance;
860 }
861 }
This page was automatically generated by Maven