Source for java.awt.geom.Line2D

   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)-&gt;(x2,y2) intersects the line segment
 286:    * (x3,y3)-&gt;(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)-&gt;(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)-&gt;(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)-&gt;(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