001    /* CubicCurve2D.java -- represents a parameterized cubic curve in 2-D space
002       Copyright (C) 2002, 2003, 2004 Free Software Foundation
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    package java.awt.geom;
039    
040    import java.awt.Rectangle;
041    import java.awt.Shape;
042    import java.util.NoSuchElementException;
043    
044    
045    /**
046     * A two-dimensional curve that is parameterized with a cubic
047     * function.
048     *
049     * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
050     * alt="A drawing of a CubicCurve2D" />
051     *
052     * @author Eric Blake (ebb9@email.byu.edu)
053     * @author Graydon Hoare (graydon@redhat.com)
054     * @author Sascha Brawer (brawer@dandelis.ch)
055     * @author Sven de Marothy (sven@physto.se)
056     *
057     * @since 1.2
058     */
059    public abstract class CubicCurve2D implements Shape, Cloneable
060    {
061      private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0;
062      private static final double EPSILON = 1E-10;
063    
064      /**
065       * Constructs a new CubicCurve2D. Typical users will want to
066       * construct instances of a subclass, such as {@link
067       * CubicCurve2D.Float} or {@link CubicCurve2D.Double}.
068       */
069      protected CubicCurve2D()
070      {
071      }
072    
073      /**
074       * Returns the <i>x</i> coordinate of the curve&#x2019;s start
075       * point.
076       */
077      public abstract double getX1();
078    
079      /**
080       * Returns the <i>y</i> coordinate of the curve&#x2019;s start
081       * point.
082       */
083      public abstract double getY1();
084    
085      /**
086       * Returns the curve&#x2019;s start point.
087       */
088      public abstract Point2D getP1();
089    
090      /**
091       * Returns the <i>x</i> coordinate of the curve&#x2019;s first
092       * control point.
093       */
094      public abstract double getCtrlX1();
095    
096      /**
097       * Returns the <i>y</i> coordinate of the curve&#x2019;s first
098       * control point.
099       */
100      public abstract double getCtrlY1();
101    
102      /**
103       * Returns the curve&#x2019;s first control point.
104       */
105      public abstract Point2D getCtrlP1();
106    
107      /**
108       * Returns the <i>x</i> coordinate of the curve&#x2019;s second
109       * control point.
110       */
111      public abstract double getCtrlX2();
112    
113      /**
114       * Returns the <i>y</i> coordinate of the curve&#x2019;s second
115       * control point.
116       */
117      public abstract double getCtrlY2();
118    
119      /**
120       * Returns the curve&#x2019;s second control point.
121       */
122      public abstract Point2D getCtrlP2();
123    
124      /**
125       * Returns the <i>x</i> coordinate of the curve&#x2019;s end
126       * point.
127       */
128      public abstract double getX2();
129    
130      /**
131       * Returns the <i>y</i> coordinate of the curve&#x2019;s end
132       * point.
133       */
134      public abstract double getY2();
135    
136      /**
137       * Returns the curve&#x2019;s end point.
138       */
139      public abstract Point2D getP2();
140    
141      /**
142       * Changes the curve geometry, separately specifying each coordinate
143       * value.
144       *
145       * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
146       * alt="A drawing of a CubicCurve2D" />
147       *
148       * @param x1 the <i>x</i> coordinate of the curve&#x2019;s new start
149       * point.
150       *
151       * @param y1 the <i>y</i> coordinate of the curve&#x2019;s new start
152       * point.
153       *
154       * @param cx1 the <i>x</i> coordinate of the curve&#x2019;s new
155       * first control point.
156       *
157       * @param cy1 the <i>y</i> coordinate of the curve&#x2019;s new
158       * first control point.
159       *
160       * @param cx2 the <i>x</i> coordinate of the curve&#x2019;s new
161       * second control point.
162       *
163       * @param cy2 the <i>y</i> coordinate of the curve&#x2019;s new
164       * second control point.
165       *
166       * @param x2 the <i>x</i> coordinate of the curve&#x2019;s new end
167       * point.
168       *
169       * @param y2 the <i>y</i> coordinate of the curve&#x2019;s new end
170       * point.
171       */
172      public abstract void setCurve(double x1, double y1, double cx1, double cy1,
173                                    double cx2, double cy2, double x2, double y2);
174    
175      /**
176       * Changes the curve geometry, specifying coordinate values in an
177       * array.
178       *
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 +
190       * 7]</code>.
191       *
192       * @param offset the offset of the first coordinate value in
193       * <code>coords</code>.
194       */
195      public void setCurve(double[] coords, int offset)
196      {
197        setCurve(coords[offset++], coords[offset++], coords[offset++],
198                 coords[offset++], coords[offset++], coords[offset++],
199                 coords[offset++], coords[offset++]);
200      }
201    
202      /**
203       * Changes the curve geometry, specifying coordinate values in
204       * separate Point objects.
205       *
206       * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
207       * alt="A drawing of a CubicCurve2D" />
208       *
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.
213       *
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.
218       */
219      public void setCurve(Point2D p1, Point2D c1, Point2D c2, Point2D p2)
220      {
221        setCurve(p1.getX(), p1.getY(), c1.getX(), c1.getY(), c2.getX(), c2.getY(),
222                 p2.getX(), p2.getY());
223      }
224    
225      /**
226       * Changes the curve geometry, specifying coordinate values in an
227       * array of Point objects.
228       *
229       * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
230       * alt="A drawing of a CubicCurve2D" />
231       *
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.
235       *
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>.
241       *
242       * @param offset the offset of the start point in <code>pts</code>.
243       */
244      public void setCurve(Point2D[] pts, int offset)
245      {
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());
249      }
250    
251      /**
252       * Changes the curve geometry to that of another curve.
253       *
254       * @param c the curve whose coordinates will be copied.
255       */
256      public void setCurve(CubicCurve2D c)
257      {
258        setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(),
259                 c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2());
260      }
261    
262      /**
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
266       * point.
267       *
268       * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
269       * alt="A drawing that illustrates the flatness" />
270       *
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.
276       *
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.
285       */
286      public static double getFlatnessSq(double x1, double y1, double cx1,
287                                         double cy1, double cx2, double cy2,
288                                         double x2, double y2)
289      {
290        return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, cx1, cy1),
291                        Line2D.ptSegDistSq(x1, y1, x2, y2, cx2, cy2));
292      }
293    
294      /**
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.
298       *
299       * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
300       * alt="A drawing that illustrates the flatness" />
301       *
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.
307       *
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.
316       */
317      public static double getFlatness(double x1, double y1, double cx1,
318                                       double cy1, double cx2, double cy2,
319                                       double x2, double y2)
320      {
321        return Math.sqrt(getFlatnessSq(x1, y1, cx1, cy1, cx2, cy2, x2, y2));
322      }
323    
324      /**
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
328       * point.
329       *
330       * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
331       * alt="A drawing that illustrates the flatness" />
332       *
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.
338       *
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 +
350       * 7]</code>.
351       *
352       * @param offset the offset of the first coordinate value in
353       * <code>coords</code>.
354       */
355      public static double getFlatnessSq(double[] coords, int offset)
356      {
357        return getFlatnessSq(coords[offset++], coords[offset++], coords[offset++],
358                             coords[offset++], coords[offset++], coords[offset++],
359                             coords[offset++], coords[offset++]);
360      }
361    
362      /**
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
366       * point.
367       *
368       * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
369       * alt="A drawing that illustrates the flatness" />
370       *
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.
376       *
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 +
388       * 7]</code>.
389       *
390       * @param offset the offset of the first coordinate value in
391       * <code>coords</code>.
392       */
393      public static double getFlatness(double[] coords, int offset)
394      {
395        return Math.sqrt(getFlatnessSq(coords[offset++], coords[offset++],
396                                       coords[offset++], coords[offset++],
397                                       coords[offset++], coords[offset++],
398                                       coords[offset++], coords[offset++]));
399      }
400    
401      /**
402       * Calculates the squared flatness of this curve.  The flatness is
403       * the maximal distance of a control point to the line between start
404       * and end point.
405       *
406       * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
407       * alt="A drawing that illustrates the flatness" />
408       *
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.
414       */
415      public double getFlatnessSq()
416      {
417        return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
418                             getCtrlX2(), getCtrlY2(), getX2(), getY2());
419      }
420    
421      /**
422       * Calculates the flatness of this curve.  The flatness is the
423       * maximal distance of a control point to the line between start and
424       * end point.
425       *
426       * <p><img src="doc-files/CubicCurve2D-4.png" width="350" height="180"
427       * alt="A drawing that illustrates the flatness" />
428       *
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.
434       */
435      public double getFlatness()
436      {
437        return Math.sqrt(getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
438                                       getCtrlX2(), getCtrlY2(), getX2(), getY2()));
439      }
440    
441      /**
442       * Subdivides this curve into two halves.
443       *
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" />
447       *
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.
451       *
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.
455       */
456      public void subdivide(CubicCurve2D left, CubicCurve2D right)
457      {
458        // Use empty slots at end to share single array.
459        double[] d = new double[]
460                     {
461                       getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(),
462                       getCtrlY2(), getX2(), getY2(), 0, 0, 0, 0, 0, 0
463                     };
464        subdivide(d, 0, d, 0, d, 6);
465        if (left != null)
466          left.setCurve(d, 0);
467        if (right != null)
468          right.setCurve(d, 6);
469      }
470    
471      /**
472       * Subdivides a cubic curve into two halves.
473       *
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" />
477       *
478       * @param src the curve to be subdivided.
479       *
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.
483       *
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.
487       */
488      public static void subdivide(CubicCurve2D src, CubicCurve2D left,
489                                   CubicCurve2D right)
490      {
491        src.subdivide(left, right);
492      }
493    
494      /**
495       * Subdivides a cubic curve into two halves, passing all coordinates
496       * in an array.
497       *
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" />
501       *
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>.
506       *
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 +
517       * 7]</code>.
518       *
519       * @param srcOff an offset into <code>src</code>, specifying
520       * the index of the start point&#x2019;s <i>x</i> coordinate.
521       *
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>.
526       *
527       * @param leftOff an offset into <code>left</code>, specifying the
528       * index where the start point&#x2019;s <i>x</i> coordinate will be
529       * stored.
530       *
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>.
535       *
536       * @param rightOff an offset into <code>right</code>, specifying the
537       * index where the start point&#x2019;s <i>x</i> coordinate will be
538       * stored.
539       */
540      public static void subdivide(double[] src, int srcOff, double[] left,
541                                   int leftOff, double[] right, int rightOff)
542      {
543        // To understand this code, please have a look at the image
544        // "CubicCurve2D-3.png" in the sub-directory "doc-files".
545        double src_C1_x;
546        double src_C1_y;
547        double src_C2_x;
548        double src_C2_y;
549        double left_P1_x;
550        double left_P1_y;
551        double left_C1_x;
552        double left_C1_y;
553        double left_C2_x;
554        double left_C2_y;
555        double right_C1_x;
556        double right_C1_y;
557        double right_C2_x;
558        double right_C2_y;
559        double right_P2_x;
560        double right_P2_y;
561        double Mid_x; // Mid = left.P2 = right.P1
562        double Mid_y; // Mid = left.P2 = right.P1
563    
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];
572    
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;
585    
586        if (left != null)
587          {
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;
596          }
597    
598        if (right != null)
599          {
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;
608          }
609      }
610    
611      /**
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:
615       *
616       * <blockquote><code>eqn[3]</code> &#xb7; <i>x</i><sup>3</sup>
617       * + <code>eqn[2]</code> &#xb7; <i>x</i><sup>2</sup>
618       * + <code>eqn[1]</code> &#xb7; <i>x</i>
619       * + <code>eqn[0]</code>
620       * = 0
621       * </blockquote>
622       *
623       * <p>For some background about solving cubic equations, see the
624       * article <a
625       * href="http://planetmath.org/encyclopedia/CubicFormula.html"
626       * >&#x201c;Cubic Formula&#x201d;</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
631       * adapted.
632       *
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.
636       *
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).
641       *
642       * @see #solveCubic(double[], double[])
643       * @see QuadCurve2D#solveQuadratic(double[],double[])
644       *
645       * @author Brian Gough (bjg@network-theory.com)
646       * (original C implementation in the <a href=
647       * "http://www.gnu.org/software/gsl/">GNU Scientific Library</a>)
648       *
649       * @author Sascha Brawer (brawer@dandelis.ch)
650       * (adaptation to Java)
651       */
652      public static int solveCubic(double[] eqn)
653      {
654        return solveCubic(eqn, eqn);
655      }
656    
657      /**
658       * Finds the non-complex roots of a cubic equation. The following
659       * equation is being solved:
660       *
661       * <blockquote><code>eqn[3]</code> &#xb7; <i>x</i><sup>3</sup>
662       * + <code>eqn[2]</code> &#xb7; <i>x</i><sup>2</sup>
663       * + <code>eqn[1]</code> &#xb7; <i>x</i>
664       * + <code>eqn[0]</code>
665       * = 0
666       * </blockquote>
667       *
668       * <p>For some background about solving cubic equations, see the
669       * article <a
670       * href="http://planetmath.org/encyclopedia/CubicFormula.html"
671       * >&#x201c;Cubic Formula&#x201d;</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
676       * adapted.
677       *
678       * @see QuadCurve2D#solveQuadratic(double[],double[])
679       *
680       * @param eqn an array with the coefficients of the equation.
681       *
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>.
686       *
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).
691       *
692       * @author Brian Gough (bjg@network-theory.com)
693       * (original C implementation in the <a href=
694       * "http://www.gnu.org/software/gsl/">GNU Scientific Library</a>)
695       *
696       * @author Sascha Brawer (brawer@dandelis.ch)
697       * (adaptation to Java)
698       */
699      public static int solveCubic(double[] eqn, double[] res)
700      {
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/
704        //
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
708        // Foundation.
709        //
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
712        // result.
713    
714        double a;
715        double b;
716        double c;
717        double q;
718        double r;
719        double Q;
720        double R;
721        double c3;
722        double Q3;
723        double R2;
724        double CR2;
725        double CQ3;
726    
727        // If the cubic coefficient is zero, we have a quadratic equation.
728        c3 = eqn[3];
729        if (c3 == 0)
730          return QuadCurve2D.solveQuadratic(eqn, res);
731    
732        // Divide the equation by the cubic coefficient.
733        c = eqn[0] / c3;
734        b = eqn[1] / c3;
735        a = eqn[2] / c3;
736    
737        // We now need to solve x^3 + ax^2 + bx + c = 0.
738        q = a * a - 3 * b;
739        r = 2 * a * a * a - 9 * a * b + 27 * c;
740    
741        Q = q / 9;
742        R = r / 54;
743    
744        Q3 = Q * Q * Q;
745        R2 = R * R;
746    
747        CR2 = 729 * r * r;
748        CQ3 = 2916 * q * q * q;
749    
750        if (R == 0 && Q == 0)
751          {
752            // The GNU Scientific Library would return three identical
753            // solutions in this case.
754            res[0] = -a / 3;
755            return 1;
756          }
757    
758        if (CR2 == CQ3)
759          {
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);
766    
767            if (R > 0)
768              {
769                res[0] = -2 * sqrtQ - a / 3;
770                res[1] = sqrtQ - a / 3;
771              }
772            else
773              {
774                res[0] = -sqrtQ - a / 3;
775                res[1] = 2 * sqrtQ - a / 3;
776              }
777            return 2;
778          }
779    
780        if (CR2 < CQ3) /* equivalent to R2 < Q3 */
781          {
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;
789    
790            // The GNU Scientific Library sorts the results. We don't.
791            return 3;
792          }
793    
794        double sgnR = (R >= 0 ? 1 : -1);
795        double A = -sgnR * Math.pow(Math.abs(R) + Math.sqrt(R2 - Q3), 1.0 / 3.0);
796        double B = Q / A;
797        res[0] = A + B - a / 3;
798        return 1;
799      }
800    
801      /**
802       * Determines whether a position lies inside the area bounded
803       * by the curve and the straight line connecting its end points.
804       *
805       * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180"
806       * alt="A drawing of the area spanned by the curve" />
807       *
808       * <p>The above drawing illustrates in which area points are
809       * considered &#x201c;inside&#x201d; a CubicCurve2D.
810       */
811      public boolean contains(double x, double y)
812      {
813        if (! getBounds2D().contains(x, y))
814          return false;
815    
816        return ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0);
817      }
818    
819      /**
820       * Determines whether a point lies inside the area bounded
821       * by the curve and the straight line connecting its end points.
822       *
823       * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180"
824       * alt="A drawing of the area spanned by the curve" />
825       *
826       * <p>The above drawing illustrates in which area points are
827       * considered &#x201c;inside&#x201d; a CubicCurve2D.
828       */
829      public boolean contains(Point2D p)
830      {
831        return contains(p.getX(), p.getY());
832      }
833    
834      /**
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.
837       *
838       * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180"
839       * alt="A drawing of the area spanned by the curve" />
840       *
841       * <p>The above drawing illustrates in which area points are
842       * considered &#x201c;inside&#x201d; in a CubicCurve2D.
843       * @see #contains(double, double)
844       */
845      public boolean intersects(double x, double y, double w, double h)
846      {
847        if (! getBounds2D().contains(x, y, w, h))
848          return false;
849    
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 */
855          return true;
856    
857        /* No intersections, is any point inside? */
858        if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0)
859          return true;
860    
861        return false;
862      }
863    
864      /**
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)
868       */
869      public boolean intersects(Rectangle2D r)
870      {
871        return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
872      }
873    
874      /**
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.
877       *
878       * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180"
879       * alt="A drawing of the area spanned by the curve" />
880       *
881       * <p>The above drawing illustrates in which area points are
882       * considered &#x201c;inside&#x201d; a CubicCurve2D.
883       * @see #contains(double, double)
884       */
885      public boolean contains(double x, double y, double w, double h)
886      {
887        if (! getBounds2D().intersects(x, y, w, h))
888          return false;
889    
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 */
895          return false;
896    
897        /* No intersections, is any point inside? */
898        if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0)
899          return true;
900    
901        return false;
902      }
903    
904      /**
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.
907       *
908       * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180"
909       * alt="A drawing of the area spanned by the curve" />
910       *
911       * <p>The above drawing illustrates in which area points are
912       * considered &#x201c;inside&#x201d; a CubicCurve2D.
913       * @see #contains(double, double)
914       */
915      public boolean contains(Rectangle2D r)
916      {
917        return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
918      }
919    
920      /**
921       * Determines the smallest rectangle that encloses the
922       * curve&#x2019;s start, end and control points.
923       */
924      public Rectangle getBounds()
925      {
926        return getBounds2D().getBounds();
927      }
928    
929      public PathIterator getPathIterator(final AffineTransform at)
930      {
931        return new PathIterator()
932          {
933            /** Current coordinate. */
934            private int current = 0;
935    
936            public int getWindingRule()
937            {
938              return WIND_NON_ZERO;
939            }
940    
941            public boolean isDone()
942            {
943              return current >= 2;
944            }
945    
946            public void next()
947            {
948              current++;
949            }
950    
951            public int currentSegment(float[] coords)
952            {
953              int result;
954              switch (current)
955                {
956                case 0:
957                  coords[0] = (float) getX1();
958                  coords[1] = (float) getY1();
959                  result = SEG_MOVETO;
960                  break;
961                case 1:
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;
969                  break;
970                default:
971                  throw new NoSuchElementException("cubic iterator out of bounds");
972                }
973              if (at != null)
974                at.transform(coords, 0, coords, 0, 3);
975              return result;
976            }
977    
978            public int currentSegment(double[] coords)
979            {
980              int result;
981              switch (current)
982                {
983                case 0:
984                  coords[0] = getX1();
985                  coords[1] = getY1();
986                  result = SEG_MOVETO;
987                  break;
988                case 1:
989                  coords[0] = getCtrlX1();
990                  coords[1] = getCtrlY1();
991                  coords[2] = getCtrlX2();
992                  coords[3] = getCtrlY2();
993                  coords[4] = getX2();
994                  coords[5] = getY2();
995                  result = SEG_CUBICTO;
996                  break;
997                default:
998                  throw new NoSuchElementException("cubic iterator out of bounds");
999                }
1000              if (at != null)
1001                at.transform(coords, 0, coords, 0, 3);
1002              return result;
1003            }
1004          };
1005      }
1006    
1007      public PathIterator getPathIterator(AffineTransform at, double flatness)
1008      {
1009        return new FlatteningPathIterator(getPathIterator(at), flatness);
1010      }
1011    
1012      /**
1013       * Create a new curve with the same contents as this one.
1014       *
1015       * @return the clone.
1016       */
1017      public Object clone()
1018      {
1019        try
1020          {
1021            return super.clone();
1022          }
1023        catch (CloneNotSupportedException e)
1024          {
1025            throw (Error) new InternalError().initCause(e); // Impossible
1026          }
1027      }
1028    
1029      /**
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.
1033       *
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.
1038       *
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/
1042       *
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.
1047       */
1048      private int getAxisIntersections(double x, double y, boolean useYaxis,
1049                                       double distance)
1050      {
1051        int nCrossings = 0;
1052        double a0;
1053        double a1;
1054        double a2;
1055        double a3;
1056        double b0;
1057        double b1;
1058        double b2;
1059        double b3;
1060        double[] r = new double[4];
1061        int nRoots;
1062    
1063        a0 = a3 = 0.0;
1064    
1065        if (useYaxis)
1066          {
1067            a0 = getY1() - y;
1068            a1 = getCtrlY1() - y;
1069            a2 = getCtrlY2() - y;
1070            a3 = getY2() - y;
1071            b0 = getX1() - x;
1072            b1 = getCtrlX1() - x;
1073            b2 = getCtrlX2() - x;
1074            b3 = getX2() - x;
1075          }
1076        else
1077          {
1078            a0 = getX1() - x;
1079            a1 = getCtrlX1() - x;
1080            a2 = getCtrlX2() - x;
1081            a3 = getX2() - x;
1082            b0 = getY1() - y;
1083            b1 = getCtrlY1() - y;
1084            b2 = getCtrlY2() - y;
1085            b3 = getY2() - y;
1086          }
1087    
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)
1092          {
1093            double small = getFlatness() * EPSILON;
1094            if (a0 == 0.0)
1095              a0 -= small;
1096            if (a3 == 0.0)
1097              a3 -= small;
1098          }
1099    
1100        if (useYaxis)
1101          {
1102            if (Line2D.linesIntersect(b0, a0, b3, a3, EPSILON, 0.0, distance, 0.0))
1103              nCrossings++;
1104          }
1105        else
1106          {
1107            if (Line2D.linesIntersect(a0, b0, a3, b3, 0.0, EPSILON, 0.0, distance))
1108              nCrossings++;
1109          }
1110    
1111        r[0] = a0;
1112        r[1] = 3 * (a1 - a0);
1113        r[2] = 3 * (a2 + a0 - 2 * a1);
1114        r[3] = a3 - 3 * a2 + 3 * a1 - a0;
1115    
1116        if ((nRoots = solveCubic(r)) != 0)
1117          for (int i = 0; i < nRoots; i++)
1118            {
1119              double t = r[i];
1120              if (t >= 0.0 && t <= 1.0)
1121                {
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)
1126                    nCrossings++;
1127                }
1128            }
1129    
1130        return (nCrossings);
1131      }
1132    
1133      /**
1134       * A two-dimensional curve that is parameterized with a cubic
1135       * function and stores coordinate values in double-precision
1136       * floating-point format.
1137       *
1138       * @see CubicCurve2D.Float
1139       *
1140       * @author Eric Blake (ebb9@email.byu.edu)
1141       * @author Sascha Brawer (brawer@dandelis.ch)
1142       */
1143      public static class Double extends CubicCurve2D
1144      {
1145        /**
1146         * The <i>x</i> coordinate of the curve&#x2019;s start point.
1147         */
1148        public double x1;
1149    
1150        /**
1151         * The <i>y</i> coordinate of the curve&#x2019;s start point.
1152         */
1153        public double y1;
1154    
1155        /**
1156         * The <i>x</i> coordinate of the curve&#x2019;s first control point.
1157         */
1158        public double ctrlx1;
1159    
1160        /**
1161         * The <i>y</i> coordinate of the curve&#x2019;s first control point.
1162         */
1163        public double ctrly1;
1164    
1165        /**
1166         * The <i>x</i> coordinate of the curve&#x2019;s second control point.
1167         */
1168        public double ctrlx2;
1169    
1170        /**
1171         * The <i>y</i> coordinate of the curve&#x2019;s second control point.
1172         */
1173        public double ctrly2;
1174    
1175        /**
1176         * The <i>x</i> coordinate of the curve&#x2019;s end point.
1177         */
1178        public double x2;
1179    
1180        /**
1181         * The <i>y</i> coordinate of the curve&#x2019;s end point.
1182         */
1183        public double y2;
1184    
1185        /**
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).
1189         */
1190        public Double()
1191        {
1192        }
1193    
1194        /**
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.
1198         *
1199         * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
1200         * alt="A drawing of a CubicCurve2D" />
1201         *
1202         * @param x1 the <i>x</i> coordinate of the curve&#x2019;s start
1203         * point.
1204         *
1205         * @param y1 the <i>y</i> coordinate of the curve&#x2019;s start
1206         * point.
1207         *
1208         * @param cx1 the <i>x</i> coordinate of the curve&#x2019;s first
1209         * control point.
1210         *
1211         * @param cy1 the <i>y</i> coordinate of the curve&#x2019;s first
1212         * control point.
1213         *
1214         * @param cx2 the <i>x</i> coordinate of the curve&#x2019;s second
1215         * control point.
1216         *
1217         * @param cy2 the <i>y</i> coordinate of the curve&#x2019;s second
1218         * control point.
1219         *
1220         * @param x2 the <i>x</i> coordinate of the curve&#x2019;s end
1221         * point.
1222         *
1223         * @param y2 the <i>y</i> coordinate of the curve&#x2019;s end
1224         * point.
1225         */
1226        public Double(double x1, double y1, double cx1, double cy1, double cx2,
1227                      double cy2, double x2, double y2)
1228        {
1229          this.x1 = x1;
1230          this.y1 = y1;
1231          ctrlx1 = cx1;
1232          ctrly1 = cy1;
1233          ctrlx2 = cx2;
1234          ctrly2 = cy2;
1235          this.x2 = x2;
1236          this.y2 = y2;
1237        }
1238    
1239        /**
1240         * Returns the <i>x</i> coordinate of the curve&#x2019;s start
1241         * point.
1242         */
1243        public double getX1()
1244        {
1245          return x1;
1246        }
1247    
1248        /**
1249         * Returns the <i>y</i> coordinate of the curve&#x2019;s start
1250         * point.
1251         */
1252        public double getY1()
1253        {
1254          return y1;
1255        }
1256    
1257        /**
1258         * Returns the curve&#x2019;s start point.
1259         */
1260        public Point2D getP1()
1261        {
1262          return new Point2D.Double(x1, y1);
1263        }
1264    
1265        /**
1266         * Returns the <i>x</i> coordinate of the curve&#x2019;s first
1267         * control point.
1268         */
1269        public double getCtrlX1()
1270        {
1271          return ctrlx1;
1272        }
1273    
1274        /**
1275         * Returns the <i>y</i> coordinate of the curve&#x2019;s first
1276         * control point.
1277         */
1278        public double getCtrlY1()
1279        {
1280          return ctrly1;
1281        }
1282    
1283        /**
1284         * Returns the curve&#x2019;s first control point.
1285         */
1286        public Point2D getCtrlP1()
1287        {
1288          return new Point2D.Double(ctrlx1, ctrly1);
1289        }
1290    
1291        /**
1292         * Returns the <i>x</i> coordinate of the curve&#x2019;s second
1293         * control point.
1294         */
1295        public double getCtrlX2()
1296        {
1297          return ctrlx2;
1298        }
1299    
1300        /**
1301         * Returns the <i>y</i> coordinate of the curve&#x2019;s second
1302         * control point.
1303         */
1304        public double getCtrlY2()
1305        {
1306          return ctrly2;
1307        }
1308    
1309        /**
1310         * Returns the curve&#x2019;s second control point.
1311         */
1312        public Point2D getCtrlP2()
1313        {
1314          return new Point2D.Double(ctrlx2, ctrly2);
1315        }
1316    
1317        /**
1318         * Returns the <i>x</i> coordinate of the curve&#x2019;s end
1319         * point.
1320         */
1321        public double getX2()
1322        {
1323          return x2;
1324        }
1325    
1326        /**
1327         * Returns the <i>y</i> coordinate of the curve&#x2019;s end
1328         * point.
1329         */
1330        public double getY2()
1331        {
1332          return y2;
1333        }
1334    
1335        /**
1336         * Returns the curve&#x2019;s end point.
1337         */
1338        public Point2D getP2()
1339        {
1340          return new Point2D.Double(x2, y2);
1341        }
1342    
1343        /**
1344         * Changes the curve geometry, separately specifying each coordinate
1345         * value.
1346         *
1347         * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
1348         * alt="A drawing of a CubicCurve2D" />
1349         *
1350         * @param x1 the <i>x</i> coordinate of the curve&#x2019;s new start
1351         * point.
1352         *
1353         * @param y1 the <i>y</i> coordinate of the curve&#x2019;s new start
1354         * point.
1355         *
1356         * @param cx1 the <i>x</i> coordinate of the curve&#x2019;s new
1357         * first control point.
1358         *
1359         * @param cy1 the <i>y</i> coordinate of the curve&#x2019;s new
1360         * first control point.
1361         *
1362         * @param cx2 the <i>x</i> coordinate of the curve&#x2019;s new
1363         * second control point.
1364         *
1365         * @param cy2 the <i>y</i> coordinate of the curve&#x2019;s new
1366         * second control point.
1367         *
1368         * @param x2 the <i>x</i> coordinate of the curve&#x2019;s new end
1369         * point.
1370         *
1371         * @param y2 the <i>y</i> coordinate of the curve&#x2019;s new end
1372         * point.
1373         */
1374        public void setCurve(double x1, double y1, double cx1, double cy1,
1375                             double cx2, double cy2, double x2, double y2)
1376        {
1377          this.x1 = x1;
1378          this.y1 = y1;
1379          ctrlx1 = cx1;
1380          ctrly1 = cy1;
1381          ctrlx2 = cx2;
1382          ctrly2 = cy2;
1383          this.x2 = x2;
1384          this.y2 = y2;
1385        }
1386    
1387        /**
1388         * Determines the smallest rectangle that encloses the
1389         * curve&#x2019;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.
1393         *
1394         * <p><img src="doc-files/CubicCurve2D-2.png" width="350" height="180"
1395         * alt="An illustration of the bounds of a CubicCurve2D" />
1396         */
1397        public Rectangle2D getBounds2D()
1398        {
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);
1404        }
1405      }
1406    
1407      /**
1408       * A two-dimensional curve that is parameterized with a cubic
1409       * function and stores coordinate values in single-precision
1410       * floating-point format.
1411       *
1412       * @see CubicCurve2D.Float
1413       *
1414       * @author Eric Blake (ebb9@email.byu.edu)
1415       * @author Sascha Brawer (brawer@dandelis.ch)
1416       */
1417      public static class Float extends CubicCurve2D
1418      {
1419        /**
1420         * The <i>x</i> coordinate of the curve&#x2019;s start point.
1421         */
1422        public float x1;
1423    
1424        /**
1425         * The <i>y</i> coordinate of the curve&#x2019;s start point.
1426         */
1427        public float y1;
1428    
1429        /**
1430         * The <i>x</i> coordinate of the curve&#x2019;s first control point.
1431         */
1432        public float ctrlx1;
1433    
1434        /**
1435         * The <i>y</i> coordinate of the curve&#x2019;s first control point.
1436         */
1437        public float ctrly1;
1438    
1439        /**
1440         * The <i>x</i> coordinate of the curve&#x2019;s second control point.
1441         */
1442        public float ctrlx2;
1443    
1444        /**
1445         * The <i>y</i> coordinate of the curve&#x2019;s second control point.
1446         */
1447        public float ctrly2;
1448    
1449        /**
1450         * The <i>x</i> coordinate of the curve&#x2019;s end point.
1451         */
1452        public float x2;
1453    
1454        /**
1455         * The <i>y</i> coordinate of the curve&#x2019;s end point.
1456         */
1457        public float y2;
1458    
1459        /**
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).
1463         */
1464        public Float()
1465        {
1466        }
1467    
1468        /**
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.
1472         *
1473         * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
1474         * alt="A drawing of a CubicCurve2D" />
1475         *
1476         * @param x1 the <i>x</i> coordinate of the curve&#x2019;s start
1477         * point.
1478         *
1479         * @param y1 the <i>y</i> coordinate of the curve&#x2019;s start
1480         * point.
1481         *
1482         * @param cx1 the <i>x</i> coordinate of the curve&#x2019;s first
1483         * control point.
1484         *
1485         * @param cy1 the <i>y</i> coordinate of the curve&#x2019;s first
1486         * control point.
1487         *
1488         * @param cx2 the <i>x</i> coordinate of the curve&#x2019;s second
1489         * control point.
1490         *
1491         * @param cy2 the <i>y</i> coordinate of the curve&#x2019;s second
1492         * control point.
1493         *
1494         * @param x2 the <i>x</i> coordinate of the curve&#x2019;s end
1495         * point.
1496         *
1497         * @param y2 the <i>y</i> coordinate of the curve&#x2019;s end
1498         * point.
1499         */
1500        public Float(float x1, float y1, float cx1, float cy1, float cx2,
1501                     float cy2, float x2, float y2)
1502        {
1503          this.x1 = x1;
1504          this.y1 = y1;
1505          ctrlx1 = cx1;
1506          ctrly1 = cy1;
1507          ctrlx2 = cx2;
1508          ctrly2 = cy2;
1509          this.x2 = x2;
1510          this.y2 = y2;
1511        }
1512    
1513        /**
1514         * Returns the <i>x</i> coordinate of the curve&#x2019;s start
1515         * point.
1516         */
1517        public double getX1()
1518        {
1519          return x1;
1520        }
1521    
1522        /**
1523         * Returns the <i>y</i> coordinate of the curve&#x2019;s start
1524         * point.
1525         */
1526        public double getY1()
1527        {
1528          return y1;
1529        }
1530    
1531        /**
1532         * Returns the curve&#x2019;s start point.
1533         */
1534        public Point2D getP1()
1535        {
1536          return new Point2D.Float(x1, y1);
1537        }
1538    
1539        /**
1540         * Returns the <i>x</i> coordinate of the curve&#x2019;s first
1541         * control point.
1542         */
1543        public double getCtrlX1()
1544        {
1545          return ctrlx1;
1546        }
1547    
1548        /**
1549         * Returns the <i>y</i> coordinate of the curve&#x2019;s first
1550         * control point.
1551         */
1552        public double getCtrlY1()
1553        {
1554          return ctrly1;
1555        }
1556    
1557        /**
1558         * Returns the curve&#x2019;s first control point.
1559         */
1560        public Point2D getCtrlP1()
1561        {
1562          return new Point2D.Float(ctrlx1, ctrly1);
1563        }
1564    
1565        /**
1566         * Returns the <i>s</i> coordinate of the curve&#x2019;s second
1567         * control point.
1568         */
1569        public double getCtrlX2()
1570        {
1571          return ctrlx2;
1572        }
1573    
1574        /**
1575         * Returns the <i>y</i> coordinate of the curve&#x2019;s second
1576         * control point.
1577         */
1578        public double getCtrlY2()
1579        {
1580          return ctrly2;
1581        }
1582    
1583        /**
1584         * Returns the curve&#x2019;s second control point.
1585         */
1586        public Point2D getCtrlP2()
1587        {
1588          return new Point2D.Float(ctrlx2, ctrly2);
1589        }
1590    
1591        /**
1592         * Returns the <i>x</i> coordinate of the curve&#x2019;s end
1593         * point.
1594         */
1595        public double getX2()
1596        {
1597          return x2;
1598        }
1599    
1600        /**
1601         * Returns the <i>y</i> coordinate of the curve&#x2019;s end
1602         * point.
1603         */
1604        public double getY2()
1605        {
1606          return y2;
1607        }
1608    
1609        /**
1610         * Returns the curve&#x2019;s end point.
1611         */
1612        public Point2D getP2()
1613        {
1614          return new Point2D.Float(x2, y2);
1615        }
1616    
1617        /**
1618         * Changes the curve geometry, separately specifying each coordinate
1619         * value as a double-precision floating-point number.
1620         *
1621         * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
1622         * alt="A drawing of a CubicCurve2D" />
1623         *
1624         * @param x1 the <i>x</i> coordinate of the curve&#x2019;s new start
1625         * point.
1626         *
1627         * @param y1 the <i>y</i> coordinate of the curve&#x2019;s new start
1628         * point.
1629         *
1630         * @param cx1 the <i>x</i> coordinate of the curve&#x2019;s new
1631         * first control point.
1632         *
1633         * @param cy1 the <i>y</i> coordinate of the curve&#x2019;s new
1634         * first control point.
1635         *
1636         * @param cx2 the <i>x</i> coordinate of the curve&#x2019;s new
1637         * second control point.
1638         *
1639         * @param cy2 the <i>y</i> coordinate of the curve&#x2019;s new
1640         * second control point.
1641         *
1642         * @param x2 the <i>x</i> coordinate of the curve&#x2019;s new end
1643         * point.
1644         *
1645         * @param y2 the <i>y</i> coordinate of the curve&#x2019;s new end
1646         * point.
1647         */
1648        public void setCurve(double x1, double y1, double cx1, double cy1,
1649                             double cx2, double cy2, double x2, double y2)
1650        {
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;
1659        }
1660    
1661        /**
1662         * Changes the curve geometry, separately specifying each coordinate
1663         * value as a single-precision floating-point number.
1664         *
1665         * <p><img src="doc-files/CubicCurve2D-1.png" width="350" height="180"
1666         * alt="A drawing of a CubicCurve2D" />
1667         *
1668         * @param x1 the <i>x</i> coordinate of the curve&#x2019;s new start
1669         * point.
1670         *
1671         * @param y1 the <i>y</i> coordinate of the curve&#x2019;s new start
1672         * point.
1673         *
1674         * @param cx1 the <i>x</i> coordinate of the curve&#x2019;s new
1675         * first control point.
1676         *
1677         * @param cy1 the <i>y</i> coordinate of the curve&#x2019;s new
1678         * first control point.
1679         *
1680         * @param cx2 the <i>x</i> coordinate of the curve&#x2019;s new
1681         * second control point.
1682         *
1683         * @param cy2 the <i>y</i> coordinate of the curve&#x2019;s new
1684         * second control point.
1685         *
1686         * @param x2 the <i>x</i> coordinate of the curve&#x2019;s new end
1687         * point.
1688         *
1689         * @param y2 the <i>y</i> coordinate of the curve&#x2019;s new end
1690         * point.
1691         */
1692        public void setCurve(float x1, float y1, float cx1, float cy1, float cx2,
1693                             float cy2, float x2, float y2)
1694        {
1695          this.x1 = x1;
1696          this.y1 = y1;
1697          ctrlx1 = cx1;
1698          ctrly1 = cy1;
1699          ctrlx2 = cx2;
1700          ctrly2 = cy2;
1701          this.x2 = x2;
1702          this.y2 = y2;
1703        }
1704    
1705        /**
1706         * Determines the smallest rectangle that encloses the
1707         * curve&#x2019;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.
1711         *
1712         * <p><img src="doc-files/CubicCurve2D-2.png" width="350" height="180"
1713         * alt="An illustration of the bounds of a CubicCurve2D" />
1714         */
1715        public Rectangle2D getBounds2D()
1716        {
1717          float nx1 = Math.min(Math.min(x1, ctrlx1), Math.min(ctrlx2, x2));
1718          float ny1 = Math.min(Math.min(y1, ctrly1), Math.min(ctrly2, y2));
1719          float nx2 = Math.max(Math.max(x1, ctrlx1), Math.max(ctrlx2, x2));
1720          float ny2 = Math.max(Math.max(y1, ctrly1), Math.max(ctrly2, y2));
1721          return new Rectangle2D.Float(nx1, ny1, nx2 - nx1, ny2 - ny1);
1722        }
1723      }
1724    }