View Javadoc

1   
2   package math.geom2d.conic;
3   
4   import java.awt.Graphics2D;
5   import java.util.ArrayList;
6   import java.util.Collection;
7   
8   import math.geom2d.AffineTransform2D;
9   import math.geom2d.Box2D;
10  import math.geom2d.Point2D;
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.ContinuousBoundary2D;
20  import math.geom2d.domain.Domain2D;
21  import math.geom2d.domain.GenericDomain2D;
22  import math.geom2d.domain.SmoothBoundary2D;
23  import math.geom2d.line.LinearShape2D;
24  
25  /**
26   * Branch of an Hyperbola2D.
27   */
28  public class HyperbolaBranch2D extends AbstractSmoothCurve2D
29  implements SmoothBoundary2D, Cloneable {
30  
31      // ===================================================================
32      // inner fields
33  
34  	/** The parent hyperbola */
35      Hyperbola2D hyperbola = null;
36      
37      /** 
38       * This field is true if it crosses the positive axis, in the basis of the
39       * parent hyperbola.
40       */
41      boolean     positive  = true;
42  
43      
44      // ===================================================================
45      // Constructors
46  
47      /**
48       * Generic constructor, using a parent Hyperbola, and a boolean to
49       * specifies if the branch is the right one (crossing the Ox axis on
50       * positive side, b true), or the left one (crossing the Oy axis on the
51       * negative side, b false).
52       */
53      public HyperbolaBranch2D(Hyperbola2D hyperbola, boolean b) {
54          this.hyperbola = hyperbola;
55          this.positive = b;
56      }
57  
58      // ===================================================================
59      // methods specific to HyperbolaBranch2D
60  
61      /**
62       * Returns the supporting hyperbola of this branch.
63       */
64      public Hyperbola2D getHyperbola() {
65          return hyperbola;
66      }
67  
68      /**
69       * Returns true if this branch is the positive one, i.e. it contains the
70       * positive axis in the basis of the supporting hyperbola.
71       * 
72       * @return true if this branch contains the positive axis.
73       */
74      public boolean isPositiveBranch() {
75          return positive;
76      }
77  
78      // ===================================================================
79      // methods inherited from SmoothCurve2D interface
80  
81      /**
82       * Use formula given in <a
83       * href="http://mathworld.wolfram.com/Hyperbola.html">http://mathworld.wolfram.com/Hyperbola.html</a>
84       */
85      public double getCurvature(double t) {
86          double a = hyperbola.a;
87          double b = hyperbola.b;
88          double asih = a*Math.sinh(t);
89          double bcoh = b*Math.cosh(t);
90          return a*b/Math.pow(Math.hypot(bcoh, asih), 3);
91      }
92  
93      public Vector2D getTangent(double t) {
94          double a = hyperbola.a;
95          double b = hyperbola.b;
96          double theta = hyperbola.theta;
97          double dx, dy;
98          if (positive) {
99              dx = a*Math.sinh(t);
100             dy = b*Math.cosh(t);
101         } else {
102             dx = -a*Math.sinh(t);
103             dy = -b*Math.cosh(t);
104         }
105         double cot = Math.cos(theta);
106         double sit = Math.sin(theta);
107         return new Vector2D(dx*cot-dy*sit, dx*sit+dy*cot);
108     }
109 
110     // ===================================================================
111     // methods inherited from Boundary2D interface
112 
113     /**
114      * Returns an instance of ArrayList<ContinuousBoundary2D> containing only
115      * <code>this</code>.
116      */
117     public Collection<ContinuousBoundary2D> getBoundaryCurves() {
118         ArrayList<ContinuousBoundary2D> list = new ArrayList<ContinuousBoundary2D>();
119         list.add(this);
120         return list;
121     }
122 
123     public Domain2D getDomain() {
124         return new GenericDomain2D(this);
125     }
126 
127     /** Throws an UnboundedShapeException */
128     public void fill(Graphics2D g2) {
129         throw new UnboundedShapeException(this);
130     }
131 
132     // ===================================================================
133     // methods inherited from OrientedCurve2D interface
134 
135     public double getSignedDistance(java.awt.geom.Point2D point) {
136         double dist = this.getDistance(point);
137         return this.isInside(point) ? -dist : dist;
138     }
139 
140     public double getSignedDistance(double x, double y) {
141         return this.getSignedDistance(new Point2D(x, y));
142     }
143 
144     public double getWindingAngle(java.awt.geom.Point2D point) {
145         // TODO Auto-generated method stub
146         return 0;
147     }
148 
149     public boolean isInside(java.awt.geom.Point2D point) {
150         if (hyperbola.isDirect()) {
151             if (hyperbola.isInside(point))
152                 return true;
153             double x = hyperbola.toLocal(new Point2D(point)).getX();
154             return positive ? x<0 : x>0;
155         } else {
156             if (!hyperbola.isInside(point))
157                 return false;
158             double x = hyperbola.toLocal(new Point2D(point)).getX();
159             return positive ? x>0 : x<0;
160         }
161     }
162 
163     // ===================================================================
164     // methods inherited from ContinuousCurve2D interface
165 
166     /** Return false, by definition of Hyperbola branch */
167     public boolean isClosed() {
168         return false;
169     }
170 
171     public java.awt.geom.GeneralPath appendPath(
172     		java.awt.geom.GeneralPath path) {
173     	throw new UnboundedShapeException(this);
174     }
175 
176     
177     // ===================================================================
178     // methods inherited from Curve2D interface
179 
180     public Point2D getPoint(double t) {
181         if (Double.isInfinite(t))
182             throw new UnboundedShapeException(this);
183 
184         double x, y;
185         if (positive) {
186             x = Math.cosh(t);
187             if (Double.isInfinite(x))
188                 x = Math.abs(t);
189             y = Math.sinh(t);
190             if (Double.isInfinite(y))
191                 y = t;
192         } else {
193             x = -Math.cosh(t);
194             if (Double.isInfinite(x))
195                 x = -Math.abs(t);
196             y = -Math.sinh(t);
197             if (Double.isInfinite(y))
198                 y = -t;
199         }
200         return hyperbola.toGlobal(new Point2D(x, y));
201     }
202 
203     public double getPosition(java.awt.geom.Point2D point) {
204         Point2D pt = hyperbola.toLocal(new Point2D(point));
205         double y = this.positive ? pt.getY() : -pt.getY();
206         return Math.log(y+Math.hypot(y, 1));
207     }
208 
209     public double project(java.awt.geom.Point2D point) {
210         Point2D pt = hyperbola.toLocal(new Point2D(point));
211         double y = this.positive ? pt.getY() : -pt.getY();
212         return Math.log(y+Math.hypot(y, 1));
213     }
214 
215     public HyperbolaBranch2D getReverseCurve() {
216         Hyperbola2D hyper2 = new Hyperbola2D(hyperbola.xc, hyperbola.yc,
217                 hyperbola.a, hyperbola.b, hyperbola.theta, !hyperbola.direct);
218         return new HyperbolaBranch2D(hyper2, positive);
219     }
220 
221     /**
222      * Returns an instance of HyprbolaBranchArc2D initialized with
223      * <code>this</code>.
224      */
225     public HyperbolaBranchArc2D getSubCurve(double t0, double t1) {
226         return new HyperbolaBranchArc2D(this, t0, t1);
227     }
228 
229     /** Returns Double.NEGATIVE_INFINITY. */
230     public double getT0() {
231         return Double.NEGATIVE_INFINITY;
232     }
233 
234     /** Returns Double.POSITIVE_INFINITY. */
235     public double getT1() {
236         return Double.POSITIVE_INFINITY;
237     }
238 
239     public Collection<Point2D> getIntersections(LinearShape2D line) {
240         // compute intersections with support hyperbola
241         Collection<Point2D> inters = hyperbola.getIntersections(line);
242 
243         // check which points belong to this branch
244         Collection<Point2D> result = new ArrayList<Point2D>();
245         for (Point2D point : inters) {
246             if (!(hyperbola.toLocal(point).getX()>0^positive))
247                 result.add(point);
248         }
249 
250         // return result
251         return result;
252     }
253 
254     
255     // ===================================================================
256     // methods inherited from Shape2D interface
257 
258     /** Returns a bounding box with infinite bounds in every direction */
259     public Box2D getBoundingBox() {
260         return new Box2D(
261         		Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
262                 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
263     }
264 
265     /**
266      * Clips the curve with a box. The result is an instance of
267      * CurveSet2D, which contains only instances of HyperbolaBranchArc2D. 
268      * If the curve does not intersect the boundary of the box,
269      * the result is an instance of CurveSet2D which contains 0 curves.
270      */
271     public CurveSet2D<? extends HyperbolaBranchArc2D> clip(Box2D box) {
272         // Clip the curve
273         CurveSet2D<SmoothCurve2D> set = Curve2DUtils.clipSmoothCurve(this, box);
274 
275         // Stores the result in appropriate structure
276         CurveArray2D<HyperbolaBranchArc2D> result = 
277         	new CurveArray2D<HyperbolaBranchArc2D>(set.getCurveNumber());
278 
279         // convert the result
280         for (Curve2D curve : set.getCurves()) {
281             if (curve instanceof HyperbolaBranchArc2D)
282                 result.addCurve((HyperbolaBranchArc2D) curve);
283         }
284         return result;
285     }
286 
287     public double getDistance(java.awt.geom.Point2D point) {
288         Point2D projected = this.getPoint(this.project(new Point2D(point)));
289         return projected.getDistance(point);
290     }
291 
292     public double getDistance(double x, double y) {
293         Point2D projected = this.getPoint(this.project(new Point2D(x, y)));
294         return projected.getDistance(x, y);
295     }
296 
297     /** Returns false, as an hyperbola branch is never bounded. */
298     public boolean isBounded() {
299         return false;
300     }
301 
302     /**
303      * Returns false, as an hyperbola branch is never empty.
304      */
305     public boolean isEmpty() {
306         return false;
307     }
308 
309     public HyperbolaBranch2D transform(AffineTransform2D trans) {
310     	// The transform the base hypebola, and a point of the branch
311     	Hyperbola2D hyperbola = this.hyperbola.transform(trans);
312     	Point2D base = this.getPoint(0).transform(trans);
313     	
314     	// compute distance of the transformed point to each branch
315     	double d1 = hyperbola.getPositiveBranch().getDistance(base);
316     	double d2 = hyperbola.getNegativeBranch().getDistance(base);
317     	
318     	// choose the 'positivity' of the branch from the closest branch
319         return new HyperbolaBranch2D(hyperbola, d1<d2);
320     }
321 
322     public boolean contains(java.awt.geom.Point2D point) {
323         return this.contains(point.getX(), point.getY());
324     }
325 
326     public boolean contains(double x, double y) {
327         if (!hyperbola.contains(x, y))
328             return false;
329         Point2D point = hyperbola.toLocal(new Point2D(x, y));
330         return point.getX()>0;
331     }
332 
333     // ===================================================================
334     // methods overriding Object class
335 
336     @Override
337     public boolean equals(Object obj) {
338         if(!(obj instanceof HyperbolaBranch2D))
339             return false;
340         HyperbolaBranch2D branch = (HyperbolaBranch2D) obj;
341         
342         if(!hyperbola.equals(branch.hyperbola)) return false;
343         return positive==branch.positive;
344     }
345     
346     @Override
347     public HyperbolaBranch2D clone() {
348         return new HyperbolaBranch2D(hyperbola.clone(), positive);
349     }
350 }