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 }