1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package math.geom2d.spline;
25
26 import java.awt.geom.QuadCurve2D;
27 import java.util.Collection;
28
29 import math.geom2d.AffineTransform2D;
30 import math.geom2d.Box2D;
31 import math.geom2d.Point2D;
32 import math.geom2d.Shape2D;
33 import math.geom2d.Vector2D;
34 import math.geom2d.curve.AbstractSmoothCurve2D;
35 import math.geom2d.curve.Curve2D;
36 import math.geom2d.curve.Curve2DUtils;
37 import math.geom2d.curve.CurveArray2D;
38 import math.geom2d.curve.CurveSet2D;
39 import math.geom2d.curve.SmoothCurve2D;
40 import math.geom2d.domain.ContinuousOrientedCurve2D;
41 import math.geom2d.line.LinearShape2D;
42 import math.geom2d.line.StraightLine2D;
43
44
45
46
47
48
49
50
51
52 public class QuadBezierCurve2D extends AbstractSmoothCurve2D
53 implements SmoothCurve2D, ContinuousOrientedCurve2D, Cloneable {
54
55 protected double x1, y1;
56 protected double ctrlx, ctrly;
57 protected double x2, y2;
58
59
60
61
62 public QuadBezierCurve2D() {
63 this(0, 0, 0, 0, 0, 0);
64 }
65
66
67
68
69
70
71
72 public QuadBezierCurve2D(double[][] coefs) {
73 this(coefs[0][0], coefs[1][0], coefs[0][0]+coefs[0][1]/2.0, coefs[1][0]
74 +coefs[1][1]/2.0, coefs[0][0]+coefs[0][1]+coefs[0][2],
75 coefs[1][0]+coefs[1][1]+coefs[1][2]);
76 }
77
78
79
80
81
82
83
84
85
86
87 public QuadBezierCurve2D(java.awt.geom.Point2D p1, java.awt.geom.Point2D ctrl,
88 java.awt.geom.Point2D p2) {
89 this(p1.getX(), p1.getY(), ctrl.getX(), ctrl.getY(), p2.getX(), p2
90 .getY());
91 }
92
93 public QuadBezierCurve2D(java.awt.geom.Point2D[] pts) {
94 this(pts[0].getX(), pts[0].getY(), pts[1].getX(), pts[1].getY(), pts[2]
95 .getX(), pts[2].getY());
96 }
97
98
99
100
101
102
103 public QuadBezierCurve2D(double x1, double y1, double xctrl, double yctrl,
104 double x2, double y2) {
105 this.x1 = x1;
106 this.y1 = y1;
107 this.ctrlx = xctrl;
108 this.ctrly = yctrl;
109 this.x2 = x2;
110 this.y2 = y2;
111 }
112
113
114
115
116
117
118
119
120 public static QuadBezierCurve2D create(Point2D p1, Point2D p2, Point2D p3) {
121 return new QuadBezierCurve2D(p1, p2, p3);
122 }
123
124
125
126
127
128 public Point2D getControl() {
129 return new Point2D(ctrlx, ctrly);
130 }
131
132 public Point2D getP1() {
133 return this.getFirstPoint();
134 }
135
136 public Point2D getP2() {
137 return this.getLastPoint();
138 }
139
140 public Point2D getCtrl() {
141 return this.getControl();
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 public double[][] getParametric() {
158 double[][] tab = new double[2][3];
159 tab[0][0] = x1;
160 tab[0][1] = 2*ctrlx-2*x1;
161 tab[0][2] = x2-2*ctrlx+x1;
162
163 tab[1][0] = y1;
164 tab[1][1] = 2*ctrly-2*y1;
165 tab[1][2] = y2-2*ctrly+y1;
166 return tab;
167 }
168
169
170
171
172
173
174
175
176
177 public double getWindingAngle(java.awt.geom.Point2D point) {
178 return this.getAsPolyline(100).getWindingAngle(point);
179 }
180
181
182
183
184
185
186
187
188 public boolean isInside(java.awt.geom.Point2D pt) {
189 return this.getAsPolyline(100).isInside(pt);
190 }
191
192 public double getSignedDistance(java.awt.geom.Point2D point) {
193 if (isInside(point))
194 return -getDistance(point.getX(), point.getY());
195 else
196 return getDistance(point.getX(), point.getY());
197 }
198
199
200
201
202 public double getSignedDistance(double x, double y) {
203 if (isInside(new Point2D(x, y)))
204 return -getDistance(x, y);
205 else
206 return getDistance(x, y);
207 }
208
209
210
211
212 public Vector2D getTangent(double t) {
213 double[][] c = getParametric();
214 double dx = c[0][1]+2*c[0][2]*t;
215 double dy = c[1][1]+2*c[1][2]*t;
216 return new Vector2D(dx, dy);
217 }
218
219
220
221
222 public double getCurvature(double t) {
223 double[][] c = getParametric();
224 double xp = c[0][1]+2*c[0][2]*t;
225 double yp = c[1][1]+2*c[1][2]*t;
226 double xs = 2*c[0][2];
227 double ys = 2*c[1][2];
228
229 return (xp*ys-yp*xs)/Math.pow(Math.hypot(xp, yp), 3);
230 }
231
232
233
234
235
236
237
238 public boolean isClosed() {
239 return false;
240 }
241
242
243
244
245
246
247
248 public double getT0() {
249 return 0;
250 }
251
252
253
254
255 public double getT1() {
256 return 1;
257 }
258
259
260
261
262
263
264 public Collection<Point2D> getIntersections(LinearShape2D line) {
265 return this.getAsPolyline(100).getIntersections(line);
266 }
267
268
269
270
271 public Point2D getPoint(double t) {
272 t = Math.min(Math.max(t, 0), 1);
273 double[][] c = getParametric();
274 double x = c[0][0]+(c[0][1]+c[0][2]*t)*t;
275 double y = c[1][0]+(c[1][1]+c[1][2]*t)*t;
276 return new Point2D(x, y);
277 }
278
279
280
281
282
283
284 @Override
285 public Point2D getFirstPoint() {
286 return new Point2D(this.x1, this.y1);
287 }
288
289
290
291
292
293
294 @Override
295 public Point2D getLastPoint() {
296 return new Point2D(this.x2, this.y2);
297 }
298
299
300
301
302 public double getPosition(java.awt.geom.Point2D point) {
303 int N = 100;
304 return this.getAsPolyline(N).getPosition(point)/(N);
305 }
306
307
308
309
310 public double project(java.awt.geom.Point2D point) {
311 int N = 100;
312 return this.getAsPolyline(N).project(point)/(N);
313 }
314
315
316
317
318 public QuadBezierCurve2D getReverseCurve() {
319 return new QuadBezierCurve2D(
320 this.getLastPoint(), this.getControl(), this.getFirstPoint());
321 }
322
323
324
325
326 public QuadBezierCurve2D getSubCurve(double t0, double t1) {
327 t0 = Math.max(t0, 0);
328 t1 = Math.min(t1, 1);
329 if (t0>t1)
330 return null;
331
332
333 Point2D p0 = getPoint(t0);
334 Point2D p1 = getPoint(t1);
335
336
337 Vector2D v0 = getTangent(t0);
338 Vector2D v1 = getTangent(t1);
339
340
341 StraightLine2D tan0 = new StraightLine2D(p0, v0);
342 StraightLine2D tan1 = new StraightLine2D(p1, v1);
343 Point2D control = tan0.getIntersection(tan1);
344
345
346 return new QuadBezierCurve2D(p0, control, p1);
347 }
348
349
350
351
352
353
354
355 public boolean contains(double x, double y) {
356 return new QuadCurve2D.Double(
357 x1, y1, ctrlx, ctrly, x2, y2).contains(x, y);
358 }
359
360
361
362
363 public boolean contains(java.awt.geom.Point2D p) {
364 return this.contains(p.getX(), p.getY());
365 }
366
367
368
369
370 public double getDistance(java.awt.geom.Point2D p) {
371 return this.getDistance(p.getX(), p.getY());
372 }
373
374
375
376
377
378
379 public double getDistance(double x, double y) {
380 return this.getAsPolyline(100).getDistance(x, y);
381 }
382
383
384
385
386 public boolean isBounded() {
387 return true;
388 }
389
390 public boolean isEmpty() {
391 return false;
392 }
393
394
395
396
397
398
399
400
401 public CurveSet2D<? extends QuadBezierCurve2D> clip(Box2D box) {
402
403 CurveSet2D<SmoothCurve2D> set = Curve2DUtils.clipSmoothCurve(this, box);
404
405
406 CurveArray2D<QuadBezierCurve2D> result =
407 new CurveArray2D<QuadBezierCurve2D>(set.getCurveNumber());
408
409
410 for (Curve2D curve : set.getCurves()) {
411 if (curve instanceof QuadBezierCurve2D)
412 result.addCurve((QuadBezierCurve2D) curve);
413 }
414 return result;
415 }
416
417 public Box2D getBoundingBox() {
418 Point2D p1 = this.getFirstPoint();
419 Point2D p2 = this.getControl();
420 Point2D p3 = this.getLastPoint();
421 double xmin = Math.min(Math.min(p1.getX(), p2.getX()), p3.getX());
422 double xmax = Math.max(Math.max(p1.getX(), p2.getX()), p3.getX());
423 double ymin = Math.min(Math.min(p1.getY(), p2.getY()), p3.getY());
424 double ymax = Math.max(Math.max(p1.getY(), p2.getY()), p3.getY());
425 return new Box2D(xmin, xmax, ymin, ymax);
426 }
427
428
429
430
431
432 public QuadBezierCurve2D transform(AffineTransform2D trans) {
433 return new QuadBezierCurve2D(
434 trans.transform(this.getFirstPoint()),
435 trans.transform(this.getControl()),
436 trans.transform(this.getLastPoint()));
437 }
438
439 public java.awt.geom.GeneralPath appendPath(java.awt.geom.GeneralPath path) {
440 Point2D p2 = this.getControl();
441 Point2D p3 = this.getLastPoint();
442 path.quadTo(p2.getX(), p2.getY(), p3.getX(), p3.getY());
443 return path;
444 }
445
446 public java.awt.geom.GeneralPath getGeneralPath() {
447 java.awt.geom.GeneralPath path = new java.awt.geom.GeneralPath();
448 Point2D p1 = this.getFirstPoint();
449 Point2D p2 = this.getControl();
450 Point2D p3 = this.getLastPoint();
451 path.moveTo(p1.getX(), p1.getY());
452 path.quadTo(p2.getX(), p2.getY(), p3.getX(), p3.getY());
453 return path;
454 }
455
456 @Override
457 public boolean equals(Object obj) {
458 if(!(obj instanceof QuadBezierCurve2D))
459 return false;
460
461
462 QuadBezierCurve2D bezier = (QuadBezierCurve2D) obj;
463
464
465 if(Math.abs(this.x1-bezier.x1)>Shape2D.ACCURACY) return false;
466 if(Math.abs(this.y1-bezier.y1)>Shape2D.ACCURACY) return false;
467 if(Math.abs(this.ctrlx-bezier.ctrlx)>Shape2D.ACCURACY) return false;
468 if(Math.abs(this.ctrly-bezier.ctrly)>Shape2D.ACCURACY) return false;
469 if(Math.abs(this.x2-bezier.x2)>Shape2D.ACCURACY) return false;
470 if(Math.abs(this.y2-bezier.y2)>Shape2D.ACCURACY) return false;
471
472 return true;
473 }
474
475 @Override
476 public QuadBezierCurve2D clone() {
477 return new QuadBezierCurve2D(x1, y1, ctrlx, ctrly, x2, y2);
478 }
479 }