1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package math.geom2d.conic;
28
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.UnboundedShapeException;
38 import math.geom2d.Vector2D;
39 import math.geom2d.curve.AbstractSmoothCurve2D;
40 import math.geom2d.curve.Curve2D;
41 import math.geom2d.curve.Curve2DUtils;
42 import math.geom2d.curve.CurveArray2D;
43 import math.geom2d.curve.CurveSet2D;
44 import math.geom2d.curve.SmoothCurve2D;
45 import math.geom2d.domain.SmoothOrientedCurve2D;
46 import math.geom2d.line.LinearShape2D;
47 import math.geom2d.line.StraightLine2D;
48
49
50
51
52
53
54
55 public class ParabolaArc2D extends AbstractSmoothCurve2D
56 implements SmoothOrientedCurve2D, Cloneable {
57
58 protected Parabola2D parabola = new Parabola2D();
59
60 protected double t0 = -10;
61 protected double t1 = 10;
62
63 public ParabolaArc2D(Parabola2D parabola, double t0, double t1) {
64 this.parabola = parabola;
65 this.t0 = t0;
66 this.t1 = t1;
67 }
68
69
70
71
72 public Parabola2D getParabola() {
73 return this.parabola;
74 }
75
76
77
78
79 public double getWindingAngle(java.awt.geom.Point2D point) {
80 double angle0, angle1;
81
82 boolean direct = parabola.isDirect();
83 boolean inside = this.isInside(point);
84
85 if (Double.isInfinite(t0)) {
86 angle0 = parabola.getAngle()+(direct ? +1 : -1)*Math.PI/2;
87 } else {
88 angle0 = Angle2D.getHorizontalAngle(point, parabola.getPoint(t0));
89 }
90
91 if (Double.isInfinite(t1)) {
92 angle1 = parabola.getAngle()+(direct ? +1 : -1)*Math.PI/2;
93 } else {
94 angle1 = Angle2D.getHorizontalAngle(point, parabola.getPoint(t1));
95 }
96
97 if (inside) {
98
99 if (angle0>angle1)
100 return 2*Math.PI-angle0+angle1;
101 else
102 return angle1-angle0;
103 } else {
104
105 if (angle0>angle1)
106 return angle1-angle0;
107 else
108 return (angle1-angle0)-2*Math.PI;
109 }
110 }
111
112 public double getSignedDistance(java.awt.geom.Point2D p) {
113 return getSignedDistance(p.getX(), p.getY());
114 }
115
116 public double getSignedDistance(double x, double y) {
117 if (isInside(new Point2D(x, y)))
118 return -getDistance(x, y);
119 return -getDistance(x, y);
120 }
121
122 public boolean isInside(java.awt.geom.Point2D point) {
123 boolean direct = parabola.isDirect();
124 boolean inside = parabola.isInside(point);
125 if (inside&&direct)
126 return true;
127 if (!inside&&!direct)
128 return false;
129
130 double pos = parabola.project(point);
131
132 if (pos<t0) {
133 Point2D p0 = parabola.getPoint(t0);
134 Vector2D v0 = parabola.getTangent(t0);
135 StraightLine2D line0 = new StraightLine2D(p0, v0);
136 return line0.isInside(point);
137 }
138
139 if (pos>t1) {
140 Point2D p1 = parabola.getPoint(t1);
141 Vector2D v1 = parabola.getTangent(t1);
142 StraightLine2D line1 = new StraightLine2D(p1, v1);
143 return line1.isInside(point);
144 }
145 return !direct;
146 }
147
148
149
150
151 public Vector2D getTangent(double t) {
152 return parabola.getTangent(t);
153 }
154
155
156
157
158 public double getCurvature(double t) {
159 return parabola.getCurvature(t);
160 }
161
162
163
164
165
166 public boolean isClosed() {
167 return false;
168 }
169
170
171
172
173
174
175
176 public double getT0() {
177 return t0;
178 }
179
180
181
182
183 public double getT1() {
184 return t1;
185 }
186
187 public Point2D getPoint(double t) {
188 t = Math.min(Math.max(t, t0), t1);
189 return parabola.getPoint(t);
190 }
191
192 public double getPosition(java.awt.geom.Point2D point) {
193 if (!this.parabola.contains(point))
194 return Double.NaN;
195 double t = this.parabola.getPosition(point);
196 if (t-t0<-ACCURACY)
197 return Double.NaN;
198 if (t1-t<ACCURACY)
199 return Double.NaN;
200 return t;
201 }
202
203 public double project(java.awt.geom.Point2D point) {
204 double t = this.parabola.project(point);
205 return Math.min(Math.max(t, t0), t1);
206 }
207
208 public Collection<Point2D> getIntersections(LinearShape2D line) {
209 Collection<Point2D> inters0 = this.parabola.getIntersections(line);
210 ArrayList<Point2D> inters = new ArrayList<Point2D>();
211 for (Point2D point : inters0) {
212 double pos = this.parabola.getPosition(point);
213 if (pos>this.t0&&pos<this.t1)
214 inters.add(point);
215 }
216
217 return inters;
218 }
219
220
221
222
223
224 public ParabolaArc2D getReverseCurve() {
225 return new ParabolaArc2D(this.parabola.getReverseCurve(), -t1, -t0);
226 }
227
228 public ParabolaArc2D getSubCurve(double t0, double t1) {
229 if (t1<t0)
230 return null;
231 t0 = Math.max(this.t0, t0);
232 t1 = Math.min(this.t1, t1);
233 return new ParabolaArc2D(parabola, t0, t1);
234 }
235
236
237
238
239 public double getDistance(java.awt.geom.Point2D p) {
240 return getDistance(p.getX(), p.getY());
241 }
242
243 public double getDistance(double x, double y) {
244
245 return this.getAsPolyline(100).getDistance(x, y);
246 }
247
248
249
250
251 public boolean isBounded() {
252 if (t0==Double.NEGATIVE_INFINITY)
253 return false;
254 if (t1==Double.POSITIVE_INFINITY)
255 return false;
256 return true;
257 }
258
259
260
261
262 public boolean isEmpty() {
263 return t1<=t0;
264 }
265
266
267
268
269
270
271
272 public CurveSet2D<? extends ParabolaArc2D> clip(Box2D box) {
273
274 CurveSet2D<SmoothCurve2D> set = Curve2DUtils.clipSmoothCurve(this, box);
275
276
277 CurveArray2D<ParabolaArc2D> result =
278 new CurveArray2D<ParabolaArc2D>(set.getCurveNumber());
279
280
281 for (Curve2D curve : set.getCurves()) {
282 if (curve instanceof ParabolaArc2D)
283 result.addCurve((ParabolaArc2D) curve);
284 }
285 return result;
286 }
287
288 public Box2D getBoundingBox() {
289
290 return this.getAsPolyline(100).getBoundingBox();
291 }
292
293 public ParabolaArc2D transform(AffineTransform2D trans) {
294 Parabola2D par = parabola.transform(trans);
295
296
297 double startPos = Double.isInfinite(t0) ? Double.NEGATIVE_INFINITY
298 : par.project(this.getFirstPoint().transform(trans));
299 double endPos = Double.isInfinite(t1) ? Double.POSITIVE_INFINITY : par
300 .project(this.getLastPoint().transform(trans));
301
302
303 return new ParabolaArc2D(par, startPos, endPos);
304 }
305
306
307
308
309 public boolean contains(double x, double y) {
310
311 if (!parabola.contains(x, y))
312 return false;
313
314
315 double t = parabola.getPosition(new Point2D(x, y));
316 if (t<this.t0)
317 return false;
318 if (t>this.t1)
319 return false;
320
321 return true;
322 }
323
324 public boolean contains(java.awt.geom.Point2D point) {
325 return contains(point.getX(), point.getY());
326 }
327
328
329
330
331 public java.awt.geom.GeneralPath appendPath(java.awt.geom.GeneralPath path) {
332
333 if (!this.isBounded())
334 throw new UnboundedShapeException(this);
335
336
337 Point2D p1 = this.getFirstPoint();
338 Point2D p2 = this.getLastPoint();
339 Vector2D v1 = this.getTangent(this.getT0());
340 Vector2D v2 = this.getTangent(this.getT1());
341
342
343 StraightLine2D line1 = new StraightLine2D(p1, v1);
344 StraightLine2D line2 = new StraightLine2D(p2, v2);
345
346
347 Point2D pc = line1.getIntersection(line2);
348
349
350 path.quadTo(pc.getX(), pc.getY(), p2.getX(), p2.getY());
351 return path;
352 }
353
354 public java.awt.geom.GeneralPath getGeneralPath() {
355 if (!this.isBounded())
356 throw new UnboundedShapeException(this);
357 return this.getAsPolyline(32).getGeneralPath();
358 }
359
360
361
362
363 @Override
364 public String toString() {
365 return String.format("ParabolaArc2D(%f,%f,%f,%f,%f,%f)",
366 parabola.xv, parabola.yv, parabola.a, parabola.theta, t0, t1);
367 }
368
369 @Override
370 public boolean equals(Object obj) {
371 if (!(obj instanceof ParabolaArc2D))
372 return false;
373 ParabolaArc2D arc = (ParabolaArc2D) obj;
374
375 if (!this.parabola.equals(arc.parabola))
376 return false;
377 if (Math.abs(this.t0-arc.t0)>Shape2D.ACCURACY)
378 return false;
379 if (Math.abs(this.t1-arc.t1)>Shape2D.ACCURACY)
380 return false;
381
382 return true;
383 }
384
385 @Override
386 public ParabolaArc2D clone() {
387 return new ParabolaArc2D(parabola.clone(), t0, t1);
388 }
389 }