View Javadoc

1   
2   package math.geom2d.conic;
3   
4   import java.util.ArrayList;
5   import java.util.Collection;
6   
7   import math.geom2d.AffineTransform2D;
8   import math.geom2d.Box2D;
9   import math.geom2d.Point2D;
10  import math.geom2d.Shape2D;
11  import math.geom2d.UnboundedShapeException;
12  import math.geom2d.Vector2D;
13  import math.geom2d.curve.AbstractSmoothCurve2D;
14  import math.geom2d.curve.Curve2D;
15  import math.geom2d.curve.Curve2DUtils;
16  import math.geom2d.curve.CurveArray2D;
17  import math.geom2d.curve.CurveSet2D;
18  import math.geom2d.curve.SmoothCurve2D;
19  import math.geom2d.domain.SmoothOrientedCurve2D;
20  import math.geom2d.line.LinearShape2D;
21  
22  /**
23   * An arc of hyperbola, defined from the parent hyperbola branch, and two
24   * positions on the parent curve.
25   * 
26   * @author dlegland
27   */
28  public class HyperbolaBranchArc2D extends AbstractSmoothCurve2D
29  implements SmoothOrientedCurve2D, Cloneable {
30  
31      /** The supporting hyperbola branch */
32      HyperbolaBranch2D branch = null;
33  
34      double            t0     = 0;
35      double            t1     = 1;
36  
37      public HyperbolaBranchArc2D(HyperbolaBranch2D branch, double t0, double t1) {
38          this.branch = branch;
39          this.t0 = t0;
40          this.t1 = t1;
41      }
42  
43      // ===================================================================
44      // methods specific to the arc
45  
46      public HyperbolaBranch2D getHyperbolaBranch() {
47          return branch;
48      }
49  
50      // ===================================================================
51      // methods inherited from SmoothCurve2D interface
52  
53      public double getCurvature(double t) {
54          return branch.getCurvature(t);
55      }
56  
57      public Vector2D getTangent(double t) {
58          return branch.getTangent(t);
59      }
60  
61      // ===================================================================
62      // methods inherited from OrientedCurve2D interface
63  
64      public double getSignedDistance(java.awt.geom.Point2D point) {
65          return this.getSignedDistance(point.getX(), point.getY());
66      }
67  
68      public double getSignedDistance(double x, double y) {
69          // TODO Auto-generated method stub
70          return 0;
71      }
72  
73      public double getWindingAngle(java.awt.geom.Point2D point) {
74          // TODO Auto-generated method stub
75          return 0;
76      }
77  
78      public boolean isInside(java.awt.geom.Point2D pt) {
79          // TODO Auto-generated method stub
80          return false;
81      }
82  
83      // ===================================================================
84      // methods inherited from ContinuousCurve2D interface
85  
86      public java.awt.geom.GeneralPath appendPath(java.awt.geom.GeneralPath path) {
87          return this.getAsPolyline(60).appendPath(path);
88      }
89  
90      /** Returns false. */
91      public boolean isClosed() {
92          return false;
93      }
94  
95      // ===================================================================
96      // methods inherited from Curve2D interface
97  
98      public Collection<Point2D> getIntersections(LinearShape2D line) {
99          Collection<Point2D> inters0 = this.branch.getIntersections(line);
100         ArrayList<Point2D> inters = new ArrayList<Point2D>();
101         for (Point2D point : inters0) {
102             double pos = this.branch.project(point);
103             if (pos>this.t0&&pos<this.t1)
104                 inters.add(point);
105         }
106 
107         return inters;
108     }
109 
110     /**
111      * If t0 equals minus infinity, throws an UnboundedShapeException.
112      */
113    public Point2D getPoint(double t) {
114        if(Double.isInfinite(t))
115            throw new UnboundedShapeException(this);
116         t = Math.min(Math.max(t, t0), t1);
117         return branch.getPoint(t);
118     }
119 
120     public double getPosition(java.awt.geom.Point2D point) {
121         if (!this.branch.contains(point))
122             return Double.NaN;
123         double t = this.branch.getPosition(point);
124         if (t-t0<-ACCURACY)
125             return Double.NaN;
126         if (t1-t<ACCURACY)
127             return Double.NaN;
128         return t;
129     }
130 
131     public double project(java.awt.geom.Point2D point) {
132         double t = this.branch.project(point);
133         return Math.min(Math.max(t, t0), t1);
134     }
135 
136     public HyperbolaBranchArc2D getReverseCurve() {
137         Hyperbola2D hyper = branch.hyperbola;
138         Hyperbola2D hyper2 = new Hyperbola2D(hyper.xc, hyper.yc, hyper.a,
139                 hyper.b, hyper.theta, !hyper.direct);
140         return new HyperbolaBranchArc2D(new HyperbolaBranch2D(hyper2,
141                 branch.positive), -t1, -t0);
142     }
143 
144     /**
145      * Returns a new HyperbolaBranchArc2D, with same parent hyperbola branch,
146      * and with new parameterization bounds. The new bounds are constrained to
147      * belong to the old bounds interval. If t1<t0, returns null.
148      */
149     public HyperbolaBranchArc2D getSubCurve(double t0, double t1) {
150         if (t1<t0)
151             return null;
152         t0 = Math.max(this.t0, t0);
153         t1 = Math.min(this.t1, t1);
154         return new HyperbolaBranchArc2D(branch, t0, t1);
155     }
156 
157     public double getT0() {
158         return t0;
159     }
160 
161     public double getT1() {
162         return t1;
163     }
164 
165     // ===================================================================
166     // methods inherited from Shape2D interface
167 
168     public Box2D getBoundingBox() {
169         if (!this.isBounded())
170             throw new UnboundedShapeException(this);
171         return this.getAsPolyline(100).getBoundingBox();
172     }
173 
174     /**
175      * Clip the hyperbola branch arc by a box. The result is an instance of
176      * CurveSet2D<HyperbolaBranchArc2D>, which contains only instances of
177      * HyperbolaBranchArc2D. If the shape is not clipped, the result is an
178      * instance of CurveSet2D<HyperbolaBranchArc2D> which contains 0 curves.
179      */
180     public CurveSet2D<? extends HyperbolaBranchArc2D> clip(Box2D box) {
181         // Clip the curve
182         CurveSet2D<SmoothCurve2D> set = Curve2DUtils.clipSmoothCurve(this, box);
183 
184         // Stores the result in appropriate structure
185         CurveArray2D<HyperbolaBranchArc2D> result = 
186         	new CurveArray2D<HyperbolaBranchArc2D>(set.getCurveNumber());
187 
188         // convert the result
189         for (Curve2D curve : set.getCurves()) {
190             if (curve instanceof HyperbolaBranchArc2D)
191                 result.addCurve((HyperbolaBranchArc2D) curve);
192         }
193         return result;
194     }
195 
196     public double getDistance(java.awt.geom.Point2D point) {
197         Point2D p = getPoint(project(new Point2D(point)));
198         return p.getDistance(point);
199     }
200 
201     public double getDistance(double x, double y) {
202         Point2D p = getPoint(project(new Point2D(x, y)));
203         return p.getDistance(x, y);
204     }
205 
206     public boolean isBounded() {
207         if (t0==Double.NEGATIVE_INFINITY)
208             return false;
209         if (t1==Double.POSITIVE_INFINITY)
210             return false;
211         return true;
212     }
213 
214     public boolean isEmpty() {
215         return false;
216     }
217 
218     public HyperbolaBranchArc2D transform(AffineTransform2D trans) {
219     	// transform the parent branch
220         HyperbolaBranch2D branch2 = branch.transform(trans);
221 
222         // Compute position of end points on the transformed parabola
223         double startPos = Double.isInfinite(t0) ? Double.NEGATIVE_INFINITY
224                 : branch2.project(this.getFirstPoint().transform(trans));
225         double endPos = Double.isInfinite(t1) ? Double.POSITIVE_INFINITY
226                 : branch2.project(this.getLastPoint().transform(trans));
227 
228         // Compute the new arc
229         if(startPos>endPos){
230         	return new HyperbolaBranchArc2D(branch2.getReverseCurve(), 
231         			endPos, startPos);
232         } else {
233         	return new HyperbolaBranchArc2D(branch2, startPos, endPos);
234         }
235     }
236 
237     public boolean contains(java.awt.geom.Point2D p) {
238         return this.contains(p.getX(), p.getY());
239     }
240 
241     public boolean contains(double x, double y) {
242         if (!branch.contains(x, y))
243             return false;
244         double t = branch.getPosition(new Point2D(x, y));
245         if (t<t0)
246             return false;
247         if (t>t1)
248             return false;
249         return true;
250     }
251 
252     public java.awt.geom.GeneralPath getGeneralPath() {
253         if (!this.isBounded())
254             throw new UnboundedShapeException(this);
255         return this.getAsPolyline(100).getGeneralPath();
256     }
257 
258     
259     // ===================================================================
260     // methods overriding object
261   
262     @Override
263     public boolean equals(Object obj) {
264         if (!(obj instanceof HyperbolaBranchArc2D))
265             return false;
266         HyperbolaBranchArc2D arc = (HyperbolaBranchArc2D) obj;
267         
268         if(!branch.equals(arc.branch)) return false;
269         if(Math.abs(t0-arc.t0)>Shape2D.ACCURACY) return false;
270         if(Math.abs(t1-arc.t1)>Shape2D.ACCURACY) return false;
271         return true;
272     }
273 
274     @Override
275     public HyperbolaBranchArc2D clone() {
276         return new HyperbolaBranchArc2D(branch.clone(), t0, t1);
277     }
278 }