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