1 /* CubicCurve2D.java -- represents a parameterized cubic curve in 2-D space
2 Copyright (C) 2002, 2003, 2004 Free Software Foundation
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package java.awt.geom;
40 import java.awt.Rectangle;
41 import java.awt.Shape;
42 import java.util.NoSuchElementException;
46 * A two-dimensional curve that is parameterized with a cubic
49 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
50 * alt="A drawing of a CubicCurve2D" />
52 * @author Eric Blake (ebb9@email.byu.edu)
53 * @author Graydon Hoare (graydon@redhat.com)
54 * @author Sascha Brawer (brawer@dandelis.ch)
55 * @author Sven de Marothy (sven@physto.se)
59 public abstract class CubicCurve2D implements Shape, Cloneable
61 private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0;
62 private static final double EPSILON = 1E-10;
65 * Constructs a new CubicCurve2D. Typical users will want to
66 * construct instances of a subclass, such as {@link
67 * CubicCurve2D.Float} or {@link CubicCurve2D.Double}.
69 protected CubicCurve2D()
74 * Returns the <i>x</i> coordinate of the curve’s start
77 public abstract double getX1();
80 * Returns the <i>y</i> coordinate of the curve’s start
83 public abstract double getY1();
86 * Returns the curve’s start point.
88 public abstract Point2D getP1();
91 * Returns the <i>x</i> coordinate of the curve’s first
94 public abstract double getCtrlX1();
97 * Returns the <i>y</i> coordinate of the curve’s first
100 public abstract double getCtrlY1();
103 * Returns the curve’s first control point.
105 public abstract Point2D getCtrlP1();
108 * Returns the <i>x</i> coordinate of the curve’s second
111 public abstract double getCtrlX2();
114 * Returns the <i>y</i> coordinate of the curve’s second
117 public abstract double getCtrlY2();
120 * Returns the curve’s second control point.
122 public abstract Point2D getCtrlP2();
125 * Returns the <i>x</i> coordinate of the curve’s end
128 public abstract double getX2();
131 * Returns the <i>y</i> coordinate of the curve’s end
134 public abstract double getY2();
137 * Returns the curve’s end point.
139 public abstract Point2D getP2();
142 * Changes the curve geometry, separately specifying each coordinate
145 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
146 * alt="A drawing of a CubicCurve2D" />
148 * @param x1 the <i>x</i> coordinate of the curve’s new start
151 * @param y1 the <i>y</i> coordinate of the curve’s new start
154 * @param cx1 the <i>x</i> coordinate of the curve’s new
155 * first control point.
157 * @param cy1 the <i>y</i> coordinate of the curve’s new
158 * first control point.
160 * @param cx2 the <i>x</i> coordinate of the curve’s new
161 * second control point.
163 * @param cy2 the <i>y</i> coordinate of the curve’s new
164 * second control point.
166 * @param x2 the <i>x</i> coordinate of the curve’s new end
169 * @param y2 the <i>y</i> coordinate of the curve’s new end
172 public abstract void setCurve(double x1, double y1, double cx1, double cy1,
173 double cx2, double cy2, double x2, double y2);
176 * Changes the curve geometry, specifying coordinate values in an
179 * @param coords an array containing the new coordinate values. The
180 * <i>x</i> coordinate of the new start point is located at
181 * <code>coords[offset]</code>, its <i>y</i> coordinate at
182 * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the
183 * new first control point is located at <code>coords[offset +
184 * 2]</code>, its <i>y</i> coordinate at <code>coords[offset +
185 * 3]</code>. The <i>x</i> coordinate of the new second control
186 * point is located at <code>coords[offset + 4]</code>, its <i>y</i>
187 * coordinate at <code>coords[offset + 5]</code>. The <i>x</i>
188 * coordinate of the new end point is located at <code>coords[offset
189 * + 6]</code>, its <i>y</i> coordinate at <code>coords[offset +
192 * @param offset the offset of the first coordinate value in
193 * <code>coords</code>.
195 public void setCurve(double[] coords, int offset)
197 setCurve(coords[offset++], coords[offset++], coords[offset++],
198 coords[offset++], coords[offset++], coords[offset++],
199 coords[offset++], coords[offset++]);
203 * Changes the curve geometry, specifying coordinate values in
204 * separate Point objects.
206 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
207 * alt="A drawing of a CubicCurve2D" />
209 * <p>The curve does not keep any reference to the passed point
210 * objects. Therefore, a later change to <code>p1</code>,
211 * <code>c1</code>, <code>c2</code> or <code>p2</code> will not
212 * affect the curve geometry.
214 * @param p1 the new start point.
215 * @param c1 the new first control point.
216 * @param c2 the new second control point.
217 * @param p2 the new end point.
219 public void setCurve(Point2D p1, Point2D c1, Point2D c2, Point2D p2)
221 setCurve(p1.getX(), p1.getY(), c1.getX(), c1.getY(), c2.getX(), c2.getY(),
222 p2.getX(), p2.getY());
226 * Changes the curve geometry, specifying coordinate values in an
227 * array of Point objects.
229 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
230 * alt="A drawing of a CubicCurve2D" />
232 * <p>The curve does not keep references to the passed point
233 * objects. Therefore, a later change to the <code>pts</code> array
234 * or any of its elements will not affect the curve geometry.
236 * @param pts an array containing the points. The new start point
237 * is located at <code>pts[offset]</code>, the new first control
238 * point at <code>pts[offset + 1]</code>, the new second control
239 * point at <code>pts[offset + 2]</code>, and the new end point
240 * at <code>pts[offset + 3]</code>.
242 * @param offset the offset of the start point in <code>pts</code>.
244 public void setCurve(Point2D[] pts, int offset)
246 setCurve(pts[offset].getX(), pts[offset++].getY(), pts[offset].getX(),
247 pts[offset++].getY(), pts[offset].getX(), pts[offset++].getY(),
248 pts[offset].getX(), pts[offset++].getY());
252 * Changes the curve geometry to that of another curve.
254 * @param c the curve whose coordinates will be copied.
256 public void setCurve(CubicCurve2D c)
258 setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(),
259 c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2());
263 * Calculates the squared flatness of a cubic curve, directly
264 * specifying each coordinate value. The flatness is the maximal
265 * distance of a control point to the line between start and end
268 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
269 * alt="A drawing that illustrates the flatness" />
271 * <p>In the above drawing, the straight line connecting start point
272 * P1 and end point P2 is depicted in gray. In comparison to C1,
273 * control point C2 is father away from the gray line. Therefore,
274 * the result will be the square of the distance between C2 and the
275 * gray line, i.e. the squared length of the red line.
277 * @param x1 the <i>x</i> coordinate of the start point P1.
278 * @param y1 the <i>y</i> coordinate of the start point P1.
279 * @param cx1 the <i>x</i> coordinate of the first control point C1.
280 * @param cy1 the <i>y</i> coordinate of the first control point C1.
281 * @param cx2 the <i>x</i> coordinate of the second control point C2.
282 * @param cy2 the <i>y</i> coordinate of the second control point C2.
283 * @param x2 the <i>x</i> coordinate of the end point P2.
284 * @param y2 the <i>y</i> coordinate of the end point P2.
286 public static double getFlatnessSq(double x1, double y1, double cx1,
287 double cy1, double cx2, double cy2,
288 double x2, double y2)
290 return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, cx1, cy1),
291 Line2D.ptSegDistSq(x1, y1, x2, y2, cx2, cy2));
295 * Calculates the flatness of a cubic curve, directly specifying
296 * each coordinate value. The flatness is the maximal distance of a
297 * control point to the line between start and end point.
299 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
300 * alt="A drawing that illustrates the flatness" />
302 * <p>In the above drawing, the straight line connecting start point
303 * P1 and end point P2 is depicted in gray. In comparison to C1,
304 * control point C2 is father away from the gray line. Therefore,
305 * the result will be the distance between C2 and the gray line,
306 * i.e. the length of the red line.
308 * @param x1 the <i>x</i> coordinate of the start point P1.
309 * @param y1 the <i>y</i> coordinate of the start point P1.
310 * @param cx1 the <i>x</i> coordinate of the first control point C1.
311 * @param cy1 the <i>y</i> coordinate of the first control point C1.
312 * @param cx2 the <i>x</i> coordinate of the second control point C2.
313 * @param cy2 the <i>y</i> coordinate of the second control point C2.
314 * @param x2 the <i>x</i> coordinate of the end point P2.
315 * @param y2 the <i>y</i> coordinate of the end point P2.
317 public static double getFlatness(double x1, double y1, double cx1,
318 double cy1, double cx2, double cy2,
319 double x2, double y2)
321 return Math.sqrt(getFlatnessSq(x1, y1, cx1, cy1, cx2, cy2, x2, y2));
325 * Calculates the squared flatness of a cubic curve, specifying the
326 * coordinate values in an array. The flatness is the maximal
327 * distance of a control point to the line between start and end
330 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
331 * alt="A drawing that illustrates the flatness" />
333 * <p>In the above drawing, the straight line connecting start point
334 * P1 and end point P2 is depicted in gray. In comparison to C1,
335 * control point C2 is father away from the gray line. Therefore,
336 * the result will be the square of the distance between C2 and the
337 * gray line, i.e. the squared length of the red line.
339 * @param coords an array containing the coordinate values. The
340 * <i>x</i> coordinate of the start point P1 is located at
341 * <code>coords[offset]</code>, its <i>y</i> coordinate at
342 * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the
343 * first control point C1 is located at <code>coords[offset +
344 * 2]</code>, its <i>y</i> coordinate at <code>coords[offset +
345 * 3]</code>. The <i>x</i> coordinate of the second control point C2
346 * is located at <code>coords[offset + 4]</code>, its <i>y</i>
347 * coordinate at <code>coords[offset + 5]</code>. The <i>x</i>
348 * coordinate of the end point P2 is located at <code>coords[offset
349 * + 6]</code>, its <i>y</i> coordinate at <code>coords[offset +
352 * @param offset the offset of the first coordinate value in
353 * <code>coords</code>.
355 public static double getFlatnessSq(double[] coords, int offset)
357 return getFlatnessSq(coords[offset++], coords[offset++], coords[offset++],
358 coords[offset++], coords[offset++], coords[offset++],
359 coords[offset++], coords[offset++]);
363 * Calculates the flatness of a cubic curve, specifying the
364 * coordinate values in an array. The flatness is the maximal
365 * distance of a control point to the line between start and end
368 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
369 * alt="A drawing that illustrates the flatness" />
371 * <p>In the above drawing, the straight line connecting start point
372 * P1 and end point P2 is depicted in gray. In comparison to C1,
373 * control point C2 is father away from the gray line. Therefore,
374 * the result will be the distance between C2 and the gray line,
375 * i.e. the length of the red line.
377 * @param coords an array containing the coordinate values. The
378 * <i>x</i> coordinate of the start point P1 is located at
379 * <code>coords[offset]</code>, its <i>y</i> coordinate at
380 * <code>coords[offset + 1]</code>. The <i>x</i> coordinate of the
381 * first control point C1 is located at <code>coords[offset +
382 * 2]</code>, its <i>y</i> coordinate at <code>coords[offset +
383 * 3]</code>. The <i>x</i> coordinate of the second control point C2
384 * is located at <code>coords[offset + 4]</code>, its <i>y</i>
385 * coordinate at <code>coords[offset + 5]</code>. The <i>x</i>
386 * coordinate of the end point P2 is located at <code>coords[offset
387 * + 6]</code>, its <i>y</i> coordinate at <code>coords[offset +
390 * @param offset the offset of the first coordinate value in
391 * <code>coords</code>.
393 public static double getFlatness(double[] coords, int offset)
395 return Math.sqrt(getFlatnessSq(coords[offset++], coords[offset++],
396 coords[offset++], coords[offset++],
397 coords[offset++], coords[offset++],
398 coords[offset++], coords[offset++]));
402 * Calculates the squared flatness of this curve. The flatness is
403 * the maximal distance of a control point to the line between start
406 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
407 * alt="A drawing that illustrates the flatness" />
409 * <p>In the above drawing, the straight line connecting start point
410 * P1 and end point P2 is depicted in gray. In comparison to C1,
411 * control point C2 is father away from the gray line. Therefore,
412 * the result will be the square of the distance between C2 and the
413 * gray line, i.e. the squared length of the red line.
415 public double getFlatnessSq()
417 return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
418 getCtrlX2(), getCtrlY2(), getX2(), getY2());
422 * Calculates the flatness of this curve. The flatness is the
423 * maximal distance of a control point to the line between start and
426 * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
427 * alt="A drawing that illustrates the flatness" />
429 * <p>In the above drawing, the straight line connecting start point
430 * P1 and end point P2 is depicted in gray. In comparison to C1,
431 * control point C2 is father away from the gray line. Therefore,
432 * the result will be the distance between C2 and the gray line,
433 * i.e. the length of the red line.
435 public double getFlatness()
437 return Math.sqrt(getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
438 getCtrlX2(), getCtrlY2(), getX2(), getY2()));
442 * Subdivides this curve into two halves.
444 * <p><img src="doc-files/CubicCurve2D-3.png" width="700"
445 * height="180" alt="A drawing that illustrates the effects of
446 * subdividing a CubicCurve2D" />
448 * @param left a curve whose geometry will be set to the left half
449 * of this curve, or <code>null</code> if the caller is not
450 * interested in the left half.
452 * @param right a curve whose geometry will be set to the right half
453 * of this curve, or <code>null</code> if the caller is not
454 * interested in the right half.
456 public void subdivide(CubicCurve2D left, CubicCurve2D right)
458 // Use empty slots at end to share single array.
459 double[] d = new double[]
461 getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(),
462 getCtrlY2(), getX2(), getY2(), 0, 0, 0, 0, 0, 0
464 subdivide(d, 0, d, 0, d, 6);
468 right.setCurve(d, 6);
472 * Subdivides a cubic curve into two halves.
474 * <p><img src="doc-files/CubicCurve2D-3.png" width="700"
475 * height="180" alt="A drawing that illustrates the effects of
476 * subdividing a CubicCurve2D" />
478 * @param src the curve to be subdivided.
480 * @param left a curve whose geometry will be set to the left half
481 * of <code>src</code>, or <code>null</code> if the caller is not
482 * interested in the left half.
484 * @param right a curve whose geometry will be set to the right half
485 * of <code>src</code>, or <code>null</code> if the caller is not
486 * interested in the right half.
488 public static void subdivide(CubicCurve2D src, CubicCurve2D left,
491 src.subdivide(left, right);
495 * Subdivides a cubic curve into two halves, passing all coordinates
498 * <p><img src="doc-files/CubicCurve2D-3.png" width="700"
499 * height="180" alt="A drawing that illustrates the effects of
500 * subdividing a CubicCurve2D" />
502 * <p>The left end point and the right start point will always be
503 * identical. Memory-concious programmers thus may want to pass the
504 * same array for both <code>left</code> and <code>right</code>, and
505 * set <code>rightOff</code> to <code>leftOff + 6</code>.
507 * @param src an array containing the coordinates of the curve to be
508 * subdivided. The <i>x</i> coordinate of the start point P1 is
509 * located at <code>src[srcOff]</code>, its <i>y</i> at
510 * <code>src[srcOff + 1]</code>. The <i>x</i> coordinate of the
511 * first control point C1 is located at <code>src[srcOff +
512 * 2]</code>, its <i>y</i> at <code>src[srcOff + 3]</code>. The
513 * <i>x</i> coordinate of the second control point C2 is located at
514 * <code>src[srcOff + 4]</code>, its <i>y</i> at <code>src[srcOff +
515 * 5]</code>. The <i>x</i> coordinate of the end point is located at
516 * <code>src[srcOff + 6]</code>, its <i>y</i> at <code>src[srcOff +
519 * @param srcOff an offset into <code>src</code>, specifying
520 * the index of the start point’s <i>x</i> coordinate.
522 * @param left an array that will receive the coordinates of the
523 * left half of <code>src</code>. It is acceptable to pass
524 * <code>src</code>. A caller who is not interested in the left half
525 * can pass <code>null</code>.
527 * @param leftOff an offset into <code>left</code>, specifying the
528 * index where the start point’s <i>x</i> coordinate will be
531 * @param right an array that will receive the coordinates of the
532 * right half of <code>src</code>. It is acceptable to pass
533 * <code>src</code> or <code>left</code>. A caller who is not
534 * interested in the right half can pass <code>null</code>.
536 * @param rightOff an offset into <code>right</code>, specifying the
537 * index where the start point’s <i>x</i> coordinate will be
540 public static void subdivide(double[] src, int srcOff, double[] left,
541 int leftOff, double[] right, int rightOff)
543 // To understand this code, please have a look at the image
544 // "CubicCurve2D-3.png" in the sub-directory "doc-files".
561 double Mid_x; // Mid = left.P2 = right.P1
562 double Mid_y; // Mid = left.P2 = right.P1
564 left_P1_x = src[srcOff];
565 left_P1_y = src[srcOff + 1];
566 src_C1_x = src[srcOff + 2];
567 src_C1_y = src[srcOff + 3];
568 src_C2_x = src[srcOff + 4];
569 src_C2_y = src[srcOff + 5];
570 right_P2_x = src[srcOff + 6];
571 right_P2_y = src[srcOff + 7];
573 left_C1_x = (left_P1_x + src_C1_x) / 2;
574 left_C1_y = (left_P1_y + src_C1_y) / 2;
575 right_C2_x = (right_P2_x + src_C2_x) / 2;
576 right_C2_y = (right_P2_y + src_C2_y) / 2;
577 Mid_x = (src_C1_x + src_C2_x) / 2;
578 Mid_y = (src_C1_y + src_C2_y) / 2;
579 left_C2_x = (left_C1_x + Mid_x) / 2;
580 left_C2_y = (left_C1_y + Mid_y) / 2;
581 right_C1_x = (Mid_x + right_C2_x) / 2;
582 right_C1_y = (Mid_y + right_C2_y) / 2;
583 Mid_x = (left_C2_x + right_C1_x) / 2;
584 Mid_y = (left_C2_y + right_C1_y) / 2;
588 left[leftOff] = left_P1_x;
589 left[leftOff + 1] = left_P1_y;
590 left[leftOff + 2] = left_C1_x;
591 left[leftOff + 3] = left_C1_y;
592 left[leftOff + 4] = left_C2_x;
593 left[leftOff + 5] = left_C2_y;
594 left[leftOff + 6] = Mid_x;
595 left[leftOff + 7] = Mid_y;
600 right[rightOff] = Mid_x;
601 right[rightOff + 1] = Mid_y;
602 right[rightOff + 2] = right_C1_x;
603 right[rightOff + 3] = right_C1_y;
604 right[rightOff + 4] = right_C2_x;
605 right[rightOff + 5] = right_C2_y;
606 right[rightOff + 6] = right_P2_x;
607 right[rightOff + 7] = right_P2_y;
612 * Finds the non-complex roots of a cubic equation, placing the
613 * results into the same array as the equation coefficients. The
614 * following equation is being solved:
616 * <blockquote><code>eqn[3]</code> · <i>x</i><sup>3</sup>
617 * + <code>eqn[2]</code> · <i>x</i><sup>2</sup>
618 * + <code>eqn[1]</code> · <i>x</i>
619 * + <code>eqn[0]</code>
623 * <p>For some background about solving cubic equations, see the
625 * href="http://planetmath.org/encyclopedia/CubicFormula.html"
626 * >“Cubic Formula”</a> in <a
627 * href="http://planetmath.org/" >PlanetMath</a>. For an extensive
628 * library of numerical algorithms written in the C programming
629 * language, see the <a href= "http://www.gnu.org/software/gsl/">GNU
630 * Scientific Library</a>, from which this implementation was
633 * @param eqn an array with the coefficients of the equation. When
634 * this procedure has returned, <code>eqn</code> will contain the
635 * non-complex solutions of the equation, in no particular order.
637 * @return the number of non-complex solutions. A result of 0
638 * indicates that the equation has no non-complex solutions. A
639 * result of -1 indicates that the equation is constant (i.e.,
640 * always or never zero).
642 * @see #solveCubic(double[], double[])
643 * @see QuadCurve2D#solveQuadratic(double[],double[])
645 * @author <a href="mailto:bjg@network-theory.com">Brian Gough</a>
646 * (original C implementation in the <a href=
647 * "http://www.gnu.org/software/gsl/">GNU Scientific Library</a>)
649 * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a>
650 * (adaptation to Java)
652 public static int solveCubic(double[] eqn)
654 return solveCubic(eqn, eqn);
658 * Finds the non-complex roots of a cubic equation. The following
659 * equation is being solved:
661 * <blockquote><code>eqn[3]</code> · <i>x</i><sup>3</sup>
662 * + <code>eqn[2]</code> · <i>x</i><sup>2</sup>
663 * + <code>eqn[1]</code> · <i>x</i>
664 * + <code>eqn[0]</code>
668 * <p>For some background about solving cubic equations, see the
670 * href="http://planetmath.org/encyclopedia/CubicFormula.html"
671 * >“Cubic Formula”</a> in <a
672 * href="http://planetmath.org/" >PlanetMath</a>. For an extensive
673 * library of numerical algorithms written in the C programming
674 * language, see the <a href= "http://www.gnu.org/software/gsl/">GNU
675 * Scientific Library</a>, from which this implementation was
678 * @see QuadCurve2D#solveQuadratic(double[],double[])
680 * @param eqn an array with the coefficients of the equation.
682 * @param res an array into which the non-complex roots will be
683 * stored. The results may be in an arbitrary order. It is safe to
684 * pass the same array object reference for both <code>eqn</code>
685 * and <code>res</code>.
687 * @return the number of non-complex solutions. A result of 0
688 * indicates that the equation has no non-complex solutions. A
689 * result of -1 indicates that the equation is constant (i.e.,
690 * always or never zero).
692 * @author <a href="mailto:bjg@network-theory.com">Brian Gough</a>
693 * (original C implementation in the <a href=
694 * "http://www.gnu.org/software/gsl/">GNU Scientific Library</a>)
696 * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a>
697 * (adaptation to Java)
699 public static int solveCubic(double[] eqn, double[] res)
701 // Adapted from poly/solve_cubic.c in the GNU Scientific Library
702 // (GSL), revision 1.7 of 2003-07-26. For the original source, see
703 // http://www.gnu.org/software/gsl/
705 // Brian Gough, the author of that code, has granted the
706 // permission to use it in GNU Classpath under the GNU Classpath
707 // license, and has assigned the copyright to the Free Software
710 // The Java implementation is very similar to the GSL code, but
711 // not a strict one-to-one copy. For example, GSL would sort the
727 // If the cubic coefficient is zero, we have a quadratic equation.
730 return QuadCurve2D.solveQuadratic(eqn, res);
732 // Divide the equation by the cubic coefficient.
737 // We now need to solve x^3 + ax^2 + bx + c = 0.
739 r = 2 * a * a * a - 9 * a * b + 27 * c;
748 CQ3 = 2916 * q * q * q;
750 if (R == 0 && Q == 0)
752 // The GNU Scientific Library would return three identical
753 // solutions in this case.
760 /* this test is actually R2 == Q3, written in a form suitable
761 for exact computation with integers */
762 /* Due to finite precision some double roots may be missed, and
763 considered to be a pair of complex roots z = x +/- epsilon i
764 close to the real axis. */
765 double sqrtQ = Math.sqrt(Q);
769 res[0] = -2 * sqrtQ - a / 3;
770 res[1] = sqrtQ - a / 3;
774 res[0] = -sqrtQ - a / 3;
775 res[1] = 2 * sqrtQ - a / 3;
780 if (CR2 < CQ3) /* equivalent to R2 < Q3 */
782 double sqrtQ = Math.sqrt(Q);
783 double sqrtQ3 = sqrtQ * sqrtQ * sqrtQ;
784 double theta = Math.acos(R / sqrtQ3);
785 double norm = -2 * sqrtQ;
786 res[0] = norm * Math.cos(theta / 3) - a / 3;
787 res[1] = norm * Math.cos((theta + 2.0 * Math.PI) / 3) - a / 3;
788 res[2] = norm * Math.cos((theta - 2.0 * Math.PI) / 3) - a / 3;
790 // The GNU Scientific Library sorts the results. We don't.
794 double sgnR = (R >= 0 ? 1 : -1);
795 double A = -sgnR * Math.pow(Math.abs(R) + Math.sqrt(R2 - Q3), 1.0 / 3.0);
797 res[0] = A + B - a / 3;
802 * Determines whether a position lies inside the area bounded
803 * by the curve and the straight line connecting its end points.
805 * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180"
806 * alt="A drawing of the area spanned by the curve" />
808 * <p>The above drawing illustrates in which area points are
809 * considered “inside” a CubicCurve2D.
811 public boolean contains(double x, double y)
813 if (! getBounds2D().contains(x, y))
816 return ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0);
820 * Determines whether a point lies inside the area bounded
821 * by the curve and the straight line connecting its end points.
823 * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180"
824 * alt="A drawing of the area spanned by the curve" />
826 * <p>The above drawing illustrates in which area points are
827 * considered “inside” a CubicCurve2D.
829 public boolean contains(Point2D p)
831 return contains(p.getX(), p.getY());
835 * Determines whether any part of a rectangle is inside the area bounded
836 * by the curve and the straight line connecting its end points.
838 * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180"
839 * alt="A drawing of the area spanned by the curve" />
841 * <p>The above drawing illustrates in which area points are
842 * considered “inside” in a CubicCurve2D.
843 * @see #contains(double, double)
845 public boolean intersects(double x, double y, double w, double h)
847 if (! getBounds2D().contains(x, y, w, h))
850 /* Does any edge intersect? */
851 if (getAxisIntersections(x, y, true, w) != 0 /* top */
852 || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */
853 || getAxisIntersections(x + w, y, false, h) != 0 /* right */
854 || getAxisIntersections(x, y, false, h) != 0) /* left */
857 /* No intersections, is any point inside? */
858 if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0)
865 * Determines whether any part of a Rectangle2D is inside the area bounded
866 * by the curve and the straight line connecting its end points.
867 * @see #intersects(double, double, double, double)
869 public boolean intersects(Rectangle2D r)
871 return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
875 * Determine whether a rectangle is entirely inside the area that is bounded
876 * by the curve and the straight line connecting its end points.
878 * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180"
879 * alt="A drawing of the area spanned by the curve" />
881 * <p>The above drawing illustrates in which area points are
882 * considered “inside” a CubicCurve2D.
883 * @see #contains(double, double)
885 public boolean contains(double x, double y, double w, double h)
887 if (! getBounds2D().intersects(x, y, w, h))
890 /* Does any edge intersect? */
891 if (getAxisIntersections(x, y, true, w) != 0 /* top */
892 || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */
893 || getAxisIntersections(x + w, y, false, h) != 0 /* right */
894 || getAxisIntersections(x, y, false, h) != 0) /* left */
897 /* No intersections, is any point inside? */
898 if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0)
905 * Determine whether a Rectangle2D is entirely inside the area that is
906 * bounded by the curve and the straight line connecting its end points.
908 * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180"
909 * alt="A drawing of the area spanned by the curve" />
911 * <p>The above drawing illustrates in which area points are
912 * considered “inside” a CubicCurve2D.
913 * @see #contains(double, double)
915 public boolean contains(Rectangle2D r)
917 return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
921 * Determines the smallest rectangle that encloses the
922 * curve’s start, end and control points.
924 public Rectangle getBounds()
926 return getBounds2D().getBounds();
929 public PathIterator getPathIterator(final AffineTransform at)
931 return new PathIterator()
933 /** Current coordinate. */
934 private int current = 0;
936 public int getWindingRule()
938 return WIND_NON_ZERO;
941 public boolean isDone()
951 public int currentSegment(float[] coords)
957 coords[0] = (float) getX1();
958 coords[1] = (float) getY1();
962 coords[0] = (float) getCtrlX1();
963 coords[1] = (float) getCtrlY1();
964 coords[2] = (float) getCtrlX2();
965 coords[3] = (float) getCtrlY2();
966 coords[4] = (float) getX2();
967 coords[5] = (float) getY2();
968 result = SEG_CUBICTO;
971 throw new NoSuchElementException("cubic iterator out of bounds");
974 at.transform(coords, 0, coords, 0, 3);
978 public int currentSegment(double[] coords)
989 coords[0] = getCtrlX1();
990 coords[1] = getCtrlY1();
991 coords[2] = getCtrlX2();
992 coords[3] = getCtrlY2();
995 result = SEG_CUBICTO;
998 throw new NoSuchElementException("cubic iterator out of bounds");
1001 at.transform(coords, 0, coords, 0, 3);
1007 public PathIterator getPathIterator(AffineTransform at, double flatness)
1009 return new FlatteningPathIterator(getPathIterator(at), flatness);
1013 * Create a new curve with the same contents as this one.
1015 * @return the clone.
1017 public Object clone()
1021 return super.clone();
1023 catch (CloneNotSupportedException e)
1025 throw (Error) new InternalError().initCause(e); // Impossible
1030 * Helper method used by contains() and intersects() methods, that
1031 * returns the number of curve/line intersections on a given axis
1032 * extending from a certain point.
1034 * @param x x coordinate of the origin point
1035 * @param y y coordinate of the origin point
1036 * @param useYaxis axis used, if true the positive Y axis is used,
1037 * false uses the positive X axis.
1039 * This is an implementation of the line-crossings algorithm,
1040 * Detailed in an article on Eric Haines' page:
1041 * http://www.acm.org/tog/editors/erich/ptinpoly/
1043 * A special-case not adressed in this code is self-intersections
1044 * of the curve, e.g. if the axis intersects the self-itersection,
1045 * the degenerate roots of the polynomial will erroneously count as
1046 * a single intersection of the curve, and not two.
1048 private int getAxisIntersections(double x, double y, boolean useYaxis,
1060 double[] r = new double[4];
1068 a1 = getCtrlY1() - y;
1069 a2 = getCtrlY2() - y;
1072 b1 = getCtrlX1() - x;
1073 b2 = getCtrlX2() - x;
1079 a1 = getCtrlX1() - x;
1080 a2 = getCtrlX2() - x;
1083 b1 = getCtrlY1() - y;
1084 b2 = getCtrlY2() - y;
1088 /* If the axis intersects a start/endpoint, shift it up by some small
1089 amount to guarantee the line is 'inside'
1090 If this is not done, bad behaviour may result for points on that axis.*/
1091 if (a0 == 0.0 || a3 == 0.0)
1093 double small = getFlatness() * EPSILON;
1102 if (Line2D.linesIntersect(b0, a0, b3, a3, EPSILON, 0.0, distance, 0.0))
1107 if (Line2D.linesIntersect(a0, b0, a3, b3, 0.0, EPSILON, 0.0, distance))
1112 r[1] = 3 * (a1 - a0);
1113 r[2] = 3 * (a2 + a0 - 2 * a1);
1114 r[3] = a3 - 3 * a2 + 3 * a1 - a0;
1116 if ((nRoots = solveCubic(r)) != 0)
1117 for (int i = 0; i < nRoots; i++)
1120 if (t >= 0.0 && t <= 1.0)
1122 double crossing = -(t * t * t) * (b0 - 3 * b1 + 3 * b2 - b3)
1123 + 3 * t * t * (b0 - 2 * b1 + b2)
1124 + 3 * t * (b1 - b0) + b0;
1125 if (crossing > 0.0 && crossing <= distance)
1130 return (nCrossings);
1134 * A two-dimensional curve that is parameterized with a cubic
1135 * function and stores coordinate values in double-precision
1136 * floating-point format.
1138 * @see CubicCurve2D.Float
1140 * @author Eric Blake (ebb9@email.byu.edu)
1141 * @author Sascha Brawer (brawer@dandelis.ch)
1143 public static class Double extends CubicCurve2D
1146 * The <i>x</i> coordinate of the curve’s start point.
1151 * The <i>y</i> coordinate of the curve’s start point.
1156 * The <i>x</i> coordinate of the curve’s first control point.
1158 public double ctrlx1;
1161 * The <i>y</i> coordinate of the curve’s first control point.
1163 public double ctrly1;
1166 * The <i>x</i> coordinate of the curve’s second control point.
1168 public double ctrlx2;
1171 * The <i>y</i> coordinate of the curve’s second control point.
1173 public double ctrly2;
1176 * The <i>x</i> coordinate of the curve’s end point.
1181 * The <i>y</i> coordinate of the curve’s end point.
1186 * Constructs a new CubicCurve2D that stores its coordinate values
1187 * in double-precision floating-point format. All points are
1188 * initially at position (0, 0).
1195 * Constructs a new CubicCurve2D that stores its coordinate values
1196 * in double-precision floating-point format, specifying the
1197 * initial position of each point.
1199 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
1200 * alt="A drawing of a CubicCurve2D" />
1202 * @param x1 the <i>x</i> coordinate of the curve’s start
1205 * @param y1 the <i>y</i> coordinate of the curve’s start
1208 * @param cx1 the <i>x</i> coordinate of the curve’s first
1211 * @param cy1 the <i>y</i> coordinate of the curve’s first
1214 * @param cx2 the <i>x</i> coordinate of the curve’s second
1217 * @param cy2 the <i>y</i> coordinate of the curve’s second
1220 * @param x2 the <i>x</i> coordinate of the curve’s end
1223 * @param y2 the <i>y</i> coordinate of the curve’s end
1226 public Double(double x1, double y1, double cx1, double cy1, double cx2,
1227 double cy2, double x2, double y2)
1240 * Returns the <i>x</i> coordinate of the curve’s start
1243 public double getX1()
1249 * Returns the <i>y</i> coordinate of the curve’s start
1252 public double getY1()
1258 * Returns the curve’s start point.
1260 public Point2D getP1()
1262 return new Point2D.Double(x1, y1);
1266 * Returns the <i>x</i> coordinate of the curve’s first
1269 public double getCtrlX1()
1275 * Returns the <i>y</i> coordinate of the curve’s first
1278 public double getCtrlY1()
1284 * Returns the curve’s first control point.
1286 public Point2D getCtrlP1()
1288 return new Point2D.Double(ctrlx1, ctrly1);
1292 * Returns the <i>x</i> coordinate of the curve’s second
1295 public double getCtrlX2()
1301 * Returns the <i>y</i> coordinate of the curve’s second
1304 public double getCtrlY2()
1310 * Returns the curve’s second control point.
1312 public Point2D getCtrlP2()
1314 return new Point2D.Double(ctrlx2, ctrly2);
1318 * Returns the <i>x</i> coordinate of the curve’s end
1321 public double getX2()
1327 * Returns the <i>y</i> coordinate of the curve’s end
1330 public double getY2()
1336 * Returns the curve’s end point.
1338 public Point2D getP2()
1340 return new Point2D.Double(x2, y2);
1344 * Changes the curve geometry, separately specifying each coordinate
1347 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
1348 * alt="A drawing of a CubicCurve2D" />
1350 * @param x1 the <i>x</i> coordinate of the curve’s new start
1353 * @param y1 the <i>y</i> coordinate of the curve’s new start
1356 * @param cx1 the <i>x</i> coordinate of the curve’s new
1357 * first control point.
1359 * @param cy1 the <i>y</i> coordinate of the curve’s new
1360 * first control point.
1362 * @param cx2 the <i>x</i> coordinate of the curve’s new
1363 * second control point.
1365 * @param cy2 the <i>y</i> coordinate of the curve’s new
1366 * second control point.
1368 * @param x2 the <i>x</i> coordinate of the curve’s new end
1371 * @param y2 the <i>y</i> coordinate of the curve’s new end
1374 public void setCurve(double x1, double y1, double cx1, double cy1,
1375 double cx2, double cy2, double x2, double y2)
1388 * Determines the smallest rectangle that encloses the
1389 * curve’s start, end and control points. As the
1390 * illustration below shows, the invisible control points may cause
1391 * the bounds to be much larger than the area that is actually
1392 * covered by the curve.
1394 * <p><img src="doc-files/CubicCurve2D-2.png" width="350" height="180"
1395 * alt="An illustration of the bounds of a CubicCurve2D" />
1397 public Rectangle2D getBounds2D()
1399 double nx1 = Math.min(Math.min(x1, ctrlx1), Math.min(ctrlx2, x2));
1400 double ny1 = Math.min(Math.min(y1, ctrly1), Math.min(ctrly2, y2));
1401 double nx2 = Math.max(Math.max(x1, ctrlx1), Math.max(ctrlx2, x2));
1402 double ny2 = Math.max(Math.max(y1, ctrly1), Math.max(ctrly2, y2));
1403 return new Rectangle2D.Double(nx1, ny1, nx2 - nx1, ny2 - ny1);
1408 * A two-dimensional curve that is parameterized with a cubic
1409 * function and stores coordinate values in single-precision
1410 * floating-point format.
1412 * @see CubicCurve2D.Float
1414 * @author Eric Blake (ebb9@email.byu.edu)
1415 * @author Sascha Brawer (brawer@dandelis.ch)
1417 public static class Float extends CubicCurve2D
1420 * The <i>x</i> coordinate of the curve’s start point.
1425 * The <i>y</i> coordinate of the curve’s start point.
1430 * The <i>x</i> coordinate of the curve’s first control point.
1432 public float ctrlx1;
1435 * The <i>y</i> coordinate of the curve’s first control point.
1437 public float ctrly1;
1440 * The <i>x</i> coordinate of the curve’s second control point.
1442 public float ctrlx2;
1445 * The <i>y</i> coordinate of the curve’s second control point.
1447 public float ctrly2;
1450 * The <i>x</i> coordinate of the curve’s end point.
1455 * The <i>y</i> coordinate of the curve’s end point.
1460 * Constructs a new CubicCurve2D that stores its coordinate values
1461 * in single-precision floating-point format. All points are
1462 * initially at position (0, 0).
1469 * Constructs a new CubicCurve2D that stores its coordinate values
1470 * in single-precision floating-point format, specifying the
1471 * initial position of each point.
1473 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
1474 * alt="A drawing of a CubicCurve2D" />
1476 * @param x1 the <i>x</i> coordinate of the curve’s start
1479 * @param y1 the <i>y</i> coordinate of the curve’s start
1482 * @param cx1 the <i>x</i> coordinate of the curve’s first
1485 * @param cy1 the <i>y</i> coordinate of the curve’s first
1488 * @param cx2 the <i>x</i> coordinate of the curve’s second
1491 * @param cy2 the <i>y</i> coordinate of the curve’s second
1494 * @param x2 the <i>x</i> coordinate of the curve’s end
1497 * @param y2 the <i>y</i> coordinate of the curve’s end
1500 public Float(float x1, float y1, float cx1, float cy1, float cx2,
1501 float cy2, float x2, float y2)
1514 * Returns the <i>x</i> coordinate of the curve’s start
1517 public double getX1()
1523 * Returns the <i>y</i> coordinate of the curve’s start
1526 public double getY1()
1532 * Returns the curve’s start point.
1534 public Point2D getP1()
1536 return new Point2D.Float(x1, y1);
1540 * Returns the <i>x</i> coordinate of the curve’s first
1543 public double getCtrlX1()
1549 * Returns the <i>y</i> coordinate of the curve’s first
1552 public double getCtrlY1()
1558 * Returns the curve’s first control point.
1560 public Point2D getCtrlP1()
1562 return new Point2D.Float(ctrlx1, ctrly1);
1566 * Returns the <i>s</i> coordinate of the curve’s second
1569 public double getCtrlX2()
1575 * Returns the <i>y</i> coordinate of the curve’s second
1578 public double getCtrlY2()
1584 * Returns the curve’s second control point.
1586 public Point2D getCtrlP2()
1588 return new Point2D.Float(ctrlx2, ctrly2);
1592 * Returns the <i>x</i> coordinate of the curve’s end
1595 public double getX2()
1601 * Returns the <i>y</i> coordinate of the curve’s end
1604 public double getY2()
1610 * Returns the curve’s end point.
1612 public Point2D getP2()
1614 return new Point2D.Float(x2, y2);
1618 * Changes the curve geometry, separately specifying each coordinate
1619 * value as a double-precision floating-point number.
1621 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
1622 * alt="A drawing of a CubicCurve2D" />
1624 * @param x1 the <i>x</i> coordinate of the curve’s new start
1627 * @param y1 the <i>y</i> coordinate of the curve’s new start
1630 * @param cx1 the <i>x</i> coordinate of the curve’s new
1631 * first control point.
1633 * @param cy1 the <i>y</i> coordinate of the curve’s new
1634 * first control point.
1636 * @param cx2 the <i>x</i> coordinate of the curve’s new
1637 * second control point.
1639 * @param cy2 the <i>y</i> coordinate of the curve’s new
1640 * second control point.
1642 * @param x2 the <i>x</i> coordinate of the curve’s new end
1645 * @param y2 the <i>y</i> coordinate of the curve’s new end
1648 public void setCurve(double x1, double y1, double cx1, double cy1,
1649 double cx2, double cy2, double x2, double y2)
1651 this.x1 = (float) x1;
1652 this.y1 = (float) y1;
1653 ctrlx1 = (float) cx1;
1654 ctrly1 = (float) cy1;
1655 ctrlx2 = (float) cx2;
1656 ctrly2 = (float) cy2;
1657 this.x2 = (float) x2;
1658 this.y2 = (float) y2;
1662 * Changes the curve geometry, separately specifying each coordinate
1663 * value as a single-precision floating-point number.
1665 * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
1666 * alt="A drawing of a CubicCurve2D" />
1668 * @param x1 the <i>x</i> coordinate of the curve’s new start
1671 * @param y1 the <i>y</i> coordinate of the curve’s new start
1674 * @param cx1 the <i>x</i> coordinate of the curve’s new
1675 * first control point.
1677 * @param cy1 the <i>y</i> coordinate of the curve’s new
1678 * first control point.
1680 * @param cx2 the <i>x</i> coordinate of the curve’s new
1681 * second control point.
1683 * @param cy2 the <i>y</i> coordinate of the curve’s new
1684 * second control point.
1686 * @param x2 the <i>x</i> coordinate of the curve’s new end
1689 * @param y2 the <i>y</i> coordinate of the curve’s new end
1692 public void setCurve(float x1, float y1, float cx1, float cy1, float cx2,
1693 float cy2, float x2, float y2)
1706 * Determines the smallest rectangle that encloses the
1707 * curve’s start, end and control points. As the
1708 * illustration below shows, the invisible control points may cause
1709 * the bounds to be much larger than the area that is actually
1710 * covered by the curve.
1712 * <p><img src="doc-files/CubicCurve2D-2.png" width="350" height="180"
1713 * alt="An illustration of the bounds of a CubicCurve2D" />
1715 public Rectangle2D getBounds2D()
1717 float nx1 = (float) Math.min(Math.min(x1, ctrlx1), Math.min(ctrlx2, x2));
1718 float ny1 = (float) Math.min(Math.min(y1, ctrly1), Math.min(ctrly2, y2));
1719 float nx2 = (float) Math.max(Math.max(x1, ctrlx1), Math.max(ctrlx2, x2));
1720 float ny2 = (float) Math.max(Math.max(y1, ctrly1), Math.max(ctrly2, y2));
1721 return new Rectangle2D.Float(nx1, ny1, nx2 - nx1, ny2 - ny1);