1 /*
2  * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */

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

71 public abstract class Path2D implements Shape, Cloneable {
72     /**
73      * An even-odd winding rule for determining the interior of
74      * a path.
75      *
76      * @see PathIterator#WIND_EVEN_ODD
77      * @since 1.6
78      */

79     public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
80
81     /**
82      * A non-zero winding rule for determining the interior of a
83      * path.
84      *
85      * @see PathIterator#WIND_NON_ZERO
86      * @since 1.6
87      */

88     public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
89
90     // For code simplicity, copy these constants to our namespace
91     // and cast them to byte constants for easy storage.
92     private static final byte SEG_MOVETO  = (byte) PathIterator.SEG_MOVETO;
93     private static final byte SEG_LINETO  = (byte) PathIterator.SEG_LINETO;
94     private static final byte SEG_QUADTO  = (byte) PathIterator.SEG_QUADTO;
95     private static final byte SEG_CUBICTO = (byte) PathIterator.SEG_CUBICTO;
96     private static final byte SEG_CLOSE   = (byte) PathIterator.SEG_CLOSE;
97
98     transient byte[] pointTypes;
99     transient int numTypes;
100     transient int numCoords;
101     transient int windingRule;
102
103     static final int INIT_SIZE = 20;
104     static final int EXPAND_MAX = 500;
105     static final int EXPAND_MAX_COORDS = EXPAND_MAX * 2;
106     static final int EXPAND_MIN = 10; // ensure > 6 (cubics)
107
108     /**
109      * Constructs a new empty {@code Path2D} object.
110      * It is assumed that the package sibling subclass that is
111      * defaulting to this constructor will fill in all values.
112      *
113      * @since 1.6
114      */

115     /* private protected */
116     Path2D() {
117     }
118
119     /**
120      * Constructs a new {@code Path2D} object from the given
121      * specified initial values.
122      * This method is only intended for internal use and should
123      * not be made public if the other constructors for this class
124      * are ever exposed.
125      *
126      * @param rule the winding rule
127      * @param initialTypes the size to make the initial array to
128      *                     store the path segment types
129      * @since 1.6
130      */

131     /* private protected */
132     Path2D(int rule, int initialTypes) {
133         setWindingRule(rule);
134         this.pointTypes = new byte[initialTypes];
135     }
136
137     abstract float[] cloneCoordsFloat(AffineTransform at);
138     abstract double[] cloneCoordsDouble(AffineTransform at);
139     abstract void append(float x, float y);
140     abstract void append(double x, double y);
141     abstract Point2D getPoint(int coordindex);
142     abstract void needRoom(boolean needMove, int newCoords);
143     abstract int pointCrossings(double px, double py);
144     abstract int rectCrossings(double rxmin, double rymin,
145                                double rxmax, double rymax);
146
147     static byte[] expandPointTypes(byte[] oldPointTypes, int needed) {
148         final int oldSize = oldPointTypes.length;
149         final int newSizeMin = oldSize + needed;
150         if (newSizeMin < oldSize) {
151             // hard overflow failure - we can't even accommodate
152             // new items without overflowing
153             throw new ArrayIndexOutOfBoundsException(
154                           "pointTypes exceeds maximum capacity !");
155         }
156         // growth algorithm computation
157         int grow = oldSize;
158         if (grow > EXPAND_MAX) {
159             grow = Math.max(EXPAND_MAX, oldSize >> 3); // 1/8th min
160         } else if (grow < EXPAND_MIN) {
161             grow = EXPAND_MIN;
162         }
163         assert grow > 0;
164
165         int newSize = oldSize + grow;
166         if (newSize < newSizeMin) {
167             // overflow in growth algorithm computation
168             newSize = Integer.MAX_VALUE;
169         }
170         while (true) {
171             try {
172                 // try allocating the larger array
173                 return Arrays.copyOf(oldPointTypes, newSize);
174             } catch (OutOfMemoryError oome) {
175                 if (newSize == newSizeMin) {
176                     throw oome;
177                 }
178             }
179             newSize = newSizeMin + (newSize - newSizeMin) / 2;
180         }
181     }
182
183     /**
184      * The {@code Float} class defines a geometric path with
185      * coordinates stored in single precision floating point.
186      *
187      * @since 1.6
188      */

189     public static class Float extends Path2D implements Serializable {
190         transient float floatCoords[];
191
192         /**
193          * Constructs a new empty single precision {@code Path2D} object
194          * with a default winding rule of {@link #WIND_NON_ZERO}.
195          *
196          * @since 1.6
197          */

198         public Float() {
199             this(WIND_NON_ZERO, INIT_SIZE);
200         }
201
202         /**
203          * Constructs a new empty single precision {@code Path2D} object
204          * with the specified winding rule to control operations that
205          * require the interior of the path to be defined.
206          *
207          * @param rule the winding rule
208          * @see #WIND_EVEN_ODD
209          * @see #WIND_NON_ZERO
210          * @since 1.6
211          */

212         public Float(int rule) {
213             this(rule, INIT_SIZE);
214         }
215
216         /**
217          * Constructs a new empty single precision {@code Path2D} object
218          * with the specified winding rule and the specified initial
219          * capacity to store path segments.
220          * This number is an initial guess as to how many path segments
221          * will be added to the path, but the storage is expanded as
222          * needed to store whatever path segments are added.
223          *
224          * @param rule the winding rule
225          * @param initialCapacity the estimate for the number of path segments
226          *                        in the path
227          * @see #WIND_EVEN_ODD
228          * @see #WIND_NON_ZERO
229          * @since 1.6
230          */

231         public Float(int rule, int initialCapacity) {
232             super(rule, initialCapacity);
233             floatCoords = new float[initialCapacity * 2];
234         }
235
236         /**
237          * Constructs a new single precision {@code Path2D} object
238          * from an arbitrary {@link Shape} object.
239          * All of the initial geometry and the winding rule for this path are
240          * taken from the specified {@code Shape} object.
241          *
242          * @param s the specified {@code Shape} object
243          * @since 1.6
244          */

245         public Float(Shape s) {
246             this(s, null);
247         }
248
249         /**
250          * Constructs a new single precision {@code Path2D} object
251          * from an arbitrary {@link Shape} object, transformed by an
252          * {@link AffineTransform} object.
253          * All of the initial geometry and the winding rule for this path are
254          * taken from the specified {@code Shape} object and transformed
255          * by the specified {@code AffineTransform} object.
256          *
257          * @param s the specified {@code Shape} object
258          * @param at the specified {@code AffineTransform} object
259          * @since 1.6
260          */

261         public Float(Shape s, AffineTransform at) {
262             if (s instanceof Path2D) {
263                 Path2D p2d = (Path2D) s;
264                 setWindingRule(p2d.windingRule);
265                 this.numTypes = p2d.numTypes;
266                 // trim arrays:
267                 this.pointTypes = Arrays.copyOf(p2d.pointTypes, p2d.numTypes);
268                 this.numCoords = p2d.numCoords;
269                 this.floatCoords = p2d.cloneCoordsFloat(at);
270             } else {
271                 PathIterator pi = s.getPathIterator(at);
272                 setWindingRule(pi.getWindingRule());
273                 this.pointTypes = new byte[INIT_SIZE];
274                 this.floatCoords = new float[INIT_SIZE * 2];
275                 append(pi, false);
276             }
277         }
278
279         @Override
280         public final void trimToSize() {
281             // trim arrays:
282             if (numTypes < pointTypes.length) {
283                 this.pointTypes = Arrays.copyOf(pointTypes, numTypes);
284             }
285             if (numCoords < floatCoords.length) {
286                 this.floatCoords = Arrays.copyOf(floatCoords, numCoords);
287             }
288         }
289
290         @Override
291         float[] cloneCoordsFloat(AffineTransform at) {
292             // trim arrays:
293             float ret[];
294             if (at == null) {
295                 ret = Arrays.copyOf(floatCoords, numCoords);
296             } else {
297                 ret = new float[numCoords];
298                 at.transform(floatCoords, 0, ret, 0, numCoords / 2);
299             }
300             return ret;
301         }
302
303         @Override
304         double[] cloneCoordsDouble(AffineTransform at) {
305             // trim arrays:
306             double ret[] = new double[numCoords];
307             if (at == null) {
308                 for (int i = 0; i < numCoords; i++) {
309                     ret[i] = floatCoords[i];
310                 }
311             } else {
312                 at.transform(floatCoords, 0, ret, 0, numCoords / 2);
313             }
314             return ret;
315         }
316
317         void append(float x, float y) {
318             floatCoords[numCoords++] = x;
319             floatCoords[numCoords++] = y;
320         }
321
322         void append(double x, double y) {
323             floatCoords[numCoords++] = (float) x;
324             floatCoords[numCoords++] = (float) y;
325         }
326
327         Point2D getPoint(int coordindex) {
328             return new Point2D.Float(floatCoords[coordindex],
329                                      floatCoords[coordindex+1]);
330         }
331
332         @Override
333         void needRoom(boolean needMove, int newCoords) {
334             if ((numTypes == 0) && needMove) {
335                 throw new IllegalPathStateException("missing initial moveto "+
336                                                     "in path definition");
337             }
338             if (numTypes >= pointTypes.length) {
339                 pointTypes = expandPointTypes(pointTypes, 1);
340             }
341             if (numCoords > (floatCoords.length - newCoords)) {
342                 floatCoords = expandCoords(floatCoords, newCoords);
343             }
344         }
345
346         static float[] expandCoords(float[] oldCoords, int needed) {
347             final int oldSize = oldCoords.length;
348             final int newSizeMin = oldSize + needed;
349             if (newSizeMin < oldSize) {
350                 // hard overflow failure - we can't even accommodate
351                 // new items without overflowing
352                 throw new ArrayIndexOutOfBoundsException(
353                               "coords exceeds maximum capacity !");
354             }
355             // growth algorithm computation
356             int grow = oldSize;
357             if (grow > EXPAND_MAX_COORDS) {
358                 grow = Math.max(EXPAND_MAX_COORDS, oldSize >> 3); // 1/8th min
359             } else if (grow < EXPAND_MIN) {
360                 grow = EXPAND_MIN;
361             }
362             assert grow > needed;
363
364             int newSize = oldSize + grow;
365             if (newSize < newSizeMin) {
366                 // overflow in growth algorithm computation
367                 newSize = Integer.MAX_VALUE;
368             }
369             while (true) {
370                 try {
371                     // try allocating the larger array
372                     return Arrays.copyOf(oldCoords, newSize);
373                 } catch (OutOfMemoryError oome) {
374                     if (newSize == newSizeMin) {
375                         throw oome;
376                     }
377                 }
378                 newSize = newSizeMin + (newSize - newSizeMin) / 2;
379             }
380         }
381
382         /**
383          * {@inheritDoc}
384          * @since 1.6
385          */

386         public final synchronized void moveTo(double x, double y) {
387             if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
388                 floatCoords[numCoords-2] = (float) x;
389                 floatCoords[numCoords-1] = (float) y;
390             } else {
391                 needRoom(false, 2);
392                 pointTypes[numTypes++] = SEG_MOVETO;
393                 floatCoords[numCoords++] = (float) x;
394                 floatCoords[numCoords++] = (float) y;
395             }
396         }
397
398         /**
399          * Adds a point to the path by moving to the specified
400          * coordinates specified in float precision.
401          * <p>
402          * This method provides a single precision variant of
403          * the double precision {@code moveTo()} method on the
404          * base {@code Path2D} class.
405          *
406          * @param x the specified X coordinate
407          * @param y the specified Y coordinate
408          * @see Path2D#moveTo
409          * @since 1.6
410          */

411         public final synchronized void moveTo(float x, float y) {
412             if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
413                 floatCoords[numCoords-2] = x;
414                 floatCoords[numCoords-1] = y;
415             } else {
416                 needRoom(false, 2);
417                 pointTypes[numTypes++] = SEG_MOVETO;
418                 floatCoords[numCoords++] = x;
419                 floatCoords[numCoords++] = y;
420             }
421         }
422
423         /**
424          * {@inheritDoc}
425          * @since 1.6
426          */

427         public final synchronized void lineTo(double x, double y) {
428             needRoom(true, 2);
429             pointTypes[numTypes++] = SEG_LINETO;
430             floatCoords[numCoords++] = (float) x;
431             floatCoords[numCoords++] = (float) y;
432         }
433
434         /**
435          * Adds a point to the path by drawing a straight line from the
436          * current coordinates to the new specified coordinates
437          * specified in float precision.
438          * <p>
439          * This method provides a single precision variant of
440          * the double precision {@code lineTo()} method on the
441          * base {@code Path2D} class.
442          *
443          * @param x the specified X coordinate
444          * @param y the specified Y coordinate
445          * @see Path2D#lineTo
446          * @since 1.6
447          */

448         public final synchronized void lineTo(float x, float y) {
449             needRoom(true, 2);
450             pointTypes[numTypes++] = SEG_LINETO;
451             floatCoords[numCoords++] = x;
452             floatCoords[numCoords++] = y;
453         }
454
455         /**
456          * {@inheritDoc}
457          * @since 1.6
458          */

459         public final synchronized void quadTo(double x1, double y1,
460                                               double x2, double y2)
461         {
462             needRoom(true, 4);
463             pointTypes[numTypes++] = SEG_QUADTO;
464             floatCoords[numCoords++] = (float) x1;
465             floatCoords[numCoords++] = (float) y1;
466             floatCoords[numCoords++] = (float) x2;
467             floatCoords[numCoords++] = (float) y2;
468         }
469
470         /**
471          * Adds a curved segment, defined by two new points, to the path by
472          * drawing a Quadratic curve that intersects both the current
473          * coordinates and the specified coordinates {@code (x2,y2)},
474          * using the specified point {@code (x1,y1)} as a quadratic
475          * parametric control point.
476          * All coordinates are specified in float precision.
477          * <p>
478          * This method provides a single precision variant of
479          * the double precision {@code quadTo()} method on the
480          * base {@code Path2D} class.
481          *
482          * @param x1 the X coordinate of the quadratic control point
483          * @param y1 the Y coordinate of the quadratic control point
484          * @param x2 the X coordinate of the final end point
485          * @param y2 the Y coordinate of the final end point
486          * @see Path2D#quadTo
487          * @since 1.6
488          */

489         public final synchronized void quadTo(float x1, float y1,
490                                               float x2, float y2)
491         {
492             needRoom(true, 4);
493             pointTypes[numTypes++] = SEG_QUADTO;
494             floatCoords[numCoords++] = x1;
495             floatCoords[numCoords++] = y1;
496             floatCoords[numCoords++] = x2;
497             floatCoords[numCoords++] = y2;
498         }
499
500         /**
501          * {@inheritDoc}
502          * @since 1.6
503          */

504         public final synchronized void curveTo(double x1, double y1,
505                                                double x2, double y2,
506                                                double x3, double y3)
507         {
508             needRoom(true, 6);
509             pointTypes[numTypes++] = SEG_CUBICTO;
510             floatCoords[numCoords++] = (float) x1;
511             floatCoords[numCoords++] = (float) y1;
512             floatCoords[numCoords++] = (float) x2;
513             floatCoords[numCoords++] = (float) y2;
514             floatCoords[numCoords++] = (float) x3;
515             floatCoords[numCoords++] = (float) y3;
516         }
517
518         /**
519          * Adds a curved segment, defined by three new points, to the path by
520          * drawing a B&eacute;zier curve that intersects both the current
521          * coordinates and the specified coordinates {@code (x3,y3)},
522          * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
523          * B&eacute;zier control points.
524          * All coordinates are specified in float precision.
525          * <p>
526          * This method provides a single precision variant of
527          * the double precision {@code curveTo()} method on the
528          * base {@code Path2D} class.
529          *
530          * @param x1 the X coordinate of the first B&eacute;zier control point
531          * @param y1 the Y coordinate of the first B&eacute;zier control point
532          * @param x2 the X coordinate of the second B&eacute;zier control point
533          * @param y2 the Y coordinate of the second B&eacute;zier control point
534          * @param x3 the X coordinate of the final end point
535          * @param y3 the Y coordinate of the final end point
536          * @see Path2D#curveTo
537          * @since 1.6
538          */

539         public final synchronized void curveTo(float x1, float y1,
540                                                float x2, float y2,
541                                                float x3, float y3)
542         {
543             needRoom(true, 6);
544             pointTypes[numTypes++] = SEG_CUBICTO;
545             floatCoords[numCoords++] = x1;
546             floatCoords[numCoords++] = y1;
547             floatCoords[numCoords++] = x2;
548             floatCoords[numCoords++] = y2;
549             floatCoords[numCoords++] = x3;
550             floatCoords[numCoords++] = y3;
551         }
552
553         int pointCrossings(double px, double py) {
554             if (numTypes == 0) {
555                 return 0;
556             }
557             double movx, movy, curx, cury, endx, endy;
558             float coords[] = floatCoords;
559             curx = movx = coords[0];
560             cury = movy = coords[1];
561             int crossings = 0;
562             int ci = 2;
563             for (int i = 1; i < numTypes; i++) {
564                 switch (pointTypes[i]) {
565                 case PathIterator.SEG_MOVETO:
566                     if (cury != movy) {
567                         crossings +=
568                             Curve.pointCrossingsForLine(px, py,
569                                                         curx, cury,
570                                                         movx, movy);
571                     }
572                     movx = curx = coords[ci++];
573                     movy = cury = coords[ci++];
574                     break;
575                 case PathIterator.SEG_LINETO:
576                     crossings +=
577                         Curve.pointCrossingsForLine(px, py,
578                                                     curx, cury,
579                                                     endx = coords[ci++],
580                                                     endy = coords[ci++]);
581                     curx = endx;
582                     cury = endy;
583                     break;
584                 case PathIterator.SEG_QUADTO:
585                     crossings +=
586                         Curve.pointCrossingsForQuad(px, py,
587                                                     curx, cury,
588                                                     coords[ci++],
589                                                     coords[ci++],
590                                                     endx = coords[ci++],
591                                                     endy = coords[ci++],
592                                                     0);
593                     curx = endx;
594                     cury = endy;
595                     break;
596             case PathIterator.SEG_CUBICTO:
597                     crossings +=
598                         Curve.pointCrossingsForCubic(px, py,
599                                                      curx, cury,
600                                                      coords[ci++],
601                                                      coords[ci++],
602                                                      coords[ci++],
603                                                      coords[ci++],
604                                                      endx = coords[ci++],
605                                                      endy = coords[ci++],
606                                                      0);
607                     curx = endx;
608                     cury = endy;
609                     break;
610                 case PathIterator.SEG_CLOSE:
611                     if (cury != movy) {
612                         crossings +=
613                             Curve.pointCrossingsForLine(px, py,
614                                                         curx, cury,
615                                                         movx, movy);
616                     }
617                     curx = movx;
618                     cury = movy;
619                     break;
620                 }
621             }
622             if (cury != movy) {
623                 crossings +=
624                     Curve.pointCrossingsForLine(px, py,
625                                                 curx, cury,
626                                                 movx, movy);
627             }
628             return crossings;
629         }
630
631         int rectCrossings(double rxmin, double rymin,
632                           double rxmax, double rymax)
633         {
634             if (numTypes == 0) {
635                 return 0;
636             }
637             float coords[] = floatCoords;
638             double curx, cury, movx, movy, endx, endy;
639             curx = movx = coords[0];
640             cury = movy = coords[1];
641             int crossings = 0;
642             int ci = 2;
643             for (int i = 1;
644                  crossings != Curve.RECT_INTERSECTS && i < numTypes;
645                  i++)
646             {
647                 switch (pointTypes[i]) {
648                 case PathIterator.SEG_MOVETO:
649                     if (curx != movx || cury != movy) {
650                         crossings =
651                             Curve.rectCrossingsForLine(crossings,
652                                                        rxmin, rymin,
653                                                        rxmax, rymax,
654                                                        curx, cury,
655                                                        movx, movy);
656                     }
657                     // Count should always be a multiple of 2 here.
658                     // assert((crossings & 1) != 0);
659                     movx = curx = coords[ci++];
660                     movy = cury = coords[ci++];
661                     break;
662                 case PathIterator.SEG_LINETO:
663                     crossings =
664                         Curve.rectCrossingsForLine(crossings,
665                                                    rxmin, rymin,
666                                                    rxmax, rymax,
667                                                    curx, cury,
668                                                    endx = coords[ci++],
669                                                    endy = coords[ci++]);
670                     curx = endx;
671                     cury = endy;
672                     break;
673                 case PathIterator.SEG_QUADTO:
674                     crossings =
675                         Curve.rectCrossingsForQuad(crossings,
676                                                    rxmin, rymin,
677                                                    rxmax, rymax,
678                                                    curx, cury,
679                                                    coords[ci++],
680                                                    coords[ci++],
681                                                    endx = coords[ci++],
682                                                    endy = coords[ci++],
683                                                    0);
684                     curx = endx;
685                     cury = endy;
686                     break;
687                 case PathIterator.SEG_CUBICTO:
688                     crossings =
689                         Curve.rectCrossingsForCubic(crossings,
690                                                     rxmin, rymin,
691                                                     rxmax, rymax,
692                                                     curx, cury,
693                                                     coords[ci++],
694                                                     coords[ci++],
695                                                     coords[ci++],
696                                                     coords[ci++],
697                                                     endx = coords[ci++],
698                                                     endy = coords[ci++],
699                                                     0);
700                     curx = endx;
701                     cury = endy;
702                     break;
703                 case PathIterator.SEG_CLOSE:
704                     if (curx != movx || cury != movy) {
705                         crossings =
706                             Curve.rectCrossingsForLine(crossings,
707                                                        rxmin, rymin,
708                                                        rxmax, rymax,
709                                                        curx, cury,
710                                                        movx, movy);
711                     }
712                     curx = movx;
713                     cury = movy;
714                     // Count should always be a multiple of 2 here.
715                     // assert((crossings & 1) != 0);
716                     break;
717                 }
718             }
719             if (crossings != Curve.RECT_INTERSECTS &&
720                 (curx != movx || cury != movy))
721             {
722                 crossings =
723                     Curve.rectCrossingsForLine(crossings,
724                                                rxmin, rymin,
725                                                rxmax, rymax,
726                                                curx, cury,
727                                                movx, movy);
728             }
729             // Count should always be a multiple of 2 here.
730             // assert((crossings & 1) != 0);
731             return crossings;
732         }
733
734         /**
735          * {@inheritDoc}
736          * @since 1.6
737          */

738         public final void append(PathIterator pi, boolean connect) {
739             float coords[] = new float[6];
740             while (!pi.isDone()) {
741                 switch (pi.currentSegment(coords)) {
742                 case SEG_MOVETO:
743                     if (!connect || numTypes < 1 || numCoords < 1) {
744                         moveTo(coords[0], coords[1]);
745                         break;
746                     }
747                     if (pointTypes[numTypes - 1] != SEG_CLOSE &&
748                         floatCoords[numCoords-2] == coords[0] &&
749                         floatCoords[numCoords-1] == coords[1])
750                     {
751                         // Collapse out initial moveto/lineto
752                         break;
753                     }
754                     lineTo(coords[0], coords[1]);
755                     break;
756                 case SEG_LINETO:
757                     lineTo(coords[0], coords[1]);
758                     break;
759                 case SEG_QUADTO:
760                     quadTo(coords[0], coords[1],
761                            coords[2], coords[3]);
762                     break;
763                 case SEG_CUBICTO:
764                     curveTo(coords[0], coords[1],
765                             coords[2], coords[3],
766                             coords[4], coords[5]);
767                     break;
768                 case SEG_CLOSE:
769                     closePath();
770                     break;
771                 }
772                 pi.next();
773                 connect = false;
774             }
775         }
776
777         /**
778          * {@inheritDoc}
779          * @since 1.6
780          */

781         public final void transform(AffineTransform at) {
782             at.transform(floatCoords, 0, floatCoords, 0, numCoords / 2);
783         }
784
785         /**
786          * {@inheritDoc}
787          * @since 1.6
788          */

789         public final synchronized Rectangle2D getBounds2D() {
790             float x1, y1, x2, y2;
791             int i = numCoords;
792             if (i > 0) {
793                 y1 = y2 = floatCoords[--i];
794                 x1 = x2 = floatCoords[--i];
795                 while (i > 0) {
796                     float y = floatCoords[--i];
797                     float x = floatCoords[--i];
798                     if (x < x1) x1 = x;
799                     if (y < y1) y1 = y;
800                     if (x > x2) x2 = x;
801                     if (y > y2) y2 = y;
802                 }
803             } else {
804                 x1 = y1 = x2 = y2 = 0.0f;
805             }
806             return new Rectangle2D.Float(x1, y1, x2 - x1, y2 - y1);
807         }
808
809         /**
810          * {@inheritDoc}
811          * <p>
812          * The iterator for this class is not multi-threaded safe,
813          * which means that the {@code Path2D} class does not
814          * guarantee that modifications to the geometry of this
815          * {@code Path2D} object do not affect any iterations of
816          * that geometry that are already in process.
817          *
818          * @since 1.6
819          */

820         public final PathIterator getPathIterator(AffineTransform at) {
821             if (at == null) {
822                 return new CopyIterator(this);
823             } else {
824                 return new TxIterator(this, at);
825             }
826         }
827
828         /**
829          * Creates a new object of the same class as this object.
830          *
831          * @return     a clone of this instance.
832          * @exception  OutOfMemoryError    if there is not enough memory.
833          * @see        java.lang.Cloneable
834          * @since      1.6
835          */

836         public final Object clone() {
837             // Note: It would be nice to have this return Path2D
838             // but one of our subclasses (GeneralPath) needs to
839             // offer "public Object clone()" for backwards
840             // compatibility so we cannot restrict it further.
841             // REMIND: Can we do both somehow?
842             if (this instanceof GeneralPath) {
843                 return new GeneralPath(this);
844             } else {
845                 return new Path2D.Float(this);
846             }
847         }
848
849         /*
850          * JDK 1.6 serialVersionUID
851          */

852         private static final long serialVersionUID = 6990832515060788886L;
853
854         /**
855          * Writes the default serializable fields to the
856          * {@code ObjectOutputStream} followed by an explicit
857          * serialization of the path segments stored in this
858          * path.
859          *
860          * @serialData
861          * <a id="Path2DSerialData"><!-- --></a>
862          * <ol>
863          * <li>The default serializable fields.
864          * There are no default serializable fields as of 1.6.
865          * <li>followed by
866          * a byte indicating the storage type of the original object
867          * as a hint (SERIAL_STORAGE_FLT_ARRAY)
868          * <li>followed by
869          * an integer indicating the number of path segments to follow (NP)
870          * or -1 to indicate an unknown number of path segments follows
871          * <li>followed by
872          * an integer indicating the total number of coordinates to follow (NC)
873          * or -1 to indicate an unknown number of coordinates follows
874          * (NC should always be even since coordinates always appear in pairs
875          *  representing an x,y pair)
876          * <li>followed by
877          * a byte indicating the winding rule
878          * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
879          *  {@link #WIND_NON_ZERO WIND_NON_ZERO})
880          * <li>followed by
881          * {@code NP} (or unlimited if {@code NP < 0}) sets of values consisting of
882          * a single byte indicating a path segment type
883          * followed by one or more pairs of float or double
884          * values representing the coordinates of the path segment
885          * <li>followed by
886          * a byte indicating the end of the path (SERIAL_PATH_END).
887          * </ol>
888          * <p>
889          * The following byte value constants are used in the serialized form
890          * of {@code Path2D} objects:
891          *
892          * <table class="striped">
893          * <caption>Constants</caption>
894          * <thead>
895          * <tr>
896          * <th>Constant Name</th>
897          * <th>Byte Value</th>
898          * <th>Followed by</th>
899          * <th>Description</th>
900          * </tr>
901          * </thead>
902          * <tbody>
903          * <tr>
904          * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
905          * <td>0x30</td>
906          * <td></td>
907          * <td>A hint that the original {@code Path2D} object stored
908          * the coordinates in a Java array of floats.</td>
909          * </tr>
910          * <tr>
911          * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
912          * <td>0x31</td>
913          * <td></td>
914          * <td>A hint that the original {@code Path2D} object stored
915          * the coordinates in a Java array of doubles.</td>
916          * </tr>
917          * <tr>
918          * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
919          * <td>0x40</td>
920          * <td>2 floats</td>
921          * <td>A {@link #moveTo moveTo} path segment follows.</td>
922          * </tr>
923          * <tr>
924          * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
925          * <td>0x41</td>
926          * <td>2 floats</td>
927          * <td>A {@link #lineTo lineTo} path segment follows.</td>
928          * </tr>
929          * <tr>
930          * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
931          * <td>0x42</td>
932          * <td>4 floats</td>
933          * <td>A {@link #quadTo quadTo} path segment follows.</td>
934          * </tr>
935          * <tr>
936          * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
937          * <td>0x43</td>
938          * <td>6 floats</td>
939          * <td>A {@link #curveTo curveTo} path segment follows.</td>
940          * </tr>
941          * <tr>
942          * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
943          * <td>0x50</td>
944          * <td>2 doubles</td>
945          * <td>A {@link #moveTo moveTo} path segment follows.</td>
946          * </tr>
947          * <tr>
948          * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
949          * <td>0x51</td>
950          * <td>2 doubles</td>
951          * <td>A {@link #lineTo lineTo} path segment follows.</td>
952          * </tr>
953          * <tr>
954          * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
955          * <td>0x52</td>
956          * <td>4 doubles</td>
957          * <td>A {@link #curveTo curveTo} path segment follows.</td>
958          * </tr>
959          * <tr>
960          * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
961          * <td>0x53</td>
962          * <td>6 doubles</td>
963          * <td>A {@link #curveTo curveTo} path segment follows.</td>
964          * </tr>
965          * <tr>
966          * <td>{@code SERIAL_SEG_CLOSE}</td>
967          * <td>0x60</td>
968          * <td></td>
969          * <td>A {@link #closePath closePath} path segment.</td>
970          * </tr>
971          * <tr>
972          * <td>{@code SERIAL_PATH_END}</td>
973          * <td>0x61</td>
974          * <td></td>
975          * <td>There are no more path segments following.</td>
976          * </tbody>
977          * </table>
978          *
979          * @since 1.6
980          */

981         private void writeObject(java.io.ObjectOutputStream s)
982             throws java.io.IOException
983         {
984             super.writeObject(s, false);
985         }
986
987         /**
988          * Reads the default serializable fields from the
989          * {@code ObjectInputStream} followed by an explicit
990          * serialization of the path segments stored in this
991          * path.
992          * <p>
993          * There are no default serializable fields as of 1.6.
994          * <p>
995          * The serial data for this object is described in the
996          * writeObject method.
997          *
998          * @since 1.6
999          */

1000         private void readObject(java.io.ObjectInputStream s)
1001             throws java.lang.ClassNotFoundException, java.io.IOException
1002         {
1003             super.readObject(s, false);
1004         }
1005
1006         static class CopyIterator extends Path2D.Iterator {
1007             float floatCoords[];
1008
1009             CopyIterator(Path2D.Float p2df) {
1010                 super(p2df);
1011                 this.floatCoords = p2df.floatCoords;
1012             }
1013
1014             public int currentSegment(float[] coords) {
1015                 int type = path.pointTypes[typeIdx];
1016                 int numCoords = curvecoords[type];
1017                 if (numCoords > 0) {
1018                     System.arraycopy(floatCoords, pointIdx,
1019                                      coords, 0, numCoords);
1020                 }
1021                 return type;
1022             }
1023
1024             public int currentSegment(double[] coords) {
1025                 int type = path.pointTypes[typeIdx];
1026                 int numCoords = curvecoords[type];
1027                 if (numCoords > 0) {
1028                     for (int i = 0; i < numCoords; i++) {
1029                         coords[i] = floatCoords[pointIdx + i];
1030                     }
1031                 }
1032                 return type;
1033             }
1034         }
1035
1036         static class TxIterator extends Path2D.Iterator {
1037             float floatCoords[];
1038             AffineTransform affine;
1039
1040             TxIterator(Path2D.Float p2df, AffineTransform at) {
1041                 super(p2df);
1042                 this.floatCoords = p2df.floatCoords;
1043                 this.affine = at;
1044             }
1045
1046             public int currentSegment(float[] coords) {
1047                 int type = path.pointTypes[typeIdx];
1048                 int numCoords = curvecoords[type];
1049                 if (numCoords > 0) {
1050                     affine.transform(floatCoords, pointIdx,
1051                                      coords, 0, numCoords / 2);
1052                 }
1053                 return type;
1054             }
1055
1056             public int currentSegment(double[] coords) {
1057                 int type = path.pointTypes[typeIdx];
1058                 int numCoords = curvecoords[type];
1059                 if (numCoords > 0) {
1060                     affine.transform(floatCoords, pointIdx,
1061                                      coords, 0, numCoords / 2);
1062                 }
1063                 return type;
1064             }
1065         }
1066
1067     }
1068
1069     /**
1070      * The {@code Double} class defines a geometric path with
1071      * coordinates stored in double precision floating point.
1072      *
1073      * @since 1.6
1074      */

1075     public static class Double extends Path2D implements Serializable {
1076         transient double doubleCoords[];
1077
1078         /**
1079          * Constructs a new empty double precision {@code Path2D} object
1080          * with a default winding rule of {@link #WIND_NON_ZERO}.
1081          *
1082          * @since 1.6
1083          */

1084         public Double() {
1085             this(WIND_NON_ZERO, INIT_SIZE);
1086         }
1087
1088         /**
1089          * Constructs a new empty double precision {@code Path2D} object
1090          * with the specified winding rule to control operations that
1091          * require the interior of the path to be defined.
1092          *
1093          * @param rule the winding rule
1094          * @see #WIND_EVEN_ODD
1095          * @see #WIND_NON_ZERO
1096          * @since 1.6
1097          */

1098         public Double(int rule) {
1099             this(rule, INIT_SIZE);
1100         }
1101
1102         /**
1103          * Constructs a new empty double precision {@code Path2D} object
1104          * with the specified winding rule and the specified initial
1105          * capacity to store path segments.
1106          * This number is an initial guess as to how many path segments
1107          * are in the path, but the storage is expanded as needed to store
1108          * whatever path segments are added to this path.
1109          *
1110          * @param rule the winding rule
1111          * @param initialCapacity the estimate for the number of path segments
1112          *                        in the path
1113          * @see #WIND_EVEN_ODD
1114          * @see #WIND_NON_ZERO
1115          * @since 1.6
1116          */

1117         public Double(int rule, int initialCapacity) {
1118             super(rule, initialCapacity);
1119             doubleCoords = new double[initialCapacity * 2];
1120         }
1121
1122         /**
1123          * Constructs a new double precision {@code Path2D} object
1124          * from an arbitrary {@link Shape} object.
1125          * All of the initial geometry and the winding rule for this path are
1126          * taken from the specified {@code Shape} object.
1127          *
1128          * @param s the specified {@code Shape} object
1129          * @since 1.6
1130          */

1131         public Double(Shape s) {
1132             this(s, null);
1133         }
1134
1135         /**
1136          * Constructs a new double precision {@code Path2D} object
1137          * from an arbitrary {@link Shape} object, transformed by an
1138          * {@link AffineTransform} object.
1139          * All of the initial geometry and the winding rule for this path are
1140          * taken from the specified {@code Shape} object and transformed
1141          * by the specified {@code AffineTransform} object.
1142          *
1143          * @param s the specified {@code Shape} object
1144          * @param at the specified {@code AffineTransform} object
1145          * @since 1.6
1146          */

1147         public Double(Shape s, AffineTransform at) {
1148             if (s instanceof Path2D) {
1149                 Path2D p2d = (Path2D) s;
1150                 setWindingRule(p2d.windingRule);
1151                 this.numTypes = p2d.numTypes;
1152                 // trim arrays:
1153                 this.pointTypes = Arrays.copyOf(p2d.pointTypes, p2d.numTypes);
1154                 this.numCoords = p2d.numCoords;
1155                 this.doubleCoords = p2d.cloneCoordsDouble(at);
1156             } else {
1157                 PathIterator pi = s.getPathIterator(at);
1158                 setWindingRule(pi.getWindingRule());
1159                 this.pointTypes = new byte[INIT_SIZE];
1160                 this.doubleCoords = new double[INIT_SIZE * 2];
1161                 append(pi, false);
1162             }
1163         }
1164
1165         @Override
1166         public final void trimToSize() {
1167             // trim arrays:
1168             if (numTypes < pointTypes.length) {
1169                 this.pointTypes = Arrays.copyOf(pointTypes, numTypes);
1170             }
1171             if (numCoords < doubleCoords.length) {
1172                 this.doubleCoords = Arrays.copyOf(doubleCoords, numCoords);
1173             }
1174         }
1175
1176         @Override
1177         float[] cloneCoordsFloat(AffineTransform at) {
1178             // trim arrays:
1179             float ret[] = new float[numCoords];
1180             if (at == null) {
1181                 for (int i = 0; i < numCoords; i++) {
1182                     ret[i] = (float) doubleCoords[i];
1183                 }
1184             } else {
1185                 at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1186             }
1187             return ret;
1188         }
1189
1190         @Override
1191         double[] cloneCoordsDouble(AffineTransform at) {
1192             // trim arrays:
1193             double ret[];
1194             if (at == null) {
1195                 ret = Arrays.copyOf(doubleCoords, numCoords);
1196             } else {
1197                 ret = new double[numCoords];
1198                 at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1199             }
1200             return ret;
1201         }
1202
1203         void append(float x, float y) {
1204             doubleCoords[numCoords++] = x;
1205             doubleCoords[numCoords++] = y;
1206         }
1207
1208         void append(double x, double y) {
1209             doubleCoords[numCoords++] = x;
1210             doubleCoords[numCoords++] = y;
1211         }
1212
1213         Point2D getPoint(int coordindex) {
1214             return new Point2D.Double(doubleCoords[coordindex],
1215                                       doubleCoords[coordindex+1]);
1216         }
1217
1218         @Override
1219         void needRoom(boolean needMove, int newCoords) {
1220             if ((numTypes == 0) && needMove) {
1221                 throw new IllegalPathStateException("missing initial moveto "+
1222                                                     "in path definition");
1223             }
1224             if (numTypes >= pointTypes.length) {
1225                 pointTypes = expandPointTypes(pointTypes, 1);
1226             }
1227             if (numCoords > (doubleCoords.length - newCoords)) {
1228                 doubleCoords = expandCoords(doubleCoords, newCoords);
1229             }
1230         }
1231
1232         static double[] expandCoords(double[] oldCoords, int needed) {
1233             final int oldSize = oldCoords.length;
1234             final int newSizeMin = oldSize + needed;
1235             if (newSizeMin < oldSize) {
1236                 // hard overflow failure - we can't even accommodate
1237                 // new items without overflowing
1238                 throw new ArrayIndexOutOfBoundsException(
1239                               "coords exceeds maximum capacity !");
1240             }
1241             // growth algorithm computation
1242             int grow = oldSize;
1243             if (grow > EXPAND_MAX_COORDS) {
1244                 grow = Math.max(EXPAND_MAX_COORDS, oldSize >> 3); // 1/8th min
1245             } else if (grow < EXPAND_MIN) {
1246                 grow = EXPAND_MIN;
1247             }
1248             assert grow > needed;
1249
1250             int newSize = oldSize + grow;
1251             if (newSize < newSizeMin) {
1252                 // overflow in growth algorithm computation
1253                 newSize = Integer.MAX_VALUE;
1254             }
1255             while (true) {
1256                 try {
1257                     // try allocating the larger array
1258                     return Arrays.copyOf(oldCoords, newSize);
1259                 } catch (OutOfMemoryError oome) {
1260                     if (newSize == newSizeMin) {
1261                         throw oome;
1262                     }
1263                 }
1264                 newSize = newSizeMin + (newSize - newSizeMin) / 2;
1265             }
1266         }
1267
1268         /**
1269          * {@inheritDoc}
1270          * @since 1.6
1271          */

1272         public final synchronized void moveTo(double x, double y) {
1273             if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
1274                 doubleCoords[numCoords-2] = x;
1275                 doubleCoords[numCoords-1] = y;
1276             } else {
1277                 needRoom(false, 2);
1278                 pointTypes[numTypes++] = SEG_MOVETO;
1279                 doubleCoords[numCoords++] = x;
1280                 doubleCoords[numCoords++] = y;
1281             }
1282         }
1283
1284         /**
1285          * {@inheritDoc}
1286          * @since 1.6
1287          */

1288         public final synchronized void lineTo(double x, double y) {
1289             needRoom(true, 2);
1290             pointTypes[numTypes++] = SEG_LINETO;
1291             doubleCoords[numCoords++] = x;
1292             doubleCoords[numCoords++] = y;
1293         }
1294
1295         /**
1296          * {@inheritDoc}
1297          * @since 1.6
1298          */

1299         public final synchronized void quadTo(double x1, double y1,
1300                                               double x2, double y2)
1301         {
1302             needRoom(true, 4);
1303             pointTypes[numTypes++] = SEG_QUADTO;
1304             doubleCoords[numCoords++] = x1;
1305             doubleCoords[numCoords++] = y1;
1306             doubleCoords[numCoords++] = x2;
1307             doubleCoords[numCoords++] = y2;
1308         }
1309
1310         /**
1311          * {@inheritDoc}
1312          * @since 1.6
1313          */

1314         public final synchronized void curveTo(double x1, double y1,
1315                                                double x2, double y2,
1316                                                double x3, double y3)
1317         {
1318             needRoom(true, 6);
1319             pointTypes[numTypes++] = SEG_CUBICTO;
1320             doubleCoords[numCoords++] = x1;
1321             doubleCoords[numCoords++] = y1;
1322             doubleCoords[numCoords++] = x2;
1323             doubleCoords[numCoords++] = y2;
1324             doubleCoords[numCoords++] = x3;
1325             doubleCoords[numCoords++] = y3;
1326         }
1327
1328         int pointCrossings(double px, double py) {
1329             if (numTypes == 0) {
1330                 return 0;
1331             }
1332             double movx, movy, curx, cury, endx, endy;
1333             double coords[] = doubleCoords;
1334             curx = movx = coords[0];
1335             cury = movy = coords[1];
1336             int crossings = 0;
1337             int ci = 2;
1338             for (int i = 1; i < numTypes; i++) {
1339                 switch (pointTypes[i]) {
1340                 case PathIterator.SEG_MOVETO:
1341                     if (cury != movy) {
1342                         crossings +=
1343                             Curve.pointCrossingsForLine(px, py,
1344                                                         curx, cury,
1345                                                         movx, movy);
1346                     }
1347                     movx = curx = coords[ci++];
1348                     movy = cury = coords[ci++];
1349                     break;
1350                 case PathIterator.SEG_LINETO:
1351                     crossings +=
1352                         Curve.pointCrossingsForLine(px, py,
1353                                                     curx, cury,
1354                                                     endx = coords[ci++],
1355                                                     endy = coords[ci++]);
1356                     curx = endx;
1357                     cury = endy;
1358                     break;
1359                 case PathIterator.SEG_QUADTO:
1360                     crossings +=
1361                         Curve.pointCrossingsForQuad(px, py,
1362                                                     curx, cury,
1363                                                     coords[ci++],
1364                                                     coords[ci++],
1365                                                     endx = coords[ci++],
1366                                                     endy = coords[ci++],
1367                                                     0);
1368                     curx = endx;
1369                     cury = endy;
1370                     break;
1371             case PathIterator.SEG_CUBICTO:
1372                     crossings +=
1373                         Curve.pointCrossingsForCubic(px, py,
1374                                                      curx, cury,
1375                                                      coords[ci++],
1376                                                      coords[ci++],
1377                                                      coords[ci++],
1378                                                      coords[ci++],
1379                                                      endx = coords[ci++],
1380                                                      endy = coords[ci++],
1381                                                      0);
1382                     curx = endx;
1383                     cury = endy;
1384                     break;
1385                 case PathIterator.SEG_CLOSE:
1386                     if (cury != movy) {
1387                         crossings +=
1388                             Curve.pointCrossingsForLine(px, py,
1389                                                         curx, cury,
1390                                                         movx, movy);
1391                     }
1392                     curx = movx;
1393                     cury = movy;
1394                     break;
1395                 }
1396             }
1397             if (cury != movy) {
1398                 crossings +=
1399                     Curve.pointCrossingsForLine(px, py,
1400                                                 curx, cury,
1401                                                 movx, movy);
1402             }
1403             return crossings;
1404         }
1405
1406         int rectCrossings(double rxmin, double rymin,
1407                           double rxmax, double rymax)
1408         {
1409             if (numTypes == 0) {
1410                 return 0;
1411             }
1412             double coords[] = doubleCoords;
1413             double curx, cury, movx, movy, endx, endy;
1414             curx = movx = coords[0];
1415             cury = movy = coords[1];
1416             int crossings = 0;
1417             int ci = 2;
1418             for (int i = 1;
1419                  crossings != Curve.RECT_INTERSECTS && i < numTypes;
1420                  i++)
1421             {
1422                 switch (pointTypes[i]) {
1423                 case PathIterator.SEG_MOVETO:
1424                     if (curx != movx || cury != movy) {
1425                         crossings =
1426                             Curve.rectCrossingsForLine(crossings,
1427                                                        rxmin, rymin,
1428                                                        rxmax, rymax,
1429                                                        curx, cury,
1430                                                        movx, movy);
1431                     }
1432                     // Count should always be a multiple of 2 here.
1433                     // assert((crossings & 1) != 0);
1434                     movx = curx = coords[ci++];
1435                     movy = cury = coords[ci++];
1436                     break;
1437                 case PathIterator.SEG_LINETO:
1438                     endx = coords[ci++];
1439                     endy = coords[ci++];
1440                     crossings =
1441                         Curve.rectCrossingsForLine(crossings,
1442                                                    rxmin, rymin,
1443                                                    rxmax, rymax,
1444                                                    curx, cury,
1445                                                    endx, endy);
1446                     curx = endx;
1447                     cury = endy;
1448                     break;
1449                 case PathIterator.SEG_QUADTO:
1450                     crossings =
1451                         Curve.rectCrossingsForQuad(crossings,
1452                                                    rxmin, rymin,
1453                                                    rxmax, rymax,
1454                                                    curx, cury,
1455                                                    coords[ci++],
1456                                                    coords[ci++],
1457                                                    endx = coords[ci++],
1458                                                    endy = coords[ci++],
1459                                                    0);
1460                     curx = endx;
1461                     cury = endy;
1462                     break;
1463                 case PathIterator.SEG_CUBICTO:
1464                     crossings =
1465                         Curve.rectCrossingsForCubic(crossings,
1466                                                     rxmin, rymin,
1467                                                     rxmax, rymax,
1468                                                     curx, cury,
1469                                                     coords[ci++],
1470                                                     coords[ci++],
1471                                                     coords[ci++],
1472                                                     coords[ci++],
1473                                                     endx = coords[ci++],
1474                                                     endy = coords[ci++],
1475                                                     0);
1476                     curx = endx;
1477                     cury = endy;
1478                     break;
1479                 case PathIterator.SEG_CLOSE:
1480                     if (curx != movx || cury != movy) {
1481                         crossings =
1482                             Curve.rectCrossingsForLine(crossings,
1483                                                        rxmin, rymin,
1484                                                        rxmax, rymax,
1485                                                        curx, cury,
1486                                                        movx, movy);
1487                     }
1488                     curx = movx;
1489                     cury = movy;
1490                     // Count should always be a multiple of 2 here.
1491                     // assert((crossings & 1) != 0);
1492                     break;
1493                 }
1494             }
1495             if (crossings != Curve.RECT_INTERSECTS &&
1496                 (curx != movx || cury != movy))
1497             {
1498                 crossings =
1499                     Curve.rectCrossingsForLine(crossings,
1500                                                rxmin, rymin,
1501                                                rxmax, rymax,
1502                                                curx, cury,
1503                                                movx, movy);
1504             }
1505             // Count should always be a multiple of 2 here.
1506             // assert((crossings & 1) != 0);
1507             return crossings;
1508         }
1509
1510         /**
1511          * {@inheritDoc}
1512          * @since 1.6
1513          */

1514         public final void append(PathIterator pi, boolean connect) {
1515             double coords[] = new double[6];
1516             while (!pi.isDone()) {
1517                 switch (pi.currentSegment(coords)) {
1518                 case SEG_MOVETO:
1519                     if (!connect || numTypes < 1 || numCoords < 1) {
1520                         moveTo(coords[0], coords[1]);
1521                         break;
1522                     }
1523                     if (pointTypes[numTypes - 1] != SEG_CLOSE &&
1524                         doubleCoords[numCoords-2] == coords[0] &&
1525                         doubleCoords[numCoords-1] == coords[1])
1526                     {
1527                         // Collapse out initial moveto/lineto
1528                         break;
1529                     }
1530                     lineTo(coords[0], coords[1]);
1531                     break;
1532                 case SEG_LINETO:
1533                     lineTo(coords[0], coords[1]);
1534                     break;
1535                 case SEG_QUADTO:
1536                     quadTo(coords[0], coords[1],
1537                            coords[2], coords[3]);
1538                     break;
1539                 case SEG_CUBICTO:
1540                     curveTo(coords[0], coords[1],
1541                             coords[2], coords[3],
1542                             coords[4], coords[5]);
1543                     break;
1544                 case SEG_CLOSE:
1545                     closePath();
1546                     break;
1547                 }
1548                 pi.next();
1549                 connect = false;
1550             }
1551         }
1552
1553         /**
1554          * {@inheritDoc}
1555          * @since 1.6
1556          */

1557         public final void transform(AffineTransform at) {
1558             at.transform(doubleCoords, 0, doubleCoords, 0, numCoords / 2);
1559         }
1560
1561         /**
1562          * {@inheritDoc}
1563          * @since 1.6
1564          */

1565         public final synchronized Rectangle2D getBounds2D() {
1566             double x1, y1, x2, y2;
1567             int i = numCoords;
1568             if (i > 0) {
1569                 y1 = y2 = doubleCoords[--i];
1570                 x1 = x2 = doubleCoords[--i];
1571                 while (i > 0) {
1572                     double y = doubleCoords[--i];
1573                     double x = doubleCoords[--i];
1574                     if (x < x1) x1 = x;
1575                     if (y < y1) y1 = y;
1576                     if (x > x2) x2 = x;
1577                     if (y > y2) y2 = y;
1578                 }
1579             } else {
1580                 x1 = y1 = x2 = y2 = 0.0;
1581             }
1582             return new Rectangle2D.Double(x1, y1, x2 - x1, y2 - y1);
1583         }
1584
1585         /**
1586          * {@inheritDoc}
1587          * <p>
1588          * The iterator for this class is not multi-threaded safe,
1589          * which means that the {@code Path2D} class does not
1590          * guarantee that modifications to the geometry of this
1591          * {@code Path2D} object do not affect any iterations of
1592          * that geometry that are already in process.
1593          *
1594          * @param at an {@code AffineTransform}
1595          * @return a new {@code PathIterator} that iterates along the boundary
1596          *         of this {@code Shape} and provides access to the geometry
1597          *         of this {@code Shape}'s outline
1598          * @since 1.6
1599          */

1600         public final PathIterator getPathIterator(AffineTransform at) {
1601             if (at == null) {
1602                 return new CopyIterator(this);
1603             } else {
1604                 return new TxIterator(this, at);
1605             }
1606         }
1607
1608         /**
1609          * Creates a new object of the same class as this object.
1610          *
1611          * @return     a clone of this instance.
1612          * @exception  OutOfMemoryError    if there is not enough memory.
1613          * @see        java.lang.Cloneable
1614          * @since      1.6
1615          */

1616         public final Object clone() {
1617             // Note: It would be nice to have this return Path2D
1618             // but one of our subclasses (GeneralPath) needs to
1619             // offer "public Object clone()" for backwards
1620             // compatibility so we cannot restrict it further.
1621             // REMIND: Can we do both somehow?
1622             return new Path2D.Double(this);
1623         }
1624
1625         /*
1626          * JDK 1.6 serialVersionUID
1627          */

1628         private static final long serialVersionUID = 1826762518450014216L;
1629
1630         /**
1631          * Writes the default serializable fields to the
1632          * {@code ObjectOutputStream} followed by an explicit
1633          * serialization of the path segments stored in this
1634          * path.
1635          *
1636          * @serialData
1637          * <a id="Path2DSerialData"><!-- --></a>
1638          * <ol>
1639          * <li>The default serializable fields.
1640          * There are no default serializable fields as of 1.6.
1641          * <li>followed by
1642          * a byte indicating the storage type of the original object
1643          * as a hint (SERIAL_STORAGE_DBL_ARRAY)
1644          * <li>followed by
1645          * an integer indicating the number of path segments to follow (NP)
1646          * or -1 to indicate an unknown number of path segments follows
1647          * <li>followed by
1648          * an integer indicating the total number of coordinates to follow (NC)
1649          * or -1 to indicate an unknown number of coordinates follows
1650          * (NC should always be even since coordinates always appear in pairs
1651          *  representing an x,y pair)
1652          * <li>followed by
1653          * a byte indicating the winding rule
1654          * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
1655          *  {@link #WIND_NON_ZERO WIND_NON_ZERO})
1656          * <li>followed by
1657          * {@code NP} (or unlimited if {@code NP < 0}) sets of values consisting of
1658          * a single byte indicating a path segment type
1659          * followed by one or more pairs of float or double
1660          * values representing the coordinates of the path segment
1661          * <li>followed by
1662          * a byte indicating the end of the path (SERIAL_PATH_END).
1663          * </ol>
1664          * <p>
1665          * The following byte value constants are used in the serialized form
1666          * of {@code Path2D} objects:
1667          * <table class="striped">
1668          * <caption>Constants</caption>
1669          * <thead>
1670          * <tr>
1671          * <th>Constant Name</th>
1672          * <th>Byte Value</th>
1673          * <th>Followed by</th>
1674          * <th>Description</th>
1675          * </tr>
1676          * </thead>
1677          * <tbody>
1678          * <tr>
1679          * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
1680          * <td>0x30</td>
1681          * <td></td>
1682          * <td>A hint that the original {@code Path2D} object stored
1683          * the coordinates in a Java array of floats.</td>
1684          * </tr>
1685          * <tr>
1686          * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
1687          * <td>0x31</td>
1688          * <td></td>
1689          * <td>A hint that the original {@code Path2D} object stored
1690          * the coordinates in a Java array of doubles.</td>
1691          * </tr>
1692          * <tr>
1693          * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
1694          * <td>0x40</td>
1695          * <td>2 floats</td>
1696          * <td>A {@link #moveTo moveTo} path segment follows.</td>
1697          * </tr>
1698          * <tr>
1699          * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
1700          * <td>0x41</td>
1701          * <td>2 floats</td>
1702          * <td>A {@link #lineTo lineTo} path segment follows.</td>
1703          * </tr>
1704          * <tr>
1705          * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
1706          * <td>0x42</td>
1707          * <td>4 floats</td>
1708          * <td>A {@link #quadTo quadTo} path segment follows.</td>
1709          * </tr>
1710          * <tr>
1711          * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
1712          * <td>0x43</td>
1713          * <td>6 floats</td>
1714          * <td>A {@link #curveTo curveTo} path segment follows.</td>
1715          * </tr>
1716          * <tr>
1717          * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
1718          * <td>0x50</td>
1719          * <td>2 doubles</td>
1720          * <td>A {@link #moveTo moveTo} path segment follows.</td>
1721          * </tr>
1722          * <tr>
1723          * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
1724          * <td>0x51</td>
1725          * <td>2 doubles</td>
1726          * <td>A {@link #lineTo lineTo} path segment follows.</td>
1727          * </tr>
1728          * <tr>
1729          * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
1730          * <td>0x52</td>
1731          * <td>4 doubles</td>
1732          * <td>A {@link #curveTo curveTo} path segment follows.</td>
1733          * </tr>
1734          * <tr>
1735          * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
1736          * <td>0x53</td>
1737          * <td>6 doubles</td>
1738          * <td>A {@link #curveTo curveTo} path segment follows.</td>
1739          * </tr>
1740          * <tr>
1741          * <td>{@code SERIAL_SEG_CLOSE}</td>
1742          * <td>0x60</td>
1743          * <td></td>
1744          * <td>A {@link #closePath closePath} path segment.</td>
1745          * </tr>
1746          * <tr>
1747          * <td>{@code SERIAL_PATH_END}</td>
1748          * <td>0x61</td>
1749          * <td></td>
1750          * <td>There are no more path segments following.</td>
1751          * </tbody>
1752          * </table>
1753          *
1754          * @since 1.6
1755          */

1756         private void writeObject(java.io.ObjectOutputStream s)
1757             throws java.io.IOException
1758         {
1759             super.writeObject(s, true);
1760         }
1761
1762         /**
1763          * Reads the default serializable fields from the
1764          * {@code ObjectInputStream} followed by an explicit
1765          * serialization of the path segments stored in this
1766          * path.
1767          * <p>
1768          * There are no default serializable fields as of 1.6.
1769          * <p>
1770          * The serial data for this object is described in the
1771          * writeObject method.
1772          *
1773          * @since 1.6
1774          */

1775         private void readObject(java.io.ObjectInputStream s)
1776             throws java.lang.ClassNotFoundException, java.io.IOException
1777         {
1778             super.readObject(s, true);
1779         }
1780
1781         static class CopyIterator extends Path2D.Iterator {
1782             double doubleCoords[];
1783
1784             CopyIterator(Path2D.Double p2dd) {
1785                 super(p2dd);
1786                 this.doubleCoords = p2dd.doubleCoords;
1787             }
1788
1789             public int currentSegment(float[] coords) {
1790                 int type = path.pointTypes[typeIdx];
1791                 int numCoords = curvecoords[type];
1792                 if (numCoords > 0) {
1793                     for (int i = 0; i < numCoords; i++) {
1794                         coords[i] = (float) doubleCoords[pointIdx + i];
1795                     }
1796                 }
1797                 return type;
1798             }
1799
1800             public int currentSegment(double[] coords) {
1801                 int type = path.pointTypes[typeIdx];
1802                 int numCoords = curvecoords[type];
1803                 if (numCoords > 0) {
1804                     System.arraycopy(doubleCoords, pointIdx,
1805                                      coords, 0, numCoords);
1806                 }
1807                 return type;
1808             }
1809         }
1810
1811         static class TxIterator extends Path2D.Iterator {
1812             double doubleCoords[];
1813             AffineTransform affine;
1814
1815             TxIterator(Path2D.Double p2dd, AffineTransform at) {
1816                 super(p2dd);
1817                 this.doubleCoords = p2dd.doubleCoords;
1818                 this.affine = at;
1819             }
1820
1821             public int currentSegment(float[] coords) {
1822                 int type = path.pointTypes[typeIdx];
1823                 int numCoords = curvecoords[type];
1824                 if (numCoords > 0) {
1825                     affine.transform(doubleCoords, pointIdx,
1826                                      coords, 0, numCoords / 2);
1827                 }
1828                 return type;
1829             }
1830
1831             public int currentSegment(double[] coords) {
1832                 int type = path.pointTypes[typeIdx];
1833                 int numCoords = curvecoords[type];
1834                 if (numCoords > 0) {
1835                     affine.transform(doubleCoords, pointIdx,
1836                                      coords, 0, numCoords / 2);
1837                 }
1838                 return type;
1839             }
1840         }
1841     }
1842
1843     /**
1844      * Adds a point to the path by moving to the specified
1845      * coordinates specified in double precision.
1846      *
1847      * @param x the specified X coordinate
1848      * @param y the specified Y coordinate
1849      * @since 1.6
1850      */

1851     public abstract void moveTo(double x, double y);
1852
1853     /**
1854      * Adds a point to the path by drawing a straight line from the
1855      * current coordinates to the new specified coordinates
1856      * specified in double precision.
1857      *
1858      * @param x the specified X coordinate
1859      * @param y the specified Y coordinate
1860      * @since 1.6
1861      */

1862     public abstract void lineTo(double x, double y);
1863
1864     /**
1865      * Adds a curved segment, defined by two new points, to the path by
1866      * drawing a Quadratic curve that intersects both the current
1867      * coordinates and the specified coordinates {@code (x2,y2)},
1868      * using the specified point {@code (x1,y1)} as a quadratic
1869      * parametric control point.
1870      * All coordinates are specified in double precision.
1871      *
1872      * @param x1 the X coordinate of the quadratic control point
1873      * @param y1 the Y coordinate of the quadratic control point
1874      * @param x2 the X coordinate of the final end point
1875      * @param y2 the Y coordinate of the final end point
1876      * @since 1.6
1877      */

1878     public abstract void quadTo(double x1, double y1,
1879                                 double x2, double y2);
1880
1881     /**
1882      * Adds a curved segment, defined by three new points, to the path by
1883      * drawing a B&eacute;zier curve that intersects both the current
1884      * coordinates and the specified coordinates {@code (x3,y3)},
1885      * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
1886      * B&eacute;zier control points.
1887      * All coordinates are specified in double precision.
1888      *
1889      * @param x1 the X coordinate of the first B&eacute;zier control point
1890      * @param y1 the Y coordinate of the first B&eacute;zier control point
1891      * @param x2 the X coordinate of the second B&eacute;zier control point
1892      * @param y2 the Y coordinate of the second B&eacute;zier control point
1893      * @param x3 the X coordinate of the final end point
1894      * @param y3 the Y coordinate of the final end point
1895      * @since 1.6
1896      */

1897     public abstract void curveTo(double x1, double y1,
1898                                  double x2, double y2,
1899                                  double x3, double y3);
1900
1901     /**
1902      * Closes the current subpath by drawing a straight line back to
1903      * the coordinates of the last {@code moveTo}.  If the path is already
1904      * closed then this method has no effect.
1905      *
1906      * @since 1.6
1907      */

1908     public final synchronized void closePath() {
1909         if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) {
1910             needRoom(true, 0);
1911             pointTypes[numTypes++] = SEG_CLOSE;
1912         }
1913     }
1914
1915     /**
1916      * Appends the geometry of the specified {@code Shape} object to the
1917      * path, possibly connecting the new geometry to the existing path
1918      * segments with a line segment.
1919      * If the {@code connect} parameter is {@code true} and the
1920      * path is not empty then any initial {@code moveTo} in the
1921      * geometry of the appended {@code Shape}
1922      * is turned into a {@code lineTo} segment.
1923      * If the destination coordinates of such a connecting {@code lineTo}
1924      * segment match the ending coordinates of a currently open
1925      * subpath then the segment is omitted as superfluous.
1926      * The winding rule of the specified {@code Shape} is ignored
1927      * and the appended geometry is governed by the winding
1928      * rule specified for this path.
1929      *
1930      * @param s the {@code Shape} whose geometry is appended
1931      *          to this path
1932      * @param connect a boolean to control whether or not to turn an initial
1933      *                {@code moveTo} segment into a {@code lineTo} segment
1934      *                to connect the new geometry to the existing path
1935      * @since 1.6
1936      */

1937     public final void append(Shape s, boolean connect) {
1938         append(s.getPathIterator(null), connect);
1939     }
1940
1941     /**
1942      * Appends the geometry of the specified
1943      * {@link PathIterator} object
1944      * to the path, possibly connecting the new geometry to the existing
1945      * path segments with a line segment.
1946      * If the {@code connect} parameter is {@code true} and the
1947      * path is not empty then any initial {@code moveTo} in the
1948      * geometry of the appended {@code Shape} is turned into a
1949      * {@code lineTo} segment.
1950      * If the destination coordinates of such a connecting {@code lineTo}
1951      * segment match the ending coordinates of a currently open
1952      * subpath then the segment is omitted as superfluous.
1953      * The winding rule of the specified {@code Shape} is ignored
1954      * and the appended geometry is governed by the winding
1955      * rule specified for this path.
1956      *
1957      * @param pi the {@code PathIterator} whose geometry is appended to
1958      *           this path
1959      * @param connect a boolean to control whether or not to turn an initial
1960      *                {@code moveTo} segment into a {@code lineTo} segment
1961      *                to connect the new geometry to the existing path
1962      * @since 1.6
1963      */

1964     public abstract void append(PathIterator pi, boolean connect);
1965
1966     /**
1967      * Returns the fill style winding rule.
1968      *
1969      * @return an integer representing the current winding rule.
1970      * @see #WIND_EVEN_ODD
1971      * @see #WIND_NON_ZERO
1972      * @see #setWindingRule
1973      * @since 1.6
1974      */

1975     public final synchronized int getWindingRule() {
1976         return windingRule;
1977     }
1978
1979     /**
1980      * Sets the winding rule for this path to the specified value.
1981      *
1982      * @param rule an integer representing the specified
1983      *             winding rule
1984      * @exception IllegalArgumentException if
1985      *          {@code rule} is not either
1986      *          {@link #WIND_EVEN_ODD} or
1987      *          {@link #WIND_NON_ZERO}
1988      * @see #getWindingRule
1989      * @since 1.6
1990      */

1991     public final void setWindingRule(int rule) {
1992         if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
1993             throw new IllegalArgumentException("winding rule must be "+
1994                                                "WIND_EVEN_ODD or "+
1995                                                "WIND_NON_ZERO");
1996         }
1997         windingRule = rule;
1998     }
1999
2000     /**
2001      * Returns the coordinates most recently added to the end of the path
2002      * as a {@link Point2D} object.
2003      *
2004      * @return a {@code Point2D} object containing the ending coordinates of
2005      *         the path or {@code nullif there are no points in the path.
2006      * @since 1.6
2007      */

2008     public final synchronized Point2D getCurrentPoint() {
2009         int index = numCoords;
2010         if (numTypes < 1 || index < 1) {
2011             return null;
2012         }
2013         if (pointTypes[numTypes - 1] == SEG_CLOSE) {
2014         loop:
2015             for (int i = numTypes - 2; i > 0; i--) {
2016                 switch (pointTypes[i]) {
2017                 case SEG_MOVETO:
2018                     break loop;
2019                 case SEG_LINETO:
2020                     index -= 2;
2021                     break;
2022                 case SEG_QUADTO:
2023                     index -= 4;
2024                     break;
2025                 case SEG_CUBICTO:
2026                     index -= 6;
2027                     break;
2028                 case SEG_CLOSE:
2029                     break;
2030                 }
2031             }
2032         }
2033         return getPoint(index - 2);
2034     }
2035
2036     /**
2037      * Resets the path to empty.  The append position is set back to the
2038      * beginning of the path and all coordinates and point types are
2039      * forgotten.
2040      *
2041      * @since 1.6
2042      */

2043     public final synchronized void reset() {
2044         numTypes = numCoords = 0;
2045     }
2046
2047     /**
2048      * Transforms the geometry of this path using the specified
2049      * {@link AffineTransform}.
2050      * The geometry is transformed in place, which permanently changes the
2051      * boundary defined by this object.
2052      *
2053      * @param at the {@code AffineTransform} used to transform the area
2054      * @since 1.6
2055      */

2056     public abstract void transform(AffineTransform at);
2057
2058     /**
2059      * Returns a new {@code Shape} representing a transformed version
2060      * of this {@code Path2D}.
2061      * Note that the exact type and coordinate precision of the return
2062      * value is not specified for this method.
2063      * The method will return a Shape that contains no less precision
2064      * for the transformed geometry than this {@code Path2D} currently
2065      * maintains, but it may contain no more precision either.
2066      * If the tradeoff of precision vs. storage size in the result is
2067      * important then the convenience constructors in the
2068      * {@link Path2D.Float#Float(Shape, AffineTransform) Path2D.Float}
2069      * and
2070      * {@link Path2D.Double#Double(Shape, AffineTransform) Path2D.Double}
2071      * subclasses should be used to make the choice explicit.
2072      *
2073      * @param at the {@code AffineTransform} used to transform a
2074      *           new {@code Shape}.
2075      * @return a new {@code Shape}, transformed with the specified
2076      *         {@code AffineTransform}.
2077      * @since 1.6
2078      */

2079     public final synchronized Shape createTransformedShape(AffineTransform at) {
2080         Path2D p2d = (Path2D) clone();
2081         if (at != null) {
2082             p2d.transform(at);
2083         }
2084         return p2d;
2085     }
2086
2087     /**
2088      * {@inheritDoc}
2089      * @since 1.6
2090      */

2091     public final Rectangle getBounds() {
2092         return getBounds2D().getBounds();
2093     }
2094
2095     /**
2096      * Tests if the specified coordinates are inside the closed
2097      * boundary of the specified {@link PathIterator}.
2098      * <p>
2099      * This method provides a basic facility for implementors of
2100      * the {@link Shape} interface to implement support for the
2101      * {@link Shape#contains(doubledouble)} method.
2102      *
2103      * @param pi the specified {@code PathIterator}
2104      * @param x the specified X coordinate
2105      * @param y the specified Y coordinate
2106      * @return {@code trueif the specified coordinates are inside the
2107      *         specified {@code PathIterator}; {@code false} otherwise
2108      * @since 1.6
2109      */

2110     public static boolean contains(PathIterator pi, double x, double y) {
2111         if (x * 0.0 + y * 0.0 == 0.0) {
2112             /* N * 0.0 is 0.0 only if N is finite.
2113              * Here we know that both x and y are finite.
2114              */

2115             int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 1);
2116             int cross = Curve.pointCrossingsForPath(pi, x, y);
2117             return ((cross & mask) != 0);
2118         } else {
2119             /* Either x or y was infinite or NaN.
2120              * A NaN always produces a negative response to any test
2121              * and Infinity values cannot be "inside" any path so
2122              * they should return false as well.
2123              */

2124             return false;
2125         }
2126     }
2127
2128     /**
2129      * Tests if the specified {@link Point2D} is inside the closed
2130      * boundary of the specified {@link PathIterator}.
2131      * <p>
2132      * This method provides a basic facility for implementors of
2133      * the {@link Shape} interface to implement support for the
2134      * {@link Shape#contains(Point2D)} method.
2135      *
2136      * @param pi the specified {@code PathIterator}
2137      * @param p the specified {@code Point2D}
2138      * @return {@code trueif the specified coordinates are inside the
2139      *         specified {@code PathIterator}; {@code false} otherwise
2140      * @since 1.6
2141      */

2142     public static boolean contains(PathIterator pi, Point2D p) {
2143         return contains(pi, p.getX(), p.getY());
2144     }
2145
2146     /**
2147      * {@inheritDoc}
2148      * @since 1.6
2149      */

2150     public final boolean contains(double x, double y) {
2151         if (x * 0.0 + y * 0.0 == 0.0) {
2152             /* N * 0.0 is 0.0 only if N is finite.
2153              * Here we know that both x and y are finite.
2154              */

2155             if (numTypes < 2) {
2156                 return false;
2157             }
2158             int mask = (windingRule == WIND_NON_ZERO ? -1 : 1);
2159             return ((pointCrossings(x, y) & mask) != 0);
2160         } else {
2161             /* Either x or y was infinite or NaN.
2162              * A NaN always produces a negative response to any test
2163              * and Infinity values cannot be "inside" any path so
2164              * they should return false as well.
2165              */

2166             return false;
2167         }
2168     }
2169
2170     /**
2171      * {@inheritDoc}
2172      * @since 1.6
2173      */

2174     public final boolean contains(Point2D p) {
2175         return contains(p.getX(), p.getY());
2176     }
2177
2178     /**
2179      * Tests if the specified rectangular area is entirely inside the
2180      * closed boundary of the specified {@link PathIterator}.
2181      * <p>
2182      * This method provides a basic facility for implementors of
2183      * the {@link Shape} interface to implement support for the
2184      * {@link Shape#contains(doubledoubledoubledouble)} method.
2185      * <p>
2186      * This method object may conservatively return false in
2187      * cases where the specified rectangular area intersects a
2188      * segment of the path, but that segment does not represent a
2189      * boundary between the interior and exterior of the path.
2190      * Such segments could lie entirely within the interior of the
2191      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2192      * winding rule or if the segments are retraced in the reverse
2193      * direction such that the two sets of segments cancel each
2194      * other out without any exterior area falling between them.
2195      * To determine whether segments represent true boundaries of
2196      * the interior of the path would require extensive calculations
2197      * involving all of the segments of the path and the winding
2198      * rule and are thus beyond the scope of this implementation.
2199      *
2200      * @param pi the specified {@code PathIterator}
2201      * @param x the specified X coordinate
2202      * @param y the specified Y coordinate
2203      * @param w the width of the specified rectangular area
2204      * @param h the height of the specified rectangular area
2205      * @return {@code trueif the specified {@code PathIterator} contains
2206      *         the specified rectangular area; {@code false} otherwise.
2207      * @since 1.6
2208      */

2209     public static boolean contains(PathIterator pi,
2210                                    double x, double y, double w, double h)
2211     {
2212         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2213             /* [xy]+[wh] is NaN if any of those values are NaN,
2214              * or if adding the two together would produce NaN
2215              * by virtue of adding opposing Infinte values.
2216              * Since we need to add them below, their sum must
2217              * not be NaN.
2218              * We return false because NaN always produces a
2219              * negative response to tests
2220              */

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

2260     public static boolean contains(PathIterator pi, Rectangle2D r) {
2261         return contains(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2262     }
2263
2264     /**
2265      * {@inheritDoc}
2266      * <p>
2267      * This method object may conservatively return false in
2268      * cases where the specified rectangular area intersects a
2269      * segment of the path, but that segment does not represent a
2270      * boundary between the interior and exterior of the path.
2271      * Such segments could lie entirely within the interior of the
2272      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2273      * winding rule or if the segments are retraced in the reverse
2274      * direction such that the two sets of segments cancel each
2275      * other out without any exterior area falling between them.
2276      * To determine whether segments represent true boundaries of
2277      * the interior of the path would require extensive calculations
2278      * involving all of the segments of the path and the winding
2279      * rule and are thus beyond the scope of this implementation.
2280      *
2281      * @since 1.6
2282      */

2283     public final boolean contains(double x, double y, double w, double h) {
2284         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2285             /* [xy]+[wh] is NaN if any of those values are NaN,
2286              * or if adding the two together would produce NaN
2287              * by virtue of adding opposing Infinte values.
2288              * Since we need to add them below, their sum must
2289              * not be NaN.
2290              * We return false because NaN always produces a
2291              * negative response to tests
2292              */

2293             return false;
2294         }
2295         if (w <= 0 || h <= 0) {
2296             return false;
2297         }
2298         int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2299         int crossings = rectCrossings(x, y, x+w, y+h);
2300         return (crossings != Curve.RECT_INTERSECTS &&
2301                 (crossings & mask) != 0);
2302     }
2303
2304     /**
2305      * {@inheritDoc}
2306      * <p>
2307      * This method object may conservatively return false in
2308      * cases where the specified rectangular area intersects a
2309      * segment of the path, but that segment does not represent a
2310      * boundary between the interior and exterior of the path.
2311      * Such segments could lie entirely within the interior of the
2312      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2313      * winding rule or if the segments are retraced in the reverse
2314      * direction such that the two sets of segments cancel each
2315      * other out without any exterior area falling between them.
2316      * To determine whether segments represent true boundaries of
2317      * the interior of the path would require extensive calculations
2318      * involving all of the segments of the path and the winding
2319      * rule and are thus beyond the scope of this implementation.
2320      *
2321      * @since 1.6
2322      */

2323     public final boolean contains(Rectangle2D r) {
2324         return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2325     }
2326
2327     /**
2328      * Tests if the interior of the specified {@link PathIterator}
2329      * intersects the interior of a specified set of rectangular
2330      * coordinates.
2331      * <p>
2332      * This method provides a basic facility for implementors of
2333      * the {@link Shape} interface to implement support for the
2334      * {@link Shape#intersects(doubledoubledoubledouble)} method.
2335      * <p>
2336      * This method object may conservatively return true in
2337      * cases where the specified rectangular area intersects a
2338      * segment of the path, but that segment does not represent a
2339      * boundary between the interior and exterior of the path.
2340      * Such a case may occur if some set of segments of the
2341      * path are retraced in the reverse direction such that the
2342      * two sets of segments cancel each other out without any
2343      * interior area between them.
2344      * To determine whether segments represent true boundaries of
2345      * the interior of the path would require extensive calculations
2346      * involving all of the segments of the path and the winding
2347      * rule and are thus beyond the scope of this implementation.
2348      *
2349      * @param pi the specified {@code PathIterator}
2350      * @param x the specified X coordinate
2351      * @param y the specified Y coordinate
2352      * @param w the width of the specified rectangular coordinates
2353      * @param h the height of the specified rectangular coordinates
2354      * @return {@code trueif the specified {@code PathIterator} and
2355      *         the interior of the specified set of rectangular
2356      *         coordinates intersect each other; {@code false} otherwise.
2357      * @since 1.6
2358      */

2359     public static boolean intersects(PathIterator pi,
2360                                      double x, double y, double w, double h)
2361     {
2362         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2363             /* [xy]+[wh] is NaN if any of those values are NaN,
2364              * or if adding the two together would produce NaN
2365              * by virtue of adding opposing Infinte values.
2366              * Since we need to add them below, their sum must
2367              * not be NaN.
2368              * We return false because NaN always produces a
2369              * negative response to tests
2370              */

2371             return false;
2372         }
2373         if (w <= 0 || h <= 0) {
2374             return false;
2375         }
2376         int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2377         int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2378         return (crossings == Curve.RECT_INTERSECTS ||
2379                 (crossings & mask) != 0);
2380     }
2381
2382     /**
2383      * Tests if the interior of the specified {@link PathIterator}
2384      * intersects the interior of a specified {@link Rectangle2D}.
2385      * <p>
2386      * This method provides a basic facility for implementors of
2387      * the {@link Shape} interface to implement support for the
2388      * {@link Shape#intersects(Rectangle2D)} method.
2389      * <p>
2390      * This method object may conservatively return true in
2391      * cases where the specified rectangular area intersects a
2392      * segment of the path, but that segment does not represent a
2393      * boundary between the interior and exterior of the path.
2394      * Such a case may occur if some set of segments of the
2395      * path are retraced in the reverse direction such that the
2396      * two sets of segments cancel each other out without any
2397      * interior area between them.
2398      * To determine whether segments represent true boundaries of
2399      * the interior of the path would require extensive calculations
2400      * involving all of the segments of the path and the winding
2401      * rule and are thus beyond the scope of this implementation.
2402      *
2403      * @param pi the specified {@code PathIterator}
2404      * @param r the specified {@code Rectangle2D}
2405      * @return {@code trueif the specified {@code PathIterator} and
2406      *         the interior of the specified {@code Rectangle2D}
2407      *         intersect each other; {@code false} otherwise.
2408      * @since 1.6
2409      */

2410     public static boolean intersects(PathIterator pi, Rectangle2D r) {
2411         return intersects(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2412     }
2413
2414     /**
2415      * {@inheritDoc}
2416      * <p>
2417      * This method object may conservatively return true in
2418      * cases where the specified rectangular area intersects a
2419      * segment of the path, but that segment does not represent a
2420      * boundary between the interior and exterior of the path.
2421      * Such a case may occur if some set of segments of the
2422      * path are retraced in the reverse direction such that the
2423      * two sets of segments cancel each other out without any
2424      * interior area between them.
2425      * To determine whether segments represent true boundaries of
2426      * the interior of the path would require extensive calculations
2427      * involving all of the segments of the path and the winding
2428      * rule and are thus beyond the scope of this implementation.
2429      *
2430      * @since 1.6
2431      */

2432     public final boolean intersects(double x, double y, double w, double h) {
2433         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2434             /* [xy]+[wh] is NaN if any of those values are NaN,
2435              * or if adding the two together would produce NaN
2436              * by virtue of adding opposing Infinte values.
2437              * Since we need to add them below, their sum must
2438              * not be NaN.
2439              * We return false because NaN always produces a
2440              * negative response to tests
2441              */

2442             return false;
2443         }
2444         if (w <= 0 || h <= 0) {
2445             return false;
2446         }
2447         int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2448         int crossings = rectCrossings(x, y, x+w, y+h);
2449         return (crossings == Curve.RECT_INTERSECTS ||
2450                 (crossings & mask) != 0);
2451     }
2452
2453     /**
2454      * {@inheritDoc}
2455      * <p>
2456      * This method object may conservatively return true in
2457      * cases where the specified rectangular area intersects a
2458      * segment of the path, but that segment does not represent a
2459      * boundary between the interior and exterior of the path.
2460      * Such a case may occur if some set of segments of the
2461      * path are retraced in the reverse direction such that the
2462      * two sets of segments cancel each other out without any
2463      * interior area between them.
2464      * To determine whether segments represent true boundaries of
2465      * the interior of the path would require extensive calculations
2466      * involving all of the segments of the path and the winding
2467      * rule and are thus beyond the scope of this implementation.
2468      *
2469      * @since 1.6
2470      */

2471     public final boolean intersects(Rectangle2D r) {
2472         return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2473     }
2474
2475     /**
2476      * {@inheritDoc}
2477      * <p>
2478      * The iterator for this class is not multi-threaded safe,
2479      * which means that this {@code Path2D} class does not
2480      * guarantee that modifications to the geometry of this
2481      * {@code Path2D} object do not affect any iterations of
2482      * that geometry that are already in process.
2483      *
2484      * @since 1.6
2485      */

2486     public final PathIterator getPathIterator(AffineTransform at,
2487                                               double flatness)
2488     {
2489         return new FlatteningPathIterator(getPathIterator(at), flatness);
2490     }
2491
2492     /**
2493      * Creates a new object of the same class as this object.
2494      *
2495      * @return     a clone of this instance.
2496      * @exception  OutOfMemoryError            if there is not enough memory.
2497      * @see        java.lang.Cloneable
2498      * @since      1.6
2499      */

2500     public abstract Object clone();
2501         // Note: It would be nice to have this return Path2D
2502         // but one of our subclasses (GeneralPath) needs to
2503         // offer "public Object clone()" for backwards
2504         // compatibility so we cannot restrict it further.
2505         // REMIND: Can we do both somehow?
2506
2507     /**
2508      * Trims the capacity of this Path2D instance to its current
2509      * size. An application can use this operation to minimize the
2510      * storage of a path.
2511      *
2512      * @since 10
2513      */

2514     public abstract void trimToSize();
2515
2516     /*
2517      * Support fields and methods for serializing the subclasses.
2518      */

2519     private static final byte SERIAL_STORAGE_FLT_ARRAY = 0x30;
2520     private static final byte SERIAL_STORAGE_DBL_ARRAY = 0x31;
2521
2522     private static final byte SERIAL_SEG_FLT_MOVETO    = 0x40;
2523     private static final byte SERIAL_SEG_FLT_LINETO    = 0x41;
2524     private static final byte SERIAL_SEG_FLT_QUADTO    = 0x42;
2525     private static final byte SERIAL_SEG_FLT_CUBICTO   = 0x43;
2526
2527     private static final byte SERIAL_SEG_DBL_MOVETO    = 0x50;
2528     private static final byte SERIAL_SEG_DBL_LINETO    = 0x51;
2529     private static final byte SERIAL_SEG_DBL_QUADTO    = 0x52;
2530     private static final byte SERIAL_SEG_DBL_CUBICTO   = 0x53;
2531
2532     private static final byte SERIAL_SEG_CLOSE         = 0x60;
2533     private static final byte SERIAL_PATH_END          = 0x61;
2534
2535     final void writeObject(java.io.ObjectOutputStream s, boolean isdbl)
2536         throws java.io.IOException
2537     {
2538         s.defaultWriteObject();
2539
2540         float fCoords[];
2541         double dCoords[];
2542
2543         if (isdbl) {
2544             dCoords = ((Path2D.Double) this).doubleCoords;
2545             fCoords = null;
2546         } else {
2547             fCoords = ((Path2D.Float) this).floatCoords;
2548             dCoords = null;
2549         }
2550
2551         int numTypes = this.numTypes;
2552
2553         s.writeByte(isdbl
2554                     ? SERIAL_STORAGE_DBL_ARRAY
2555                     : SERIAL_STORAGE_FLT_ARRAY);
2556         s.writeInt(numTypes);
2557         s.writeInt(numCoords);
2558         s.writeByte((byte) windingRule);
2559
2560         int cindex = 0;
2561         for (int i = 0; i < numTypes; i++) {
2562             int npoints;
2563             byte serialtype;
2564             switch (pointTypes[i]) {
2565             case SEG_MOVETO:
2566                 npoints = 1;
2567                 serialtype = (isdbl
2568                               ? SERIAL_SEG_DBL_MOVETO
2569                               : SERIAL_SEG_FLT_MOVETO);
2570                 break;
2571             case SEG_LINETO:
2572                 npoints = 1;
2573                 serialtype = (isdbl
2574                               ? SERIAL_SEG_DBL_LINETO
2575                               : SERIAL_SEG_FLT_LINETO);
2576                 break;
2577             case SEG_QUADTO:
2578                 npoints = 2;
2579                 serialtype = (isdbl
2580                               ? SERIAL_SEG_DBL_QUADTO
2581                               : SERIAL_SEG_FLT_QUADTO);
2582                 break;
2583             case SEG_CUBICTO:
2584                 npoints = 3;
2585                 serialtype = (isdbl
2586                               ? SERIAL_SEG_DBL_CUBICTO
2587                               : SERIAL_SEG_FLT_CUBICTO);
2588                 break;
2589             case SEG_CLOSE:
2590                 npoints = 0;
2591                 serialtype = SERIAL_SEG_CLOSE;
2592                 break;
2593
2594             default:
2595                 // Should never happen
2596                 throw new InternalError("unrecognized path type");
2597             }
2598             s.writeByte(serialtype);
2599             while (--npoints >= 0) {
2600                 if (isdbl) {
2601                     s.writeDouble(dCoords[cindex++]);
2602                     s.writeDouble(dCoords[cindex++]);
2603                 } else {
2604                     s.writeFloat(fCoords[cindex++]);
2605                     s.writeFloat(fCoords[cindex++]);
2606                 }
2607             }
2608         }
2609         s.writeByte(SERIAL_PATH_END);
2610     }
2611
2612     final void readObject(java.io.ObjectInputStream s, boolean storedbl)
2613         throws java.lang.ClassNotFoundException, java.io.IOException
2614     {
2615         s.defaultReadObject();
2616
2617         // The subclass calls this method with the storage type that
2618         // they want us to use (storedbl) so we ignore the storage
2619         // method hint from the stream.
2620         s.readByte();
2621         int nT = s.readInt();
2622         int nC = s.readInt();
2623         try {
2624             setWindingRule(s.readByte());
2625         } catch (IllegalArgumentException iae) {
2626             throw new java.io.InvalidObjectException(iae.getMessage());
2627         }
2628
2629         // Accept the size from the stream only if it is less than INIT_SIZE
2630         // otherwise the size will be based on the real data in the stream
2631         pointTypes = new byte[(nT < 0 || nT > INIT_SIZE) ? INIT_SIZE : nT];
2632         final int initX2 = INIT_SIZE * 2;
2633         if (nC < 0 || nC > initX2) {
2634             nC = initX2;
2635         }
2636         if (storedbl) {
2637             ((Path2D.Double) this).doubleCoords = new double[nC];
2638         } else {
2639             ((Path2D.Float) this).floatCoords = new float[nC];
2640         }
2641
2642     PATHDONE:
2643         for (int i = 0; nT < 0 || i < nT; i++) {
2644             boolean isdbl;
2645             int npoints;
2646             byte segtype;
2647
2648             byte serialtype = s.readByte();
2649             switch (serialtype) {
2650             case SERIAL_SEG_FLT_MOVETO:
2651                 isdbl = false;
2652                 npoints = 1;
2653                 segtype = SEG_MOVETO;
2654                 break;
2655             case SERIAL_SEG_FLT_LINETO:
2656                 isdbl = false;
2657                 npoints = 1;
2658                 segtype = SEG_LINETO;
2659                 break;
2660             case SERIAL_SEG_FLT_QUADTO:
2661                 isdbl = false;
2662                 npoints = 2;
2663                 segtype = SEG_QUADTO;
2664                 break;
2665             case SERIAL_SEG_FLT_CUBICTO:
2666                 isdbl = false;
2667                 npoints = 3;
2668                 segtype = SEG_CUBICTO;
2669                 break;
2670
2671             case SERIAL_SEG_DBL_MOVETO:
2672                 isdbl = true;
2673                 npoints = 1;
2674                 segtype = SEG_MOVETO;
2675                 break;
2676             case SERIAL_SEG_DBL_LINETO:
2677                 isdbl = true;
2678                 npoints = 1;
2679                 segtype = SEG_LINETO;
2680                 break;
2681             case SERIAL_SEG_DBL_QUADTO:
2682                 isdbl = true;
2683                 npoints = 2;
2684                 segtype = SEG_QUADTO;
2685                 break;
2686             case SERIAL_SEG_DBL_CUBICTO:
2687                 isdbl = true;
2688                 npoints = 3;
2689                 segtype = SEG_CUBICTO;
2690                 break;
2691
2692             case SERIAL_SEG_CLOSE:
2693                 isdbl = false;
2694                 npoints = 0;
2695                 segtype = SEG_CLOSE;
2696                 break;
2697
2698             case SERIAL_PATH_END:
2699                 if (nT < 0) {
2700                     break PATHDONE;
2701                 }
2702                 throw new StreamCorruptedException("unexpected PATH_END");
2703
2704             default:
2705                 throw new StreamCorruptedException("unrecognized path type");
2706             }
2707             needRoom(segtype != SEG_MOVETO, npoints * 2);
2708             if (isdbl) {
2709                 while (--npoints >= 0) {
2710                     append(s.readDouble(), s.readDouble());
2711                 }
2712             } else {
2713                 while (--npoints >= 0) {
2714                     append(s.readFloat(), s.readFloat());
2715                 }
2716             }
2717             pointTypes[numTypes++] = segtype;
2718         }
2719         if (nT >= 0 && s.readByte() != SERIAL_PATH_END) {
2720             throw new StreamCorruptedException("missing PATH_END");
2721         }
2722     }
2723
2724     abstract static class Iterator implements PathIterator {
2725         int typeIdx;
2726         int pointIdx;
2727         Path2D path;
2728
2729         static final int curvecoords[] = {2, 2, 4, 6, 0};
2730
2731         Iterator(Path2D path) {
2732             this.path = path;
2733         }
2734
2735         public int getWindingRule() {
2736             return path.getWindingRule();
2737         }
2738
2739         public boolean isDone() {
2740             return (typeIdx >= path.numTypes);
2741         }
2742
2743         public void next() {
2744             int type = path.pointTypes[typeIdx++];
2745             pointIdx += curvecoords[type];
2746         }
2747     }
2748 }
2749