Frames | No Frames |
1: /* Line2D.java -- represents a line in 2-D space, plus operations on a line 2: Copyright (C) 2000, 2001, 2002 Free Software Foundation 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package java.awt.geom; 39: 40: import java.awt.Rectangle; 41: import java.awt.Shape; 42: import java.util.NoSuchElementException; 43: 44: /** 45: * Represents a directed line bewteen two points in (x,y) Cartesian space. 46: * Remember, on-screen graphics have increasing x from left-to-right, and 47: * increasing y from top-to-bottom. The storage is left to subclasses. 48: * 49: * @author Tom Tromey (tromey@cygnus.com) 50: * @author Eric Blake (ebb9@email.byu.edu) 51: * @author David Gilbert 52: * @since 1.2 53: * @status updated to 1.4 54: */ 55: public abstract class Line2D implements Shape, Cloneable 56: { 57: /** 58: * The default constructor. 59: */ 60: protected Line2D() 61: { 62: } 63: 64: /** 65: * Return the x coordinate of the first point. 66: * 67: * @return the starting x coordinate 68: */ 69: public abstract double getX1(); 70: 71: /** 72: * Return the y coordinate of the first point. 73: * 74: * @return the starting y coordinate 75: */ 76: public abstract double getY1(); 77: 78: /** 79: * Return the first point. 80: * 81: * @return the starting point 82: */ 83: public abstract Point2D getP1(); 84: 85: /** 86: * Return the x coordinate of the second point. 87: * 88: * @return the ending x coordinate 89: */ 90: public abstract double getX2(); 91: 92: /** 93: * Return the y coordinate of the second point. 94: * 95: * @return the ending y coordinate 96: */ 97: public abstract double getY2(); 98: 99: /** 100: * Return the second point. 101: * 102: * @return the ending point 103: */ 104: public abstract Point2D getP2(); 105: 106: /** 107: * Set the coordinates of the line to the given coordinates. Loss of 108: * precision may occur due to rounding issues. 109: * 110: * @param x1 the first x coordinate 111: * @param y1 the first y coordinate 112: * @param x2 the second x coordinate 113: * @param y2 the second y coordinate 114: */ 115: public abstract void setLine(double x1, double y1, double x2, double y2); 116: 117: /** 118: * Set the coordinates to the given points. 119: * 120: * @param p1 the first point 121: * @param p2 the second point 122: * @throws NullPointerException if either point is null 123: */ 124: public void setLine(Point2D p1, Point2D p2) 125: { 126: setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY()); 127: } 128: 129: /** 130: * Set the coordinates to those of the given line. 131: * 132: * @param l the line to copy 133: * @throws NullPointerException if l is null 134: */ 135: public void setLine(Line2D l) 136: { 137: setLine(l.getX1(), l.getY1(), l.getX2(), l.getY2()); 138: } 139: 140: /** 141: * Computes the relative rotation direction needed to pivot the line about 142: * the first point in order to have the second point colinear with point p. 143: * Because of floating point rounding, don't expect this to be a perfect 144: * measure of colinearity. The answer is 1 if the line has a shorter rotation 145: * in the direction of the positive X axis to the negative Y axis 146: * (counter-clockwise in the default Java coordinate system), or -1 if the 147: * shortest rotation is in the opposite direction (clockwise). If p 148: * is already colinear, the return value is -1 if it lies beyond the first 149: * point, 0 if it lies in the segment, or 1 if it lies beyond the second 150: * point. If the first and second point are coincident, this returns 0. 151: * 152: * @param x1 the first x coordinate 153: * @param y1 the first y coordinate 154: * @param x2 the second x coordinate 155: * @param y2 the second y coordinate 156: * @param px the reference x coordinate 157: * @param py the reference y coordinate 158: * @return the relative rotation direction 159: */ 160: public static int relativeCCW(double x1, double y1, double x2, double y2, 161: double px, double py) 162: { 163: if ((x1 == x2 && y1 == y2) 164: || (x1 == px && y1 == py)) 165: return 0; // Coincident points. 166: // Translate to the origin. 167: x2 -= x1; 168: y2 -= y1; 169: px -= x1; 170: py -= y1; 171: double slope2 = y2 / x2; 172: double slopep = py / px; 173: if (slope2 == slopep || (x2 == 0 && px == 0)) 174: return y2 > 0 // Colinear. 175: ? (py < 0 ? -1 : py > y2 ? 1 : 0) 176: : (py > 0 ? -1 : py < y2 ? 1 : 0); 177: if (x2 >= 0 && slope2 >= 0) 178: return px >= 0 // Quadrant 1. 179: ? (slope2 > slopep ? 1 : -1) 180: : (slope2 < slopep ? 1 : -1); 181: if (y2 > 0) 182: return px < 0 // Quadrant 2. 183: ? (slope2 > slopep ? 1 : -1) 184: : (slope2 < slopep ? 1 : -1); 185: if (slope2 >= 0.0) 186: return px >= 0 // Quadrant 3. 187: ? (slope2 < slopep ? 1 : -1) 188: : (slope2 > slopep ? 1 : -1); 189: return px < 0 // Quadrant 4. 190: ? (slope2 < slopep ? 1 : -1) 191: : (slope2 > slopep ? 1 : -1); 192: } 193: 194: /** 195: * Computes the relative rotation direction needed to pivot this line about 196: * the first point in order to have the second point colinear with point p. 197: * Because of floating point rounding, don't expect this to be a perfect 198: * measure of colinearity. The answer is 1 if the line has a shorter rotation 199: * in the direction of the positive X axis to the negative Y axis 200: * (counter-clockwise in the default Java coordinate system), or -1 if the 201: * shortest rotation is in the opposite direction (clockwise). If p 202: * is already colinear, the return value is -1 if it lies beyond the first 203: * point, 0 if it lies in the segment, or 1 if it lies beyond the second 204: * point. If the first and second point are coincident, this returns 0. 205: * 206: * @param px the reference x coordinate 207: * @param py the reference y coordinate 208: * @return the relative rotation direction 209: * @see #relativeCCW(double, double, double, double, double, double) 210: */ 211: public int relativeCCW(double px, double py) 212: { 213: return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py); 214: } 215: 216: /** 217: * Computes the relative rotation direction needed to pivot this line about 218: * the first point in order to have the second point colinear with point p. 219: * Because of floating point rounding, don't expect this to be a perfect 220: * measure of colinearity. The answer is 1 if the line has a shorter rotation 221: * in the direction of the positive X axis to the negative Y axis 222: * (counter-clockwise in the default Java coordinate system), or -1 if the 223: * shortest rotation is in the opposite direction (clockwise). If p 224: * is already colinear, the return value is -1 if it lies beyond the first 225: * point, 0 if it lies in the segment, or 1 if it lies beyond the second 226: * point. If the first and second point are coincident, this returns 0. 227: * 228: * @param p the reference point 229: * @return the relative rotation direction 230: * @throws NullPointerException if p is null 231: * @see #relativeCCW(double, double, double, double, double, double) 232: */ 233: public int relativeCCW(Point2D p) 234: { 235: return relativeCCW(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); 236: } 237: 238: /** 239: * Computes twice the (signed) area of the triangle defined by the three 240: * points. This method is used for intersection testing. 241: * 242: * @param x1 the x-coordinate of the first point. 243: * @param y1 the y-coordinate of the first point. 244: * @param x2 the x-coordinate of the second point. 245: * @param y2 the y-coordinate of the second point. 246: * @param x3 the x-coordinate of the third point. 247: * @param y3 the y-coordinate of the third point. 248: * 249: * @return Twice the area. 250: */ 251: private static double area2(double x1, double y1, 252: double x2, double y2, 253: double x3, double y3) 254: { 255: return (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); 256: } 257: 258: /** 259: * Returns <code>true</code> if (x3, y3) lies between (x1, y1) and (x2, y2), 260: * and false otherwise, This test assumes that the three points are 261: * collinear, and is used for intersection testing. 262: * 263: * @param x1 the x-coordinate of the first point. 264: * @param y1 the y-coordinate of the first point. 265: * @param x2 the x-coordinate of the second point. 266: * @param y2 the y-coordinate of the second point. 267: * @param x3 the x-coordinate of the third point. 268: * @param y3 the y-coordinate of the third point. 269: * 270: * @return A boolean. 271: */ 272: private static boolean between(double x1, double y1, 273: double x2, double y2, 274: double x3, double y3) 275: { 276: if (x1 != x2) { 277: return (x1 <= x3 && x3 <= x2) || (x1 >= x3 && x3 >= x2); 278: } 279: else { 280: return (y1 <= y3 && y3 <= y2) || (y1 >= y3 && y3 >= y2); 281: } 282: } 283: 284: /** 285: * Test if the line segment (x1,y1)->(x2,y2) intersects the line segment 286: * (x3,y3)->(x4,y4). 287: * 288: * @param x1 the first x coordinate of the first segment 289: * @param y1 the first y coordinate of the first segment 290: * @param x2 the second x coordinate of the first segment 291: * @param y2 the second y coordinate of the first segment 292: * @param x3 the first x coordinate of the second segment 293: * @param y3 the first y coordinate of the second segment 294: * @param x4 the second x coordinate of the second segment 295: * @param y4 the second y coordinate of the second segment 296: * @return true if the segments intersect 297: */ 298: public static boolean linesIntersect(double x1, double y1, 299: double x2, double y2, 300: double x3, double y3, 301: double x4, double y4) 302: { 303: double a1, a2, a3, a4; 304: 305: // deal with special cases 306: if ((a1 = area2(x1, y1, x2, y2, x3, y3)) == 0.0) 307: { 308: // check if p3 is between p1 and p2 OR 309: // p4 is collinear also AND either between p1 and p2 OR at opposite ends 310: if (between(x1, y1, x2, y2, x3, y3)) 311: { 312: return true; 313: } 314: else 315: { 316: if (area2(x1, y1, x2, y2, x4, y4) == 0.0) 317: { 318: return between(x3, y3, x4, y4, x1, y1) 319: || between (x3, y3, x4, y4, x2, y2); 320: } 321: else { 322: return false; 323: } 324: } 325: } 326: else if ((a2 = area2(x1, y1, x2, y2, x4, y4)) == 0.0) 327: { 328: // check if p4 is between p1 and p2 (we already know p3 is not 329: // collinear) 330: return between(x1, y1, x2, y2, x4, y4); 331: } 332: 333: if ((a3 = area2(x3, y3, x4, y4, x1, y1)) == 0.0) { 334: // check if p1 is between p3 and p4 OR 335: // p2 is collinear also AND either between p1 and p2 OR at opposite ends 336: if (between(x3, y3, x4, y4, x1, y1)) { 337: return true; 338: } 339: else { 340: if (area2(x3, y3, x4, y4, x2, y2) == 0.0) { 341: return between(x1, y1, x2, y2, x3, y3) 342: || between (x1, y1, x2, y2, x4, y4); 343: } 344: else { 345: return false; 346: } 347: } 348: } 349: else if ((a4 = area2(x3, y3, x4, y4, x2, y2)) == 0.0) { 350: // check if p2 is between p3 and p4 (we already know p1 is not 351: // collinear) 352: return between(x3, y3, x4, y4, x2, y2); 353: } 354: else { // test for regular intersection 355: return ((a1 > 0.0) ^ (a2 > 0.0)) && ((a3 > 0.0) ^ (a4 > 0.0)); 356: } 357: } 358: 359: /** 360: * Test if this line intersects the line given by (x1,y1)->(x2,y2). 361: * 362: * @param x1 the first x coordinate of the other segment 363: * @param y1 the first y coordinate of the other segment 364: * @param x2 the second x coordinate of the other segment 365: * @param y2 the second y coordinate of the other segment 366: * @return true if the segments intersect 367: * @see #linesIntersect(double, double, double, double, 368: * double, double, double, double) 369: */ 370: public boolean intersectsLine(double x1, double y1, double x2, double y2) 371: { 372: return linesIntersect(getX1(), getY1(), getX2(), getY2(), 373: x1, y1, x2, y2); 374: } 375: 376: /** 377: * Test if this line intersects the given line. 378: * 379: * @param l the other segment 380: * @return true if the segments intersect 381: * @throws NullPointerException if l is null 382: * @see #linesIntersect(double, double, double, double, 383: * double, double, double, double) 384: */ 385: public boolean intersectsLine(Line2D l) 386: { 387: return linesIntersect(getX1(), getY1(), getX2(), getY2(), 388: l.getX1(), l.getY1(), l.getX2(), l.getY2()); 389: } 390: 391: /** 392: * Measures the square of the shortest distance from the reference point 393: * to a point on the line segment. If the point is on the segment, the 394: * result will be 0. 395: * 396: * @param x1 the first x coordinate of the segment 397: * @param y1 the first y coordinate of the segment 398: * @param x2 the second x coordinate of the segment 399: * @param y2 the second y coordinate of the segment 400: * @param px the x coordinate of the point 401: * @param py the y coordinate of the point 402: * @return the square of the distance from the point to the segment 403: * @see #ptSegDist(double, double, double, double, double, double) 404: * @see #ptLineDistSq(double, double, double, double, double, double) 405: */ 406: public static double ptSegDistSq(double x1, double y1, double x2, double y2, 407: double px, double py) 408: { 409: double pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); 410: 411: double x, y; 412: if (pd2 == 0) 413: { 414: // Points are coincident. 415: x = x1; 416: y = y2; 417: } 418: else 419: { 420: double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2; 421: 422: if (u < 0) 423: { 424: // "Off the end" 425: x = x1; 426: y = y1; 427: } 428: else if (u > 1.0) 429: { 430: x = x2; 431: y = y2; 432: } 433: else 434: { 435: x = x1 + u * (x2 - x1); 436: y = y1 + u * (y2 - y1); 437: } 438: } 439: 440: return (x - px) * (x - px) + (y - py) * (y - py); 441: } 442: 443: /** 444: * Measures the shortest distance from the reference point to a point on 445: * the line segment. If the point is on the segment, the result will be 0. 446: * 447: * @param x1 the first x coordinate of the segment 448: * @param y1 the first y coordinate of the segment 449: * @param x2 the second x coordinate of the segment 450: * @param y2 the second y coordinate of the segment 451: * @param px the x coordinate of the point 452: * @param py the y coordinate of the point 453: * @return the distance from the point to the segment 454: * @see #ptSegDistSq(double, double, double, double, double, double) 455: * @see #ptLineDist(double, double, double, double, double, double) 456: */ 457: public static double ptSegDist(double x1, double y1, double x2, double y2, 458: double px, double py) 459: { 460: return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py)); 461: } 462: 463: /** 464: * Measures the square of the shortest distance from the reference point 465: * to a point on this line segment. If the point is on the segment, the 466: * result will be 0. 467: * 468: * @param px the x coordinate of the point 469: * @param py the y coordinate of the point 470: * @return the square of the distance from the point to the segment 471: * @see #ptSegDistSq(double, double, double, double, double, double) 472: */ 473: public double ptSegDistSq(double px, double py) 474: { 475: return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), px, py); 476: } 477: 478: /** 479: * Measures the square of the shortest distance from the reference point 480: * to a point on this line segment. If the point is on the segment, the 481: * result will be 0. 482: * 483: * @param p the point 484: * @return the square of the distance from the point to the segment 485: * @throws NullPointerException if p is null 486: * @see #ptSegDistSq(double, double, double, double, double, double) 487: */ 488: public double ptSegDistSq(Point2D p) 489: { 490: return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); 491: } 492: 493: /** 494: * Measures the shortest distance from the reference point to a point on 495: * this line segment. If the point is on the segment, the result will be 0. 496: * 497: * @param px the x coordinate of the point 498: * @param py the y coordinate of the point 499: * @return the distance from the point to the segment 500: * @see #ptSegDist(double, double, double, double, double, double) 501: */ 502: public double ptSegDist(double px, double py) 503: { 504: return ptSegDist(getX1(), getY1(), getX2(), getY2(), px, py); 505: } 506: 507: /** 508: * Measures the shortest distance from the reference point to a point on 509: * this line segment. If the point is on the segment, the result will be 0. 510: * 511: * @param p the point 512: * @return the distance from the point to the segment 513: * @throws NullPointerException if p is null 514: * @see #ptSegDist(double, double, double, double, double, double) 515: */ 516: public double ptSegDist(Point2D p) 517: { 518: return ptSegDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); 519: } 520: 521: /** 522: * Measures the square of the shortest distance from the reference point 523: * to a point on the infinite line extended from the segment. If the point 524: * is on the segment, the result will be 0. If the segment is length 0, 525: * the distance is to the common endpoint. 526: * 527: * @param x1 the first x coordinate of the segment 528: * @param y1 the first y coordinate of the segment 529: * @param x2 the second x coordinate of the segment 530: * @param y2 the second y coordinate of the segment 531: * @param px the x coordinate of the point 532: * @param py the y coordinate of the point 533: * @return the square of the distance from the point to the extended line 534: * @see #ptLineDist(double, double, double, double, double, double) 535: * @see #ptSegDistSq(double, double, double, double, double, double) 536: */ 537: public static double ptLineDistSq(double x1, double y1, double x2, double y2, 538: double px, double py) 539: { 540: double pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); 541: 542: double x, y; 543: if (pd2 == 0) 544: { 545: // Points are coincident. 546: x = x1; 547: y = y2; 548: } 549: else 550: { 551: double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2; 552: x = x1 + u * (x2 - x1); 553: y = y1 + u * (y2 - y1); 554: } 555: 556: return (x - px) * (x - px) + (y - py) * (y - py); 557: } 558: 559: /** 560: * Measures the shortest distance from the reference point to a point on 561: * the infinite line extended from the segment. If the point is on the 562: * segment, the result will be 0. If the segment is length 0, the distance 563: * is to the common endpoint. 564: * 565: * @param x1 the first x coordinate of the segment 566: * @param y1 the first y coordinate of the segment 567: * @param x2 the second x coordinate of the segment 568: * @param y2 the second y coordinate of the segment 569: * @param px the x coordinate of the point 570: * @param py the y coordinate of the point 571: * @return the distance from the point to the extended line 572: * @see #ptLineDistSq(double, double, double, double, double, double) 573: * @see #ptSegDist(double, double, double, double, double, double) 574: */ 575: public static double ptLineDist(double x1, double y1, 576: double x2, double y2, 577: double px, double py) 578: { 579: return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py)); 580: } 581: 582: /** 583: * Measures the square of the shortest distance from the reference point 584: * to a point on the infinite line extended from this segment. If the point 585: * is on the segment, the result will be 0. If the segment is length 0, 586: * the distance is to the common endpoint. 587: * 588: * @param px the x coordinate of the point 589: * @param py the y coordinate of the point 590: * @return the square of the distance from the point to the extended line 591: * @see #ptLineDistSq(double, double, double, double, double, double) 592: */ 593: public double ptLineDistSq(double px, double py) 594: { 595: return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), px, py); 596: } 597: 598: /** 599: * Measures the square of the shortest distance from the reference point 600: * to a point on the infinite line extended from this segment. If the point 601: * is on the segment, the result will be 0. If the segment is length 0, 602: * the distance is to the common endpoint. 603: * 604: * @param p the point 605: * @return the square of the distance from the point to the extended line 606: * @throws NullPointerException if p is null 607: * @see #ptLineDistSq(double, double, double, double, double, double) 608: */ 609: public double ptLineDistSq(Point2D p) 610: { 611: return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), 612: p.getX(), p.getY()); 613: } 614: 615: /** 616: * Measures the shortest distance from the reference point to a point on 617: * the infinite line extended from this segment. If the point is on the 618: * segment, the result will be 0. If the segment is length 0, the distance 619: * is to the common endpoint. 620: * 621: * @param px the x coordinate of the point 622: * @param py the y coordinate of the point 623: * @return the distance from the point to the extended line 624: * @see #ptLineDist(double, double, double, double, double, double) 625: */ 626: public double ptLineDist(double px, double py) 627: { 628: return ptLineDist(getX1(), getY1(), getX2(), getY2(), px, py); 629: } 630: 631: /** 632: * Measures the shortest distance from the reference point to a point on 633: * the infinite line extended from this segment. If the point is on the 634: * segment, the result will be 0. If the segment is length 0, the distance 635: * is to the common endpoint. 636: * 637: * @param p the point 638: * @return the distance from the point to the extended line 639: * @throws NullPointerException if p is null 640: * @see #ptLineDist(double, double, double, double, double, double) 641: */ 642: public double ptLineDist(Point2D p) 643: { 644: return ptLineDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); 645: } 646: 647: /** 648: * Test if a point is contained inside the line. Since a line has no area, 649: * this returns false. 650: * 651: * @param x the x coordinate 652: * @param y the y coordinate 653: * @return false; the line does not contain points 654: */ 655: public boolean contains(double x, double y) 656: { 657: return false; 658: } 659: 660: /** 661: * Test if a point is contained inside the line. Since a line has no area, 662: * this returns false. 663: * 664: * @param p the point 665: * @return false; the line does not contain points 666: */ 667: public boolean contains(Point2D p) 668: { 669: return false; 670: } 671: 672: /** 673: * Tests if this line intersects the interior of the specified rectangle. 674: * 675: * @param x the x coordinate of the rectangle 676: * @param y the y coordinate of the rectangle 677: * @param w the width of the rectangle 678: * @param h the height of the rectangle 679: * @return true if the line intersects the rectangle 680: */ 681: public boolean intersects(double x, double y, double w, double h) 682: { 683: if (w <= 0 || h <= 0) 684: return false; 685: double x1 = getX1(); 686: double y1 = getY1(); 687: double x2 = getX2(); 688: double y2 = getY2(); 689: 690: if (x1 >= x && x1 <= x + w && y1 >= y && y1 <= y + h) 691: return true; 692: if (x2 >= x && x2 <= x + w && y2 >= y && y2 <= y + h) 693: return true; 694: 695: double x3 = x + w; 696: double y3 = y + h; 697: 698: return (linesIntersect(x1, y1, x2, y2, x, y, x, y3) 699: || linesIntersect(x1, y1, x2, y2, x, y3, x3, y3) 700: || linesIntersect(x1, y1, x2, y2, x3, y3, x3, y) 701: || linesIntersect(x1, y1, x2, y2, x3, y, x, y)); 702: } 703: 704: /** 705: * Tests if this line intersects the interior of the specified rectangle. 706: * 707: * @param r the rectangle 708: * @return true if the line intersects the rectangle 709: * @throws NullPointerException if r is null 710: */ 711: public boolean intersects(Rectangle2D r) 712: { 713: return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); 714: } 715: 716: /** 717: * Tests if the line contains a rectangle. Since lines have no area, this 718: * always returns false. 719: * 720: * @param x the x coordinate of the rectangle 721: * @param y the y coordinate of the rectangle 722: * @param w the width of the rectangle 723: * @param h the height of the rectangle 724: * @return false; the line does not contain points 725: */ 726: public boolean contains(double x, double y, double w, double h) 727: { 728: return false; 729: } 730: 731: /** 732: * Tests if the line contains a rectangle. Since lines have no area, this 733: * always returns false. 734: * 735: * @param r the rectangle 736: * @return false; the line does not contain points 737: */ 738: public boolean contains(Rectangle2D r) 739: { 740: return false; 741: } 742: 743: /** 744: * Gets a bounding box (not necessarily minimal) for this line. 745: * 746: * @return the integer bounding box 747: * @see #getBounds2D() 748: */ 749: public Rectangle getBounds() 750: { 751: return getBounds2D().getBounds(); 752: } 753: 754: /** 755: * Return a path iterator, possibly applying a transform on the result. This 756: * iterator is not threadsafe. 757: * 758: * @param at the transform, or null 759: * @return a new path iterator 760: */ 761: public PathIterator getPathIterator(final AffineTransform at) 762: { 763: return new PathIterator() 764: { 765: /** Current coordinate. */ 766: private int current = 0; 767: 768: public int getWindingRule() 769: { 770: return WIND_NON_ZERO; 771: } 772: 773: public boolean isDone() 774: { 775: return current >= 2; 776: } 777: 778: public void next() 779: { 780: current++; 781: } 782: 783: public int currentSegment(float[] coords) 784: { 785: int result; 786: switch (current) 787: { 788: case 0: 789: coords[0] = (float) getX1(); 790: coords[1] = (float) getY1(); 791: result = SEG_MOVETO; 792: break; 793: case 1: 794: coords[0] = (float) getX2(); 795: coords[1] = (float) getY2(); 796: result = SEG_LINETO; 797: break; 798: default: 799: throw new NoSuchElementException("line iterator out of bounds"); 800: } 801: if (at != null) 802: at.transform(coords, 0, coords, 0, 1); 803: return result; 804: } 805: 806: public int currentSegment(double[] coords) 807: { 808: int result; 809: switch (current) 810: { 811: case 0: 812: coords[0] = getX1(); 813: coords[1] = getY1(); 814: result = SEG_MOVETO; 815: break; 816: case 1: 817: coords[0] = getX2(); 818: coords[1] = getY2(); 819: result = SEG_LINETO; 820: break; 821: default: 822: throw new NoSuchElementException("line iterator out of bounds"); 823: } 824: if (at != null) 825: at.transform(coords, 0, coords, 0, 1); 826: return result; 827: } 828: }; 829: } 830: 831: /** 832: * Return a flat path iterator, possibly applying a transform on the result. 833: * This iterator is not threadsafe. 834: * 835: * @param at the transform, or null 836: * @param flatness ignored, since lines are already flat 837: * @return a new path iterator 838: * @see #getPathIterator(AffineTransform) 839: */ 840: public PathIterator getPathIterator(AffineTransform at, double flatness) 841: { 842: return getPathIterator(at); 843: } 844: 845: /** 846: * Create a new line of the same run-time type with the same contents as 847: * this one. 848: * 849: * @return the clone 850: * 851: * @exception OutOfMemoryError If there is not enough memory available. 852: * 853: * @since 1.2 854: */ 855: public Object clone() 856: { 857: try 858: { 859: return super.clone(); 860: } 861: catch (CloneNotSupportedException e) 862: { 863: throw (Error) new InternalError().initCause(e); // Impossible 864: } 865: } 866: 867: /** 868: * This class defines a point in <code>double</code> precision. 869: * 870: * @author Eric Blake (ebb9@email.byu.edu) 871: * @since 1.2 872: * @status updated to 1.4 873: */ 874: public static class Double extends Line2D 875: { 876: /** The x coordinate of the first point. */ 877: public double x1; 878: 879: /** The y coordinate of the first point. */ 880: public double y1; 881: 882: /** The x coordinate of the second point. */ 883: public double x2; 884: 885: /** The y coordinate of the second point. */ 886: public double y2; 887: 888: /** 889: * Construct the line segment (0,0)->(0,0). 890: */ 891: public Double() 892: { 893: } 894: 895: /** 896: * Construct the line segment with the specified points. 897: * 898: * @param x1 the x coordinate of the first point 899: * @param y1 the y coordinate of the first point 900: * @param x2 the x coordinate of the second point 901: * @param y2 the y coordinate of the second point 902: */ 903: public Double(double x1, double y1, double x2, double y2) 904: { 905: this.x1 = x1; 906: this.y1 = y1; 907: this.x2 = x2; 908: this.y2 = y2; 909: } 910: 911: /** 912: * Construct the line segment with the specified points. 913: * 914: * @param p1 the first point 915: * @param p2 the second point 916: * @throws NullPointerException if either point is null 917: */ 918: public Double(Point2D p1, Point2D p2) 919: { 920: x1 = p1.getX(); 921: y1 = p1.getY(); 922: x2 = p2.getX(); 923: y2 = p2.getY(); 924: } 925: 926: /** 927: * Return the x coordinate of the first point. 928: * 929: * @return the value of x1 930: */ 931: public double getX1() 932: { 933: return x1; 934: } 935: 936: /** 937: * Return the y coordinate of the first point. 938: * 939: * @return the value of y1 940: */ 941: public double getY1() 942: { 943: return y1; 944: } 945: 946: /** 947: * Return the first point. 948: * 949: * @return the point (x1,y1) 950: */ 951: public Point2D getP1() 952: { 953: return new Point2D.Double(x1, y1); 954: } 955: 956: /** 957: * Return the x coordinate of the second point. 958: * 959: * @return the value of x2 960: */ 961: public double getX2() 962: { 963: return x2; 964: } 965: 966: /** 967: * Return the y coordinate of the second point. 968: * 969: * @return the value of y2 970: */ 971: public double getY2() 972: { 973: return y2; 974: } 975: 976: /** 977: * Return the second point. 978: * 979: * @return the point (x2,y2) 980: */ 981: public Point2D getP2() 982: { 983: return new Point2D.Double(x2, y2); 984: } 985: 986: /** 987: * Set this line to the given points. 988: * 989: * @param x1 the new x coordinate of the first point 990: * @param y1 the new y coordinate of the first point 991: * @param x2 the new x coordinate of the second point 992: * @param y2 the new y coordinate of the second point 993: */ 994: public void setLine(double x1, double y1, double x2, double y2) 995: { 996: this.x1 = x1; 997: this.y1 = y1; 998: this.x2 = x2; 999: this.y2 = y2; 1000: } 1001: 1002: /** 1003: * Return the exact bounds of this line segment. 1004: * 1005: * @return the bounding box 1006: */ 1007: public Rectangle2D getBounds2D() 1008: { 1009: double x = Math.min(x1, x2); 1010: double y = Math.min(y1, y2); 1011: double w = Math.abs(x1 - x2); 1012: double h = Math.abs(y1 - y2); 1013: return new Rectangle2D.Double(x, y, w, h); 1014: } 1015: } // class Double 1016: 1017: /** 1018: * This class defines a point in <code>float</code> precision. 1019: * 1020: * @author Eric Blake (ebb9@email.byu.edu) 1021: * @since 1.2 1022: * @status updated to 1.4 1023: */ 1024: public static class Float extends Line2D 1025: { 1026: /** The x coordinate of the first point. */ 1027: public float x1; 1028: 1029: /** The y coordinate of the first point. */ 1030: public float y1; 1031: 1032: /** The x coordinate of the second point. */ 1033: public float x2; 1034: 1035: /** The y coordinate of the second point. */ 1036: public float y2; 1037: 1038: /** 1039: * Construct the line segment (0,0)->(0,0). 1040: */ 1041: public Float() 1042: { 1043: } 1044: 1045: /** 1046: * Construct the line segment with the specified points. 1047: * 1048: * @param x1 the x coordinate of the first point 1049: * @param y1 the y coordinate of the first point 1050: * @param x2 the x coordinate of the second point 1051: * @param y2 the y coordinate of the second point 1052: */ 1053: public Float(float x1, float y1, float x2, float y2) 1054: { 1055: this.x1 = x1; 1056: this.y1 = y1; 1057: this.x2 = x2; 1058: this.y2 = y2; 1059: } 1060: 1061: /** 1062: * Construct the line segment with the specified points. 1063: * 1064: * @param p1 the first point 1065: * @param p2 the second point 1066: * @throws NullPointerException if either point is null 1067: */ 1068: public Float(Point2D p1, Point2D p2) 1069: { 1070: x1 = (float) p1.getX(); 1071: y1 = (float) p1.getY(); 1072: x2 = (float) p2.getX(); 1073: y2 = (float) p2.getY(); 1074: } 1075: 1076: /** 1077: * Return the x coordinate of the first point. 1078: * 1079: * @return the value of x1 1080: */ 1081: public double getX1() 1082: { 1083: return x1; 1084: } 1085: 1086: /** 1087: * Return the y coordinate of the first point. 1088: * 1089: * @return the value of y1 1090: */ 1091: public double getY1() 1092: { 1093: return y1; 1094: } 1095: 1096: /** 1097: * Return the first point. 1098: * 1099: * @return the point (x1,y1) 1100: */ 1101: public Point2D getP1() 1102: { 1103: return new Point2D.Float(x1, y1); 1104: } 1105: 1106: /** 1107: * Return the x coordinate of the second point. 1108: * 1109: * @return the value of x2 1110: */ 1111: public double getX2() 1112: { 1113: return x2; 1114: } 1115: 1116: /** 1117: * Return the y coordinate of the second point. 1118: * 1119: * @return the value of y2 1120: */ 1121: public double getY2() 1122: { 1123: return y2; 1124: } 1125: 1126: /** 1127: * Return the second point. 1128: * 1129: * @return the point (x2,y2) 1130: */ 1131: public Point2D getP2() 1132: { 1133: return new Point2D.Float(x2, y2); 1134: } 1135: 1136: /** 1137: * Set this line to the given points. 1138: * 1139: * @param x1 the new x coordinate of the first point 1140: * @param y1 the new y coordinate of the first point 1141: * @param x2 the new x coordinate of the second point 1142: * @param y2 the new y coordinate of the second point 1143: */ 1144: public void setLine(double x1, double y1, double x2, double y2) 1145: { 1146: this.x1 = (float) x1; 1147: this.y1 = (float) y1; 1148: this.x2 = (float) x2; 1149: this.y2 = (float) y2; 1150: } 1151: 1152: /** 1153: * Set this line to the given points. 1154: * 1155: * @param x1 the new x coordinate of the first point 1156: * @param y1 the new y coordinate of the first point 1157: * @param x2 the new x coordinate of the second point 1158: * @param y2 the new y coordinate of the second point 1159: */ 1160: public void setLine(float x1, float y1, float x2, float y2) 1161: { 1162: this.x1 = x1; 1163: this.y1 = y1; 1164: this.x2 = x2; 1165: this.y2 = y2; 1166: } 1167: 1168: /** 1169: * Return the exact bounds of this line segment. 1170: * 1171: * @return the bounding box 1172: */ 1173: public Rectangle2D getBounds2D() 1174: { 1175: float x = Math.min(x1, x2); 1176: float y = Math.min(y1, y2); 1177: float w = Math.abs(x1 - x2); 1178: float h = Math.abs(y1 - y2); 1179: return new Rectangle2D.Float(x, y, w, h); 1180: } 1181: } // class Float 1182: } // class Line2D