View Javadoc
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