View Javadoc

1   /* File AbstractLine2D.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  import java.util.ArrayList;
30  import java.util.Collection;
31  
32  import math.geom2d.AffineTransform2D;
33  import math.geom2d.Angle2D;
34  import math.geom2d.Box2D;
35  import math.geom2d.Point2D;
36  import math.geom2d.Shape2D;
37  import math.geom2d.Vector2D;
38  import math.geom2d.circulinear.CirculinearCurve2DUtils;
39  import math.geom2d.circulinear.CirculinearDomain2D;
40  import math.geom2d.circulinear.CirculinearElement2D;
41  import math.geom2d.conic.Circle2D;
42  import math.geom2d.conic.CircleArc2D;
43  import math.geom2d.curve.AbstractSmoothCurve2D;
44  
45  import math.geom2d.curve.ContinuousCurve2D;
46  import math.geom2d.curve.Curve2D;
47  import math.geom2d.curve.Curve2DUtils;
48  import math.geom2d.curve.CurveArray2D;
49  import math.geom2d.curve.CurveSet2D;
50  import math.geom2d.domain.SmoothOrientedCurve2D;
51  import math.geom2d.transform.CircleInversion2D;
52  
53  /**
54   * <p>
55   * Base class for straight curves, such as straight lines, rays, or edges.
56   * </p>
57   * <p>
58   * Internal representation of straight objects is parametric: (x0, y0) is a
59   * point in the object, and (dx, dy) is a direction vector of the line.
60   * </p>
61   * <p>
62   * If the line is defined by two point, we can set (x0,y0) to the first point,
63   * and (dx,dy) to the vector (p1, p2).
64   * </p>
65   * <p>
66   * Then, coordinates for a point (x,y) such as x=x0+t*dx and y=y0+t=dy, t
67   * between 0 and 1 give a point inside p1 and p2, t<0 give a point 'before' p1,
68   * and t>1 give a point 'after' p2, so it is convenient to easily manage edges,
69   * rays and straight lines.
70   * <p>
71   */
72  public abstract class AbstractLine2D extends AbstractSmoothCurve2D
73  implements SmoothOrientedCurve2D, LinearShape2D, CirculinearElement2D {
74  
75      // ===================================================================
76      // constants
77  
78      // ===================================================================
79      // class variables
80  
81      /**
82       * Coordinates of starting point of the line
83       */
84      protected double x0, y0;
85  
86      /**
87       * Direction vector of the line. dx and dy should not be both zero.
88       */
89      protected double dx, dy;
90  
91      // ===================================================================
92      // static methods
93  
94      /**
95       * Returns the unique intersection of two straight objects. If intersection
96       * doesn't exist (parallel lines), return null.
97       */
98      public final static Point2D getIntersection(AbstractLine2D l1,
99              AbstractLine2D l2) {
100         double t = ((l1.y0-l2.y0)*l2.dx-(l1.x0-l2.x0)*l2.dy)
101                 /(l1.dx*l2.dy-l1.dy*l2.dx);
102         return new Point2D(l1.x0+t*l1.dx, l1.y0+t*l1.dy);
103     }
104 
105     /**
106      * Test if the two linear objects are located on the same straight line.
107      */
108     public final static boolean isColinear(AbstractLine2D line1,
109             AbstractLine2D line2) {
110         // test if the two lines are parallel
111         if (Math.abs(line1.dx*line2.dy-line1.dy*line2.dx)>ACCURACY)
112             return false;
113 
114         // test if the two lines share at least one point (see the contains()
115         // method for details on tests)
116         return (Math.abs((line2.y0-line1.y0)*line2.dx-(line2.x0-line1.x0)
117                 *line2.dy)
118                 /Math.hypot(line2.dx, line2.dy)<Shape2D.ACCURACY);
119     }
120 
121     /**
122      * Test if the two linear objects are parallel.
123      */
124     public final static boolean isParallel(AbstractLine2D line1,
125             AbstractLine2D line2) {
126         return (Math.abs(line1.dx*line2.dy-line1.dy*line2.dx)<ACCURACY);
127     }
128 
129     // ===================================================================
130     // Protected constructors
131 
132     protected AbstractLine2D(double x0, double y0, double dx, double dy) {
133         this.x0 = x0;
134         this.y0 = y0;
135         this.dx = dx;
136         this.dy = dy;
137     }
138 
139     protected AbstractLine2D(Point2D point, Vector2D vector) {
140         this.x0 = point.getX();
141         this.y0 = point.getY();
142         this.dx = vector.getX();
143         this.dy = vector.getY();
144     }
145 
146     protected AbstractLine2D(LinearShape2D line) {
147         this(line.getOrigin(), line.getVector());
148     }
149 
150     // ===================================================================
151     // Methods specific to Line shapes
152 
153     public boolean isColinear(LinearShape2D linear) {
154         // test if the two lines are parallel
155         if (!isParallel(linear))
156             return false;
157 
158         // test if the two lines share at least one point (see the contains()
159         // method for details on tests)
160         StraightLine2D line = linear.getSupportingLine();
161         if (Math.abs(dx)>Math.abs(dy)) {
162             if (Math.abs((line.x0-x0)*dy/dx+y0-line.y0)>Shape2D.ACCURACY)
163                 return false;
164             else
165                 return true;
166         } else {
167             if (Math.abs((line.y0-y0)*dx/dy+x0-line.x0)>Shape2D.ACCURACY)
168                 return false;
169             else
170                 return true;
171         }
172     }
173 
174     /**
175      * Test if the this object is parallel to the given one.
176      */
177     public boolean isParallel(LinearShape2D line) {
178         return Vector2D.isColinear(this.getVector(), line.getVector());
179     }
180 
181     /**
182      * Returns true if the point (x, y) lies on the line covering the object,
183      * with precision given by Shape2D.ACCURACY.
184      */
185     protected boolean supportContains(double x, double y) {
186         return (Math.abs((x-x0)*dy-(y-y0)*dx)/Math.hypot(dx, dy)<Shape2D.ACCURACY);
187     }
188 
189     /**
190      * Returns the matrix of parametric representation of the line. Result has
191      * the form:
192      * <p> [ x0 dx ]
193      * <p> [ y0 dy ]
194      * <p>
195      * It can be easily extended to higher dimensions and/or higher polynomial
196      * forms.
197      */
198     public double[][] getParametric() {
199         double tab[][] = new double[2][2];
200         tab[0][0] = x0;
201         tab[0][1] = dx;
202         tab[1][0] = y0;
203         tab[1][1] = dy;
204         return tab;
205     }
206 
207     /**
208      * Returns the coefficient of the Cartesian representation of the line.
209      * Cartesian equation has the form: <code>ax+by+c=0</code>
210      * 
211      * @return the array {a, b, c}.
212      */
213     public double[] getCartesianEquation() {
214         double tab[] = new double[3];
215         tab[0] = dy;
216         tab[1] = -dx;
217         tab[2] = dx*y0-dy*x0;
218         return tab;
219     }
220 
221     /**
222      * Returns polar coefficients.
223      * 
224      * @return an array of 2 elements, the first one is the distance to the
225      *         origin, the second one is the angle with horizontal, between 0
226      *         and 2*PI.
227      */
228     public double[] getPolarCoefficients() {
229         double tab[] = new double[2];
230         double d = getSignedDistance(0, 0);
231         tab[0] = Math.abs(d);
232         if (d>0)
233             tab[1] = (getHorizontalAngle()+Math.PI)%(2*Math.PI);
234         else
235             tab[1] = getHorizontalAngle();
236         return tab;
237     }
238 
239     /**
240      * Returns the signed polar coefficients. Distance to origin can be
241      * negative: this allows representation of directed lines.
242      * 
243      * @return an array of 2 elements, the first one is the signed distance to
244      *         the origin, the second one is the angle with horizontal, between
245      *         0 and 2*PI.
246      */
247     public double[] getSignedPolarCoefficients() {
248         double tab[] = new double[2];
249         tab[0] = getSignedDistance(0, 0);
250         tab[1] = getHorizontalAngle();
251         return tab;
252     }
253 
254     public double getPositionOnLine(java.awt.geom.Point2D point) {
255         return getPositionOnLine(point.getX(), point.getY());
256     }
257 
258     /**
259      * Compute position on the line, that is the number t such that if the point
260      * belong to the line, it location is given by x=x0+t*dx and y=y0+t*dy.
261      * <p>
262      * If the point does not belong to the line, the method returns the position
263      * of its projection on the line.
264      */
265     public double getPositionOnLine(double x, double y) {
266         return ((y-y0)*dy+(x-x0)*dx)/(dx*dx+dy*dy);
267     }
268 
269     /**
270      * Return the projection of point p on the line. The returned point can be
271      * used to compute distance from point to line.
272      * 
273      * @param p a point outside the line (if point p lies on the line, it is
274      *            returned)
275      * @return the projection of the point p on the line
276      */
277     public Point2D getProjectedPoint(Point2D p) {
278         return getProjectedPoint(p.getX(), p.getY());
279     }
280 
281     /**
282      * Return the projection of point p on the line. The returned point can be
283      * used to compute distance from point to line.
284      * 
285      * @param x : coordinate x of point to be projected
286      * @param y : coordinate y of point to be projected
287      * @return the projection of the point p on the line
288      */
289     public Point2D getProjectedPoint(double x, double y) {
290         if (contains(x, y))
291             return new Point2D(x, y);
292 
293         // compute position on the line
294         double t = getPositionOnLine(x, y);
295 
296         // compute position of intersection point
297         return new Point2D(x0+t*dx, y0+t*dy);
298     }
299 
300     /**
301      * Return the symmetric of point p relative to this straight line.
302      * 
303      * @param p a point outside the line (if point p lies on the line, it is
304      *            returned)
305      * @return the projection of the point p on the line
306      */
307     public Point2D getSymmetric(Point2D p) {
308         return getSymmetric(p.getX(), p.getY());
309     }
310 
311     /**
312      * Return the symmetric of point with coordinate (x, y) relative to this
313      * straight line.
314      * 
315      * @param x : coordinate x of point to be projected
316      * @param y : coordinate y of point to be projected
317      * @return the projection of the point (x,y) on the line
318      */
319     public Point2D getSymmetric(double x, double y) {
320         // compute position on the line
321         double t = 2*getPositionOnLine(x, y);
322 
323         // compute position of intersection point
324         return new Point2D(2*x0+t*dx-x, 2*y0+t*dy-y);
325     }
326 
327     /**
328      * Create a straight line parallel to this object, and going through the
329      * given point.
330      * 
331      * @param point the point to go through
332      * @return the parallel through the point
333      */
334     public StraightLine2D getParallel(Point2D point) {
335         return new StraightLine2D(point, this.dx, this.dy);
336     }
337 
338     /**
339      * Create a straight line perpendicular to this object, and going through
340      * the given point.
341      * 
342      * @param point the point to go through
343      * @return the perpendicular through the point
344      */
345     public StraightLine2D getPerpendicular(Point2D point) {
346         return new StraightLine2D(point, -this.dy, this.dx);
347     }
348 
349    // ===================================================================
350 
351     // Methods implementing the LinearShape2D interface
352 
353     public Point2D getOrigin() {
354         return new Point2D(x0, y0);
355     }
356 
357     public Vector2D getVector() {
358         return new Vector2D(dx, dy);
359     }
360 
361     /**
362      * Gets Angle with axis (O,i), counted counter-clockwise. Result is given
363      * between 0 and 2*pi.
364      */
365     public double getHorizontalAngle() {
366         return (Math.atan2(dy, dx)+2*Math.PI)%(2*Math.PI);
367     }
368 
369     /**
370      * Returns the unique intersection with a linear shape. If the intersection
371      * doesn't exist (parallel lines), returns null.
372      */
373     public Point2D getIntersection(LinearShape2D line) {
374         Vector2D vect = line.getVector();
375         double dx2 = vect.getX();
376         double dy2 = vect.getY();
377 
378         // test if two lines are parallel
379         if (Math.abs(dx*dy2-dy*dx2)<Shape2D.ACCURACY)
380             return null;
381 
382         // compute position on the line
383         Point2D origin = line.getOrigin();
384         double x2 = origin.getX();
385         double y2 = origin.getY();
386         double t = ((y0-y2)*dx2-(x0-x2)*dy2)/(dx*dy2-dy*dx2);
387 
388         // compute position of intersection point
389         Point2D point = new Point2D(x0+t*dx, y0+t*dy);
390 
391         // check if point is inside the bounds of the obejct. This test
392         // is left to derivated classes.
393         if (contains(point)&&line.contains(point))
394             return point;
395         return null;
396     }
397 
398     public StraightLine2D getSupportingLine() {
399         return new StraightLine2D(this);
400     }
401 
402 
403     // ===================================================================
404     // methods implementing the CirculinearCurve2D interface
405   
406 	/* (non-Javadoc)
407 	 * @see math.geom2d.circulinear.CirculinearShape2D#getBuffer(double)
408 	 */
409 	public CirculinearDomain2D getBuffer(double dist) {
410 		return CirculinearCurve2DUtils.computeBuffer(this, dist);
411 	}
412 
413 	/* (non-Javadoc)
414 	 * @see math.geom2d.circulinear.CirculinearCurve2D#getLength()
415 	 */
416 	public double getLength() {
417 		if(!this.isBounded()) return Double.POSITIVE_INFINITY;
418 		return (getT1()-getT0())*Math.hypot(dx, dy);
419 	}
420 
421 	/* (non-Javadoc)
422 	 * @see math.geom2d.circulinear.CirculinearCurve2D#getLength(double)
423 	 */
424 	public double getLength(double pos) {
425 		return pos*Math.hypot(dx, dy);
426 	}
427 
428 	/* (non-Javadoc)
429 	 * @see math.geom2d.circulinear.CirculinearCurve2D#getPosition(double)
430 	 */
431 	public double getPosition(double length) {
432 		return length/Math.hypot(dx, dy);
433 	}
434 
435 	/* (non-Javadoc)
436 	 * @see math.geom2d.circulinear.CirculinearCurve2D#transform(math.geom2d.transform.CircleInversion2D)
437 	 */
438 	public CirculinearElement2D transform(CircleInversion2D inv) {
439 		// Extract inversion parameters
440         Point2D center 	= inv.getCenter();
441         double r 		= inv.getRadius();
442         
443         // compute distance of line to inversion center
444         Point2D po 	= this.getProjectedPoint(center);
445         double d 	= this.getDistance(po);
446 
447         // flag for indicating if line extremities are finite
448         boolean inf0 = Double.isInfinite(this.getT0());
449         boolean inf1 = Double.isInfinite(this.getT1());
450 
451         // Degenerate case of a line passing through the center.
452         // returns the line itself.
453         if (Math.abs(d)<Shape2D.ACCURACY){
454         	if (inf0){
455         		if (inf1){
456         			// case of a straight line, which transform into itself
457         			return new StraightLine2D(this);
458         		} else {
459         			// case of an inverted ray, which transform into another
460         			// inverted ray
461         			Point2D p2 = this.getLastPoint().transform(inv);
462         			return new InvertedRay2D(p2, this.getVector());
463         		}
464         	} else {
465         		Point2D p1 = this.getFirstPoint().transform(inv);
466                 if (inf1){
467         			// case of a ray, which transform into another ray
468         			return new Ray2D(p1, this.getVector());
469         		} else {
470         			// case of an line segment
471         			Point2D p2 = this.getLastPoint().transform(inv);
472         			return new LineSegment2D(p1, p2);
473         		}
474         	}
475         }
476         
477         // angle from center to line
478         double angle = Angle2D.getHorizontalAngle(center, po);
479 
480         // center of transformed circle
481         double r2 	= r*r/d/2;
482         Point2D c2 	= Point2D.createPolar(center, r2, angle);
483 
484         // choose direction of circle arc
485         boolean direct = !this.isInside(center);
486         
487         // case of a straight line
488         if (inf0 && inf1) {
489         	return new Circle2D(c2, r2, direct);
490         }
491         
492         // Compute the transform of the end points, which can be the center of
493         // the inversion circle in the case of an infinite line.
494         Point2D p1 = inf0 ? center : this.getFirstPoint();
495         Point2D p2 = inf1 ? center : this.getLastPoint();
496         
497         // compute angle between center of transformed circle and end points
498         double theta1 = Angle2D.getHorizontalAngle(c2, p1);
499         double theta2 = Angle2D.getHorizontalAngle(c2, p2);
500         
501         // create the new circle arc
502         return new CircleArc2D(c2, r2, theta1, theta2, direct);
503 	}
504 
505 
506     // ===================================================================
507     // methods of OrientedCurve2D interface
508 
509     public double getWindingAngle(java.awt.geom.Point2D point) {
510 
511         double t0 = this.getT0();
512         double t1 = this.getT1();
513 
514         double angle1, angle2;
515         if (t0==Double.NEGATIVE_INFINITY)
516             angle1 = Angle2D.getHorizontalAngle(-dx, -dy);
517         else
518             angle1 = Angle2D.getHorizontalAngle(point.getX(), point.getY(), x0
519                     +t0*dx, y0+t0*dy);
520 
521         if (t1==Double.POSITIVE_INFINITY)
522             angle2 = Angle2D.getHorizontalAngle(dx, dy);
523         else
524             angle2 = Angle2D.getHorizontalAngle(point.getX(), point.getY(), x0
525                     +t1*dx, y0+t1*dy);
526 
527         if (this.isInside(point)) {
528             if (angle2>angle1)
529                 return angle2-angle1;
530             else
531                 return 2*Math.PI-angle1+angle2;
532         } else {
533             if (angle2>angle1)
534                 return angle2-angle1-2*Math.PI;
535             else
536                 return angle2-angle1;
537         }
538     }
539 
540     /**
541      * Get the signed distance of the StraightObject2d to the given point. The
542      * signed distance is positive if point lies 'to the right' of the line,
543      * when moving in the direction given by direction vector. This method is
544      * not designed to be used directly, because AbstractLine2D is an abstract
545      * class, but it can be used by subclasses to help computations.
546      */
547     public double getSignedDistance(java.awt.geom.Point2D p) {
548         return getSignedDistance(p.getX(), p.getY());
549     }
550 
551     /**
552      * Get the signed distance of the StraightObject2d to the given point. The
553      * signed distance is positive if point lies 'to the right' of the line,
554      * when moving in the direction given by direction vector. This method is
555      * not designed to be used directly, because AbstractLine2D is an abstract
556      * class, but it can be used by subclasses to help computations.
557      */
558     public double getSignedDistance(double x, double y) {
559         return ((x-x0)*dy-(y-y0)*dx)/Math.hypot(dx, dy);
560     }
561 
562     /**
563      * Returns true if the given point lies to the left of the line when
564      * traveling along the line in the direction given by its direction vector.
565      * 
566      * @param p the point to test
567      * @return true if point p lies on the 'left' of the line.
568      */
569     public boolean isInside(java.awt.geom.Point2D p) {
570         return ((p.getX()-x0)*dy-(p.getY()-y0)*dx<0);
571     }
572 
573     // ===================================================================
574     // methods of SmoothCurve2D interface
575 
576     public Vector2D getTangent(double t) {
577         return new Vector2D(dx, dy);
578     }
579 
580     /**
581      * returns 0 as every straight object.
582      */
583     public double getCurvature(double t) {
584         return 0.0;
585     }
586 
587     // ===================================================================
588     // methods implementing the ContinuousCurve2D interface
589 
590     /**
591      * Always returns false, because we can not come back to starting point if
592      * we always go straight...
593      */
594     public boolean isClosed() {
595         return false;
596     }
597 
598     // ===================================================================
599     // methods implementing the Curve2D interface
600 
601     /**
602      * Return the intersection points of the curve with the specified line. The
603      * length of the result array is the number of intersection points.
604      */
605 	@Override
606     public Collection<? extends AbstractLine2D> getSmoothPieces() {
607         return wrapCurve(this);
608     }
609 
610 
611     public Collection<Point2D> getIntersections(LinearShape2D line) {
612         ArrayList<Point2D> points = new ArrayList<Point2D>();
613 
614         Point2D point = getIntersection(line);
615         if (point==null)
616             return points;
617 
618         // return array with the intersection point.
619         points.add(point);
620         return points;
621     }
622 
623     /**
624      * Gets the position of the point on the line arc. If point belongs to the
625      * line, this position is defined by the ratio:
626      * <p>
627      * <code> t = (xp - x0)/dx <\code>, or equivalently:<p>
628      * <code> t = (yp - y0)/dy <\code>.<p>
629      * If point does not belong to edge, returns Double.NaN.
630      */
631     public double getPosition(java.awt.geom.Point2D point) {
632         double pos = this.getPositionOnLine(point);
633 
634         // return either pos or NaN
635         if (pos<this.getT0())
636             return Double.NaN;
637         if (pos>this.getT1())
638             return Double.NaN;
639         return pos;
640     }
641 
642     /**
643      * Gets the position of the closest point on the line arc. If point belongs
644      * to the line, this position is defined by the ratio:
645      * <p>
646      * <code> t = (xp - x0)/dx <\code>, or equivalently:<p>
647      * <code> t = (yp - y0)/dy <\code>.<p>
648      * If point does not belong to edge, returns t0, or t1, depending on which
649      * one is the closest.
650      */
651     public double project(java.awt.geom.Point2D point) {
652         double pos = this.getPositionOnLine(point);
653 
654         // Bounds between t0 and t1
655         return Math.min(Math.max(pos, this.getT0()), this.getT1());
656     }
657 
658     /**
659      * Returns a new AbstractLine2D, which is the portion of this AbstractLine2D
660      * delimited by parameters t0 and t1. Casts the result to StraightLine2D,
661      * Ray2D or LineSegment2D when appropriate.
662      */
663     public AbstractLine2D getSubCurve(double t0, double t1) {
664         t0 = Math.max(t0, this.getT0());
665         t1 = Math.min(t1, this.getT1());
666         if (Double.isInfinite(t1)) {
667             if (Double.isInfinite(t0))
668                 return new StraightLine2D(this);
669             else
670                 return new Ray2D(this.getPoint(t0), this.getVector());
671         }
672 
673         if (Double.isInfinite(t0))
674             return new InvertedRay2D(this.getPoint(t1), this.getVector());
675         else
676             return new LineSegment2D(this.getPoint(t0), this.getPoint(t1));
677 
678     }
679 
680 	@Override
681 	public Collection<? extends AbstractLine2D> getContinuousCurves() {
682     	return wrapCurve(this);
683     }
684 
685     // ===================================================================
686     // methods implementing the Shape2D
687 
688     /**
689      * Gets the distance of the StraightObject2d to the given point. This method
690      * is not designed to be used directly, because AbstractLine2D is an
691      * abstract class, but it can be called by subclasses to help computations.
692      */
693     public double getDistance(java.awt.geom.Point2D p) {
694         return getDistance(p.getX(), p.getY());
695     }
696 
697     /**
698      * Gets the distance of the StraightObject2d to the given point. This method
699      * is not designed to be used directly, because AbstractLine2D is an
700      * abstract class, but it can be used by subclasses to help computations.
701      * 
702      * @param x x-coordinate of the point
703      * @param y y-coordinate of the point
704      * @return distance between this object and the point (x,y)
705      */
706     public double getDistance(double x, double y) {
707     	// first project on the line
708         Point2D proj = getProjectedPoint(x, y);
709         
710         // if the line contains the projection, returns the distance
711         if (contains(proj))
712             return proj.distance(x, y);
713         
714         // otherwise, returns the distance to the closest singular point
715         double dist = Double.POSITIVE_INFINITY;
716         if(!Double.isInfinite(getT0()))
717         	dist = getFirstPoint().getDistance(x, y);
718         if(!Double.isInfinite(getT1()))
719         	dist = Math.min(dist, getLastPoint().getDistance(x, y));
720        	return dist;
721     }
722 
723     public boolean contains(java.awt.geom.Point2D p) {
724         return this.contains(p.getX(), p.getY());
725     }
726 
727     /**
728      * Returns false, unless both dx and dy equal 0.
729      */
730     public boolean isEmpty() {
731         return Math.hypot(dx, dy)<Shape2D.ACCURACY;
732     }
733 
734     public abstract AbstractLine2D transform(AffineTransform2D transform);
735 
736     public CurveSet2D<? extends AbstractLine2D> clip(Box2D box) {
737         // Clip the curve
738         CurveSet2D<ContinuousCurve2D> set = Curve2DUtils.clipContinuousCurve(
739                 this, box);
740 
741         // Stores the result in appropriate structure
742         CurveArray2D<AbstractLine2D> result = 
743         	new CurveArray2D<AbstractLine2D>(set.getCurveNumber());
744 
745         // convert the result
746         for (Curve2D curve : set.getCurves()) {
747             if (curve instanceof AbstractLine2D)
748                 result.addCurve((AbstractLine2D) curve);
749         }
750         return result;
751     }
752     
753     /**
754      * Ensures public declaration of clone(), and ensures valid return type.
755      */
756 	@Override
757     public abstract AbstractLine2D clone();
758 }