View Javadoc

1   /* File StraightLine2D.java 
2    *
3    * Project : Java Geometry Library
4    *
5    * ===========================================
6    * 
7    * This library is free software; you can redistribute it and/or modify it 
8    * under the terms of the GNU Lesser General Public License as published by
9    * the Free Software Foundation, either version 2.1 of the License, or (at
10   * your option) any later version.
11   *
12   * This library is distributed in the hope that it will be useful, but 
13   * WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
14   * or FITNESS FOR A PARTICULAR PURPOSE.
15   *
16   * See the GNU Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public License
19   * along with this library. if not, write to :
20   * The Free Software Foundation, Inc., 59 Temple Place, Suite 330,
21   * Boston, MA 02111-1307, USA.
22   */
23  
24  // package
25  
26  package math.geom2d.line;
27  
28  //Imports
29  
30  import java.awt.Graphics2D;
31  import java.awt.geom.GeneralPath;
32  import java.util.ArrayList;
33  import java.util.Collection;
34  
35  import math.geom2d.AffineTransform2D;
36  import math.geom2d.Angle2D;
37  import math.geom2d.Box2D;
38  import math.geom2d.Point2D;
39  import math.geom2d.Shape2D;
40  import math.geom2d.UnboundedShapeException;
41  import math.geom2d.Vector2D;
42  import math.geom2d.circulinear.CircleLine2D;
43  import math.geom2d.conic.Circle2D;
44  import math.geom2d.domain.ContinuousBoundary2D;
45  import math.geom2d.domain.Domain2D;
46  import math.geom2d.domain.GenericDomain2D;
47  import math.geom2d.domain.SmoothBoundary2D;
48  import math.geom2d.polygon.Polyline2D;
49  import math.geom2d.transform.CircleInversion2D;
50  
51  /**
52   * Implementation of a straight line. Such a line can be constructed using two
53   * points, a point and a parallel line or straight object, or with coefficient
54   * of the Cartesian equation.
55   */
56  public class StraightLine2D extends AbstractLine2D implements
57          SmoothBoundary2D, Cloneable, CircleLine2D {
58  
59      // ===================================================================
60      // constants
61  
62  	/**
63  	 * Auto-generated.
64  	 */
65  	private static final long serialVersionUID = 7121417900301006740L;
66  	
67      // ===================================================================
68      // class variables
69  
70      // ===================================================================
71      // static methods
72  
73  	/**
74       * Creates a straight line going through a point and with a given angle.
75       */
76      public final static StraightLine2D create(java.awt.geom.Point2D point,
77              double angle) {
78          return new StraightLine2D(point.getX(), point.getY(), Math.cos(angle),
79                  Math.sin(angle));
80      }
81  
82      /**
83       * Creates a straight line through 2 points.
84       */
85      public final static StraightLine2D create(java.awt.geom.Point2D p1,
86              java.awt.geom.Point2D p2) {
87          return new StraightLine2D(p1, p2);
88      }
89  
90      /**
91       * Creates a straight line through a point and with a given direction
92       * vector.
93       */
94      public final static StraightLine2D create(java.awt.geom.Point2D origin,
95              Vector2D direction) {
96          return new StraightLine2D(origin, direction);
97      }
98  
99      /**
100      * @deprecated use create(Point2D, Point2D) instead
101      */
102     @Deprecated
103     public final static StraightLine2D createStraightLine2D(
104             java.awt.geom.Point2D p1, java.awt.geom.Point2D p2) {
105         return new StraightLine2D(p1, p2);
106     }
107 
108     /**
109      * Creates a median between 2 points.
110      * 
111      * @param p1 one point
112      * @param p2 another point
113      * @return the median of points p1 and p2
114      * @since 0.6.3
115      */
116     public final static StraightLine2D createMedian(java.awt.geom.Point2D p1,
117             java.awt.geom.Point2D p2) {
118         Point2D mid = Point2D.midPoint(p1, p2);
119         StraightLine2D line = StraightLine2D.create(p1, p2);
120         return StraightLine2D.createPerpendicular(line, mid);
121     }
122 
123     /**
124      * Creates a median between 2 points.
125      * 
126      * @param p1 one point
127      * @param p2 another point
128      * @return the median of points p1 and p2
129      * @deprecated since 0.6.3, use createMedian instead
130      */
131     @Deprecated
132     public final static StraightLine2D createMedian2D(java.awt.geom.Point2D p1,
133             java.awt.geom.Point2D p2) {
134         Point2D mid = Point2D.midPoint(p1, p2);
135         StraightLine2D line = StraightLine2D.create(p1, p2);
136         return StraightLine2D.createPerpendicular(line, mid);
137     }
138 
139     /**
140      * Return a new Straight line going through the given point, and with the
141      * specified direction vector.
142      * 
143      * @deprecated since 0.6.3, use create() instead
144      */
145     @Deprecated
146     public final static StraightLine2D createStraightLine2D(
147             java.awt.geom.Point2D point, double dx, double dy) {
148         return new StraightLine2D(point, dx, dy);
149     }
150 
151     /**
152      * Return a new Straight line, parallel to another straight object (ray,
153      * straight line or edge), and going through the given point.
154      * 
155      * @since 0.6.3
156      */
157     public final static StraightLine2D createParallel(LinearShape2D line,
158             java.awt.geom.Point2D point) {
159         return new StraightLine2D(line, point);
160     }
161 
162     /**
163      * Return a new Straight line, parallel to another straight object (ray,
164      * straight line or edge), and going through the given point.
165      * 
166      * @deprecated since 0.6.3, use createParallel() instead
167      */
168     @Deprecated
169     public final static StraightLine2D createParallelLine2D(LinearShape2D line,
170             java.awt.geom.Point2D point) {
171         return new StraightLine2D(line, point);
172     }
173 
174     /**
175      * Return a new Straight line, parallel to another straight object (ray,
176      * straight line or edge), and going through the given point.
177      * 
178      * @since 0.6.3
179      */
180     public final static StraightLine2D createParallel(LinearShape2D linear,
181             double d) {
182         StraightLine2D line = linear.getSupportingLine();
183         double dd = Math.hypot(line.dx, line.dy);
184         return new StraightLine2D(line.x0+line.dy*d/dd, line.y0-line.dx*d/dd,
185                 line.dx, line.dy);
186     }
187 
188     /**
189      * Return a new Straight line, parallel to another straight object (ray,
190      * straight line or edge), and going through the given point.
191      * 
192      * @deprecated since 0.6.3, use createParallel() instead
193      */
194     @Deprecated
195     public final static StraightLine2D createParallelLine2D(
196             LinearShape2D linear, double d) {
197         StraightLine2D line = linear.getSupportingLine();
198         double dd = Math.hypot(line.dx, line.dy);
199         return new StraightLine2D(line.x0+line.dy*d/dd, line.y0-line.dx*d/dd,
200                 line.dx, line.dy);
201     }
202 
203     /**
204      * Return a new Straight line, perpendicular to a straight object (ray,
205      * straight line or edge), and going through the given point.
206      * 
207      * @since 0.6.3
208      */
209     public final static StraightLine2D createPerpendicular(
210             LinearShape2D linear, Point2D point) {
211         StraightLine2D line = linear.getSupportingLine();
212         return new StraightLine2D(point, -line.dy, line.dx);
213     }
214 
215     /**
216      * Return a new Straight line, parallel to another straight object (ray,
217      * straight line or edge), and going through the given point.
218      * 
219      * @deprecated since 0.6.3, use createPerpendicular instead
220      */
221     @Deprecated
222     public final static StraightLine2D createOrthogonalLine2D(
223             LinearShape2D linear, Point2D point) {
224         StraightLine2D line = linear.getSupportingLine();
225         return new StraightLine2D(point, -line.dy, line.dx);
226     }
227 
228     /**
229      * Return a new Straight line, with the given coefficient of the cartesian
230      * equation (a*x + b*y + c = 0).
231      */
232     public final static StraightLine2D createCartesian(double a, double b,
233             double c) {
234         return new StraightLine2D(a, b, c);
235     }
236 
237     /**
238      * Return a new Straight line, with the given coefficient of the cartesian
239      * equation (a*x + b*y + c = 0).
240      * 
241      * @deprecated since 0.6.3, use createCartesian instead
242      */
243     @Deprecated
244     public final static StraightLine2D createCartesianLine2D(double a,
245             double b, double c) {
246         return new StraightLine2D(a, b, c);
247     }
248 
249     /**
250      * Compute the intersection point of the two (infinite) lines going through
251      * p1 and p2 for the first one, and p3 and p4 for the second one. Returns
252      * null if two lines are parallel.
253      */
254     public final static Point2D getIntersection(java.awt.geom.Point2D p1,
255             java.awt.geom.Point2D p2, java.awt.geom.Point2D p3,
256             java.awt.geom.Point2D p4) {
257         StraightLine2D line1 = new StraightLine2D(p1, p2);
258         StraightLine2D line2 = new StraightLine2D(p3, p4);
259         return line1.getIntersection(line2);
260     }
261 
262     // ===================================================================
263     // constructors
264 
265     /** Empty constructor: a straight line corresponding to horizontal axis. */
266     public StraightLine2D() {
267         this(0, 0, 1, 0);
268     }
269 
270     /** Define a new Straight line going through the two given points. */
271     public StraightLine2D(java.awt.geom.Point2D point1,
272             java.awt.geom.Point2D point2) {
273         this(point1, new Vector2D(point1, point2));
274     }
275 
276     /**
277      * Define a new Straight line going through the given point, and with the
278      * specified direction vector.
279      */
280     public StraightLine2D(java.awt.geom.Point2D point, Vector2D direction) {
281         this(point.getX(), point.getY(), direction.getX(), direction.getY());
282     }
283 
284     /**
285      * Define a new Straight line going through the given point, and with the
286      * specified direction vector.
287      */
288     public StraightLine2D(java.awt.geom.Point2D point, double dx, double dy) {
289         this(point.getX(), point.getY(), dx, dy);
290     }
291 
292     /**
293      * Define a new Straight line going through the given point, and with the
294      * specified direction given by angle.
295      */
296     public StraightLine2D(java.awt.geom.Point2D point, double angle) {
297         this(point.getX(), point.getY(), Math.cos(angle), Math.sin(angle));
298     }
299 
300     /**
301      * Define a new Straight line at the same position and with the same
302      * direction than an other straight object (line, edge or ray).
303      */
304     public StraightLine2D(LinearShape2D line) {
305         super(line);
306     }
307 
308     /**
309      * Define a new Straight line going through the point (xp, yp) and with the
310      * direction dx, dy.
311      */
312     public StraightLine2D(double xp, double yp, double dx, double dy) {
313         super(xp, yp, dx, dy);
314     }
315 
316     /**
317      * Define a new Straight line, parallel to another straigth object (ray,
318      * straight line or edge), and going through the given point.
319      */
320     public StraightLine2D(LinearShape2D line, java.awt.geom.Point2D point) {
321         this(point, line.getVector());
322     }
323 
324     /**
325      * Define a new straight line, from the coefficients of the cartesian
326      * equation. The starting point of the line is then the point of the line
327      * closest to the origin, and the direction vector has unit norm.
328      */
329     public StraightLine2D(double a, double b, double c) {
330         this(0, 0, 1, 0);
331         double d = a*a+b*b;
332         x0 = -a*c/d;
333         y0 = -b*c/d;
334         double theta = Math.atan2(-a, b);
335         dx = Math.cos(theta);
336         dy = Math.sin(theta);
337     }
338 
339     // ===================================================================
340     // methods specific to StraightLine2D
341 
342     /**
343      * @deprecated lines will become imutable in a future release
344      */
345     @Deprecated
346     public void setLine(double x0, double y0, double dx, double dy) {
347         this.x0 = x0;
348         this.y0 = y0;
349         this.dx = dx;
350         this.dy = dy;
351     }
352 
353     /**
354      * @deprecated lines will become imutable in a future release
355      */
356     @Deprecated
357     public void setPoints(double x1, double y1, double x2, double y2) {
358         this.x0 = x1;
359         this.y0 = y1;
360         this.dx = x2-x1;
361         this.dy = y2-y1;
362     }
363 
364     /**
365      * @deprecated lines will become imutable in a future release
366      */
367     @Deprecated
368     public void setLine(java.awt.geom.Point2D p1, java.awt.geom.Point2D p2) {
369         this.x0 = p1.getX();
370         this.y0 = p1.getY();
371         this.dx = p2.getX()-x0;
372         this.dy = p2.getY()-y0;
373     }
374 
375     /**
376      * @deprecated lines will become imutable in a future release
377      */
378     @Deprecated
379     public void setLine(LinearShape2D linear) {
380         StraightLine2D line = linear.getSupportingLine();
381         this.x0 = line.x0;
382         this.y0 = line.y0;
383         this.dx = line.dx;
384         this.dy = line.dy;
385     }
386 
387     /**
388      * @deprecated lines will become imutable in a future release
389      */
390     @Deprecated
391     public void setCartesianEquation(double a, double b, double c) {
392         dx = -b;
393         dy = a;
394         x0 = -a*c/(a*a+b*b);
395         y0 = -b*c/(a*a+b*b);
396     }
397 
398     /**
399      * Returns a new Straight line, parallel to another straight object (ray,
400      * straight line or edge), and going through the given point.
401      */
402     public StraightLine2D getParallel(java.awt.geom.Point2D point) {
403         return new StraightLine2D(point, dx, dy);
404     }
405 
406     // ===================================================================
407     // methods implementing the CirculinearCurve2D interface
408 
409    /**
410      * Return the parallel line located at a distance d. Distance is positive in
411      * the 'right' side of the line (outside of the limiting half-plane), and
412      * negative in the 'left' of the line.
413      */
414     public StraightLine2D getParallel(double d) {
415         double dd = Math.sqrt(dx*dx+dy*dy);
416         return new StraightLine2D(x0+dy*d/dd, y0-dx*d/dd, dx, dy);
417     }
418 
419     /**
420      * Return a new Straight line, parallel to another straigth object (ray,
421      * straight line or edge), and going through the given point.
422      */
423     @Override
424     public StraightLine2D getPerpendicular(Point2D point) {
425         return new StraightLine2D(point, -dy, dx);
426     }
427     
428 	/* (non-Javadoc)
429 	 * @see math.geom2d.circulinear.CirculinearCurve2D#transform(math.geom2d.transform.CircleInversion2D)
430 	 */
431 	@Override
432 	public CircleLine2D transform(CircleInversion2D inv) {
433 		// Extract inversion parameters
434         Point2D center 	= inv.getCenter();
435         double r 		= inv.getRadius();
436         
437         Point2D po 	= this.getProjectedPoint(center);
438         double d 	= this.getDistance(po);
439 
440         // Degenerate case of a point belonging to the line:
441         // the transform is the line itself.
442         if (Math.abs(d)<Shape2D.ACCURACY){
443         	return new StraightLine2D(this);
444         }
445         
446         // angle from center to line
447         double angle = Angle2D.getHorizontalAngle(center, po);
448 
449         // center of transformed circle
450         double r2 	= r*r/d/2;
451         Point2D c2 	= Point2D.createPolar(center, r2, angle);
452 
453         // choose direction of circle arc
454         boolean direct = !this.isInside(center);
455         
456         // return the created circle
457         return new Circle2D(c2, r2, direct);
458     }
459 	
460 
461     // ===================================================================
462     // methods specific to Boundary2D interface
463 
464     public Collection<ContinuousBoundary2D> getBoundaryCurves() {
465         ArrayList<ContinuousBoundary2D> list = new ArrayList<ContinuousBoundary2D>(
466                 1);
467         list.add(this);
468         return list;
469     }
470 
471     public Domain2D getDomain() {
472         return new GenericDomain2D(this);
473     }
474 
475     public void fill(Graphics2D g2) {
476         g2.fill(this.getGeneralPath());
477     }
478 
479     // ===================================================================
480     // methods specific to OrientedCurve2D interface
481 
482     @Override
483     public double getWindingAngle(java.awt.geom.Point2D point) {
484 
485         double angle1 = Angle2D.getHorizontalAngle(-dx, -dy);
486         double angle2 = Angle2D.getHorizontalAngle(dx, dy);
487 
488         if (this.isInside(point)) {
489             if (angle2>angle1)
490                 return angle2-angle1;
491             else
492                 return 2*Math.PI-angle1+angle2;
493         } else {
494             if (angle2>angle1)
495                 return angle2-angle1-2*Math.PI;
496             else
497                 return angle2-angle1;
498         }
499     }
500 
501     
502     // ===================================================================
503     // methods implementing the ContinuousCurve2D interface
504 
505     /**
506      * Throws an exception when called.
507      */
508 	@Override
509     public Polyline2D getAsPolyline(int n) {
510         throw new UnboundedShapeException(this);
511     }
512 
513     
514     // ===================================================================
515     // methods implementing the Curve2D interface
516 
517     /** Throws an infiniteShapeException */
518 	@Override
519     public Point2D getFirstPoint() {
520         throw new UnboundedShapeException(this);
521     }
522 
523 	/** Throws an infiniteShapeException */
524 	@Override
525 	public Point2D getLastPoint() {
526 		throw new UnboundedShapeException(this);
527 	}
528 
529     /** Returns an empty list of points. */
530 	@Override
531     public Collection<Point2D> getSingularPoints() {
532         return new ArrayList<Point2D>(0);
533     }
534 
535     /** Returns false, whatever the position. */
536 	@Override
537     public boolean isSingular(double pos) {
538         return false;
539     }
540 
541     /**
542      * Returns the parameter of the first point of the line, which is always
543      * Double.NEGATIVE_INFINITY.
544      */
545     public double getT0() {
546         return Double.NEGATIVE_INFINITY;
547     }
548 
549     /**
550      * Returns the parameter of the last point of the line, which is always
551      * Double.POSITIVE_INFINITY.
552      */
553     public double getT1() {
554         return Double.POSITIVE_INFINITY;
555     }
556 
557     /**
558      * Gets the point specified with the parametric representation of the line.
559      */
560     public Point2D getPoint(double t) {
561         return new Point2D(x0+dx*t, y0+dy*t);
562     }
563 
564     /**
565      * Need to override to cast the type.
566      */
567     @Override
568     public Collection<? extends StraightLine2D> getContinuousCurves() {
569         ArrayList<StraightLine2D> list = 
570         	new ArrayList<StraightLine2D>(1);
571         list.add(this);
572         return list;
573     }
574 
575     /**
576      * Returns the straight line with same origin but with opposite direction
577      * vector.
578      */
579     public StraightLine2D getReverseCurve() {
580         return new StraightLine2D(this.x0, this.y0, -this.dx, -this.dy);
581     }
582 
583     public GeneralPath appendPath(GeneralPath path) {
584         throw new UnboundedShapeException(this);
585     }
586 
587     // ===================================================================
588     // methods implementing the Shape2D interface
589 
590     /** Always returns false, because a line is not bounded. */
591     public boolean isBounded() {
592         return false;
593     }
594 
595     /**
596      * Returns the distance of the point (x, y) to this straight line.
597      */
598     @Override
599     public double getDistance(double x, double y) {
600         Point2D proj = super.getProjectedPoint(x, y);
601         return proj.distance(x, y);
602     }
603 
604     public Box2D getBoundingBox() {
605         if (Math.abs(dx)<0)
606             return new Box2D(
607                     x0, x0, 
608                     Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
609         if (Math.abs(dy)<0)
610             return new Box2D(
611                     Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 
612                     x0, y0);
613 
614         return new Box2D(
615                 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
616                 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
617     }
618 
619     /**
620      * Returns the transformed line. The result is still a StraightLine2D.
621      */
622     @Override
623     public StraightLine2D transform(AffineTransform2D trans) {
624         double[] tab = trans.getCoefficients();
625         return new StraightLine2D(
626                 x0*tab[0]+y0*tab[1]+tab[2], 
627                 x0*tab[3]+y0*tab[4]+tab[5], 
628                 dx*tab[0]+dy*tab[1], 
629                 dx*tab[3]+dy*tab[4]);
630     }
631 
632     
633     // ===================================================================
634     // methods implementing the Shape interface
635 
636     /**
637      * Returns true if the point (x, y) lies on the line, with precision given
638      * by Shape2D.ACCURACY.
639      */
640     public boolean contains(double x, double y) {
641         return super.supportContains(x, y);
642     }
643 
644     /**
645      * Returns true if the point p lies on the line, with precision given by
646      * Shape2D.ACCURACY.
647      */
648     @Override
649     public boolean contains(java.awt.geom.Point2D p) {
650         return super.supportContains(p.getX(), p.getY());
651     }
652 
653     /** Throws an infiniteShapeException */
654     public java.awt.geom.GeneralPath getGeneralPath() {
655         throw new UnboundedShapeException(this);
656     }
657 
658    
659     // ===================================================================
660     // methods implementing the Object interface
661 
662     @Override
663     public String toString() {
664         return new String("StraightLine2D(" + x0 + "," + y0 + "," + 
665         		dx + "," + dy + ")");
666     }
667     
668     @Override
669     public boolean equals(Object obj) {
670         if (!(obj instanceof StraightLine2D))
671             return false;
672         StraightLine2D line = (StraightLine2D) obj;
673         if (Math.abs(x0-line.x0)>Shape2D.ACCURACY)
674             return false;
675         if (Math.abs(y0-line.y0)>Shape2D.ACCURACY)
676             return false;
677         if (Math.abs(dx-line.dx)>Shape2D.ACCURACY)
678             return false;
679         if (Math.abs(dy-line.dy)>Shape2D.ACCURACY)
680             return false;
681         return true;
682     }
683     
684     @Override
685     public StraightLine2D clone() {
686         return new StraightLine2D(x0, y0, dx, dy);
687     }
688 }