001 /* Line2D.java -- represents a line in 2-D space, plus operations on a line
002 Copyright (C) 2000, 2001, 2002 Free Software Foundation
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038 package java.awt.geom;
039
040 import java.awt.Rectangle;
041 import java.awt.Shape;
042 import java.util.NoSuchElementException;
043
044 /**
045 * Represents a directed line bewteen two points in (x,y) Cartesian space.
046 * Remember, on-screen graphics have increasing x from left-to-right, and
047 * increasing y from top-to-bottom. The storage is left to subclasses.
048 *
049 * @author Tom Tromey (tromey@cygnus.com)
050 * @author Eric Blake (ebb9@email.byu.edu)
051 * @author David Gilbert
052 * @since 1.2
053 * @status updated to 1.4
054 */
055 public abstract class Line2D implements Shape, Cloneable
056 {
057 /**
058 * The default constructor.
059 */
060 protected Line2D()
061 {
062 }
063
064 /**
065 * Return the x coordinate of the first point.
066 *
067 * @return the starting x coordinate
068 */
069 public abstract double getX1();
070
071 /**
072 * Return the y coordinate of the first point.
073 *
074 * @return the starting y coordinate
075 */
076 public abstract double getY1();
077
078 /**
079 * Return the first point.
080 *
081 * @return the starting point
082 */
083 public abstract Point2D getP1();
084
085 /**
086 * Return the x coordinate of the second point.
087 *
088 * @return the ending x coordinate
089 */
090 public abstract double getX2();
091
092 /**
093 * Return the y coordinate of the second point.
094 *
095 * @return the ending y coordinate
096 */
097 public abstract double getY2();
098
099 /**
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