KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > geom > Path2D


1 /*
2  * @(#)Path2D.java 1.4 06/04/19
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt.geom;
9
10 import java.awt.Shape JavaDoc;
11 import java.awt.Rectangle JavaDoc;
12 import sun.awt.geom.Curve;
13 import java.io.Serializable JavaDoc;
14 import java.io.StreamCorruptedException JavaDoc;
15 import java.util.Arrays JavaDoc;
16
17 /**
18  * The {@code Path2D} class provides a simple, yet flexible
19  * shape which represents an arbitrary geometric path.
20  * It can fully represent any path which can be iterated by the
21  * {@link PathIterator} interface including all of its segment
22  * types and winding rules and it implements all of the
23  * basic hit testing methods of the {@link Shape} interface.
24  * <p>
25  * Use {@link Path2D.Float} when dealing with data that can be represented
26  * and used with floating point precision. Use {@link Path2D.Double}
27  * for data that requires the accuracy or range of double precision.
28  * <p>
29  * {@code Path2D} provides exactly those facilities required for
30  * basic construction and management of a geometric path and
31  * implementation of the above interfaces with little added
32  * interpretation.
33  * If it is useful to manipulate the interiors of closed
34  * geometric shapes beyond simple hit testing then the
35  * {@link Area} class provides additional capabilities
36  * specifically targeted at closed figures.
37  * While both classes nominally implement the {@code Shape}
38  * interface, they differ in purpose and together they provide
39  * two useful views of a geometric shape where {@code Path2D}
40  * deals primarily with a trajectory formed by path segments
41  * and {@code Area} deals more with interpretation and manipulation
42  * of enclosed regions of 2D geometric space.
43  * <p>
44  * The {@link PathIterator} interface has more detailed descriptions
45  * of the types of segments that make up a path and the winding rules
46  * that control how to determine which regions are inside or outside
47  * the path.
48  *
49  * @version 1.4, 04/19/06
50  * @author Jim Graham
51  * @since 1.6
52  */

53 public abstract class Path2D implements Shape JavaDoc, Cloneable JavaDoc {
54     /**
55      * An even-odd winding rule for determining the interior of
56      * a path.
57      *
58      * @see PathIterator#WIND_EVEN_ODD
59      * @since 1.6
60      */

61     public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
62
63     /**
64      * A non-zero winding rule for determining the interior of a
65      * path.
66      *
67      * @see PathIterator#WIND_NON_ZERO
68      * @since 1.6
69      */

70     public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
71     
72     // For code simplicity, copy these constants to our namespace
73
// and cast them to byte constants for easy storage.
74
private static final byte SEG_MOVETO = (byte) PathIterator.SEG_MOVETO;
75     private static final byte SEG_LINETO = (byte) PathIterator.SEG_LINETO;
76     private static final byte SEG_QUADTO = (byte) PathIterator.SEG_QUADTO;
77     private static final byte SEG_CUBICTO = (byte) PathIterator.SEG_CUBICTO;
78     private static final byte SEG_CLOSE = (byte) PathIterator.SEG_CLOSE;
79
80     transient byte[] pointTypes;
81     transient int numTypes;
82     transient int numCoords;
83     transient int windingRule;
84
85     static final int INIT_SIZE = 20;
86     static final int EXPAND_MAX = 500;
87
88     /**
89      * Constructs a new empty {@code Path2D} object.
90      * It is assumed that the package sibling subclass that is
91      * defaulting to this constructor will fill in all values.
92      *
93      * @since 1.6
94      */

95     /* private protected */
96     Path2D() {
97     }
98
99     /**
100      * Constructs a new {@code Path2D} object from the given
101      * specified initial values.
102      * This method is only intended for internal use and should
103      * not be made public if the other constructors for this class
104      * are ever exposed.
105      *
106      * @param rule the winding rule
107      * @param initialTypes the size to make the initial array to
108      * store the path segment types
109      * @since 1.6
110      */

111     /* private protected */
112     Path2D(int rule, int initialTypes) {
113         setWindingRule(rule);
114         this.pointTypes = new byte[initialTypes];
115     }
116  
117     abstract float[] cloneCoordsFloat(AffineTransform JavaDoc at);
118     abstract double[] cloneCoordsDouble(AffineTransform JavaDoc at);
119     abstract void append(float x, float y);
120     abstract void append(double x, double y);
121     abstract Point2D JavaDoc getPoint(int coordindex);
122     abstract void needRoom(boolean needMove, int newCoords);
123     abstract int pointCrossings(double px, double py);
124     abstract int rectCrossings(double rxmin, double rymin,
125                                double rxmax, double rymax);
126
127     /**
128      * The {@code Float} class defines a geometric path with
129      * coordinates stored in single precision floating point.
130      *
131      * @since 1.6
132      */

133     public static class Float extends Path2D JavaDoc implements Serializable JavaDoc {
134         transient float floatCoords[];
135
136         /**
137          * Constructs a new empty single precision {@code Path2D} object
138          * with a default winding rule of {@link #WIND_NON_ZERO}.
139          *
140          * @since 1.6
141          */

142         public Float() {
143             this(WIND_NON_ZERO, INIT_SIZE);
144         }
145
146         /**
147          * Constructs a new empty single precision {@code Path2D} object
148          * with the specified winding rule to control operations that
149          * require the interior of the path to be defined.
150          *
151          * @param rule the winding rule
152          * @see #WIND_EVEN_ODD
153          * @see #WIND_NON_ZERO
154          * @since 1.6
155          */

156         public Float(int rule) {
157             this(rule, INIT_SIZE);
158         }
159
160         /**
161          * Constructs a new empty single precision {@code Path2D} object
162          * with the specified winding rule and the specified initial
163          * capacity to store path segments.
164          * This number is an initial guess as to how many path segments
165          * will be added to the path, but the storage is expanded as
166          * needed to store whatever path segments are added.
167          *
168          * @param rule the winding rule
169          * @param initialCapacity the estimate for the number of path segments
170          * in the path
171          * @see #WIND_EVEN_ODD
172          * @see #WIND_NON_ZERO
173          * @since 1.6
174          */

175         public Float(int rule, int initialCapacity) {
176             super(rule, initialCapacity);
177             floatCoords = new float[initialCapacity * 2];
178         }
179
180         /**
181          * Constructs a new single precision {@code Path2D} object
182          * from an arbitrary {@link Shape} object.
183          * All of the initial geometry and the winding rule for this path are
184          * taken from the specified {@code Shape} object.
185          *
186          * @param s the specified {@code Shape} object
187          * @since 1.6
188          */

189         public Float(Shape JavaDoc s) {
190             this(s, null);
191         }
192
193         /**
194          * Constructs a new single precision {@code Path2D} object
195          * from an arbitrary {@link Shape} object, transformed by an
196          * {@link AffineTransform} object.
197          * All of the initial geometry and the winding rule for this path are
198          * taken from the specified {@code Shape} object and transformed
199          * by the specified {@code AffineTransform} object.
200          *
201          * @param s the specified {@code Shape} object
202          * @param at the specified {@code AffineTransform} object
203          * @since 1.6
204          */

205         public Float(Shape JavaDoc s, AffineTransform JavaDoc at) {
206             if (s instanceof Path2D JavaDoc) {
207                 Path2D JavaDoc p2d = (Path2D JavaDoc) s;
208                 setWindingRule(p2d.windingRule);
209                 this.numTypes = p2d.numTypes;
210                 this.pointTypes = Arrays.copyOf(p2d.pointTypes,
211                                                 p2d.pointTypes.length);
212                 this.numCoords = p2d.numCoords;
213                 this.floatCoords = p2d.cloneCoordsFloat(at);
214             } else {
215                 PathIterator JavaDoc pi = s.getPathIterator(at);
216                 setWindingRule(pi.getWindingRule());
217                 this.pointTypes = new byte[INIT_SIZE];
218                 this.floatCoords = new float[INIT_SIZE * 2];
219                 append(pi, false);
220             }
221         }
222
223         float[] cloneCoordsFloat(AffineTransform JavaDoc at) {
224             float ret[];
225             if (at == null) {
226                 ret = Arrays.copyOf(this.floatCoords, this.floatCoords.length);
227             } else {
228                 ret = new float[floatCoords.length];
229                 at.transform(floatCoords, 0, ret, 0, numCoords / 2);
230             }
231             return ret;
232         }
233
234         double[] cloneCoordsDouble(AffineTransform JavaDoc at) {
235             double ret[] = new double[floatCoords.length];
236             if (at == null) {
237                 for (int i = 0; i < numCoords; i++) {
238                     ret[i] = floatCoords[i];
239                 }
240             } else {
241                 at.transform(floatCoords, 0, ret, 0, numCoords / 2);
242             }
243             return ret;
244         }
245
246         void append(float x, float y) {
247             floatCoords[numCoords++] = x;
248             floatCoords[numCoords++] = y;
249         }
250
251         void append(double x, double y) {
252             floatCoords[numCoords++] = (float) x;
253             floatCoords[numCoords++] = (float) y;
254         }
255
256         Point2D JavaDoc getPoint(int coordindex) {
257             return new Point2D.Float JavaDoc(floatCoords[coordindex],
258                                      floatCoords[coordindex+1]);
259         }
260
261         void needRoom(boolean needMove, int newCoords) {
262             if (needMove && numTypes == 0) {
263                 throw new IllegalPathStateException JavaDoc("missing initial moveto "+
264                                                     "in path definition");
265             }
266             int size = pointTypes.length;
267             if (numTypes >= size) {
268                 int grow = size;
269                 if (grow > EXPAND_MAX) {
270                     grow = EXPAND_MAX;
271                 }
272                 pointTypes = Arrays.copyOf(pointTypes, size+grow);
273             }
274             size = floatCoords.length;
275             if (numCoords + newCoords > size) {
276                 int grow = size;
277                 if (grow > EXPAND_MAX * 2) {
278                     grow = EXPAND_MAX * 2;
279                 }
280                 if (grow < newCoords) {
281                     grow = newCoords;
282                 }
283                 floatCoords = Arrays.copyOf(floatCoords, size+grow);
284             }
285         }
286
287         /**
288          * {@inheritDoc}
289          * @since 1.6
290          */

291         public final synchronized void moveTo(double x, double y) {
292             if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
293                 floatCoords[numCoords-2] = (float) x;
294                 floatCoords[numCoords-1] = (float) y;
295             } else {
296                 needRoom(false, 2);
297                 pointTypes[numTypes++] = SEG_MOVETO;
298                 floatCoords[numCoords++] = (float) x;
299                 floatCoords[numCoords++] = (float) y;
300             }
301         }
302
303         /**
304          * Adds a point to the path by moving to the specified
305          * coordinates specified in float precision.
306          * <p>
307          * This method provides a single precision variant of
308          * the double precision {@code moveTo()} method on the
309          * base {@code Path2D} class.
310          *
311          * @param x the specified X coordinate
312          * @param y the specified Y coordinate
313          * @see Path2D#moveTo
314          * @since 1.6
315          */

316         public final synchronized void moveTo(float x, float y) {
317             if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
318                 floatCoords[numCoords-2] = x;
319                 floatCoords[numCoords-1] = y;
320             } else {
321                 needRoom(false, 2);
322                 pointTypes[numTypes++] = SEG_MOVETO;
323                 floatCoords[numCoords++] = x;
324                 floatCoords[numCoords++] = y;
325             }
326         }
327
328         /**
329          * {@inheritDoc}
330          * @since 1.6
331          */

332         public final synchronized void lineTo(double x, double y) {
333             needRoom(true, 2);
334             pointTypes[numTypes++] = SEG_LINETO;
335             floatCoords[numCoords++] = (float) x;
336             floatCoords[numCoords++] = (float) y;
337         }
338
339         /**
340          * Adds a point to the path by drawing a straight line from the
341          * current coordinates to the new specified coordinates
342          * specified in float precision.
343          * <p>
344          * This method provides a single precision variant of
345          * the double precision {@code lineTo()} method on the
346          * base {@code Path2D} class.
347          *
348          * @param x the specified X coordinate
349          * @param y the specified Y coordinate
350          * @see Path2D#lineTo
351          * @since 1.6
352          */

353         public final synchronized void lineTo(float x, float y) {
354             needRoom(true, 2);
355             pointTypes[numTypes++] = SEG_LINETO;
356             floatCoords[numCoords++] = x;
357             floatCoords[numCoords++] = y;
358         }
359
360         /**
361          * {@inheritDoc}
362          * @since 1.6
363          */

364         public final synchronized void quadTo(double x1, double y1,
365                                               double x2, double y2)
366         {
367             needRoom(true, 4);
368             pointTypes[numTypes++] = SEG_QUADTO;
369             floatCoords[numCoords++] = (float) x1;
370             floatCoords[numCoords++] = (float) y1;
371             floatCoords[numCoords++] = (float) x2;
372             floatCoords[numCoords++] = (float) y2;
373         }
374
375         /**
376          * Adds a curved segment, defined by two new points, to the path by
377          * drawing a Quadratic curve that intersects both the current
378          * coordinates and the specified coordinates {@code (x2,y2)},
379          * using the specified point {@code (x1,y1)} as a quadratic
380          * parametric control point.
381          * All coordinates are specified in float precision.
382          * <p>
383          * This method provides a single precision variant of
384          * the double precision {@code quadTo()} method on the
385          * base {@code Path2D} class.
386          *
387          * @param x1 the X coordinate of the quadratic control point
388          * @param y1 the Y coordinate of the quadratic control point
389          * @param x2 the X coordinate of the final end point
390          * @param y2 the Y coordinate of the final end point
391          * @see Path2D#quadTo
392          * @since 1.6
393          */

394         public final synchronized void quadTo(float x1, float y1,
395                                               float x2, float y2)
396         {
397             needRoom(true, 4);
398             pointTypes[numTypes++] = SEG_QUADTO;
399             floatCoords[numCoords++] = x1;
400             floatCoords[numCoords++] = y1;
401             floatCoords[numCoords++] = x2;
402             floatCoords[numCoords++] = y2;
403         }
404
405         /**
406          * {@inheritDoc}
407          * @since 1.6
408          */

409         public final synchronized void curveTo(double x1, double y1,
410                                                double x2, double y2,
411                                                double x3, double y3)
412         {
413             needRoom(true, 6);
414             pointTypes[numTypes++] = SEG_CUBICTO;
415             floatCoords[numCoords++] = (float) x1;
416             floatCoords[numCoords++] = (float) y1;
417             floatCoords[numCoords++] = (float) x2;
418             floatCoords[numCoords++] = (float) y2;
419             floatCoords[numCoords++] = (float) x3;
420             floatCoords[numCoords++] = (float) y3;
421         }
422
423         /**
424          * Adds a curved segment, defined by three new points, to the path by
425          * drawing a B&eacute;zier curve that intersects both the current
426          * coordinates and the specified coordinates {@code (x3,y3)},
427          * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
428          * B&eacute;zier control points.
429          * All coordinates are specified in float precision.
430          * <p>
431          * This method provides a single precision variant of
432          * the double precision {@code curveTo()} method on the
433          * base {@code Path2D} class.
434          *
435          * @param x1 the X coordinate of the first B&eacute;zier control point
436          * @param y1 the Y coordinate of the first B&eacute;zier control point
437          * @param x2 the X coordinate of the second B&eacute;zier control point
438          * @param y2 the Y coordinate of the second B&eacute;zier control point
439          * @param x3 the X coordinate of the final end point
440          * @param y3 the Y coordinate of the final end point
441          * @see Path2D#curveTo
442          * @since 1.6
443          */

444         public final synchronized void curveTo(float x1, float y1,
445                                                float x2, float y2,
446                                                float x3, float y3)
447         {
448             needRoom(true, 6);
449             pointTypes[numTypes++] = SEG_CUBICTO;
450             floatCoords[numCoords++] = x1;
451             floatCoords[numCoords++] = y1;
452             floatCoords[numCoords++] = x2;
453             floatCoords[numCoords++] = y2;
454             floatCoords[numCoords++] = x3;
455             floatCoords[numCoords++] = y3;
456         }
457
458         int pointCrossings(double px, double py) {
459             double movx, movy, curx, cury, endx, endy;
460             float coords[] = floatCoords;
461             curx = movx = coords[0];
462             cury = movy = coords[1];
463             int crossings = 0;
464             int ci = 2;
465             for (int i = 1; i < numTypes; i++) {
466                 switch (pointTypes[i]) {
467                 case PathIterator.SEG_MOVETO:
468                     if (cury != movy) {
469                         crossings +=
470                             Curve.pointCrossingsForLine(px, py,
471                                                         curx, cury,
472                                                         movx, movy);
473                     }
474                     movx = curx = coords[ci++];
475                     movy = cury = coords[ci++];
476                     break;
477                 case PathIterator.SEG_LINETO:
478                     crossings +=
479                         Curve.pointCrossingsForLine(px, py,
480                                                     curx, cury,
481                                                     endx = coords[ci++],
482                                                     endy = coords[ci++]);
483                     curx = endx;
484                     cury = endy;
485                     break;
486                 case PathIterator.SEG_QUADTO:
487                     crossings +=
488                         Curve.pointCrossingsForQuad(px, py,
489                                                     curx, cury,
490                                                     coords[ci++],
491                                                     coords[ci++],
492                                                     endx = coords[ci++],
493                                                     endy = coords[ci++],
494                                                     0);
495                     curx = endx;
496                     cury = endy;
497                     break;
498             case PathIterator.SEG_CUBICTO:
499                     crossings +=
500                         Curve.pointCrossingsForCubic(px, py,
501                                                      curx, cury,
502                                                      coords[ci++],
503                                                      coords[ci++],
504                                                      coords[ci++],
505                                                      coords[ci++],
506                                                      endx = coords[ci++],
507                                                      endy = coords[ci++],
508                                                      0);
509                     curx = endx;
510                     cury = endy;
511                     break;
512                 case PathIterator.SEG_CLOSE:
513                     if (cury != movy) {
514                         crossings +=
515                             Curve.pointCrossingsForLine(px, py,
516                                                         curx, cury,
517                                                         movx, movy);
518                     }
519                     curx = movx;
520                     cury = movy;
521                     break;
522                 }
523             }
524             if (cury != movy) {
525                 crossings +=
526                     Curve.pointCrossingsForLine(px, py,
527                                                 curx, cury,
528                                                 movx, movy);
529             }
530             return crossings;
531         }
532
533         int rectCrossings(double rxmin, double rymin,
534                           double rxmax, double rymax)
535         {
536             float coords[] = floatCoords;
537             double curx, cury, movx, movy, endx, endy;
538             curx = movx = coords[0];
539             cury = movy = coords[1];
540             int crossings = 0;
541             int ci = 2;
542             for (int i = 1;
543                  crossings != Curve.RECT_INTERSECTS && i < numTypes;
544                  i++)
545             {
546                 switch (pointTypes[i]) {
547                 case PathIterator.SEG_MOVETO:
548                     if (curx != movx || cury != movy) {
549                         crossings =
550                             Curve.rectCrossingsForLine(crossings,
551                                                        rxmin, rymin,
552                                                        rxmax, rymax,
553                                                        curx, cury,
554                                                        movx, movy);
555                     }
556                     // Count should always be a multiple of 2 here.
557
// assert((crossings & 1) != 0);
558
movx = curx = coords[ci++];
559                     movy = cury = coords[ci++];
560                     break;
561                 case PathIterator.SEG_LINETO:
562                     crossings =
563                         Curve.rectCrossingsForLine(crossings,
564                                                    rxmin, rymin,
565                                                    rxmax, rymax,
566                                                    curx, cury,
567                                                    endx = coords[ci++],
568                                                    endy = coords[ci++]);
569                     curx = endx;
570                     cury = endy;
571                     break;
572                 case PathIterator.SEG_QUADTO:
573                     crossings =
574                         Curve.rectCrossingsForQuad(crossings,
575                                                    rxmin, rymin,
576                                                    rxmax, rymax,
577                                                    curx, cury,
578                                                    coords[ci++],
579                                                    coords[ci++],
580                                                    endx = coords[ci++],
581                                                    endy = coords[ci++],
582                                                    0);
583                     curx = endx;
584                     cury = endy;
585                     break;
586                 case PathIterator.SEG_CUBICTO:
587                     crossings =
588                         Curve.rectCrossingsForCubic(crossings,
589                                                     rxmin, rymin,
590                                                     rxmax, rymax,
591                                                     curx, cury,
592                                                     coords[ci++],
593                                                     coords[ci++],
594                                                     coords[ci++],
595                                                     coords[ci++],
596                                                     endx = coords[ci++],
597                                                     endy = coords[ci++],
598                                                     0);
599                     curx = endx;
600                     cury = endy;
601                     break;
602                 case PathIterator.SEG_CLOSE:
603                     if (curx != movx || cury != movy) {
604                         crossings =
605                             Curve.rectCrossingsForLine(crossings,
606                                                        rxmin, rymin,
607                                                        rxmax, rymax,
608                                                        curx, cury,
609                                                        movx, movy);
610                     }
611                     curx = movx;
612                     cury = movy;
613                     // Count should always be a multiple of 2 here.
614
// assert((crossings & 1) != 0);
615
break;
616                 }
617             }
618             if (crossings != Curve.RECT_INTERSECTS &&
619                 (curx != movx || cury != movy))
620             {
621                 crossings =
622                     Curve.rectCrossingsForLine(crossings,
623                                                rxmin, rymin,
624                                                rxmax, rymax,
625                                                curx, cury,
626                                                movx, movy);
627             }
628             // Count should always be a multiple of 2 here.
629
// assert((crossings & 1) != 0);
630
return crossings;
631         }
632
633         /**
634          * {@inheritDoc}
635          * @since 1.6
636          */

637         public final void append(PathIterator JavaDoc pi, boolean connect) {
638             float coords[] = new float[6];
639             while (!pi.isDone()) {
640                 switch (pi.currentSegment(coords)) {
641                 case SEG_MOVETO:
642                     if (!connect || numTypes < 1 || numCoords < 1) {
643                         moveTo(coords[0], coords[1]);
644                         break;
645                     }
646                     if (pointTypes[numTypes - 1] != SEG_CLOSE &&
647                         floatCoords[numCoords-2] == coords[0] &&
648                         floatCoords[numCoords-1] == coords[1])
649                     {
650                         // Collapse out initial moveto/lineto
651
break;
652                     }
653                     // NO BREAK;
654
case SEG_LINETO:
655                     lineTo(coords[0], coords[1]);
656                     break;
657                 case SEG_QUADTO:
658                     quadTo(coords[0], coords[1],
659                            coords[2], coords[3]);
660                     break;
661                 case SEG_CUBICTO:
662                     curveTo(coords[0], coords[1],
663                             coords[2], coords[3],
664                             coords[4], coords[5]);
665                     break;
666                 case SEG_CLOSE:
667                     closePath();
668                     break;
669                 }
670                 pi.next();
671                 connect = false;
672             }
673         }
674
675         /**
676          * {@inheritDoc}
677          * @since 1.6
678          */

679         public final void transform(AffineTransform JavaDoc at) {
680             at.transform(floatCoords, 0, floatCoords, 0, numCoords / 2);
681         }
682
683         /**
684          * {@inheritDoc}
685          * @since 1.6
686          */

687         public final synchronized Rectangle2D JavaDoc getBounds2D() {
688             float x1, y1, x2, y2;
689             int i = numCoords;
690             if (i > 0) {
691                 y1 = y2 = floatCoords[--i];
692                 x1 = x2 = floatCoords[--i];
693                 while (i > 0) {
694                     float y = floatCoords[--i];
695                     float x = floatCoords[--i];
696                     if (x < x1) x1 = x;
697                     if (y < y1) y1 = y;
698                     if (x > x2) x2 = x;
699                     if (y > y2) y2 = y;
700                 }
701             } else {
702                 x1 = y1 = x2 = y2 = 0.0f;
703             }
704             return new Rectangle2D.Float JavaDoc(x1, y1, x2 - x1, y2 - y1);
705         }
706
707         /**
708          * {@inheritDoc}
709          * <p>
710          * The iterator for this class is not multi-threaded safe,
711          * which means that the {@code Path2D} class does not
712          * guarantee that modifications to the geometry of this
713          * {@code Path2D} object do not affect any iterations of
714          * that geometry that are already in process.
715          *
716          * @since 1.6
717          */

718         public PathIterator JavaDoc getPathIterator(AffineTransform JavaDoc at) {
719             if (at == null) {
720                 return new CopyIterator(this);
721             } else {
722                 return new TxIterator(this, at);
723             }
724         }
725
726         /**
727          * Creates a new object of the same class as this object.
728          *
729          * @return a clone of this instance.
730          * @exception OutOfMemoryError if there is not enough memory.
731          * @see java.lang.Cloneable
732          * @since 1.6
733          */

734         public final Object JavaDoc clone() {
735             // Note: It would be nice to have this return Path2D
736
// but one of our subclasses (GeneralPath) needs to
737
// offer "public Object clone()" for backwards
738
// compatibility so we cannot restrict it further.
739
// REMIND: Can we do both somehow?
740
if (this instanceof GeneralPath JavaDoc) {
741                 return new GeneralPath JavaDoc(this);
742             } else {
743                 return new Path2D.Float JavaDoc(this);
744             }
745         }
746
747         /*
748          * JDK 1.6 serialVersionUID
749          */

750         private static final long serialVersionUID = 6990832515060788886L;
751
752         /**
753          * Writes the default serializable fields to the
754          * {@code ObjectOutputStream} followed by an explicit
755          * serialization of the path segments stored in this
756          * path.
757          *
758          * @serialData
759          * <a name="Path2DSerialData"><!-- --></a>
760          * <ol>
761          * <li>The default serializable fields.
762          * There are no default serializable fields as of 1.6.
763          * <li>followed by
764          * a byte indicating the storage type of the original object
765          * as a hint (SERIAL_STORAGE_FLT_ARRAY)
766          * <li>followed by
767          * an integer indicating the number of path segments to follow (NP)
768          * or -1 to indicate an unknown number of path segments follows
769          * <li>followed by
770          * an integer indicating the total number of coordinates to follow (NC)
771          * or -1 to indicate an unknown number of coordinates follows
772          * (NC should always be even since coordinates always appear in pairs
773          * representing an x,y pair)
774          * <li>followed by
775          * a byte indicating the winding rule
776          * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
777          * {@link #WIND_NON_ZERO WIND_NON_ZERO})
778          * <li>followed by
779          * NP (or unlimited if NP < 0) sets of values consisting of
780          * a single byte indicating a path segment type
781          * followed by one or more pairs of float or double
782          * values representing the coordinates of the path segment
783          * <li>followed by
784          * a byte indicating the end of the path (SERIAL_PATH_END).
785          * </ol>
786          * <p>
787          * The following byte value constants are used in the serialized form
788          * of {@code Path2D} objects:
789          * <table>
790          * <tr>
791          * <th>Constant Name</th>
792          * <th>Byte Value</th>
793          * <th>Followed by</th>
794          * <th>Description</th>
795          * </tr>
796          * <tr>
797          * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
798          * <td>0x30</td>
799          * <td></td>
800          * <td>A hint that the original {@code Path2D} object stored
801          * the coordinates in a Java array of floats.</td>
802          * </tr>
803          * <tr>
804          * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
805          * <td>0x31</td>
806          * <td></td>
807          * <td>A hint that the original {@code Path2D} object stored
808          * the coordinates in a Java array of doubles.</td>
809          * </tr>
810          * <tr>
811          * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
812          * <td>0x40</td>
813          * <td>2 floats</td>
814          * <td>A {@link #moveTo moveTo} path segment follows.</td>
815          * </tr>
816          * <tr>
817          * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
818          * <td>0x41</td>
819          * <td>2 floats</td>
820          * <td>A {@link #lineTo lineTo} path segment follows.</td>
821          * </tr>
822          * <tr>
823          * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
824          * <td>0x42</td>
825          * <td>4 floats</td>
826          * <td>A {@link #quadTo quadTo} path segment follows.</td>
827          * </tr>
828          * <tr>
829          * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
830          * <td>0x43</td>
831          * <td>6 floats</td>
832          * <td>A {@link #curveTo curveTo} path segment follows.</td>
833          * </tr>
834          * <tr>
835          * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
836          * <td>0x50</td>
837          * <td>2 doubles</td>
838          * <td>A {@link #moveTo moveTo} path segment follows.</td>
839          * </tr>
840          * <tr>
841          * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
842          * <td>0x51</td>
843          * <td>2 doubles</td>
844          * <td>A {@link #lineTo lineTo} path segment follows.</td>
845          * </tr>
846          * <tr>
847          * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
848          * <td>0x52</td>
849          * <td>4 doubles</td>
850          * <td>A {@link #curveTo curveTo} path segment follows.</td>
851          * </tr>
852          * <tr>
853          * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
854          * <td>0x53</td>
855          * <td>6 doubles</td>
856          * <td>A {@link #curveTo curveTo} path segment follows.</td>
857          * </tr>
858          * <tr>
859          * <td>{@code SERIAL_SEG_CLOSE}</td>
860          * <td>0x60</td>
861          * <td></td>
862          * <td>A {@link #closePath closePath} path segment.</td>
863          * </tr>
864          * <tr>
865          * <td>{@code SERIAL_PATH_END}</td>
866          * <td>0x61</td>
867          * <td></td>
868          * <td>There are no more path segments following.</td>
869          * </table>
870          *
871          * @since 1.6
872          */

873         private void writeObject(java.io.ObjectOutputStream JavaDoc s)
874             throws java.io.IOException JavaDoc
875         {
876             super.writeObject(s, false);
877         }
878
879         /**
880          * Reads the default serializable fields from the
881          * {@code ObjectInputStream} followed by an explicit
882          * serialization of the path segments stored in this
883          * path.
884          * <p>
885          * There are no default serializable fields as of 1.6.
886          * <p>
887          * The serial data for this object is described in the
888          * writeObject method.
889          *
890          * @since 1.6
891          */

892         private void readObject(java.io.ObjectInputStream JavaDoc s)
893             throws java.lang.ClassNotFoundException JavaDoc, java.io.IOException JavaDoc
894         {
895             super.readObject(s, false);
896         }
897
898         static class CopyIterator extends Path2D.Iterator JavaDoc {
899             float floatCoords[];
900
901             CopyIterator(Path2D.Float JavaDoc p2df) {
902                 super(p2df);
903                 this.floatCoords = p2df.floatCoords;
904             }
905
906             public int currentSegment(float[] coords) {
907                 int type = path.pointTypes[typeIdx];
908                 int numCoords = curvecoords[type];
909                 if (numCoords > 0) {
910                     System.arraycopy(floatCoords, pointIdx,
911                                      coords, 0, numCoords);
912                 }
913                 return type;
914             }
915
916             public int currentSegment(double[] coords) {
917                 int type = path.pointTypes[typeIdx];
918                 int numCoords = curvecoords[type];
919                 if (numCoords > 0) {
920                     for (int i = 0; i < numCoords; i++) {
921                         coords[i] = floatCoords[pointIdx + i];
922                     }
923                 }
924                 return type;
925             }
926         }
927
928         static class TxIterator extends Path2D.Iterator JavaDoc {
929             float floatCoords[];
930             AffineTransform JavaDoc affine;
931
932             TxIterator(Path2D.Float JavaDoc p2df, AffineTransform JavaDoc at) {
933                 super(p2df);
934                 this.floatCoords = p2df.floatCoords;
935                 this.affine = at;
936             }
937
938             public int currentSegment(float[] coords) {
939                 int type = path.pointTypes[typeIdx];
940                 int numCoords = curvecoords[type];
941                 if (numCoords > 0) {
942                     affine.transform(floatCoords, pointIdx,
943                                      coords, 0, numCoords / 2);
944                 }
945                 return type;
946             }
947
948             public int currentSegment(double[] coords) {
949                 int type = path.pointTypes[typeIdx];
950                 int numCoords = curvecoords[type];
951                 if (numCoords > 0) {
952                     affine.transform(floatCoords, pointIdx,
953                                      coords, 0, numCoords / 2);
954                 }
955                 return type;
956             }
957         }
958
959     }
960
961     /**
962      * The {@code Double} class defines a geometric path with
963      * coordinates stored in double precision floating point.
964      *
965      * @since 1.6
966      */

967     public static class Double extends Path2D JavaDoc implements Serializable JavaDoc {
968         transient double doubleCoords[];
969
970         /**
971          * Constructs a new empty double precision {@code Path2D} object
972          * with a default winding rule of {@link #WIND_NON_ZERO}.
973          *
974          * @since 1.6
975          */

976         public Double() {
977             this(WIND_NON_ZERO, INIT_SIZE);
978         }
979
980         /**
981          * Constructs a new empty double precision {@code Path2D} object
982          * with the specified winding rule to control operations that
983          * require the interior of the path to be defined.
984          *
985          * @param rule the winding rule
986          * @see #WIND_EVEN_ODD
987          * @see #WIND_NON_ZERO
988          * @since 1.6
989          */

990         public Double(int rule) {
991             this(rule, INIT_SIZE);
992         }
993
994         /**
995          * Constructs a new empty double precision {@code Path2D} object
996          * with the specified winding rule and the specified initial
997          * capacity to store path segments.
998          * This number is an initial guess as to how many path segments
999          * are in the path, but the storage is expanded as needed to store
1000         * whatever path segments are added to this path.
1001         *
1002         * @param rule the winding rule
1003         * @param initialCapacity the estimate for the number of path segments
1004         * in the path
1005         * @see #WIND_EVEN_ODD
1006         * @see #WIND_NON_ZERO
1007         * @since 1.6
1008         */

1009        public Double(int rule, int initialCapacity) {
1010            super(rule, initialCapacity);
1011            doubleCoords = new double[initialCapacity * 2];
1012        }
1013
1014        /**
1015         * Constructs a new double precision {@code Path2D} object
1016         * from an arbitrary {@link Shape} object.
1017         * All of the initial geometry and the winding rule for this path are
1018         * taken from the specified {@code Shape} object.
1019         *
1020         * @param s the specified {@code Shape} object
1021         * @since 1.6
1022         */

1023        public Double(Shape JavaDoc s) {
1024            this(s, null);
1025        }
1026
1027        /**
1028         * Constructs a new double precision {@code Path2D} object
1029         * from an arbitrary {@link Shape} object, transformed by an
1030         * {@link AffineTransform} object.
1031         * All of the initial geometry and the winding rule for this path are
1032         * taken from the specified {@code Shape} object and transformed
1033         * by the specified {@code AffineTransform} object.
1034         *
1035         * @param s the specified {@code Shape} object
1036         * @param at the specified {@code AffineTransform} object
1037         * @since 1.6
1038         */

1039        public Double(Shape JavaDoc s, AffineTransform JavaDoc at) {
1040            if (s instanceof Path2D JavaDoc) {
1041                Path2D JavaDoc p2d = (Path2D JavaDoc) s;
1042                setWindingRule(p2d.windingRule);
1043                this.numTypes = p2d.numTypes;
1044                this.pointTypes = Arrays.copyOf(p2d.pointTypes,
1045                                                p2d.pointTypes.length);
1046                this.numCoords = p2d.numCoords;
1047                this.doubleCoords = p2d.cloneCoordsDouble(at);
1048            } else {
1049                PathIterator JavaDoc pi = s.getPathIterator(at);
1050                setWindingRule(pi.getWindingRule());
1051                this.pointTypes = new byte[INIT_SIZE];
1052                this.doubleCoords = new double[INIT_SIZE * 2];
1053                append(pi, false);
1054            }
1055        }
1056
1057        float[] cloneCoordsFloat(AffineTransform JavaDoc at) {
1058            float ret[] = new float[doubleCoords.length];
1059            if (at == null) {
1060                for (int i = 0; i < numCoords; i++) {
1061                    ret[i] = (float) doubleCoords[i];
1062                }
1063            } else {
1064                at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1065            }
1066            return ret;
1067        }
1068
1069        double[] cloneCoordsDouble(AffineTransform JavaDoc at) {
1070            double ret[];
1071            if (at == null) {
1072                ret = Arrays.copyOf(this.doubleCoords,
1073                                    this.doubleCoords.length);
1074            } else {
1075                ret = new double[doubleCoords.length];
1076                at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1077            }
1078            return ret;
1079        }
1080
1081        void append(float x, float y) {
1082            doubleCoords[numCoords++] = x;
1083            doubleCoords[numCoords++] = y;
1084        }
1085
1086        void append(double x, double y) {
1087            doubleCoords[numCoords++] = x;
1088            doubleCoords[numCoords++] = y;
1089        }
1090
1091        Point2D JavaDoc getPoint(int coordindex) {
1092            return new Point2D.Double JavaDoc(doubleCoords[coordindex],
1093                                      doubleCoords[coordindex+1]);
1094        }
1095
1096        void needRoom(boolean needMove, int newCoords) {
1097            if (needMove && numTypes == 0) {
1098                throw new IllegalPathStateException JavaDoc("missing initial moveto "+
1099                                                    "in path definition");
1100            }
1101            int size = pointTypes.length;
1102            if (numTypes >= size) {
1103                int grow = size;
1104                if (grow > EXPAND_MAX) {
1105                    grow = EXPAND_MAX;
1106                }
1107                pointTypes = Arrays.copyOf(pointTypes, size+grow);
1108            }
1109            size = doubleCoords.length;
1110            if (numCoords + newCoords > size) {
1111                int grow = size;
1112                if (grow > EXPAND_MAX * 2) {
1113                    grow = EXPAND_MAX * 2;
1114                }
1115                if (grow < newCoords) {
1116                    grow = newCoords;
1117                }
1118                doubleCoords = Arrays.copyOf(doubleCoords, size+grow);
1119            }
1120        }
1121
1122        /**
1123         * {@inheritDoc}
1124         * @since 1.6
1125         */

1126        public final synchronized void moveTo(double x, double y) {
1127            if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
1128                doubleCoords[numCoords-2] = x;
1129                doubleCoords[numCoords-1] = y;
1130            } else {
1131                needRoom(false, 2);
1132                pointTypes[numTypes++] = SEG_MOVETO;
1133                doubleCoords[numCoords++] = x;
1134                doubleCoords[numCoords++] = y;
1135            }
1136        }
1137
1138        /**
1139         * {@inheritDoc}
1140         * @since 1.6
1141         */

1142        public final synchronized void lineTo(double x, double y) {
1143            needRoom(true, 2);
1144            pointTypes[numTypes++] = SEG_LINETO;
1145            doubleCoords[numCoords++] = x;
1146            doubleCoords[numCoords++] = y;
1147        }
1148
1149        /**
1150         * {@inheritDoc}
1151         * @since 1.6
1152         */

1153        public final synchronized void quadTo(double x1, double y1,
1154                                              double x2, double y2)
1155        {
1156            needRoom(true, 4);
1157            pointTypes[numTypes++] = SEG_QUADTO;
1158            doubleCoords[numCoords++] = x1;
1159            doubleCoords[numCoords++] = y1;
1160            doubleCoords[numCoords++] = x2;
1161            doubleCoords[numCoords++] = y2;
1162        }
1163
1164        /**
1165         * {@inheritDoc}
1166         * @since 1.6
1167         */

1168        public final synchronized void curveTo(double x1, double y1,
1169                                               double x2, double y2,
1170                                               double x3, double y3)
1171        {
1172            needRoom(true, 6);
1173            pointTypes[numTypes++] = SEG_CUBICTO;
1174            doubleCoords[numCoords++] = x1;
1175            doubleCoords[numCoords++] = y1;
1176            doubleCoords[numCoords++] = x2;
1177            doubleCoords[numCoords++] = y2;
1178            doubleCoords[numCoords++] = x3;
1179            doubleCoords[numCoords++] = y3;
1180        }
1181
1182        int pointCrossings(double px, double py) {
1183            double movx, movy, curx, cury, endx, endy;
1184            double coords[] = doubleCoords;
1185            curx = movx = coords[0];
1186            cury = movy = coords[1];
1187            int crossings = 0;
1188            int ci = 2;
1189            for (int i = 1; i < numTypes; i++) {
1190                switch (pointTypes[i]) {
1191                case PathIterator.SEG_MOVETO:
1192                    if (cury != movy) {
1193                        crossings +=
1194                            Curve.pointCrossingsForLine(px, py,
1195                                                        curx, cury,
1196                                                        movx, movy);
1197                    }
1198                    movx = curx = coords[ci++];
1199                    movy = cury = coords[ci++];
1200                    break;
1201                case PathIterator.SEG_LINETO:
1202                    crossings +=
1203                        Curve.pointCrossingsForLine(px, py,
1204                                                    curx, cury,
1205                                                    endx = coords[ci++],
1206                                                    endy = coords[ci++]);
1207                    curx = endx;
1208                    cury = endy;
1209                    break;
1210                case PathIterator.SEG_QUADTO:
1211                    crossings +=
1212                        Curve.pointCrossingsForQuad(px, py,
1213                                                    curx, cury,
1214                                                    coords[ci++],
1215                                                    coords[ci++],
1216                                                    endx = coords[ci++],
1217                                                    endy = coords[ci++],
1218                                                    0);
1219                    curx = endx;
1220                    cury = endy;
1221                    break;
1222            case PathIterator.SEG_CUBICTO:
1223                    crossings +=
1224                        Curve.pointCrossingsForCubic(px, py,
1225                                                     curx, cury,
1226                                                     coords[ci++],
1227                                                     coords[ci++],
1228                                                     coords[ci++],
1229                                                     coords[ci++],
1230                                                     endx = coords[ci++],
1231                                                     endy = coords[ci++],
1232                                                     0);
1233                    curx = endx;
1234                    cury = endy;
1235                    break;
1236                case PathIterator.SEG_CLOSE:
1237                    if (cury != movy) {
1238                        crossings +=
1239                            Curve.pointCrossingsForLine(px, py,
1240                                                        curx, cury,
1241                                                        movx, movy);
1242                    }
1243                    curx = movx;
1244                    cury = movy;
1245                    break;
1246                }
1247            }
1248            if (cury != movy) {
1249                crossings +=
1250                    Curve.pointCrossingsForLine(px, py,
1251                                                curx, cury,
1252                                                movx, movy);
1253            }
1254            return crossings;
1255        }
1256
1257        int rectCrossings(double rxmin, double rymin,
1258                          double rxmax, double rymax)
1259        {
1260            double coords[] = doubleCoords;
1261            double curx, cury, movx, movy, endx, endy;
1262            curx = movx = coords[0];
1263            cury = movy = coords[1];
1264            int crossings = 0;
1265            int ci = 2;
1266            for (int i = 1;
1267                 crossings != Curve.RECT_INTERSECTS && i < numTypes;
1268                 i++)
1269            {
1270                switch (pointTypes[i]) {
1271                case PathIterator.SEG_MOVETO:
1272                    if (curx != movx || cury != movy) {
1273                        crossings =
1274                            Curve.rectCrossingsForLine(crossings,
1275                                                       rxmin, rymin,
1276                                                       rxmax, rymax,
1277                                                       curx, cury,
1278                                                       movx, movy);
1279                    }
1280                    // Count should always be a multiple of 2 here.
1281
// assert((crossings & 1) != 0);
1282
movx = curx = coords[ci++];
1283                    movy = cury = coords[ci++];
1284                    break;
1285                case PathIterator.SEG_LINETO:
1286                    endx = coords[ci++];
1287                    endy = coords[ci++];
1288                    crossings =
1289                        Curve.rectCrossingsForLine(crossings,
1290                                                   rxmin, rymin,
1291                                                   rxmax, rymax,
1292                                                   curx, cury,
1293                                                   endx, endy);
1294                    curx = endx;
1295                    cury = endy;
1296                    break;
1297                case PathIterator.SEG_QUADTO:
1298                    crossings =
1299                        Curve.rectCrossingsForQuad(crossings,
1300                                                   rxmin, rymin,
1301                                                   rxmax, rymax,
1302                                                   curx, cury,
1303                                                   coords[ci++],
1304                                                   coords[ci++],
1305                                                   endx = coords[ci++],
1306                                                   endy = coords[ci++],
1307                                                   0);
1308                    curx = endx;
1309                    cury = endy;
1310                    break;
1311                case PathIterator.SEG_CUBICTO:
1312                    crossings =
1313                        Curve.rectCrossingsForCubic(crossings,
1314                                                    rxmin, rymin,
1315                                                    rxmax, rymax,
1316                                                    curx, cury,
1317                                                    coords[ci++],
1318                                                    coords[ci++],
1319                                                    coords[ci++],
1320                                                    coords[ci++],
1321                                                    endx = coords[ci++],
1322                                                    endy = coords[ci++],
1323                                                    0);
1324                    curx = endx;
1325                    cury = endy;
1326                    break;
1327                case PathIterator.SEG_CLOSE:
1328                    if (curx != movx || cury != movy) {
1329                        crossings =
1330                            Curve.rectCrossingsForLine(crossings,
1331                                                       rxmin, rymin,
1332                                                       rxmax, rymax,
1333                                                       curx, cury,
1334                                                       movx, movy);
1335                    }
1336                    curx = movx;
1337                    cury = movy;
1338                    // Count should always be a multiple of 2 here.
1339
// assert((crossings & 1) != 0);
1340
break;
1341                }
1342            }
1343            if (crossings != Curve.RECT_INTERSECTS &&
1344                (curx != movx || cury != movy))
1345            {
1346                crossings =
1347                    Curve.rectCrossingsForLine(crossings,
1348                                               rxmin, rymin,
1349                                               rxmax, rymax,
1350                                               curx, cury,
1351                                               movx, movy);
1352            }
1353            // Count should always be a multiple of 2 here.
1354
// assert((crossings & 1) != 0);
1355
return crossings;
1356        }
1357
1358        /**
1359         * {@inheritDoc}
1360         * @since 1.6
1361         */

1362        public final void append(PathIterator JavaDoc pi, boolean connect) {
1363            double coords[] = new double[6];
1364            while (!pi.isDone()) {
1365                switch (pi.currentSegment(coords)) {
1366                case SEG_MOVETO:
1367                    if (!connect || numTypes < 1 || numCoords < 1) {
1368                        moveTo(coords[0], coords[1]);
1369                        break;
1370                    }
1371                    if (pointTypes[numTypes - 1] != SEG_CLOSE &&
1372                        doubleCoords[numCoords-2] == coords[0] &&
1373                        doubleCoords[numCoords-1] == coords[1])
1374                    {
1375                        // Collapse out initial moveto/lineto
1376
break;
1377                    }
1378                    // NO BREAK;
1379
case SEG_LINETO:
1380                    lineTo(coords[0], coords[1]);
1381                    break;
1382                case SEG_QUADTO:
1383                    quadTo(coords[0], coords[1],
1384                           coords[2], coords[3]);
1385                    break;
1386                case SEG_CUBICTO:
1387                    curveTo(coords[0], coords[1],
1388                            coords[2], coords[3],
1389                            coords[4], coords[5]);
1390                    break;
1391                case SEG_CLOSE:
1392                    closePath();
1393                    break;
1394                }
1395                pi.next();
1396                connect = false;
1397            }
1398        }
1399
1400        /**
1401         * {@inheritDoc}
1402         * @since 1.6
1403         */

1404        public final void transform(AffineTransform JavaDoc at) {
1405            at.transform(doubleCoords, 0, doubleCoords, 0, numCoords / 2);
1406        }
1407
1408        /**
1409         * {@inheritDoc}
1410         * @since 1.6
1411         */

1412        public final synchronized Rectangle2D JavaDoc getBounds2D() {
1413            double x1, y1, x2, y2;
1414            int i = numCoords;
1415            if (i > 0) {
1416                y1 = y2 = doubleCoords[--i];
1417                x1 = x2 = doubleCoords[--i];
1418                while (i > 0) {
1419                    double y = doubleCoords[--i];
1420                    double x = doubleCoords[--i];
1421                    if (x < x1) x1 = x;
1422                    if (y < y1) y1 = y;
1423                    if (x > x2) x2 = x;
1424                    if (y > y2) y2 = y;
1425                }
1426            } else {
1427                x1 = y1 = x2 = y2 = 0.0;
1428            }
1429            return new Rectangle2D.Double JavaDoc(x1, y1, x2 - x1, y2 - y1);
1430        }
1431
1432        /**
1433         * {@inheritDoc}
1434         * <p>
1435         * The iterator for this class is not multi-threaded safe,
1436         * which means that the {@code Path2D} class does not
1437         * guarantee that modifications to the geometry of this
1438         * {@code Path2D} object do not affect any iterations of
1439         * that geometry that are already in process.
1440         *
1441         * @param at an {@code AffineTransform}
1442         * @return a new {@code PathIterator} that iterates along the boundary
1443         * of this {@code Shape} and provides access to the geometry
1444         * of this {@code Shape}'s outline
1445         * @since 1.6
1446         */

1447        public PathIterator JavaDoc getPathIterator(AffineTransform JavaDoc at) {
1448            if (at == null) {
1449                return new CopyIterator(this);
1450            } else {
1451                return new TxIterator(this, at);
1452            }
1453        }
1454
1455        /**
1456         * Creates a new object of the same class as this object.
1457         *
1458         * @return a clone of this instance.
1459         * @exception OutOfMemoryError if there is not enough memory.
1460         * @see java.lang.Cloneable
1461         * @since 1.6
1462         */

1463        public final Object JavaDoc clone() {
1464            // Note: It would be nice to have this return Path2D
1465
// but one of our subclasses (GeneralPath) needs to
1466
// offer "public Object clone()" for backwards
1467
// compatibility so we cannot restrict it further.
1468
// REMIND: Can we do both somehow?
1469
return new Path2D.Double JavaDoc(this);
1470        }
1471
1472        /*
1473         * JDK 1.6 serialVersionUID
1474         */

1475        private static final long serialVersionUID = 1826762518450014216L;
1476
1477        /**
1478         * Writes the default serializable fields to the
1479         * {@code ObjectOutputStream} followed by an explicit
1480         * serialization of the path segments stored in this
1481         * path.
1482         *
1483         * @serialData
1484         * <a name="Path2DSerialData"><!-- --></a>
1485         * <ol>
1486         * <li>The default serializable fields.
1487         * There are no default serializable fields as of 1.6.
1488         * <li>followed by
1489         * a byte indicating the storage type of the original object
1490         * as a hint (SERIAL_STORAGE_DBL_ARRAY)
1491         * <li>followed by
1492         * an integer indicating the number of path segments to follow (NP)
1493         * or -1 to indicate an unknown number of path segments follows
1494         * <li>followed by
1495         * an integer indicating the total number of coordinates to follow (NC)
1496         * or -1 to indicate an unknown number of coordinates follows
1497         * (NC should always be even since coordinates always appear in pairs
1498         * representing an x,y pair)
1499         * <li>followed by
1500         * a byte indicating the winding rule
1501         * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
1502         * {@link #WIND_NON_ZERO WIND_NON_ZERO})
1503         * <li>followed by
1504         * NP (or unlimited if NP < 0) sets of values consisting of
1505         * a single byte indicating a path segment type
1506         * followed by one or more pairs of float or double
1507         * values representing the coordinates of the path segment
1508         * <li>followed by
1509         * a byte indicating the end of the path (SERIAL_PATH_END).
1510         * </ol>
1511         * <p>
1512         * The following byte value constants are used in the serialized form
1513         * of {@code Path2D} objects:
1514         * <table>
1515         * <tr>
1516         * <th>Constant Name</th>
1517         * <th>Byte Value</th>
1518         * <th>Followed by</th>
1519         * <th>Description</th>
1520         * </tr>
1521         * <tr>
1522         * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
1523         * <td>0x30</td>
1524         * <td></td>
1525         * <td>A hint that the original {@code Path2D} object stored
1526         * the coordinates in a Java array of floats.</td>
1527         * </tr>
1528         * <tr>
1529         * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
1530         * <td>0x31</td>
1531         * <td></td>
1532         * <td>A hint that the original {@code Path2D} object stored
1533         * the coordinates in a Java array of doubles.</td>
1534         * </tr>
1535         * <tr>
1536         * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
1537         * <td>0x40</td>
1538         * <td>2 floats</td>
1539         * <td>A {@link #moveTo moveTo} path segment follows.</td>
1540         * </tr>
1541         * <tr>
1542         * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
1543         * <td>0x41</td>
1544         * <td>2 floats</td>
1545         * <td>A {@link #lineTo lineTo} path segment follows.</td>
1546         * </tr>
1547         * <tr>
1548         * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
1549         * <td>0x42</td>
1550         * <td>4 floats</td>
1551         * <td>A {@link #quadTo quadTo} path segment follows.</td>
1552         * </tr>
1553         * <tr>
1554         * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
1555         * <td>0x43</td>
1556         * <td>6 floats</td>
1557         * <td>A {@link #curveTo curveTo} path segment follows.</td>
1558         * </tr>
1559         * <tr>
1560         * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
1561         * <td>0x50</td>
1562         * <td>2 doubles</td>
1563         * <td>A {@link #moveTo moveTo} path segment follows.</td>
1564         * </tr>
1565         * <tr>
1566         * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
1567         * <td>0x51</td>
1568         * <td>2 doubles</td>
1569         * <td>A {@link #lineTo lineTo} path segment follows.</td>
1570         * </tr>
1571         * <tr>
1572         * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
1573         * <td>0x52</td>
1574         * <td>4 doubles</td>
1575         * <td>A {@link #curveTo curveTo} path segment follows.</td>
1576         * </tr>
1577         * <tr>
1578         * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
1579         * <td>0x53</td>
1580         * <td>6 doubles</td>
1581         * <td>A {@link #curveTo curveTo} path segment follows.</td>
1582         * </tr>
1583         * <tr>
1584         * <td>{@code SERIAL_SEG_CLOSE}</td>
1585         * <td>0x60</td>
1586         * <td></td>
1587         * <td>A {@link #closePath closePath} path segment.</td>
1588         * </tr>
1589         * <tr>
1590         * <td>{@code SERIAL_PATH_END}</td>
1591         * <td>0x61</td>
1592         * <td></td>
1593         * <td>There are no more path segments following.</td>
1594         * </table>
1595         *
1596         * @since 1.6
1597         */

1598        private void writeObject(java.io.ObjectOutputStream JavaDoc s)
1599            throws java.io.IOException JavaDoc
1600        {
1601            super.writeObject(s, true);
1602        }
1603
1604        /**
1605         * Reads the default serializable fields from the
1606         * {@code ObjectInputStream} followed by an explicit
1607         * serialization of the path segments stored in this
1608         * path.
1609         * <p>
1610         * There are no default serializable fields as of 1.6.
1611         * <p>
1612         * The serial data for this object is described in the
1613         * writeObject method.
1614         *
1615         * @since 1.6
1616         */

1617        private void readObject(java.io.ObjectInputStream JavaDoc s)
1618            throws java.lang.ClassNotFoundException JavaDoc, java.io.IOException JavaDoc
1619        {
1620            super.readObject(s, true);
1621        }
1622
1623        static class CopyIterator extends Path2D.Iterator JavaDoc {
1624            double doubleCoords[];
1625
1626            CopyIterator(Path2D.Double JavaDoc p2dd) {
1627                super(p2dd);
1628                this.doubleCoords = p2dd.doubleCoords;
1629            }
1630
1631            public int currentSegment(float[] coords) {
1632                int type = path.pointTypes[typeIdx];
1633                int numCoords = curvecoords[type];
1634                if (numCoords > 0) {
1635                    for (int i = 0; i < numCoords; i++) {
1636                        coords[i] = (float) doubleCoords[pointIdx + i];
1637                    }
1638                }
1639                return type;
1640            }
1641
1642            public int currentSegment(double[] coords) {
1643                int type = path.pointTypes[typeIdx];
1644                int numCoords = curvecoords[type];
1645                if (numCoords > 0) {
1646                    System.arraycopy(doubleCoords, pointIdx,
1647                                     coords, 0, numCoords);
1648                }
1649                return type;
1650            }
1651        }
1652
1653        static class TxIterator extends Path2D.Iterator JavaDoc {
1654            double doubleCoords[];
1655            AffineTransform JavaDoc affine;
1656
1657            TxIterator(Path2D.Double JavaDoc p2dd, AffineTransform JavaDoc at) {
1658                super(p2dd);
1659                this.doubleCoords = p2dd.doubleCoords;
1660                this.affine = at;
1661            }
1662
1663            public int currentSegment(float[] coords) {
1664                int type = path.pointTypes[typeIdx];
1665                int numCoords = curvecoords[type];
1666                if (numCoords > 0) {
1667                    affine.transform(doubleCoords, pointIdx,
1668                                     coords, 0, numCoords / 2);
1669                }
1670                return type;
1671            }
1672
1673            public int currentSegment(double[] coords) {
1674                int type = path.pointTypes[typeIdx];
1675                int numCoords = curvecoords[type];
1676                if (numCoords > 0) {
1677                    affine.transform(doubleCoords, pointIdx,
1678                                     coords, 0, numCoords / 2);
1679                }
1680                return type;
1681            }
1682        }
1683    }
1684
1685    /**
1686     * Adds a point to the path by moving to the specified
1687     * coordinates specified in double precision.
1688     *
1689     * @param x the specified X coordinate
1690     * @param y the specified Y coordinate
1691     * @since 1.6
1692     */

1693    public abstract void moveTo(double x, double y);
1694
1695    /**
1696     * Adds a point to the path by drawing a straight line from the
1697     * current coordinates to the new specified coordinates
1698     * specified in double precision.
1699     *
1700     * @param x the specified X coordinate
1701     * @param y the specified Y coordinate
1702     * @since 1.6
1703     */

1704    public abstract void lineTo(double x, double y);
1705
1706    /**
1707     * Adds a curved segment, defined by two new points, to the path by
1708     * drawing a Quadratic curve that intersects both the current
1709     * coordinates and the specified coordinates {@code (x2,y2)},
1710     * using the specified point {@code (x1,y1)} as a quadratic
1711     * parametric control point.
1712     * All coordinates are specified in double precision.
1713     *
1714     * @param x1 the X coordinate of the quadratic control point
1715     * @param y1 the Y coordinate of the quadratic control point
1716     * @param x2 the X coordinate of the final end point
1717     * @param y2 the Y coordinate of the final end point
1718     * @since 1.6
1719     */

1720    public abstract void quadTo(double x1, double y1,
1721                                double x2, double y2);
1722
1723    /**
1724     * Adds a curved segment, defined by three new points, to the path by
1725     * drawing a B&eacute;zier curve that intersects both the current
1726     * coordinates and the specified coordinates {@code (x3,y3)},
1727     * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
1728     * B&eacute;zier control points.
1729     * All coordinates are specified in double precision.
1730     *
1731     * @param x1 the X coordinate of the first B&eacute;zier control point
1732     * @param y1 the Y coordinate of the first B&eacute;zier control point
1733     * @param x2 the X coordinate of the second B&eacute;zier control point
1734     * @param y2 the Y coordinate of the second B&eacute;zier control point
1735     * @param x3 the X coordinate of the final end point
1736     * @param y3 the Y coordinate of the final end point
1737     * @since 1.6
1738     */

1739    public abstract void curveTo(double x1, double y1,
1740                                 double x2, double y2,
1741                                 double x3, double y3);
1742
1743    /**
1744     * Closes the current subpath by drawing a straight line back to
1745     * the coordinates of the last {@code moveTo}. If the path is already
1746     * closed then this method has no effect.
1747     *
1748     * @since 1.6
1749     */

1750    public final synchronized void closePath() {
1751    if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) {
1752        needRoom(true, 0);
1753        pointTypes[numTypes++] = SEG_CLOSE;
1754    }
1755    }
1756
1757    /**
1758     * Appends the geometry of the specified {@code Shape} object to the
1759     * path, possibly connecting the new geometry to the existing path
1760     * segments with a line segment.
1761     * If the {@code connect} parameter is {@code true} and the
1762     * path is not empty then any initial {@code moveTo} in the
1763     * geometry of the appended {@code Shape}
1764     * is turned into a {@code lineTo} segment.
1765     * If the destination coordinates of such a connecting {@code lineTo}
1766     * segment match the ending coordinates of a currently open
1767     * subpath then the segment is omitted as superfluous.
1768     * The winding rule of the specified {@code Shape} is ignored
1769     * and the appended geometry is governed by the winding
1770     * rule specified for this path.
1771     *
1772     * @param s the {@code Shape} whose geometry is appended
1773     * to this path
1774     * @param connect a boolean to control whether or not to turn an initial
1775     * {@code moveTo} segment into a {@code lineTo} segment
1776     * to connect the new geometry to the existing path
1777     * @since 1.6
1778     */

1779    public final void append(Shape JavaDoc s, boolean connect) {
1780        append(s.getPathIterator(null), connect);
1781    }
1782
1783    /**
1784     * Appends the geometry of the specified
1785     * {@link PathIterator} object
1786     * to the path, possibly connecting the new geometry to the existing
1787     * path segments with a line segment.
1788     * If the {@code connect} parameter is {@code true} and the
1789     * path is not empty then any initial {@code moveTo} in the
1790     * geometry of the appended {@code Shape} is turned into a
1791     * {@code lineTo} segment.
1792     * If the destination coordinates of such a connecting {@code lineTo}
1793     * segment match the ending coordinates of a currently open
1794     * subpath then the segment is omitted as superfluous.
1795     * The winding rule of the specified {@code Shape} is ignored
1796     * and the appended geometry is governed by the winding
1797     * rule specified for this path.
1798     *
1799     * @param pi the {@code PathIterator} whose geometry is appended to
1800     * this path
1801     * @param connect a boolean to control whether or not to turn an initial
1802     * {@code moveTo} segment into a {@code lineTo} segment
1803     * to connect the new geometry to the existing path
1804     * @since 1.6
1805     */

1806    public abstract void append(PathIterator JavaDoc pi, boolean connect);
1807
1808    /**
1809     * Returns the fill style winding rule.
1810     *
1811     * @return an integer representing the current winding rule.
1812     * @see #WIND_EVEN_ODD
1813     * @see #WIND_NON_ZERO
1814     * @see #setWindingRule
1815     * @since 1.6
1816     */

1817    public final synchronized int getWindingRule() {
1818        return windingRule;
1819    }
1820
1821    /**
1822     * Sets the winding rule for this path to the specified value.
1823     *
1824     * @param rule an integer representing the specified
1825     * winding rule
1826     * @exception IllegalArgumentException if
1827     * {@code rule} is not either
1828     * {@link #WIND_EVEN_ODD} or
1829     * {@link #WIND_NON_ZERO}
1830     * @see #getWindingRule
1831     * @since 1.6
1832     */

1833    public final void setWindingRule(int rule) {
1834    if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
1835        throw new IllegalArgumentException JavaDoc("winding rule must be "+
1836                           "WIND_EVEN_ODD or "+
1837                           "WIND_NON_ZERO");
1838    }
1839    windingRule = rule;
1840    }
1841
1842    /**
1843     * Returns the coordinates most recently added to the end of the path
1844     * as a {@link Point2D} object.
1845     *
1846     * @return a {@code Point2D} object containing the ending coordinates of
1847     * the path or {@code null} if there are no points in the path.
1848     * @since 1.6
1849     */

1850    public final synchronized Point2D JavaDoc getCurrentPoint() {
1851    int index = numCoords;
1852    if (numTypes < 1 || index < 1) {
1853        return null;
1854    }
1855    if (pointTypes[numTypes - 1] == SEG_CLOSE) {
1856    loop:
1857        for (int i = numTypes - 2; i > 0; i--) {
1858        switch (pointTypes[i]) {
1859        case SEG_MOVETO:
1860            break loop;
1861        case SEG_LINETO:
1862            index -= 2;
1863            break;
1864        case SEG_QUADTO:
1865            index -= 4;
1866            break;
1867        case SEG_CUBICTO:
1868            index -= 6;
1869            break;
1870        case SEG_CLOSE:
1871            break;
1872        }
1873        }
1874    }
1875    return getPoint(index - 2);
1876    }
1877
1878    /**
1879     * Resets the path to empty. The append position is set back to the
1880     * beginning of the path and all coordinates and point types are
1881     * forgotten.
1882     *
1883     * @since 1.6
1884     */

1885    public final synchronized void reset() {
1886    numTypes = numCoords = 0;
1887    }
1888
1889    /**
1890     * Transforms the geometry of this path using the specified
1891     * {@link AffineTransform}.
1892     * The geometry is transformed in place, which permanently changes the
1893     * boundary defined by this object.
1894     *
1895     * @param at the {@code AffineTransform} used to transform the area
1896     * @since 1.6
1897     */

1898    public abstract void transform(AffineTransform JavaDoc at);
1899
1900    /**
1901     * Returns a new {@code Shape} representing a transformed version
1902     * of this {@code Path2D}.
1903     * Note that the exact type and coordinate precision of the return
1904     * value is not specified for this method.
1905     * The method will return a Shape that contains no less precision
1906     * for the transformed geometry than this {@code Path2D} currently
1907     * maintains, but it may contain no more precision either.
1908     * If the tradeoff of precision vs. storage size in the result is
1909     * important then the convenience constructors in the
1910     * {@link Path2D.Float#Path2D.Float(Shape, AffineTransform) Path2D.Float}
1911     * and
1912     * {@link Path2D.Double#Path2D.Double(Shape, AffineTransform) Path2D.Double}
1913     * subclasses should be used to make the choice explicit.
1914     *
1915     * @param at the {@code AffineTransform} used to transform a
1916     * new {@code Shape}.
1917     * @return a new {@code Shape}, transformed with the specified
1918     * {@code AffineTransform}.
1919     * @since 1.6
1920     */

1921    public final synchronized Shape JavaDoc createTransformedShape(AffineTransform JavaDoc at) {
1922        Path2D JavaDoc p2d = (Path2D JavaDoc) clone();
1923        if (at != null) {
1924            p2d.transform(at);
1925        }
1926        return p2d;
1927    }
1928
1929    /**
1930     * {@inheritDoc}
1931     * @since 1.6
1932     */

1933    public final Rectangle JavaDoc getBounds() {
1934    return getBounds2D().getBounds();
1935    }
1936
1937    /**
1938     * Tests if the specified coordinates are inside the closed
1939     * boundary of the specified {@link PathIterator}.
1940     * <p>
1941     * This method provides a basic facility for implementors of
1942     * the {@link Shape} interface to implement support for the
1943     * {@link Shape#contains(double, double)} method.
1944     *
1945     * @param pi the specified {@code PathIterator}
1946     * @param x the specified X coordinate
1947     * @param y the specified Y coordinate
1948     * @return {@code true} if the specified coordinates are inside the
1949     * specified {@code PathIterator}; {@code false} otherwise
1950     * @since 1.6
1951     */

1952    public static boolean contains(PathIterator JavaDoc pi, double x, double y) {
1953        if (x * 0.0 + y * 0.0 == 0.0) {
1954            /* N * 0.0 is 0.0 only if N is finite.
1955             * Here we know that both x and y are finite.
1956             */

1957            int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 1);
1958            int cross = Curve.pointCrossingsForPath(pi, x, y);
1959            return ((cross & mask) != 0);
1960        } else {
1961            /* Either x or y was infinite or NaN.
1962             * A NaN always produces a negative response to any test
1963             * and Infinity values cannot be "inside" any path so
1964             * they should return false as well.
1965             */

1966            return false;
1967        }
1968    }
1969
1970    /**
1971     * Tests if the specified {@link Point2D} is inside the closed
1972     * boundary of the specified {@link PathIterator}.
1973     * <p>
1974     * This method provides a basic facility for implementors of
1975     * the {@link Shape} interface to implement support for the
1976     * {@link Shape#contains(Point2D)} method.
1977     *
1978     * @param pi the specified {@code PathIterator}
1979     * @param p the specified {@code Point2D}
1980     * @return {@code true} if the specified coordinates are inside the
1981     * specified {@code PathIterator}; {@code false} otherwise
1982     * @since 1.6
1983     */

1984    public static boolean contains(PathIterator JavaDoc pi, Point2D JavaDoc p) {
1985        return contains(pi, p.getX(), p.getY());
1986    }
1987
1988    /**
1989     * {@inheritDoc}
1990     * @since 1.6
1991     */

1992    public final boolean contains(double x, double y) {
1993        if (x * 0.0 + y * 0.0 == 0.0) {
1994            /* N * 0.0 is 0.0 only if N is finite.
1995             * Here we know that both x and y are finite.
1996             */

1997            if (numTypes < 2) {
1998                return false;
1999            }
2000            int mask = (windingRule == WIND_NON_ZERO ? -1 : 1);
2001            return ((pointCrossings(x, y) & mask) != 0);
2002        } else {
2003            /* Either x or y was infinite or NaN.
2004             * A NaN always produces a negative response to any test
2005             * and Infinity values cannot be "inside" any path so
2006             * they should return false as well.
2007             */

2008            return false;
2009        }
2010    }
2011
2012    /**
2013     * {@inheritDoc}
2014     * @since 1.6
2015     */

2016    public final boolean contains(Point2D JavaDoc p) {
2017    return contains(p.getX(), p.getY());
2018    }
2019
2020    /**
2021     * Tests if the specified rectangular area is entirely inside the
2022     * closed boundary of the specified {@link PathIterator}.
2023     * <p>
2024     * This method provides a basic facility for implementors of
2025     * the {@link Shape} interface to implement support for the
2026     * {@link Shape#contains(double, double, double, double)} method.
2027     * <p>
2028     * This method object may conservatively return false in
2029     * cases where the specified rectangular area intersects a
2030     * segment of the path, but that segment does not represent a
2031     * boundary between the interior and exterior of the path.
2032     * Such segments could lie entirely within the interior of the
2033     * path if they are part of a path with a {@link #WIND_NON_ZERO}
2034     * winding rule or if the segments are retraced in the reverse
2035     * direction such that the two sets of segments cancel each
2036     * other out without any exterior area falling between them.
2037     * To determine whether segments represent true boundaries of
2038     * the interior of the path would require extensive calculations
2039     * involving all of the segments of the path and the winding
2040     * rule and are thus beyond the scope of this implementation.
2041     *
2042     * @param pi the specified {@code PathIterator}
2043     * @param x the specified X coordinate
2044     * @param y the specified Y coordinate
2045     * @param w the width of the specified rectangular area
2046     * @param h the height of the specified rectangular area
2047     * @return {@code true} if the specified {@code PathIterator} contains
2048     * the specified rectangluar area; {@code false} otherwise.
2049     * @since 1.6
2050     */

2051    public static boolean contains(PathIterator JavaDoc pi,
2052                                   double x, double y, double w, double h)
2053    {
2054        if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2055            /* [xy]+[wh] is NaN if any of those values are NaN,
2056             * or if adding the two together would produce NaN
2057             * by virtue of adding opposing Infinte values.
2058             * Since we need to add them below, their sum must
2059             * not be NaN.
2060             * We return false because NaN always produces a
2061             * negative response to tests
2062             */

2063            return false;
2064        }
2065        if (w <= 0 || h <= 0) {
2066            return false;
2067        }
2068        int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2069    int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2070    return (crossings != Curve.RECT_INTERSECTS &&
2071                (crossings & mask) != 0);
2072    }
2073
2074    /**
2075     * Tests if the specified {@link Rectangle2D} is entirely inside the
2076     * closed boundary of the specified {@link PathIterator}.
2077     * <p>
2078     * This method provides a basic facility for implementors of
2079     * the {@link Shape} interface to implement support for the
2080     * {@link Shape#contains(Rectangle2D)} method.
2081     * <p>
2082     * This method object may conservatively return false in
2083     * cases where the specified rectangular area intersects a
2084     * segment of the path, but that segment does not represent a
2085     * boundary between the interior and exterior of the path.
2086     * Such segments could lie entirely within the interior of the
2087     * path if they are part of a path with a {@link #WIND_NON_ZERO}
2088     * winding rule or if the segments are retraced in the reverse
2089     * direction such that the two sets of segments cancel each
2090     * other out without any exterior area falling between them.
2091     * To determine whether segments represent true boundaries of
2092     * the interior of the path would require extensive calculations
2093     * involving all of the segments of the path and the winding
2094     * rule and are thus beyond the scope of this implementation.
2095     *
2096     * @param pi the specified {@code PathIterator}
2097     * @param r a specified {@code Rectangle2D}
2098     * @return {@code true} if the specified {@code PathIterator} contains
2099     * the specified {@code Rectangle2D}; {@code false} otherwise.
2100     * @since 1.6
2101     */

2102    public static boolean contains(PathIterator JavaDoc pi, Rectangle2D JavaDoc r) {
2103        return contains(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2104    }
2105
2106    /**
2107     * {@inheritDoc}
2108     * <p>
2109     * This method object may conservatively return false in
2110     * cases where the specified rectangular area intersects a
2111     * segment of the path, but that segment does not represent a
2112     * boundary between the interior and exterior of the path.
2113     * Such segments could lie entirely within the interior of the
2114     * path if they are part of a path with a {@link #WIND_NON_ZERO}
2115     * winding rule or if the segments are retraced in the reverse
2116     * direction such that the two sets of segments cancel each
2117     * other out without any exterior area falling between them.
2118     * To determine whether segments represent true boundaries of
2119     * the interior of the path would require extensive calculations
2120     * involving all of the segments of the path and the winding
2121     * rule and are thus beyond the scope of this implementation.
2122     *
2123     * @since 1.6
2124     */

2125    public final boolean contains(double x, double y, double w, double h) {
2126        if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2127            /* [xy]+[wh] is NaN if any of those values are NaN,
2128             * or if adding the two together would produce NaN
2129             * by virtue of adding opposing Infinte values.
2130             * Since we need to add them below, their sum must
2131             * not be NaN.
2132             * We return false because NaN always produces a
2133             * negative response to tests
2134             */

2135            return false;
2136        }
2137        if (w <= 0 || h <= 0) {
2138            return false;
2139        }
2140        int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2141    int crossings = rectCrossings(x, y, x+w, y+h);
2142    return (crossings != Curve.RECT_INTERSECTS &&
2143                (crossings & mask) != 0);
2144    }
2145
2146    /**
2147     * {@inheritDoc}
2148     * <p>
2149     * This method object may conservatively return false in
2150     * cases where the specified rectangular area intersects a
2151     * segment of the path, but that segment does not represent a
2152     * boundary between the interior and exterior of the path.
2153     * Such segments could lie entirely within the interior of the
2154     * path if they are part of a path with a {@link #WIND_NON_ZERO}
2155     * winding rule or if the segments are retraced in the reverse
2156     * direction such that the two sets of segments cancel each
2157     * other out without any exterior area falling between them.
2158     * To determine whether segments represent true boundaries of
2159     * the interior of the path would require extensive calculations
2160     * involving all of the segments of the path and the winding
2161     * rule and are thus beyond the scope of this implementation.
2162     *
2163     * @since 1.6
2164     */

2165    public final boolean contains(Rectangle2D JavaDoc r) {
2166    return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2167    }
2168
2169    /**
2170     * Tests if the interior of the specified {@link PathIterator}
2171     * intersects the interior of a specified set of rectangular
2172     * coordinates.
2173     * <p>
2174     * This method provides a basic facility for implementors of
2175     * the {@link Shape} interface to implement support for the
2176     * {@link Shape#intersects(double, double, double, double)} method.
2177     * <p>
2178     * This method object may conservatively return true in
2179     * cases where the specified rectangular area intersects a
2180     * segment of the path, but that segment does not represent a
2181     * boundary between the interior and exterior of the path.
2182     * Such a case may occur if some set of segments of the
2183     * path are retraced in the reverse direction such that the
2184     * two sets of segments cancel each other out without any
2185     * interior area between them.
2186     * To determine whether segments represent true boundaries of
2187     * the interior of the path would require extensive calculations
2188     * involving all of the segments of the path and the winding
2189     * rule and are thus beyond the scope of this implementation.
2190     *
2191     * @param pi the specified {@code PathIterator}
2192     * @param x the specified X coordinate
2193     * @param y the specified Y coordinate
2194     * @param w the width of the specified rectangular coordinates
2195     * @param h the height of the specified rectangular coordinates
2196     * @return {@code true} if the specified {@code PathIterator} and
2197     * the interior of the specified set of rectangular
2198     * coordinates intersect each other; {@code false} otherwise.
2199     * @since 1.6
2200     */

2201    public static boolean intersects(PathIterator JavaDoc pi,
2202                                     double x, double y, double w, double h)
2203    {
2204        if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2205            /* [xy]+[wh] is NaN if any of those values are NaN,
2206             * or if adding the two together would produce NaN
2207             * by virtue of adding opposing Infinte values.
2208             * Since we need to add them below, their sum must
2209             * not be NaN.
2210             * We return false because NaN always produces a
2211             * negative response to tests
2212             */

2213            return false;
2214        }
2215        if (w <= 0 || h <= 0) {
2216            return false;
2217        }
2218        int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2219    int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2220    return (crossings == Curve.RECT_INTERSECTS ||
2221                (crossings & mask) != 0);
2222    }
2223
2224    /**
2225     * Tests if the interior of the specified {@link PathIterator}
2226     * intersects the interior of a specified {@link Rectangle2D}.
2227     * <p>
2228     * This method provides a basic facility for implementors of
2229     * the {@link Shape} interface to implement support for the
2230     * {@link Shape#intersects(Rectangle2D)} method.
2231     * <p>
2232     * This method object may conservatively return true in
2233     * cases where the specified rectangular area intersects a
2234     * segment of the path, but that segment does not represent a
2235     * boundary between the interior and exterior of the path.
2236     * Such a case may occur if some set of segments of the
2237     * path are retraced in the reverse direction such that the
2238     * two sets of segments cancel each other out without any
2239     * interior area between them.
2240     * To determine whether segments represent true boundaries of
2241     * the interior of the path would require extensive calculations
2242     * involving all of the segments of the path and the winding
2243     * rule and are thus beyond the scope of this implementation.
2244     *
2245     * @param pi the specified {@code PathIterator}
2246     * @param r the specified {@code Rectangle2D}
2247     * @return {@code true} if the specified {@code PathIterator} and
2248     * the interior of the specified {@code Rectangle2D}
2249     * intersect each other; {@code false} otherwise.
2250     * @since 1.6
2251     */

2252    public static boolean intersects(PathIterator JavaDoc pi, Rectangle2D JavaDoc r) {
2253        return intersects(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2254    }
2255
2256    /**
2257     * {@inheritDoc}
2258     * <p>
2259     * This method object may conservatively return true in
2260     * cases where the specified rectangular area intersects a
2261     * segment of the path, but that segment does not represent a
2262     * boundary between the interior and exterior of the path.
2263     * Such a case may occur if some set of segments of the
2264     * path are retraced in the reverse direction such that the
2265     * two sets of segments cancel each other out without any
2266     * interior area between them.
2267     * To determine whether segments represent true boundaries of
2268     * the interior of the path would require extensive calculations
2269     * involving all of the segments of the path and the winding
2270     * rule and are thus beyond the scope of this implementation.
2271     *
2272     * @since 1.6
2273     */

2274    public final boolean intersects(double x, double y, double w, double h) {
2275        if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2276            /* [xy]+[wh] is NaN if any of those values are NaN,
2277             * or if adding the two together would produce NaN
2278             * by virtue of adding opposing Infinte values.
2279             * Since we need to add them below, their sum must
2280             * not be NaN.
2281             * We return false because NaN always produces a
2282             * negative response to tests
2283             */

2284            return false;
2285        }
2286        if (w <= 0 || h <= 0) {
2287            return false;
2288        }
2289        int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2290    int crossings = rectCrossings(x, y, x+w, y+h);
2291    return (crossings == Curve.RECT_INTERSECTS ||
2292                (crossings & mask) != 0);
2293    }
2294
2295    /**
2296     * {@inheritDoc}
2297     * <p>
2298     * This method object may conservatively return true in
2299     * cases where the specified rectangular area intersects a
2300     * segment of the path, but that segment does not represent a
2301     * boundary between the interior and exterior of the path.
2302     * Such a case may occur if some set of segments of the
2303     * path are retraced in the reverse direction such that the
2304     * two sets of segments cancel each other out without any
2305     * interior area between them.
2306     * To determine whether segments represent true boundaries of
2307     * the interior of the path would require extensive calculations
2308     * involving all of the segments of the path and the winding
2309     * rule and are thus beyond the scope of this implementation.
2310     *
2311     * @since 1.6
2312     */

2313    public final boolean intersects(Rectangle2D JavaDoc r) {
2314    return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2315    }
2316
2317    /**
2318     * {@inheritDoc}
2319     * <p>
2320     * The iterator for this class is not multi-threaded safe,
2321     * which means that this {@code Path2D} class does not
2322     * guarantee that modifications to the geometry of this
2323     * {@code Path2D} object do not affect any iterations of
2324     * that geometry that are already in process.
2325     *
2326     * @since 1.6
2327     */

2328    public PathIterator JavaDoc getPathIterator(AffineTransform JavaDoc at,
2329                                        double flatness)
2330    {
2331    return new FlatteningPathIterator JavaDoc(getPathIterator(at), flatness);
2332    }
2333
2334    /**
2335     * Creates a new object of the same class as this object.
2336     *
2337     * @return a clone of this instance.
2338     * @exception OutOfMemoryError if there is not enough memory.
2339     * @see java.lang.Cloneable
2340     * @since 1.6
2341     */

2342    public abstract Object JavaDoc clone();
2343        // Note: It would be nice to have this return Path2D
2344
// but one of our subclasses (GeneralPath) needs to
2345
// offer "public Object clone()" for backwards
2346
// compatibility so we cannot restrict it further.
2347
// REMIND: Can we do both somehow?
2348

2349    /*
2350     * Support fields and methods for serializing the subclasses.
2351     */

2352    private static final byte SERIAL_STORAGE_FLT_ARRAY = 0x30;
2353    private static final byte SERIAL_STORAGE_DBL_ARRAY = 0x31;
2354
2355    private static final byte SERIAL_SEG_FLT_MOVETO = 0x40;
2356    private static final byte SERIAL_SEG_FLT_LINETO = 0x41;
2357    private static final byte SERIAL_SEG_FLT_QUADTO = 0x42;
2358    private static final byte SERIAL_SEG_FLT_CUBICTO = 0x43;
2359
2360    private static final byte SERIAL_SEG_DBL_MOVETO = 0x50;
2361    private static final byte SERIAL_SEG_DBL_LINETO = 0x51;
2362    private static final byte SERIAL_SEG_DBL_QUADTO = 0x52;
2363    private static final byte SERIAL_SEG_DBL_CUBICTO = 0x53;
2364
2365    private static final byte SERIAL_SEG_CLOSE = 0x60;
2366    private static final byte SERIAL_PATH_END = 0x61;
2367
2368    final void writeObject(java.io.ObjectOutputStream JavaDoc s, boolean isdbl)
2369        throws java.io.IOException JavaDoc
2370    {
2371        s.defaultWriteObject();
2372
2373        float fCoords[];
2374        double dCoords[];
2375
2376        if (isdbl) {
2377            dCoords = ((Path2D.Double JavaDoc) this).doubleCoords;
2378            fCoords = null;
2379        } else {
2380            fCoords = ((Path2D.Float JavaDoc) this).floatCoords;
2381            dCoords = null;
2382        }
2383
2384        int numTypes = this.numTypes;
2385
2386        s.writeByte(isdbl
2387                    ? SERIAL_STORAGE_DBL_ARRAY
2388                    : SERIAL_STORAGE_FLT_ARRAY);
2389        s.writeInt(numTypes);
2390        s.writeInt(numCoords);
2391        s.writeByte((byte) windingRule);
2392
2393        int cindex = 0;
2394        for (int i = 0; i < numTypes; i++) {
2395            int npoints;
2396            byte serialtype;
2397            switch (pointTypes[i]) {
2398            case SEG_MOVETO:
2399                npoints = 1;
2400                serialtype = (isdbl
2401                              ? SERIAL_SEG_DBL_MOVETO
2402                              : SERIAL_SEG_FLT_MOVETO);
2403                break;
2404            case SEG_LINETO:
2405                npoints = 1;
2406                serialtype = (isdbl
2407                              ? SERIAL_SEG_DBL_LINETO
2408                              : SERIAL_SEG_FLT_LINETO);
2409                break;
2410            case SEG_QUADTO:
2411                npoints = 2;
2412                serialtype = (isdbl
2413                              ? SERIAL_SEG_DBL_QUADTO
2414                              : SERIAL_SEG_FLT_QUADTO);
2415                break;
2416            case SEG_CUBICTO:
2417                npoints = 3;
2418                serialtype = (isdbl
2419                              ? SERIAL_SEG_DBL_CUBICTO
2420                              : SERIAL_SEG_FLT_CUBICTO);
2421                break;
2422            case SEG_CLOSE:
2423                npoints = 0;
2424                serialtype = SERIAL_SEG_CLOSE;
2425                break;
2426
2427            default:
2428                // Should never happen
2429
throw new InternalError JavaDoc("unrecognized path type");
2430            }
2431            s.writeByte(serialtype);
2432            while (--npoints >= 0) {
2433                if (isdbl) {
2434                    s.writeDouble(dCoords[cindex++]);
2435                    s.writeDouble(dCoords[cindex++]);
2436                } else {
2437                    s.writeFloat(fCoords[cindex++]);
2438                    s.writeFloat(fCoords[cindex++]);
2439                }
2440            }
2441        }
2442        s.writeByte((byte) SERIAL_PATH_END);
2443    }
2444
2445    final void readObject(java.io.ObjectInputStream JavaDoc s, boolean storedbl)
2446        throws java.lang.ClassNotFoundException JavaDoc, java.io.IOException JavaDoc
2447    {
2448        s.defaultReadObject();
2449
2450        // The subclass calls this method with the storage type that
2451
// they want us to use (storedbl) so we ignore the storage
2452
// method hint from the stream.
2453
s.readByte();
2454        int nT = s.readInt();
2455        int nC = s.readInt();
2456        try {
2457            setWindingRule(s.readByte());
2458        } catch (IllegalArgumentException JavaDoc iae) {
2459            throw new java.io.InvalidObjectException JavaDoc(iae.getMessage());
2460        }
2461
2462        pointTypes = new byte[(nT < 0) ? INIT_SIZE : nT];
2463        if (nC < 0) {
2464            nC = INIT_SIZE * 2;
2465        }
2466        if (storedbl) {
2467            ((Path2D.Double JavaDoc) this).doubleCoords = new double[nC];
2468        } else {
2469            ((Path2D.Float JavaDoc) this).floatCoords = new float[nC];
2470        }
2471
2472    PATHDONE:
2473        for (int i = 0; nT < 0 || i < nT; i++) {
2474            boolean isdbl;
2475            int npoints;
2476            byte segtype;
2477
2478            byte serialtype = s.readByte();
2479            switch (serialtype) {
2480            case SERIAL_SEG_FLT_MOVETO:
2481                isdbl = false;
2482                npoints = 1;
2483                segtype = SEG_MOVETO;
2484                break;
2485            case SERIAL_SEG_FLT_LINETO:
2486                isdbl = false;
2487                npoints = 1;
2488                segtype = SEG_LINETO;
2489                break;
2490            case SERIAL_SEG_FLT_QUADTO:
2491                isdbl = false;
2492                npoints = 2;
2493                segtype = SEG_QUADTO;
2494                break;
2495            case SERIAL_SEG_FLT_CUBICTO:
2496                isdbl = false;
2497                npoints = 3;
2498                segtype = SEG_CUBICTO;
2499                break;
2500
2501            case SERIAL_SEG_DBL_MOVETO:
2502                isdbl = true;
2503                npoints = 1;
2504                segtype = SEG_MOVETO;
2505                break;
2506            case SERIAL_SEG_DBL_LINETO:
2507                isdbl = true;
2508                npoints = 1;
2509                segtype = SEG_LINETO;
2510                break;
2511            case SERIAL_SEG_DBL_QUADTO:
2512                isdbl = true;
2513                npoints = 2;
2514                segtype = SEG_QUADTO;
2515                break;
2516            case SERIAL_SEG_DBL_CUBICTO:
2517                isdbl = true;
2518                npoints = 3;
2519                segtype = SEG_CUBICTO;
2520                break;
2521
2522            case SERIAL_SEG_CLOSE:
2523                isdbl = false;
2524                npoints = 0;
2525                segtype = SEG_CLOSE;
2526                break;
2527
2528            case SERIAL_PATH_END:
2529                if (nT < 0) {
2530                    break PATHDONE;
2531                }
2532                throw new StreamCorruptedException JavaDoc("unexpected PATH_END");
2533
2534            default:
2535                throw new StreamCorruptedException JavaDoc("unrecognized path type");
2536            }
2537            needRoom(segtype != SEG_MOVETO, npoints * 2);
2538            if (isdbl) {
2539                while (--npoints >= 0) {
2540                    append(s.readDouble(), s.readDouble());
2541                }
2542            } else {
2543                while (--npoints >= 0) {
2544                    append(s.readFloat(), s.readFloat());
2545                }
2546            }
2547            pointTypes[numTypes++] = segtype;
2548        }
2549        if (nT >= 0 && s.readByte() != SERIAL_PATH_END) {
2550            throw new StreamCorruptedException JavaDoc("missing PATH_END");
2551        }
2552    }
2553
2554    static abstract class Iterator implements PathIterator JavaDoc {
2555        int typeIdx;
2556        int pointIdx;
2557        Path2D JavaDoc path;
2558
2559        static final int curvecoords[] = {2, 2, 4, 6, 0};
2560
2561        Iterator(Path2D JavaDoc path) {
2562            this.path = path;
2563        }
2564
2565        public int getWindingRule() {
2566            return path.getWindingRule();
2567        }
2568
2569        public boolean isDone() {
2570            return (typeIdx >= path.numTypes);
2571        }
2572
2573        public void next() {
2574            int type = path.pointTypes[typeIdx++];
2575            pointIdx += curvecoords[type];
2576        }
2577    }
2578}
2579
Popular Tags