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
26package java.awt.geom;
27
28import java.awt.Shape;
29import java.awt.Rectangle;
30import sun.awt.geom.Curve;
31import java.io.Serializable;
32import java.io.StreamCorruptedException;
33import java.util.Arrays;
34
35/**
36 * The {@code Path2D} class provides a simple, yet flexible
37 * shape which represents an arbitrary geometric path.
38 * It can fully represent any path which can be iterated by the
39 * {@link PathIterator} interface including all of its segment
40 * types and winding rules and it implements all of the
41 * basic hit testing methods of the {@link Shape} interface.
42 * <p>
43 * Use {@link Path2D.Float} when dealing with data that can be represented
44 * and used with floating point precision.  Use {@link Path2D.Double}
45 * for data that requires the accuracy or range of double precision.
46 * <p>
47 * {@code Path2D} provides exactly those facilities required for
48 * basic construction and management of a geometric path and
49 * implementation of the above interfaces with little added
50 * interpretation.
51 * If it is useful to manipulate the interiors of closed
52 * geometric shapes beyond simple hit testing then the
53 * {@link Area} class provides additional capabilities
54 * specifically targeted at closed figures.
55 * While both classes nominally implement the {@code Shape}
56 * interface, they differ in purpose and together they provide
57 * two useful views of a geometric shape where {@code Path2D}
58 * deals primarily with a trajectory formed by path segments
59 * and {@code Area} deals more with interpretation and manipulation
60 * of enclosed regions of 2D geometric space.
61 * <p>
62 * The {@link PathIterator} interface has more detailed descriptions
63 * of the types of segments that make up a path and the winding rules
64 * that control how to determine which regions are inside or outside
65 * the path.
66 *
67 * @author Jim Graham
68 * @since 1.6
69 */
70public abstract class Path2D implements Shape, Cloneable {
71    /**
72     * An even-odd winding rule for determining the interior of
73     * a path.
74     *
75     * @see PathIterator#WIND_EVEN_ODD
76     * @since 1.6
77     */
78    public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
79
80    /**
81     * A non-zero winding rule for determining the interior of a
82     * path.
83     *
84     * @see PathIterator#WIND_NON_ZERO
85     * @since 1.6
86     */
87    public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
88
89    // For code simplicity, copy these constants to our namespace
90    // and cast them to byte constants for easy storage.
91    private static final byte SEG_MOVETO  = (byte) PathIterator.SEG_MOVETO;
92    private static final byte SEG_LINETO  = (byte) PathIterator.SEG_LINETO;
93    private static final byte SEG_QUADTO  = (byte) PathIterator.SEG_QUADTO;
94    private static final byte SEG_CUBICTO = (byte) PathIterator.SEG_CUBICTO;
95    private static final byte SEG_CLOSE   = (byte) PathIterator.SEG_CLOSE;
96
97    transient byte[] pointTypes;
98    transient int numTypes;
99    transient int numCoords;
100    transient int windingRule;
101
102    static final int INIT_SIZE = 20;
103    static final int EXPAND_MAX = 500;
104    static final int EXPAND_MAX_COORDS = EXPAND_MAX * 2;
105    static final int EXPAND_MIN = 10; // ensure > 6 (cubics)
106
107    /**
108     * Constructs a new empty {@code Path2D} object.
109     * It is assumed that the package sibling subclass that is
110     * defaulting to this constructor will fill in all values.
111     *
112     * @since 1.6
113     */
114    /* private protected */
115    Path2D() {
116    }
117
118    /**
119     * Constructs a new {@code Path2D} object from the given
120     * specified initial values.
121     * This method is only intended for internal use and should
122     * not be made public if the other constructors for this class
123     * are ever exposed.
124     *
125     * @param rule the winding rule
126     * @param initialTypes the size to make the initial array to
127     *                     store the path segment types
128     * @since 1.6
129     */
130    /* private protected */
131    Path2D(int rule, int initialTypes) {
132        setWindingRule(rule);
133        this.pointTypes = new byte[initialTypes];
134    }
135
136    abstract float[] cloneCoordsFloat(AffineTransform at);
137    abstract double[] cloneCoordsDouble(AffineTransform at);
138    abstract void append(float x, float y);
139    abstract void append(double x, double y);
140    abstract Point2D getPoint(int coordindex);
141    abstract void needRoom(boolean needMove, int newCoords);
142    abstract int pointCrossings(double px, double py);
143    abstract int rectCrossings(double rxmin, double rymin,
144                               double rxmax, double rymax);
145
146    static byte[] expandPointTypes(byte[] oldPointTypes, int needed) {
147        final int oldSize = oldPointTypes.length;
148        final int newSizeMin = oldSize + needed;
149        if (newSizeMin < oldSize) {
150            // hard overflow failure - we can't even accommodate
151            // new items without overflowing
152            throw new ArrayIndexOutOfBoundsException(
153                          "pointTypes exceeds maximum capacity !");
154        }
155        // growth algorithm computation
156        int grow = oldSize;
157        if (grow > EXPAND_MAX) {
158            grow = Math.max(EXPAND_MAX, oldSize >> 3); // 1/8th min
159        } else if (grow < EXPAND_MIN) {
160            grow = EXPAND_MIN;
161        }
162        assert grow > 0;
163
164        int newSize = oldSize + grow;
165        if (newSize < newSizeMin) {
166            // overflow in growth algorithm computation
167            newSize = Integer.MAX_VALUE;
168        }
169        while (true) {
170            try {
171                // try allocating the larger array
172                return Arrays.copyOf(oldPointTypes, newSize);
173            } catch (OutOfMemoryError oome) {
174                if (newSize == newSizeMin) {
175                    throw oome;
176                }
177            }
178            newSize = newSizeMin + (newSize - newSizeMin) / 2;
179        }
180    }
181
182    /**
183     * The {@code Float} class defines a geometric path with
184     * coordinates stored in single precision floating point.
185     *
186     * @since 1.6
187     */
188    public static class Float extends Path2D implements Serializable {
189        transient float floatCoords[];
190
191        /**
192         * Constructs a new empty single precision {@code Path2D} object
193         * with a default winding rule of {@link #WIND_NON_ZERO}.
194         *
195         * @since 1.6
196         */
197        public Float() {
198            this(WIND_NON_ZERO, INIT_SIZE);
199        }
200
201        /**
202         * Constructs a new empty single precision {@code Path2D} object
203         * with the specified winding rule to control operations that
204         * require the interior of the path to be defined.
205         *
206         * @param rule the winding rule
207         * @see #WIND_EVEN_ODD
208         * @see #WIND_NON_ZERO
209         * @since 1.6
210         */
211        public Float(int rule) {
212            this(rule, INIT_SIZE);
213        }
214
215        /**
216         * Constructs a new empty single precision {@code Path2D} object
217         * with the specified winding rule and the specified initial
218         * capacity to store path segments.
219         * This number is an initial guess as to how many path segments
220         * will be added to the path, but the storage is expanded as
221         * needed to store whatever path segments are added.
222         *
223         * @param rule the winding rule
224         * @param initialCapacity the estimate for the number of path segments
225         *                        in the path
226         * @see #WIND_EVEN_ODD
227         * @see #WIND_NON_ZERO
228         * @since 1.6
229         */
230        public Float(int rule, int initialCapacity) {
231            super(rule, initialCapacity);
232            floatCoords = new float[initialCapacity * 2];
233        }
234
235        /**
236         * Constructs a new single precision {@code Path2D} object
237         * from an arbitrary {@link Shape} object.
238         * All of the initial geometry and the winding rule for this path are
239         * taken from the specified {@code Shape} object.
240         *
241         * @param s the specified {@code Shape} object
242         * @since 1.6
243         */
244        public Float(Shape s) {
245            this(s, null);
246        }
247
248        /**
249         * Constructs a new single precision {@code Path2D} object
250         * from an arbitrary {@link Shape} object, transformed by an
251         * {@link AffineTransform} object.
252         * All of the initial geometry and the winding rule for this path are
253         * taken from the specified {@code Shape} object and transformed
254         * by the specified {@code AffineTransform} object.
255         *
256         * @param s the specified {@code Shape} object
257         * @param at the specified {@code AffineTransform} object
258         * @since 1.6
259         */
260        public Float(Shape s, AffineTransform at) {
261            if (s instanceof Path2D) {
262                Path2D p2d = (Path2D) s;
263                setWindingRule(p2d.windingRule);
264                this.numTypes = p2d.numTypes;
265                // trim arrays:
266                this.pointTypes = Arrays.copyOf(p2d.pointTypes, p2d.numTypes);
267                this.numCoords = p2d.numCoords;
268                this.floatCoords = p2d.cloneCoordsFloat(at);
269            } else {
270                PathIterator pi = s.getPathIterator(at);
271                setWindingRule(pi.getWindingRule());
272                this.pointTypes = new byte[INIT_SIZE];
273                this.floatCoords = new float[INIT_SIZE * 2];
274                append(pi, false);
275            }
276        }
277
278        @Override
279        float[] cloneCoordsFloat(AffineTransform at) {
280            // trim arrays:
281            float ret[];
282            if (at == null) {
283                ret = Arrays.copyOf(floatCoords, numCoords);
284            } else {
285                ret = new float[numCoords];
286                at.transform(floatCoords, 0, ret, 0, numCoords / 2);
287            }
288            return ret;
289        }
290
291        @Override
292        double[] cloneCoordsDouble(AffineTransform at) {
293            // trim arrays:
294            double ret[] = new double[numCoords];
295            if (at == null) {
296                for (int i = 0; i < numCoords; i++) {
297                    ret[i] = floatCoords[i];
298                }
299            } else {
300                at.transform(floatCoords, 0, ret, 0, numCoords / 2);
301            }
302            return ret;
303        }
304
305        void append(float x, float y) {
306            floatCoords[numCoords++] = x;
307            floatCoords[numCoords++] = y;
308        }
309
310        void append(double x, double y) {
311            floatCoords[numCoords++] = (float) x;
312            floatCoords[numCoords++] = (float) y;
313        }
314
315        Point2D getPoint(int coordindex) {
316            return new Point2D.Float(floatCoords[coordindex],
317                                     floatCoords[coordindex+1]);
318        }
319
320        @Override
321        void needRoom(boolean needMove, int newCoords) {
322            if ((numTypes == 0) && needMove) {
323                throw new IllegalPathStateException("missing initial moveto "+
324                                                    "in path definition");
325            }
326            if (numTypes >= pointTypes.length) {
327                pointTypes = expandPointTypes(pointTypes, 1);
328            }
329            if (numCoords > (floatCoords.length - newCoords)) {
330                floatCoords = expandCoords(floatCoords, newCoords);
331            }
332        }
333
334        static float[] expandCoords(float[] oldCoords, int needed) {
335            final int oldSize = oldCoords.length;
336            final int newSizeMin = oldSize + needed;
337            if (newSizeMin < oldSize) {
338                // hard overflow failure - we can't even accommodate
339                // new items without overflowing
340                throw new ArrayIndexOutOfBoundsException(
341                              "coords exceeds maximum capacity !");
342            }
343            // growth algorithm computation
344            int grow = oldSize;
345            if (grow > EXPAND_MAX_COORDS) {
346                grow = Math.max(EXPAND_MAX_COORDS, oldSize >> 3); // 1/8th min
347            } else if (grow < EXPAND_MIN) {
348                grow = EXPAND_MIN;
349            }
350            assert grow > needed;
351
352            int newSize = oldSize + grow;
353            if (newSize < newSizeMin) {
354                // overflow in growth algorithm computation
355                newSize = Integer.MAX_VALUE;
356            }
357            while (true) {
358                try {
359                    // try allocating the larger array
360                    return Arrays.copyOf(oldCoords, newSize);
361                } catch (OutOfMemoryError oome) {
362                    if (newSize == newSizeMin) {
363                        throw oome;
364                    }
365                }
366                newSize = newSizeMin + (newSize - newSizeMin) / 2;
367            }
368        }
369
370        /**
371         * {@inheritDoc}
372         * @since 1.6
373         */
374        public final synchronized void moveTo(double x, double y) {
375            if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
376                floatCoords[numCoords-2] = (float) x;
377                floatCoords[numCoords-1] = (float) y;
378            } else {
379                needRoom(false, 2);
380                pointTypes[numTypes++] = SEG_MOVETO;
381                floatCoords[numCoords++] = (float) x;
382                floatCoords[numCoords++] = (float) y;
383            }
384        }
385
386        /**
387         * Adds a point to the path by moving to the specified
388         * coordinates specified in float precision.
389         * <p>
390         * This method provides a single precision variant of
391         * the double precision {@code moveTo()} method on the
392         * base {@code Path2D} class.
393         *
394         * @param x the specified X coordinate
395         * @param y the specified Y coordinate
396         * @see Path2D#moveTo
397         * @since 1.6
398         */
399        public final synchronized void moveTo(float x, float y) {
400            if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
401                floatCoords[numCoords-2] = x;
402                floatCoords[numCoords-1] = y;
403            } else {
404                needRoom(false, 2);
405                pointTypes[numTypes++] = SEG_MOVETO;
406                floatCoords[numCoords++] = x;
407                floatCoords[numCoords++] = y;
408            }
409        }
410
411        /**
412         * {@inheritDoc}
413         * @since 1.6
414         */
415        public final synchronized void lineTo(double x, double y) {
416            needRoom(true, 2);
417            pointTypes[numTypes++] = SEG_LINETO;
418            floatCoords[numCoords++] = (float) x;
419            floatCoords[numCoords++] = (float) y;
420        }
421
422        /**
423         * Adds a point to the path by drawing a straight line from the
424         * current coordinates to the new specified coordinates
425         * specified in float precision.
426         * <p>
427         * This method provides a single precision variant of
428         * the double precision {@code lineTo()} method on the
429         * base {@code Path2D} class.
430         *
431         * @param x the specified X coordinate
432         * @param y the specified Y coordinate
433         * @see Path2D#lineTo
434         * @since 1.6
435         */
436        public final synchronized void lineTo(float x, float y) {
437            needRoom(true, 2);
438            pointTypes[numTypes++] = SEG_LINETO;
439            floatCoords[numCoords++] = x;
440            floatCoords[numCoords++] = y;
441        }
442
443        /**
444         * {@inheritDoc}
445         * @since 1.6
446         */
447        public final synchronized void quadTo(double x1, double y1,
448                                              double x2, double y2)
449        {
450            needRoom(true, 4);
451            pointTypes[numTypes++] = SEG_QUADTO;
452            floatCoords[numCoords++] = (float) x1;
453            floatCoords[numCoords++] = (float) y1;
454            floatCoords[numCoords++] = (float) x2;
455            floatCoords[numCoords++] = (float) y2;
456        }
457
458        /**
459         * Adds a curved segment, defined by two new points, to the path by
460         * drawing a Quadratic curve that intersects both the current
461         * coordinates and the specified coordinates {@code (x2,y2)},
462         * using the specified point {@code (x1,y1)} as a quadratic
463         * parametric control point.
464         * All coordinates are specified in float precision.
465         * <p>
466         * This method provides a single precision variant of
467         * the double precision {@code quadTo()} method on the
468         * base {@code Path2D} class.
469         *
470         * @param x1 the X coordinate of the quadratic control point
471         * @param y1 the Y coordinate of the quadratic control point
472         * @param x2 the X coordinate of the final end point
473         * @param y2 the Y coordinate of the final end point
474         * @see Path2D#quadTo
475         * @since 1.6
476         */
477        public final synchronized void quadTo(float x1, float y1,
478                                              float x2, float y2)
479        {
480            needRoom(true, 4);
481            pointTypes[numTypes++] = SEG_QUADTO;
482            floatCoords[numCoords++] = x1;
483            floatCoords[numCoords++] = y1;
484            floatCoords[numCoords++] = x2;
485            floatCoords[numCoords++] = y2;
486        }
487
488        /**
489         * {@inheritDoc}
490         * @since 1.6
491         */
492        public final synchronized void curveTo(double x1, double y1,
493                                               double x2, double y2,
494                                               double x3, double y3)
495        {
496            needRoom(true, 6);
497            pointTypes[numTypes++] = SEG_CUBICTO;
498            floatCoords[numCoords++] = (float) x1;
499            floatCoords[numCoords++] = (float) y1;
500            floatCoords[numCoords++] = (float) x2;
501            floatCoords[numCoords++] = (float) y2;
502            floatCoords[numCoords++] = (float) x3;
503            floatCoords[numCoords++] = (float) y3;
504        }
505
506        /**
507         * Adds a curved segment, defined by three new points, to the path by
508         * drawing a B&eacute;zier curve that intersects both the current
509         * coordinates and the specified coordinates {@code (x3,y3)},
510         * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
511         * B&eacute;zier control points.
512         * All coordinates are specified in float precision.
513         * <p>
514         * This method provides a single precision variant of
515         * the double precision {@code curveTo()} method on the
516         * base {@code Path2D} class.
517         *
518         * @param x1 the X coordinate of the first B&eacute;zier control point
519         * @param y1 the Y coordinate of the first B&eacute;zier control point
520         * @param x2 the X coordinate of the second B&eacute;zier control point
521         * @param y2 the Y coordinate of the second B&eacute;zier control point
522         * @param x3 the X coordinate of the final end point
523         * @param y3 the Y coordinate of the final end point
524         * @see Path2D#curveTo
525         * @since 1.6
526         */
527        public final synchronized void curveTo(float x1, float y1,
528                                               float x2, float y2,
529                                               float x3, float y3)
530        {
531            needRoom(true, 6);
532            pointTypes[numTypes++] = SEG_CUBICTO;
533            floatCoords[numCoords++] = x1;
534            floatCoords[numCoords++] = y1;
535            floatCoords[numCoords++] = x2;
536            floatCoords[numCoords++] = y2;
537            floatCoords[numCoords++] = x3;
538            floatCoords[numCoords++] = y3;
539        }
540
541        int pointCrossings(double px, double py) {
542            if (numTypes == 0) {
543                return 0;
544            }
545            double movx, movy, curx, cury, endx, endy;
546            float coords[] = floatCoords;
547            curx = movx = coords[0];
548            cury = movy = coords[1];
549            int crossings = 0;
550            int ci = 2;
551            for (int i = 1; i < numTypes; i++) {
552                switch (pointTypes[i]) {
553                case PathIterator.SEG_MOVETO:
554                    if (cury != movy) {
555                        crossings +=
556                            Curve.pointCrossingsForLine(px, py,
557                                                        curx, cury,
558                                                        movx, movy);
559                    }
560                    movx = curx = coords[ci++];
561                    movy = cury = coords[ci++];
562                    break;
563                case PathIterator.SEG_LINETO:
564                    crossings +=
565                        Curve.pointCrossingsForLine(px, py,
566                                                    curx, cury,
567                                                    endx = coords[ci++],
568                                                    endy = coords[ci++]);
569                    curx = endx;
570                    cury = endy;
571                    break;
572                case PathIterator.SEG_QUADTO:
573                    crossings +=
574                        Curve.pointCrossingsForQuad(px, py,
575                                                    curx, cury,
576                                                    coords[ci++],
577                                                    coords[ci++],
578                                                    endx = coords[ci++],
579                                                    endy = coords[ci++],
580                                                    0);
581                    curx = endx;
582                    cury = endy;
583                    break;
584            case PathIterator.SEG_CUBICTO:
585                    crossings +=
586                        Curve.pointCrossingsForCubic(px, py,
587                                                     curx, cury,
588                                                     coords[ci++],
589                                                     coords[ci++],
590                                                     coords[ci++],
591                                                     coords[ci++],
592                                                     endx = coords[ci++],
593                                                     endy = coords[ci++],
594                                                     0);
595                    curx = endx;
596                    cury = endy;
597                    break;
598                case PathIterator.SEG_CLOSE:
599                    if (cury != movy) {
600                        crossings +=
601                            Curve.pointCrossingsForLine(px, py,
602                                                        curx, cury,
603                                                        movx, movy);
604                    }
605                    curx = movx;
606                    cury = movy;
607                    break;
608                }
609            }
610            if (cury != movy) {
611                crossings +=
612                    Curve.pointCrossingsForLine(px, py,
613                                                curx, cury,
614                                                movx, movy);
615            }
616            return crossings;
617        }
618
619        int rectCrossings(double rxmin, double rymin,
620                          double rxmax, double rymax)
621        {
622            if (numTypes == 0) {
623                return 0;
624            }
625            float coords[] = floatCoords;
626            double curx, cury, movx, movy, endx, endy;
627            curx = movx = coords[0];
628            cury = movy = coords[1];
629            int crossings = 0;
630            int ci = 2;
631            for (int i = 1;
632                 crossings != Curve.RECT_INTERSECTS && i < numTypes;
633                 i++)
634            {
635                switch (pointTypes[i]) {
636                case PathIterator.SEG_MOVETO:
637                    if (curx != movx || cury != movy) {
638                        crossings =
639                            Curve.rectCrossingsForLine(crossings,
640                                                       rxmin, rymin,
641                                                       rxmax, rymax,
642                                                       curx, cury,
643                                                       movx, movy);
644                    }
645                    // Count should always be a multiple of 2 here.
646                    // assert((crossings & 1) != 0);
647                    movx = curx = coords[ci++];
648                    movy = cury = coords[ci++];
649                    break;
650                case PathIterator.SEG_LINETO:
651                    crossings =
652                        Curve.rectCrossingsForLine(crossings,
653                                                   rxmin, rymin,
654                                                   rxmax, rymax,
655                                                   curx, cury,
656                                                   endx = coords[ci++],
657                                                   endy = coords[ci++]);
658                    curx = endx;
659                    cury = endy;
660                    break;
661                case PathIterator.SEG_QUADTO:
662                    crossings =
663                        Curve.rectCrossingsForQuad(crossings,
664                                                   rxmin, rymin,
665                                                   rxmax, rymax,
666                                                   curx, cury,
667                                                   coords[ci++],
668                                                   coords[ci++],
669                                                   endx = coords[ci++],
670                                                   endy = coords[ci++],
671                                                   0);
672                    curx = endx;
673                    cury = endy;
674                    break;
675                case PathIterator.SEG_CUBICTO:
676                    crossings =
677                        Curve.rectCrossingsForCubic(crossings,
678                                                    rxmin, rymin,
679                                                    rxmax, rymax,
680                                                    curx, cury,
681                                                    coords[ci++],
682                                                    coords[ci++],
683                                                    coords[ci++],
684                                                    coords[ci++],
685                                                    endx = coords[ci++],
686                                                    endy = coords[ci++],
687                                                    0);
688                    curx = endx;
689                    cury = endy;
690                    break;
691                case PathIterator.SEG_CLOSE:
692                    if (curx != movx || cury != movy) {
693                        crossings =
694                            Curve.rectCrossingsForLine(crossings,
695                                                       rxmin, rymin,
696                                                       rxmax, rymax,
697                                                       curx, cury,
698                                                       movx, movy);
699                    }
700                    curx = movx;
701                    cury = movy;
702                    // Count should always be a multiple of 2 here.
703                    // assert((crossings & 1) != 0);
704                    break;
705                }
706            }
707            if (crossings != Curve.RECT_INTERSECTS &&
708                (curx != movx || cury != movy))
709            {
710                crossings =
711                    Curve.rectCrossingsForLine(crossings,
712                                               rxmin, rymin,
713                                               rxmax, rymax,
714                                               curx, cury,
715                                               movx, movy);
716            }
717            // Count should always be a multiple of 2 here.
718            // assert((crossings & 1) != 0);
719            return crossings;
720        }
721
722        /**
723         * {@inheritDoc}
724         * @since 1.6
725         */
726        public final void append(PathIterator pi, boolean connect) {
727            float coords[] = new float[6];
728            while (!pi.isDone()) {
729                switch (pi.currentSegment(coords)) {
730                case SEG_MOVETO:
731                    if (!connect || numTypes < 1 || numCoords < 1) {
732                        moveTo(coords[0], coords[1]);
733                        break;
734                    }
735                    if (pointTypes[numTypes - 1] != SEG_CLOSE &&
736                        floatCoords[numCoords-2] == coords[0] &&
737                        floatCoords[numCoords-1] == coords[1])
738                    {
739                        // Collapse out initial moveto/lineto
740                        break;
741                    }
742                    lineTo(coords[0], coords[1]);
743                    break;
744                case SEG_LINETO:
745                    lineTo(coords[0], coords[1]);
746                    break;
747                case SEG_QUADTO:
748                    quadTo(coords[0], coords[1],
749                           coords[2], coords[3]);
750                    break;
751                case SEG_CUBICTO:
752                    curveTo(coords[0], coords[1],
753                            coords[2], coords[3],
754                            coords[4], coords[5]);
755                    break;
756                case SEG_CLOSE:
757                    closePath();
758                    break;
759                }
760                pi.next();
761                connect = false;
762            }
763        }
764
765        /**
766         * {@inheritDoc}
767         * @since 1.6
768         */
769        public final void transform(AffineTransform at) {
770            at.transform(floatCoords, 0, floatCoords, 0, numCoords / 2);
771        }
772
773        /**
774         * {@inheritDoc}
775         * @since 1.6
776         */
777        public final synchronized Rectangle2D getBounds2D() {
778            float x1, y1, x2, y2;
779            int i = numCoords;
780            if (i > 0) {
781                y1 = y2 = floatCoords[--i];
782                x1 = x2 = floatCoords[--i];
783                while (i > 0) {
784                    float y = floatCoords[--i];
785                    float x = floatCoords[--i];
786                    if (x < x1) x1 = x;
787                    if (y < y1) y1 = y;
788                    if (x > x2) x2 = x;
789                    if (y > y2) y2 = y;
790                }
791            } else {
792                x1 = y1 = x2 = y2 = 0.0f;
793            }
794            return new Rectangle2D.Float(x1, y1, x2 - x1, y2 - y1);
795        }
796
797        /**
798         * {@inheritDoc}
799         * <p>
800         * The iterator for this class is not multi-threaded safe,
801         * which means that the {@code Path2D} class does not
802         * guarantee that modifications to the geometry of this
803         * {@code Path2D} object do not affect any iterations of
804         * that geometry that are already in process.
805         *
806         * @since 1.6
807         */
808        public final PathIterator getPathIterator(AffineTransform at) {
809            if (at == null) {
810                return new CopyIterator(this);
811            } else {
812                return new TxIterator(this, at);
813            }
814        }
815
816        /**
817         * Creates a new object of the same class as this object.
818         *
819         * @return     a clone of this instance.
820         * @exception  OutOfMemoryError    if there is not enough memory.
821         * @see        java.lang.Cloneable
822         * @since      1.6
823         */
824        public final Object clone() {
825            // Note: It would be nice to have this return Path2D
826            // but one of our subclasses (GeneralPath) needs to
827            // offer "public Object clone()" for backwards
828            // compatibility so we cannot restrict it further.
829            // REMIND: Can we do both somehow?
830            if (this instanceof GeneralPath) {
831                return new GeneralPath(this);
832            } else {
833                return new Path2D.Float(this);
834            }
835        }
836
837        /*
838         * JDK 1.6 serialVersionUID
839         */
840        private static final long serialVersionUID = 6990832515060788886L;
841
842        /**
843         * Writes the default serializable fields to the
844         * {@code ObjectOutputStream} followed by an explicit
845         * serialization of the path segments stored in this
846         * path.
847         *
848         * @serialData
849         * <a id="Path2DSerialData"><!-- --></a>
850         * <ol>
851         * <li>The default serializable fields.
852         * There are no default serializable fields as of 1.6.
853         * <li>followed by
854         * a byte indicating the storage type of the original object
855         * as a hint (SERIAL_STORAGE_FLT_ARRAY)
856         * <li>followed by
857         * an integer indicating the number of path segments to follow (NP)
858         * or -1 to indicate an unknown number of path segments follows
859         * <li>followed by
860         * an integer indicating the total number of coordinates to follow (NC)
861         * or -1 to indicate an unknown number of coordinates follows
862         * (NC should always be even since coordinates always appear in pairs
863         *  representing an x,y pair)
864         * <li>followed by
865         * a byte indicating the winding rule
866         * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
867         *  {@link #WIND_NON_ZERO WIND_NON_ZERO})
868         * <li>followed by
869         * {@code NP} (or unlimited if {@code NP < 0}) sets of values consisting of
870         * a single byte indicating a path segment type
871         * followed by one or more pairs of float or double
872         * values representing the coordinates of the path segment
873         * <li>followed by
874         * a byte indicating the end of the path (SERIAL_PATH_END).
875         * </ol>
876         * <p>
877         * The following byte value constants are used in the serialized form
878         * of {@code Path2D} objects:
879         *
880         * <table class="striped">
881         * <caption>Constants</caption>
882         * <thead>
883         * <tr>
884         * <th>Constant Name</th>
885         * <th>Byte Value</th>
886         * <th>Followed by</th>
887         * <th>Description</th>
888         * </tr>
889         * </thead>
890         * <tbody>
891         * <tr>
892         * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
893         * <td>0x30</td>
894         * <td></td>
895         * <td>A hint that the original {@code Path2D} object stored
896         * the coordinates in a Java array of floats.</td>
897         * </tr>
898         * <tr>
899         * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
900         * <td>0x31</td>
901         * <td></td>
902         * <td>A hint that the original {@code Path2D} object stored
903         * the coordinates in a Java array of doubles.</td>
904         * </tr>
905         * <tr>
906         * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
907         * <td>0x40</td>
908         * <td>2 floats</td>
909         * <td>A {@link #moveTo moveTo} path segment follows.</td>
910         * </tr>
911         * <tr>
912         * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
913         * <td>0x41</td>
914         * <td>2 floats</td>
915         * <td>A {@link #lineTo lineTo} path segment follows.</td>
916         * </tr>
917         * <tr>
918         * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
919         * <td>0x42</td>
920         * <td>4 floats</td>
921         * <td>A {@link #quadTo quadTo} path segment follows.</td>
922         * </tr>
923         * <tr>
924         * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
925         * <td>0x43</td>
926         * <td>6 floats</td>
927         * <td>A {@link #curveTo curveTo} path segment follows.</td>
928         * </tr>
929         * <tr>
930         * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
931         * <td>0x50</td>
932         * <td>2 doubles</td>
933         * <td>A {@link #moveTo moveTo} path segment follows.</td>
934         * </tr>
935         * <tr>
936         * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
937         * <td>0x51</td>
938         * <td>2 doubles</td>
939         * <td>A {@link #lineTo lineTo} path segment follows.</td>
940         * </tr>
941         * <tr>
942         * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
943         * <td>0x52</td>
944         * <td>4 doubles</td>
945         * <td>A {@link #curveTo curveTo} path segment follows.</td>
946         * </tr>
947         * <tr>
948         * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
949         * <td>0x53</td>
950         * <td>6 doubles</td>
951         * <td>A {@link #curveTo curveTo} path segment follows.</td>
952         * </tr>
953         * <tr>
954         * <td>{@code SERIAL_SEG_CLOSE}</td>
955         * <td>0x60</td>
956         * <td></td>
957         * <td>A {@link #closePath closePath} path segment.</td>
958         * </tr>
959         * <tr>
960         * <td>{@code SERIAL_PATH_END}</td>
961         * <td>0x61</td>
962         * <td></td>
963         * <td>There are no more path segments following.</td>
964         * </tbody>
965         * </table>
966         *
967         * @since 1.6
968         */
969        private void writeObject(java.io.ObjectOutputStream s)
970            throws java.io.IOException
971        {
972            super.writeObject(s, false);
973        }
974
975        /**
976         * Reads the default serializable fields from the
977         * {@code ObjectInputStream} followed by an explicit
978         * serialization of the path segments stored in this
979         * path.
980         * <p>
981         * There are no default serializable fields as of 1.6.
982         * <p>
983         * The serial data for this object is described in the
984         * writeObject method.
985         *
986         * @since 1.6
987         */
988        private void readObject(java.io.ObjectInputStream s)
989            throws java.lang.ClassNotFoundException, java.io.IOException
990        {
991            super.readObject(s, false);
992        }
993
994        static class CopyIterator extends Path2D.Iterator {
995            float floatCoords[];
996
997            CopyIterator(Path2D.Float p2df) {
998                super(p2df);
999                this.floatCoords = p2df.floatCoords;
1000            }
1001
1002            public int currentSegment(float[] coords) {
1003                int type = path.pointTypes[typeIdx];
1004                int numCoords = curvecoords[type];
1005                if (numCoords > 0) {
1006                    System.arraycopy(floatCoords, pointIdx,
1007                                     coords, 0, numCoords);
1008                }
1009                return type;
1010            }
1011
1012            public int currentSegment(double[] coords) {
1013                int type = path.pointTypes[typeIdx];
1014                int numCoords = curvecoords[type];
1015                if (numCoords > 0) {
1016                    for (int i = 0; i < numCoords; i++) {
1017                        coords[i] = floatCoords[pointIdx + i];
1018                    }
1019                }
1020                return type;
1021            }
1022        }
1023
1024        static class TxIterator extends Path2D.Iterator {
1025            float floatCoords[];
1026            AffineTransform affine;
1027
1028            TxIterator(Path2D.Float p2df, AffineTransform at) {
1029                super(p2df);
1030                this.floatCoords = p2df.floatCoords;
1031                this.affine = at;
1032            }
1033
1034            public int currentSegment(float[] coords) {
1035                int type = path.pointTypes[typeIdx];
1036                int numCoords = curvecoords[type];
1037                if (numCoords > 0) {
1038                    affine.transform(floatCoords, pointIdx,
1039                                     coords, 0, numCoords / 2);
1040                }
1041                return type;
1042            }
1043
1044            public int currentSegment(double[] coords) {
1045                int type = path.pointTypes[typeIdx];
1046                int numCoords = curvecoords[type];
1047                if (numCoords > 0) {
1048                    affine.transform(floatCoords, pointIdx,
1049                                     coords, 0, numCoords / 2);
1050                }
1051                return type;
1052            }
1053        }
1054
1055    }
1056
1057    /**
1058     * The {@code Double} class defines a geometric path with
1059     * coordinates stored in double precision floating point.
1060     *
1061     * @since 1.6
1062     */
1063    public static class Double extends Path2D implements Serializable {
1064        transient double doubleCoords[];
1065
1066        /**
1067         * Constructs a new empty double precision {@code Path2D} object
1068         * with a default winding rule of {@link #WIND_NON_ZERO}.
1069         *
1070         * @since 1.6
1071         */
1072        public Double() {
1073            this(WIND_NON_ZERO, INIT_SIZE);
1074        }
1075
1076        /**
1077         * Constructs a new empty double precision {@code Path2D} object
1078         * with the specified winding rule to control operations that
1079         * require the interior of the path to be defined.
1080         *
1081         * @param rule the winding rule
1082         * @see #WIND_EVEN_ODD
1083         * @see #WIND_NON_ZERO
1084         * @since 1.6
1085         */
1086        public Double(int rule) {
1087            this(rule, INIT_SIZE);
1088        }
1089
1090        /**
1091         * Constructs a new empty double precision {@code Path2D} object
1092         * with the specified winding rule and the specified initial
1093         * capacity to store path segments.
1094         * This number is an initial guess as to how many path segments
1095         * are in the path, but the storage is expanded as needed to store
1096         * whatever path segments are added to this path.
1097         *
1098         * @param rule the winding rule
1099         * @param initialCapacity the estimate for the number of path segments
1100         *                        in the path
1101         * @see #WIND_EVEN_ODD
1102         * @see #WIND_NON_ZERO
1103         * @since 1.6
1104         */
1105        public Double(int rule, int initialCapacity) {
1106            super(rule, initialCapacity);
1107            doubleCoords = new double[initialCapacity * 2];
1108        }
1109
1110        /**
1111         * Constructs a new double precision {@code Path2D} object
1112         * from an arbitrary {@link Shape} object.
1113         * All of the initial geometry and the winding rule for this path are
1114         * taken from the specified {@code Shape} object.
1115         *
1116         * @param s the specified {@code Shape} object
1117         * @since 1.6
1118         */
1119        public Double(Shape s) {
1120            this(s, null);
1121        }
1122
1123        /**
1124         * Constructs a new double precision {@code Path2D} object
1125         * from an arbitrary {@link Shape} object, transformed by an
1126         * {@link AffineTransform} object.
1127         * All of the initial geometry and the winding rule for this path are
1128         * taken from the specified {@code Shape} object and transformed
1129         * by the specified {@code AffineTransform} object.
1130         *
1131         * @param s the specified {@code Shape} object
1132         * @param at the specified {@code AffineTransform} object
1133         * @since 1.6
1134         */
1135        public Double(Shape s, AffineTransform at) {
1136            if (s instanceof Path2D) {
1137                Path2D p2d = (Path2D) s;
1138                setWindingRule(p2d.windingRule);
1139                this.numTypes = p2d.numTypes;
1140                // trim arrays:
1141                this.pointTypes = Arrays.copyOf(p2d.pointTypes, p2d.numTypes);
1142                this.numCoords = p2d.numCoords;
1143                this.doubleCoords = p2d.cloneCoordsDouble(at);
1144            } else {
1145                PathIterator pi = s.getPathIterator(at);
1146                setWindingRule(pi.getWindingRule());
1147                this.pointTypes = new byte[INIT_SIZE];
1148                this.doubleCoords = new double[INIT_SIZE * 2];
1149                append(pi, false);
1150            }
1151        }
1152
1153        @Override
1154        float[] cloneCoordsFloat(AffineTransform at) {
1155            // trim arrays:
1156            float ret[] = new float[numCoords];
1157            if (at == null) {
1158                for (int i = 0; i < numCoords; i++) {
1159                    ret[i] = (float) doubleCoords[i];
1160                }
1161            } else {
1162                at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1163            }
1164            return ret;
1165        }
1166
1167        @Override
1168        double[] cloneCoordsDouble(AffineTransform at) {
1169            // trim arrays:
1170            double ret[];
1171            if (at == null) {
1172                ret = Arrays.copyOf(doubleCoords, numCoords);
1173            } else {
1174                ret = new double[numCoords];
1175                at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1176            }
1177            return ret;
1178        }
1179
1180        void append(float x, float y) {
1181            doubleCoords[numCoords++] = x;
1182            doubleCoords[numCoords++] = y;
1183        }
1184
1185        void append(double x, double y) {
1186            doubleCoords[numCoords++] = x;
1187            doubleCoords[numCoords++] = y;
1188        }
1189
1190        Point2D getPoint(int coordindex) {
1191            return new Point2D.Double(doubleCoords[coordindex],
1192                                      doubleCoords[coordindex+1]);
1193        }
1194
1195        @Override
1196        void needRoom(boolean needMove, int newCoords) {
1197            if ((numTypes == 0) && needMove) {
1198                throw new IllegalPathStateException("missing initial moveto "+
1199                                                    "in path definition");
1200            }
1201            if (numTypes >= pointTypes.length) {
1202                pointTypes = expandPointTypes(pointTypes, 1);
1203            }
1204            if (numCoords > (doubleCoords.length - newCoords)) {
1205                doubleCoords = expandCoords(doubleCoords, newCoords);
1206            }
1207        }
1208
1209        static double[] expandCoords(double[] oldCoords, int needed) {
1210            final int oldSize = oldCoords.length;
1211            final int newSizeMin = oldSize + needed;
1212            if (newSizeMin < oldSize) {
1213                // hard overflow failure - we can't even accommodate
1214                // new items without overflowing
1215                throw new ArrayIndexOutOfBoundsException(
1216                              "coords exceeds maximum capacity !");
1217            }
1218            // growth algorithm computation
1219            int grow = oldSize;
1220            if (grow > EXPAND_MAX_COORDS) {
1221                grow = Math.max(EXPAND_MAX_COORDS, oldSize >> 3); // 1/8th min
1222            } else if (grow < EXPAND_MIN) {
1223                grow = EXPAND_MIN;
1224            }
1225            assert grow > needed;
1226
1227            int newSize = oldSize + grow;
1228            if (newSize < newSizeMin) {
1229                // overflow in growth algorithm computation
1230                newSize = Integer.MAX_VALUE;
1231            }
1232            while (true) {
1233                try {
1234                    // try allocating the larger array
1235                    return Arrays.copyOf(oldCoords, newSize);
1236                } catch (OutOfMemoryError oome) {
1237                    if (newSize == newSizeMin) {
1238                        throw oome;
1239                    }
1240                }
1241                newSize = newSizeMin + (newSize - newSizeMin) / 2;
1242            }
1243        }
1244
1245        /**
1246         * {@inheritDoc}
1247         * @since 1.6
1248         */
1249        public final synchronized void moveTo(double x, double y) {
1250            if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
1251                doubleCoords[numCoords-2] = x;
1252                doubleCoords[numCoords-1] = y;
1253            } else {
1254                needRoom(false, 2);
1255                pointTypes[numTypes++] = SEG_MOVETO;
1256                doubleCoords[numCoords++] = x;
1257                doubleCoords[numCoords++] = y;
1258            }
1259        }
1260
1261        /**
1262         * {@inheritDoc}
1263         * @since 1.6
1264         */
1265        public final synchronized void lineTo(double x, double y) {
1266            needRoom(true, 2);
1267            pointTypes[numTypes++] = SEG_LINETO;
1268            doubleCoords[numCoords++] = x;
1269            doubleCoords[numCoords++] = y;
1270        }
1271
1272        /**
1273         * {@inheritDoc}
1274         * @since 1.6
1275         */
1276        public final synchronized void quadTo(double x1, double y1,
1277                                              double x2, double y2)
1278        {
1279            needRoom(true, 4);
1280            pointTypes[numTypes++] = SEG_QUADTO;
1281            doubleCoords[numCoords++] = x1;
1282            doubleCoords[numCoords++] = y1;
1283            doubleCoords[numCoords++] = x2;
1284            doubleCoords[numCoords++] = y2;
1285        }
1286
1287        /**
1288         * {@inheritDoc}
1289         * @since 1.6
1290         */
1291        public final synchronized void curveTo(double x1, double y1,
1292                                               double x2, double y2,
1293                                               double x3, double y3)
1294        {
1295            needRoom(true, 6);
1296            pointTypes[numTypes++] = SEG_CUBICTO;
1297            doubleCoords[numCoords++] = x1;
1298            doubleCoords[numCoords++] = y1;
1299            doubleCoords[numCoords++] = x2;
1300            doubleCoords[numCoords++] = y2;
1301            doubleCoords[numCoords++] = x3;
1302            doubleCoords[numCoords++] = y3;
1303        }
1304
1305        int pointCrossings(double px, double py) {
1306            if (numTypes == 0) {
1307                return 0;
1308            }
1309            double movx, movy, curx, cury, endx, endy;
1310            double coords[] = doubleCoords;
1311            curx = movx = coords[0];
1312            cury = movy = coords[1];
1313            int crossings = 0;
1314            int ci = 2;
1315            for (int i = 1; i < numTypes; i++) {
1316                switch (pointTypes[i]) {
1317                case PathIterator.SEG_MOVETO:
1318                    if (cury != movy) {
1319                        crossings +=
1320                            Curve.pointCrossingsForLine(px, py,
1321                                                        curx, cury,
1322                                                        movx, movy);
1323                    }
1324                    movx = curx = coords[ci++];
1325                    movy = cury = coords[ci++];
1326                    break;
1327                case PathIterator.SEG_LINETO:
1328                    crossings +=
1329                        Curve.pointCrossingsForLine(px, py,
1330                                                    curx, cury,
1331                                                    endx = coords[ci++],
1332                                                    endy = coords[ci++]);
1333                    curx = endx;
1334                    cury = endy;
1335                    break;
1336                case PathIterator.SEG_QUADTO:
1337                    crossings +=
1338                        Curve.pointCrossingsForQuad(px, py,
1339                                                    curx, cury,
1340                                                    coords[ci++],
1341                                                    coords[ci++],
1342                                                    endx = coords[ci++],
1343                                                    endy = coords[ci++],
1344                                                    0);
1345                    curx = endx;
1346                    cury = endy;
1347                    break;
1348            case PathIterator.SEG_CUBICTO:
1349                    crossings +=
1350                        Curve.pointCrossingsForCubic(px, py,
1351                                                     curx, cury,
1352                                                     coords[ci++],
1353                                                     coords[ci++],
1354                                                     coords[ci++],
1355                                                     coords[ci++],
1356                                                     endx = coords[ci++],
1357                                                     endy = coords[ci++],
1358                                                     0);
1359                    curx = endx;
1360                    cury = endy;
1361                    break;
1362                case PathIterator.SEG_CLOSE:
1363                    if (cury != movy) {
1364                        crossings +=
1365                            Curve.pointCrossingsForLine(px, py,
1366                                                        curx, cury,
1367                                                        movx, movy);
1368                    }
1369                    curx = movx;
1370                    cury = movy;
1371                    break;
1372                }
1373            }
1374            if (cury != movy) {
1375                crossings +=
1376                    Curve.pointCrossingsForLine(px, py,
1377                                                curx, cury,
1378                                                movx, movy);
1379            }
1380            return crossings;
1381        }
1382
1383        int rectCrossings(double rxmin, double rymin,
1384                          double rxmax, double rymax)
1385        {
1386            if (numTypes == 0) {
1387                return 0;
1388            }
1389            double coords[] = doubleCoords;
1390            double curx, cury, movx, movy, endx, endy;
1391            curx = movx = coords[0];
1392            cury = movy = coords[1];
1393            int crossings = 0;
1394            int ci = 2;
1395            for (int i = 1;
1396                 crossings != Curve.RECT_INTERSECTS && i < numTypes;
1397                 i++)
1398            {
1399                switch (pointTypes[i]) {
1400                case PathIterator.SEG_MOVETO:
1401                    if (curx != movx || cury != movy) {
1402                        crossings =
1403                            Curve.rectCrossingsForLine(crossings,
1404                                                       rxmin, rymin,
1405                                                       rxmax, rymax,
1406                                                       curx, cury,
1407                                                       movx, movy);
1408                    }
1409                    // Count should always be a multiple of 2 here.
1410                    // assert((crossings & 1) != 0);
1411                    movx = curx = coords[ci++];
1412                    movy = cury = coords[ci++];
1413                    break;
1414                case PathIterator.SEG_LINETO:
1415                    endx = coords[ci++];
1416                    endy = coords[ci++];
1417                    crossings =
1418                        Curve.rectCrossingsForLine(crossings,
1419                                                   rxmin, rymin,
1420                                                   rxmax, rymax,
1421                                                   curx, cury,
1422                                                   endx, endy);
1423                    curx = endx;
1424                    cury = endy;
1425                    break;
1426                case PathIterator.SEG_QUADTO:
1427                    crossings =
1428                        Curve.rectCrossingsForQuad(crossings,
1429                                                   rxmin, rymin,
1430                                                   rxmax, rymax,
1431                                                   curx, cury,
1432                                                   coords[ci++],
1433                                                   coords[ci++],
1434                                                   endx = coords[ci++],
1435                                                   endy = coords[ci++],
1436                                                   0);
1437                    curx = endx;
1438                    cury = endy;
1439                    break;
1440                case PathIterator.SEG_CUBICTO:
1441                    crossings =
1442                        Curve.rectCrossingsForCubic(crossings,
1443                                                    rxmin, rymin,
1444                                                    rxmax, rymax,
1445                                                    curx, cury,
1446                                                    coords[ci++],
1447                                                    coords[ci++],
1448                                                    coords[ci++],
1449                                                    coords[ci++],
1450                                                    endx = coords[ci++],
1451                                                    endy = coords[ci++],
1452                                                    0);
1453                    curx = endx;
1454                    cury = endy;
1455                    break;
1456                case PathIterator.SEG_CLOSE:
1457                    if (curx != movx || cury != movy) {
1458                        crossings =
1459                            Curve.rectCrossingsForLine(crossings,
1460                                                       rxmin, rymin,
1461                                                       rxmax, rymax,
1462                                                       curx, cury,
1463                                                       movx, movy);
1464                    }
1465                    curx = movx;
1466                    cury = movy;
1467                    // Count should always be a multiple of 2 here.
1468                    // assert((crossings & 1) != 0);
1469                    break;
1470                }
1471            }
1472            if (crossings != Curve.RECT_INTERSECTS &&
1473                (curx != movx || cury != movy))
1474            {
1475                crossings =
1476                    Curve.rectCrossingsForLine(crossings,
1477                                               rxmin, rymin,
1478                                               rxmax, rymax,
1479                                               curx, cury,
1480                                               movx, movy);
1481            }
1482            // Count should always be a multiple of 2 here.
1483            // assert((crossings & 1) != 0);
1484            return crossings;
1485        }
1486
1487        /**
1488         * {@inheritDoc}
1489         * @since 1.6
1490         */
1491        public final void append(PathIterator pi, boolean connect) {
1492            double coords[] = new double[6];
1493            while (!pi.isDone()) {
1494                switch (pi.currentSegment(coords)) {
1495                case SEG_MOVETO:
1496                    if (!connect || numTypes < 1 || numCoords < 1) {
1497                        moveTo(coords[0], coords[1]);
1498                        break;
1499                    }
1500                    if (pointTypes[numTypes - 1] != SEG_CLOSE &&
1501                        doubleCoords[numCoords-2] == coords[0] &&
1502                        doubleCoords[numCoords-1] == coords[1])
1503                    {
1504                        // Collapse out initial moveto/lineto
1505                        break;
1506                    }
1507                    lineTo(coords[0], coords[1]);
1508                    break;
1509                case SEG_LINETO:
1510                    lineTo(coords[0], coords[1]);
1511                    break;
1512                case SEG_QUADTO:
1513                    quadTo(coords[0], coords[1],
1514                           coords[2], coords[3]);
1515                    break;
1516                case SEG_CUBICTO:
1517                    curveTo(coords[0], coords[1],
1518                            coords[2], coords[3],
1519                            coords[4], coords[5]);
1520                    break;
1521                case SEG_CLOSE:
1522                    closePath();
1523                    break;
1524                }
1525                pi.next();
1526                connect = false;
1527            }
1528        }
1529
1530        /**
1531         * {@inheritDoc}
1532         * @since 1.6
1533         */
1534        public final void transform(AffineTransform at) {
1535            at.transform(doubleCoords, 0, doubleCoords, 0, numCoords / 2);
1536        }
1537
1538        /**
1539         * {@inheritDoc}
1540         * @since 1.6
1541         */
1542        public final synchronized Rectangle2D getBounds2D() {
1543            double x1, y1, x2, y2;
1544            int i = numCoords;
1545            if (i > 0) {
1546                y1 = y2 = doubleCoords[--i];
1547                x1 = x2 = doubleCoords[--i];
1548                while (i > 0) {
1549                    double y = doubleCoords[--i];
1550                    double x = doubleCoords[--i];
1551                    if (x < x1) x1 = x;
1552                    if (y < y1) y1 = y;
1553                    if (x > x2) x2 = x;
1554                    if (y > y2) y2 = y;
1555                }
1556            } else {
1557                x1 = y1 = x2 = y2 = 0.0;
1558            }
1559            return new Rectangle2D.Double(x1, y1, x2 - x1, y2 - y1);
1560        }
1561
1562        /**
1563         * {@inheritDoc}
1564         * <p>
1565         * The iterator for this class is not multi-threaded safe,
1566         * which means that the {@code Path2D} class does not
1567         * guarantee that modifications to the geometry of this
1568         * {@code Path2D} object do not affect any iterations of
1569         * that geometry that are already in process.
1570         *
1571         * @param at an {@code AffineTransform}
1572         * @return a new {@code PathIterator} that iterates along the boundary
1573         *         of this {@code Shape} and provides access to the geometry
1574         *         of this {@code Shape}'s outline
1575         * @since 1.6
1576         */
1577        public final PathIterator getPathIterator(AffineTransform at) {
1578            if (at == null) {
1579                return new CopyIterator(this);
1580            } else {
1581                return new TxIterator(this, at);
1582            }
1583        }
1584
1585        /**
1586         * Creates a new object of the same class as this object.
1587         *
1588         * @return     a clone of this instance.
1589         * @exception  OutOfMemoryError    if there is not enough memory.
1590         * @see        java.lang.Cloneable
1591         * @since      1.6
1592         */
1593        public final Object clone() {
1594            // Note: It would be nice to have this return Path2D
1595            // but one of our subclasses (GeneralPath) needs to
1596            // offer "public Object clone()" for backwards
1597            // compatibility so we cannot restrict it further.
1598            // REMIND: Can we do both somehow?
1599            return new Path2D.Double(this);
1600        }
1601
1602        /*
1603         * JDK 1.6 serialVersionUID
1604         */
1605        private static final long serialVersionUID = 1826762518450014216L;
1606
1607        /**
1608         * Writes the default serializable fields to the
1609         * {@code ObjectOutputStream} followed by an explicit
1610         * serialization of the path segments stored in this
1611         * path.
1612         *
1613         * @serialData
1614         * <a id="Path2DSerialData"><!-- --></a>
1615         * <ol>
1616         * <li>The default serializable fields.
1617         * There are no default serializable fields as of 1.6.
1618         * <li>followed by
1619         * a byte indicating the storage type of the original object
1620         * as a hint (SERIAL_STORAGE_DBL_ARRAY)
1621         * <li>followed by
1622         * an integer indicating the number of path segments to follow (NP)
1623         * or -1 to indicate an unknown number of path segments follows
1624         * <li>followed by
1625         * an integer indicating the total number of coordinates to follow (NC)
1626         * or -1 to indicate an unknown number of coordinates follows
1627         * (NC should always be even since coordinates always appear in pairs
1628         *  representing an x,y pair)
1629         * <li>followed by
1630         * a byte indicating the winding rule
1631         * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
1632         *  {@link #WIND_NON_ZERO WIND_NON_ZERO})
1633         * <li>followed by
1634         * {@code NP} (or unlimited if {@code NP < 0}) sets of values consisting of
1635         * a single byte indicating a path segment type
1636         * followed by one or more pairs of float or double
1637         * values representing the coordinates of the path segment
1638         * <li>followed by
1639         * a byte indicating the end of the path (SERIAL_PATH_END).
1640         * </ol>
1641         * <p>
1642         * The following byte value constants are used in the serialized form
1643         * of {@code Path2D} objects:
1644         * <table class="striped">
1645         * <caption>Constants</caption>
1646         * <thead>
1647         * <tr>
1648         * <th>Constant Name</th>
1649         * <th>Byte Value</th>
1650         * <th>Followed by</th>
1651         * <th>Description</th>
1652         * </tr>
1653         * </thead>
1654         * <tbody>
1655         * <tr>
1656         * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
1657         * <td>0x30</td>
1658         * <td></td>
1659         * <td>A hint that the original {@code Path2D} object stored
1660         * the coordinates in a Java array of floats.</td>
1661         * </tr>
1662         * <tr>
1663         * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
1664         * <td>0x31</td>
1665         * <td></td>
1666         * <td>A hint that the original {@code Path2D} object stored
1667         * the coordinates in a Java array of doubles.</td>
1668         * </tr>
1669         * <tr>
1670         * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
1671         * <td>0x40</td>
1672         * <td>2 floats</td>
1673         * <td>A {@link #moveTo moveTo} path segment follows.</td>
1674         * </tr>
1675         * <tr>
1676         * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
1677         * <td>0x41</td>
1678         * <td>2 floats</td>
1679         * <td>A {@link #lineTo lineTo} path segment follows.</td>
1680         * </tr>
1681         * <tr>
1682         * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
1683         * <td>0x42</td>
1684         * <td>4 floats</td>
1685         * <td>A {@link #quadTo quadTo} path segment follows.</td>
1686         * </tr>
1687         * <tr>
1688         * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
1689         * <td>0x43</td>
1690         * <td>6 floats</td>
1691         * <td>A {@link #curveTo curveTo} path segment follows.</td>
1692         * </tr>
1693         * <tr>
1694         * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
1695         * <td>0x50</td>
1696         * <td>2 doubles</td>
1697         * <td>A {@link #moveTo moveTo} path segment follows.</td>
1698         * </tr>
1699         * <tr>
1700         * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
1701         * <td>0x51</td>
1702         * <td>2 doubles</td>
1703         * <td>A {@link #lineTo lineTo} path segment follows.</td>
1704         * </tr>
1705         * <tr>
1706         * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
1707         * <td>0x52</td>
1708         * <td>4 doubles</td>
1709         * <td>A {@link #curveTo curveTo} path segment follows.</td>
1710         * </tr>
1711         * <tr>
1712         * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
1713         * <td>0x53</td>
1714         * <td>6 doubles</td>
1715         * <td>A {@link #curveTo curveTo} path segment follows.</td>
1716         * </tr>
1717         * <tr>
1718         * <td>{@code SERIAL_SEG_CLOSE}</td>
1719         * <td>0x60</td>
1720         * <td></td>
1721         * <td>A {@link #closePath closePath} path segment.</td>
1722         * </tr>
1723         * <tr>
1724         * <td>{@code SERIAL_PATH_END}</td>
1725         * <td>0x61</td>
1726         * <td></td>
1727         * <td>There are no more path segments following.</td>
1728         * </tbody>
1729         * </table>
1730         *
1731         * @since 1.6
1732         */
1733        private void writeObject(java.io.ObjectOutputStream s)
1734            throws java.io.IOException
1735        {
1736            super.writeObject(s, true);
1737        }
1738
1739        /**
1740         * Reads the default serializable fields from the
1741         * {@code ObjectInputStream} followed by an explicit
1742         * serialization of the path segments stored in this
1743         * path.
1744         * <p>
1745         * There are no default serializable fields as of 1.6.
1746         * <p>
1747         * The serial data for this object is described in the
1748         * writeObject method.
1749         *
1750         * @since 1.6
1751         */
1752        private void readObject(java.io.ObjectInputStream s)
1753            throws java.lang.ClassNotFoundException, java.io.IOException
1754        {
1755            super.readObject(s, true);
1756        }
1757
1758        static class CopyIterator extends Path2D.Iterator {
1759            double doubleCoords[];
1760
1761            CopyIterator(Path2D.Double p2dd) {
1762                super(p2dd);
1763                this.doubleCoords = p2dd.doubleCoords;
1764            }
1765
1766            public int currentSegment(float[] coords) {
1767                int type = path.pointTypes[typeIdx];
1768                int numCoords = curvecoords[type];
1769                if (numCoords > 0) {
1770                    for (int i = 0; i < numCoords; i++) {
1771                        coords[i] = (float) doubleCoords[pointIdx + i];
1772                    }
1773                }
1774                return type;
1775            }
1776
1777            public int currentSegment(double[] coords) {
1778                int type = path.pointTypes[typeIdx];
1779                int numCoords = curvecoords[type];
1780                if (numCoords > 0) {
1781                    System.arraycopy(doubleCoords, pointIdx,
1782                                     coords, 0, numCoords);
1783                }
1784                return type;
1785            }
1786        }
1787
1788        static class TxIterator extends Path2D.Iterator {
1789            double doubleCoords[];
1790            AffineTransform affine;
1791
1792            TxIterator(Path2D.Double p2dd, AffineTransform at) {
1793                super(p2dd);
1794                this.doubleCoords = p2dd.doubleCoords;
1795                this.affine = at;
1796            }
1797
1798            public int currentSegment(float[] coords) {
1799                int type = path.pointTypes[typeIdx];
1800                int numCoords = curvecoords[type];
1801                if (numCoords > 0) {
1802                    affine.transform(doubleCoords, pointIdx,
1803                                     coords, 0, numCoords / 2);
1804                }
1805                return type;
1806            }
1807
1808            public int currentSegment(double[] coords) {
1809                int type = path.pointTypes[typeIdx];
1810                int numCoords = curvecoords[type];
1811                if (numCoords > 0) {
1812                    affine.transform(doubleCoords, pointIdx,
1813                                     coords, 0, numCoords / 2);
1814                }
1815                return type;
1816            }
1817        }
1818    }
1819
1820    /**
1821     * Adds a point to the path by moving to the specified
1822     * coordinates specified in double precision.
1823     *
1824     * @param x the specified X coordinate
1825     * @param y the specified Y coordinate
1826     * @since 1.6
1827     */
1828    public abstract void moveTo(double x, double y);
1829
1830    /**
1831     * Adds a point to the path by drawing a straight line from the
1832     * current coordinates to the new specified coordinates
1833     * specified in double precision.
1834     *
1835     * @param x the specified X coordinate
1836     * @param y the specified Y coordinate
1837     * @since 1.6
1838     */
1839    public abstract void lineTo(double x, double y);
1840
1841    /**
1842     * Adds a curved segment, defined by two new points, to the path by
1843     * drawing a Quadratic curve that intersects both the current
1844     * coordinates and the specified coordinates {@code (x2,y2)},
1845     * using the specified point {@code (x1,y1)} as a quadratic
1846     * parametric control point.
1847     * All coordinates are specified in double precision.
1848     *
1849     * @param x1 the X coordinate of the quadratic control point
1850     * @param y1 the Y coordinate of the quadratic control point
1851     * @param x2 the X coordinate of the final end point
1852     * @param y2 the Y coordinate of the final end point
1853     * @since 1.6
1854     */
1855    public abstract void quadTo(double x1, double y1,
1856                                double x2, double y2);
1857
1858    /**
1859     * Adds a curved segment, defined by three new points, to the path by
1860     * drawing a B&eacute;zier curve that intersects both the current
1861     * coordinates and the specified coordinates {@code (x3,y3)},
1862     * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
1863     * B&eacute;zier control points.
1864     * All coordinates are specified in double precision.
1865     *
1866     * @param x1 the X coordinate of the first B&eacute;zier control point
1867     * @param y1 the Y coordinate of the first B&eacute;zier control point
1868     * @param x2 the X coordinate of the second B&eacute;zier control point
1869     * @param y2 the Y coordinate of the second B&eacute;zier control point
1870     * @param x3 the X coordinate of the final end point
1871     * @param y3 the Y coordinate of the final end point
1872     * @since 1.6
1873     */
1874    public abstract void curveTo(double x1, double y1,
1875                                 double x2, double y2,
1876                                 double x3, double y3);
1877
1878    /**
1879     * Closes the current subpath by drawing a straight line back to
1880     * the coordinates of the last {@code moveTo}.  If the path is already
1881     * closed then this method has no effect.
1882     *
1883     * @since 1.6
1884     */
1885    public final synchronized void closePath() {
1886        if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) {
1887            needRoom(true, 0);
1888            pointTypes[numTypes++] = SEG_CLOSE;
1889        }
1890    }
1891
1892    /**
1893     * Appends the geometry of the specified {@code Shape} object to the
1894     * path, possibly connecting the new geometry to the existing path
1895     * segments with a line segment.
1896     * If the {@code connect} parameter is {@code true} and the
1897     * path is not empty then any initial {@code moveTo} in the
1898     * geometry of the appended {@code Shape}
1899     * is turned into a {@code lineTo} segment.
1900     * If the destination coordinates of such a connecting {@code lineTo}
1901     * segment match the ending coordinates of a currently open
1902     * subpath then the segment is omitted as superfluous.
1903     * The winding rule of the specified {@code Shape} is ignored
1904     * and the appended geometry is governed by the winding
1905     * rule specified for this path.
1906     *
1907     * @param s the {@code Shape} whose geometry is appended
1908     *          to this path
1909     * @param connect a boolean to control whether or not to turn an initial
1910     *                {@code moveTo} segment into a {@code lineTo} segment
1911     *                to connect the new geometry to the existing path
1912     * @since 1.6
1913     */
1914    public final void append(Shape s, boolean connect) {
1915        append(s.getPathIterator(null), connect);
1916    }
1917
1918    /**
1919     * Appends the geometry of the specified
1920     * {@link PathIterator} object
1921     * to the path, possibly connecting the new geometry to the existing
1922     * path segments with a line segment.
1923     * If the {@code connect} parameter is {@code true} and the
1924     * path is not empty then any initial {@code moveTo} in the
1925     * geometry of the appended {@code Shape} is turned into a
1926     * {@code lineTo} segment.
1927     * If the destination coordinates of such a connecting {@code lineTo}
1928     * segment match the ending coordinates of a currently open
1929     * subpath then the segment is omitted as superfluous.
1930     * The winding rule of the specified {@code Shape} is ignored
1931     * and the appended geometry is governed by the winding
1932     * rule specified for this path.
1933     *
1934     * @param pi the {@code PathIterator} whose geometry is appended to
1935     *           this path
1936     * @param connect a boolean to control whether or not to turn an initial
1937     *                {@code moveTo} segment into a {@code lineTo} segment
1938     *                to connect the new geometry to the existing path
1939     * @since 1.6
1940     */
1941    public abstract void append(PathIterator pi, boolean connect);
1942
1943    /**
1944     * Returns the fill style winding rule.
1945     *
1946     * @return an integer representing the current winding rule.
1947     * @see #WIND_EVEN_ODD
1948     * @see #WIND_NON_ZERO
1949     * @see #setWindingRule
1950     * @since 1.6
1951     */
1952    public final synchronized int getWindingRule() {
1953        return windingRule;
1954    }
1955
1956    /**
1957     * Sets the winding rule for this path to the specified value.
1958     *
1959     * @param rule an integer representing the specified
1960     *             winding rule
1961     * @exception IllegalArgumentException if
1962     *          {@code rule} is not either
1963     *          {@link #WIND_EVEN_ODD} or
1964     *          {@link #WIND_NON_ZERO}
1965     * @see #getWindingRule
1966     * @since 1.6
1967     */
1968    public final void setWindingRule(int rule) {
1969        if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
1970            throw new IllegalArgumentException("winding rule must be "+
1971                                               "WIND_EVEN_ODD or "+
1972                                               "WIND_NON_ZERO");
1973        }
1974        windingRule = rule;
1975    }
1976
1977    /**
1978     * Returns the coordinates most recently added to the end of the path
1979     * as a {@link Point2D} object.
1980     *
1981     * @return a {@code Point2D} object containing the ending coordinates of
1982     *         the path or {@code null} if there are no points in the path.
1983     * @since 1.6
1984     */
1985    public final synchronized Point2D getCurrentPoint() {
1986        int index = numCoords;
1987        if (numTypes < 1 || index < 1) {
1988            return null;
1989        }
1990        if (pointTypes[numTypes - 1] == SEG_CLOSE) {
1991        loop:
1992            for (int i = numTypes - 2; i > 0; i--) {
1993                switch (pointTypes[i]) {
1994                case SEG_MOVETO:
1995                    break loop;
1996                case SEG_LINETO:
1997                    index -= 2;
1998                    break;
1999                case SEG_QUADTO:
2000                    index -= 4;
2001                    break;
2002                case SEG_CUBICTO:
2003                    index -= 6;
2004                    break;
2005                case SEG_CLOSE:
2006                    break;
2007                }
2008            }
2009        }
2010        return getPoint(index - 2);
2011    }
2012
2013    /**
2014     * Resets the path to empty.  The append position is set back to the
2015     * beginning of the path and all coordinates and point types are
2016     * forgotten.
2017     *
2018     * @since 1.6
2019     */
2020    public final synchronized void reset() {
2021        numTypes = numCoords = 0;
2022    }
2023
2024    /**
2025     * Transforms the geometry of this path using the specified
2026     * {@link AffineTransform}.
2027     * The geometry is transformed in place, which permanently changes the
2028     * boundary defined by this object.
2029     *
2030     * @param at the {@code AffineTransform} used to transform the area
2031     * @since 1.6
2032     */
2033    public abstract void transform(AffineTransform at);
2034
2035    /**
2036     * Returns a new {@code Shape} representing a transformed version
2037     * of this {@code Path2D}.
2038     * Note that the exact type and coordinate precision of the return
2039     * value is not specified for this method.
2040     * The method will return a Shape that contains no less precision
2041     * for the transformed geometry than this {@code Path2D} currently
2042     * maintains, but it may contain no more precision either.
2043     * If the tradeoff of precision vs. storage size in the result is
2044     * important then the convenience constructors in the
2045     * {@link Path2D.Float#Float(Shape, AffineTransform) Path2D.Float}
2046     * and
2047     * {@link Path2D.Double#Double(Shape, AffineTransform) Path2D.Double}
2048     * subclasses should be used to make the choice explicit.
2049     *
2050     * @param at the {@code AffineTransform} used to transform a
2051     *           new {@code Shape}.
2052     * @return a new {@code Shape}, transformed with the specified
2053     *         {@code AffineTransform}.
2054     * @since 1.6
2055     */
2056    public final synchronized Shape createTransformedShape(AffineTransform at) {
2057        Path2D p2d = (Path2D) clone();
2058        if (at != null) {
2059            p2d.transform(at);
2060        }
2061        return p2d;
2062    }
2063
2064    /**
2065     * {@inheritDoc}
2066     * @since 1.6
2067     */
2068    public final Rectangle getBounds() {
2069        return getBounds2D().getBounds();
2070    }
2071
2072    /**
2073     * Tests if the specified coordinates are inside the closed
2074     * boundary of the specified {@link PathIterator}.
2075     * <p>
2076     * This method provides a basic facility for implementors of
2077     * the {@link Shape} interface to implement support for the
2078     * {@link Shape#contains(double, double)} method.
2079     *
2080     * @param pi the specified {@code PathIterator}
2081     * @param x the specified X coordinate
2082     * @param y the specified Y coordinate
2083     * @return {@code true} if the specified coordinates are inside the
2084     *         specified {@code PathIterator}; {@code false} otherwise
2085     * @since 1.6
2086     */
2087    public static boolean contains(PathIterator pi, double x, double y) {
2088        if (x * 0.0 + y * 0.0 == 0.0) {
2089            /* N * 0.0 is 0.0 only if N is finite.
2090             * Here we know that both x and y are finite.
2091             */
2092            int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 1);
2093            int cross = Curve.pointCrossingsForPath(pi, x, y);
2094            return ((cross & mask) != 0);
2095        } else {
2096            /* Either x or y was infinite or NaN.
2097             * A NaN always produces a negative response to any test
2098             * and Infinity values cannot be "inside" any path so
2099             * they should return false as well.
2100             */
2101            return false;
2102        }
2103    }
2104
2105    /**
2106     * Tests if the specified {@link Point2D} is inside the closed
2107     * boundary of the specified {@link PathIterator}.
2108     * <p>
2109     * This method provides a basic facility for implementors of
2110     * the {@link Shape} interface to implement support for the
2111     * {@link Shape#contains(Point2D)} method.
2112     *
2113     * @param pi the specified {@code PathIterator}
2114     * @param p the specified {@code Point2D}
2115     * @return {@code true} if the specified coordinates are inside the
2116     *         specified {@code PathIterator}; {@code false} otherwise
2117     * @since 1.6
2118     */
2119    public static boolean contains(PathIterator pi, Point2D p) {
2120        return contains(pi, p.getX(), p.getY());
2121    }
2122
2123    /**
2124     * {@inheritDoc}
2125     * @since 1.6
2126     */
2127    public final boolean contains(double x, double y) {
2128        if (x * 0.0 + y * 0.0 == 0.0) {
2129            /* N * 0.0 is 0.0 only if N is finite.
2130             * Here we know that both x and y are finite.
2131             */
2132            if (numTypes < 2) {
2133                return false;
2134            }
2135            int mask = (windingRule == WIND_NON_ZERO ? -1 : 1);
2136            return ((pointCrossings(x, y) & mask) != 0);
2137        } else {
2138            /* Either x or y was infinite or NaN.
2139             * A NaN always produces a negative response to any test
2140             * and Infinity values cannot be "inside" any path so
2141             * they should return false as well.
2142             */
2143            return false;
2144        }
2145    }
2146
2147    /**
2148     * {@inheritDoc}
2149     * @since 1.6
2150     */
2151    public final boolean contains(Point2D p) {
2152        return contains(p.getX(), p.getY());
2153    }
2154
2155    /**
2156     * Tests if the specified rectangular area is entirely inside the
2157     * closed boundary of the specified {@link PathIterator}.
2158     * <p>
2159     * This method provides a basic facility for implementors of
2160     * the {@link Shape} interface to implement support for the
2161     * {@link Shape#contains(double, double, double, double)} method.
2162     * <p>
2163     * This method object may conservatively return false in
2164     * cases where the specified rectangular area intersects a
2165     * segment of the path, but that segment does not represent a
2166     * boundary between the interior and exterior of the path.
2167     * Such segments could lie entirely within the interior of the
2168     * path if they are part of a path with a {@link #WIND_NON_ZERO}
2169     * winding rule or if the segments are retraced in the reverse
2170     * direction such that the two sets of segments cancel each
2171     * other out without any exterior area falling between them.
2172     * To determine whether segments represent true boundaries of
2173     * the interior of the path would require extensive calculations
2174     * involving all of the segments of the path and the winding
2175     * rule and are thus beyond the scope of this implementation.
2176     *
2177     * @param pi the specified {@code PathIterator}
2178     * @param x the specified X coordinate
2179     * @param y the specified Y coordinate
2180     * @param w the width of the specified rectangular area
2181     * @param h the height of the specified rectangular area
2182     * @return {@code true} if the specified {@code PathIterator} contains
2183     *         the specified rectangular area; {@code false} otherwise.
2184     * @since 1.6
2185     */
2186    public static boolean contains(PathIterator pi,
2187                                   double x, double y, double w, double h)
2188    {
2189        if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2190            /* [xy]+[wh] is NaN if any of those values are NaN,
2191             * or if adding the two together would produce NaN
2192             * by virtue of adding opposing Infinte values.
2193             * Since we need to add them below, their sum must
2194             * not be NaN.
2195             * We return false because NaN always produces a
2196             * negative response to tests
2197             */
2198            return false;
2199        }
2200        if (w <= 0 || h <= 0) {
2201            return false;
2202        }
2203        int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2204        int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2205        return (crossings != Curve.RECT_INTERSECTS &&
2206                (crossings & mask) != 0);
2207    }
2208
2209    /**
2210     * Tests if the specified {@link Rectangle2D} is entirely inside the
2211     * closed boundary of the specified {@link PathIterator}.
2212     * <p>
2213     * This method provides a basic facility for implementors of
2214     * the {@link Shape} interface to implement support for the
2215     * {@link Shape#contains(Rectangle2D)} method.
2216     * <p>
2217     * This method object may conservatively return false in
2218     * cases where the specified rectangular area intersects a
2219     * segment of the path, but that segment does not represent a
2220     * boundary between the interior and exterior of the path.
2221     * Such segments could lie entirely within the interior of the
2222     * path if they are part of a path with a {@link #WIND_NON_ZERO}
2223     * winding rule or if the segments are retraced in the reverse
2224     * direction such that the two sets of segments cancel each
2225     * other out without any exterior area falling between them.
2226     * To determine whether segments represent true boundaries of
2227     * the interior of the path would require extensive calculations
2228     * involving all of the segments of the path and the winding
2229     * rule and are thus beyond the scope of this implementation.
2230     *
2231     * @param pi the specified {@code PathIterator}
2232     * @param r a specified {@code Rectangle2D}
2233     * @return {@code true} if the specified {@code PathIterator} contains
2234     *         the specified {@code Rectangle2D}; {@code false} otherwise.
2235     * @since 1.6
2236     */
2237    public static boolean contains(PathIterator pi, Rectangle2D r) {
2238        return contains(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2239    }
2240
2241    /**
2242     * {@inheritDoc}
2243     * <p>
2244     * This method object may conservatively return false in
2245     * cases where the specified rectangular area intersects a
2246     * segment of the path, but that segment does not represent a
2247     * boundary between the interior and exterior of the path.
2248     * Such segments could lie entirely within the interior of the
2249     * path if they are part of a path with a {@link #WIND_NON_ZERO}
2250     * winding rule or if the segments are retraced in the reverse
2251     * direction such that the two sets of segments cancel each
2252     * other out without any exterior area falling between them.
2253     * To determine whether segments represent true boundaries of
2254     * the interior of the path would require extensive calculations
2255     * involving all of the segments of the path and the winding
2256     * rule and are thus beyond the scope of this implementation.
2257     *
2258     * @since 1.6
2259     */
2260    public final boolean contains(double x, double y, double w, double h) {
2261        if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2262            /* [xy]+[wh] is NaN if any of those values are NaN,
2263             * or if adding the two together would produce NaN
2264             * by virtue of adding opposing Infinte values.
2265             * Since we need to add them below, their sum must
2266             * not be NaN.
2267             * We return false because NaN always produces a
2268             * negative response to tests
2269             */
2270            return false;
2271        }
2272        if (w <= 0 || h <= 0) {
2273            return false;
2274        }
2275        int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2276        int crossings = rectCrossings(x, y, x+w, y+h);
2277        return (crossings != Curve.RECT_INTERSECTS &&
2278                (crossings & mask) != 0);
2279    }
2280
2281    /**
2282     * {@inheritDoc}
2283     * <p>
2284     * This method object may conservatively return false in
2285     * cases where the specified rectangular area intersects a
2286     * segment of the path, but that segment does not represent a
2287     * boundary between the interior and exterior of the path.
2288     * Such segments could lie entirely within the interior of the
2289     * path if they are part of a path with a {@link #WIND_NON_ZERO}
2290     * winding rule or if the segments are retraced in the reverse
2291     * direction such that the two sets of segments cancel each
2292     * other out without any exterior area falling between them.
2293     * To determine whether segments represent true boundaries of
2294     * the interior of the path would require extensive calculations
2295     * involving all of the segments of the path and the winding
2296     * rule and are thus beyond the scope of this implementation.
2297     *
2298     * @since 1.6
2299     */
2300    public final boolean contains(Rectangle2D r) {
2301        return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2302    }
2303
2304    /**
2305     * Tests if the interior of the specified {@link PathIterator}
2306     * intersects the interior of a specified set of rectangular
2307     * coordinates.
2308     * <p>
2309     * This method provides a basic facility for implementors of
2310     * the {@link Shape} interface to implement support for the
2311     * {@link Shape#intersects(double, double, double, double)} method.
2312     * <p>
2313     * This method object may conservatively return true in
2314     * cases where the specified rectangular area intersects a
2315     * segment of the path, but that segment does not represent a
2316     * boundary between the interior and exterior of the path.
2317     * Such a case may occur if some set of segments of the
2318     * path are retraced in the reverse direction such that the
2319     * two sets of segments cancel each other out without any
2320     * interior area between them.
2321     * To determine whether segments represent true boundaries of
2322     * the interior of the path would require extensive calculations
2323     * involving all of the segments of the path and the winding
2324     * rule and are thus beyond the scope of this implementation.
2325     *
2326     * @param pi the specified {@code PathIterator}
2327     * @param x the specified X coordinate
2328     * @param y the specified Y coordinate
2329     * @param w the width of the specified rectangular coordinates
2330     * @param h the height of the specified rectangular coordinates
2331     * @return {@code true} if the specified {@code PathIterator} and
2332     *         the interior of the specified set of rectangular
2333     *         coordinates intersect each other; {@code false} otherwise.
2334     * @since 1.6
2335     */
2336    public static boolean intersects(PathIterator pi,
2337                                     double x, double y, double w, double h)
2338    {
2339        if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2340            /* [xy]+[wh] is NaN if any of those values are NaN,
2341             * or if adding the two together would produce NaN
2342             * by virtue of adding opposing Infinte values.
2343             * Since we need to add them below, their sum must
2344             * not be NaN.
2345             * We return false because NaN always produces a
2346             * negative response to tests
2347             */
2348            return false;
2349        }
2350        if (w <= 0 || h <= 0) {
2351            return false;
2352        }
2353        int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2354        int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2355        return (crossings == Curve.RECT_INTERSECTS ||
2356                (crossings & mask) != 0);
2357    }
2358
2359    /**
2360     * Tests if the interior of the specified {@link PathIterator}
2361     * intersects the interior of a specified {@link Rectangle2D}.
2362     * <p>
2363     * This method provides a basic facility for implementors of
2364     * the {@link Shape} interface to implement support for the
2365     * {@link Shape#intersects(Rectangle2D)} method.
2366     * <p>
2367     * This method object may conservatively return true in
2368     * cases where the specified rectangular area intersects a
2369     * segment of the path, but that segment does not represent a
2370     * boundary between the interior and exterior of the path.
2371     * Such a case may occur if some set of segments of the
2372     * path are retraced in the reverse direction such that the
2373     * two sets of segments cancel each other out without any
2374     * interior area between them.
2375     * To determine whether segments represent true boundaries of
2376     * the interior of the path would require extensive calculations
2377     * involving all of the segments of the path and the winding
2378     * rule and are thus beyond the scope of this implementation.
2379     *
2380     * @param pi the specified {@code PathIterator}
2381     * @param r the specified {@code Rectangle2D}
2382     * @return {@code true} if the specified {@code PathIterator} and
2383     *         the interior of the specified {@code Rectangle2D}
2384     *         intersect each other; {@code false} otherwise.
2385     * @since 1.6
2386     */
2387    public static boolean intersects(PathIterator pi, Rectangle2D r) {
2388        return intersects(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2389    }
2390
2391    /**
2392     * {@inheritDoc}
2393     * <p>
2394     * This method object may conservatively return true in
2395     * cases where the specified rectangular area intersects a
2396     * segment of the path, but that segment does not represent a
2397     * boundary between the interior and exterior of the path.
2398     * Such a case may occur if some set of segments of the
2399     * path are retraced in the reverse direction such that the
2400     * two sets of segments cancel each other out without any
2401     * interior area between them.
2402     * To determine whether segments represent true boundaries of
2403     * the interior of the path would require extensive calculations
2404     * involving all of the segments of the path and the winding
2405     * rule and are thus beyond the scope of this implementation.
2406     *
2407     * @since 1.6
2408     */
2409    public final boolean intersects(double x, double y, double w, double h) {
2410        if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2411            /* [xy]+[wh] is NaN if any of those values are NaN,
2412             * or if adding the two together would produce NaN
2413             * by virtue of adding opposing Infinte values.
2414             * Since we need to add them below, their sum must
2415             * not be NaN.
2416             * We return false because NaN always produces a
2417             * negative response to tests
2418             */
2419            return false;
2420        }
2421        if (w <= 0 || h <= 0) {
2422            return false;
2423        }
2424        int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2425        int crossings = rectCrossings(x, y, x+w, y+h);
2426        return (crossings == Curve.RECT_INTERSECTS ||
2427                (crossings & mask) != 0);
2428    }
2429
2430    /**
2431     * {@inheritDoc}
2432     * <p>
2433     * This method object may conservatively return true in
2434     * cases where the specified rectangular area intersects a
2435     * segment of the path, but that segment does not represent a
2436     * boundary between the interior and exterior of the path.
2437     * Such a case may occur if some set of segments of the
2438     * path are retraced in the reverse direction such that the
2439     * two sets of segments cancel each other out without any
2440     * interior area between them.
2441     * To determine whether segments represent true boundaries of
2442     * the interior of the path would require extensive calculations
2443     * involving all of the segments of the path and the winding
2444     * rule and are thus beyond the scope of this implementation.
2445     *
2446     * @since 1.6
2447     */
2448    public final boolean intersects(Rectangle2D r) {
2449        return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2450    }
2451
2452    /**
2453     * {@inheritDoc}
2454     * <p>
2455     * The iterator for this class is not multi-threaded safe,
2456     * which means that this {@code Path2D} class does not
2457     * guarantee that modifications to the geometry of this
2458     * {@code Path2D} object do not affect any iterations of
2459     * that geometry that are already in process.
2460     *
2461     * @since 1.6
2462     */
2463    public final PathIterator getPathIterator(AffineTransform at,
2464                                              double flatness)
2465    {
2466        return new FlatteningPathIterator(getPathIterator(at), flatness);
2467    }
2468
2469    /**
2470     * Creates a new object of the same class as this object.
2471     *
2472     * @return     a clone of this instance.
2473     * @exception  OutOfMemoryError            if there is not enough memory.
2474     * @see        java.lang.Cloneable
2475     * @since      1.6
2476     */
2477    public abstract Object clone();
2478        // Note: It would be nice to have this return Path2D
2479        // but one of our subclasses (GeneralPath) needs to
2480        // offer "public Object clone()" for backwards
2481        // compatibility so we cannot restrict it further.
2482        // REMIND: Can we do both somehow?
2483
2484    /*
2485     * Support fields and methods for serializing the subclasses.
2486     */
2487    private static final byte SERIAL_STORAGE_FLT_ARRAY = 0x30;
2488    private static final byte SERIAL_STORAGE_DBL_ARRAY = 0x31;
2489
2490    private static final byte SERIAL_SEG_FLT_MOVETO    = 0x40;
2491    private static final byte SERIAL_SEG_FLT_LINETO    = 0x41;
2492    private static final byte SERIAL_SEG_FLT_QUADTO    = 0x42;
2493    private static final byte SERIAL_SEG_FLT_CUBICTO   = 0x43;
2494
2495    private static final byte SERIAL_SEG_DBL_MOVETO    = 0x50;
2496    private static final byte SERIAL_SEG_DBL_LINETO    = 0x51;
2497    private static final byte SERIAL_SEG_DBL_QUADTO    = 0x52;
2498    private static final byte SERIAL_SEG_DBL_CUBICTO   = 0x53;
2499
2500    private static final byte SERIAL_SEG_CLOSE         = 0x60;
2501    private static final byte SERIAL_PATH_END          = 0x61;
2502
2503    final void writeObject(java.io.ObjectOutputStream s, boolean isdbl)
2504        throws java.io.IOException
2505    {
2506        s.defaultWriteObject();
2507
2508        float fCoords[];
2509        double dCoords[];
2510
2511        if (isdbl) {
2512            dCoords = ((Path2D.Double) this).doubleCoords;
2513            fCoords = null;
2514        } else {
2515            fCoords = ((Path2D.Float) this).floatCoords;
2516            dCoords = null;
2517        }
2518
2519        int numTypes = this.numTypes;
2520
2521        s.writeByte(isdbl
2522                    ? SERIAL_STORAGE_DBL_ARRAY
2523                    : SERIAL_STORAGE_FLT_ARRAY);
2524        s.writeInt(numTypes);
2525        s.writeInt(numCoords);
2526        s.writeByte((byte) windingRule);
2527
2528        int cindex = 0;
2529        for (int i = 0; i < numTypes; i++) {
2530            int npoints;
2531            byte serialtype;
2532            switch (pointTypes[i]) {
2533            case SEG_MOVETO:
2534                npoints = 1;
2535                serialtype = (isdbl
2536                              ? SERIAL_SEG_DBL_MOVETO
2537                              : SERIAL_SEG_FLT_MOVETO);
2538                break;
2539            case SEG_LINETO:
2540                npoints = 1;
2541                serialtype = (isdbl
2542                              ? SERIAL_SEG_DBL_LINETO
2543                              : SERIAL_SEG_FLT_LINETO);
2544                break;
2545            case SEG_QUADTO:
2546                npoints = 2;
2547                serialtype = (isdbl
2548                              ? SERIAL_SEG_DBL_QUADTO
2549                              : SERIAL_SEG_FLT_QUADTO);
2550                break;
2551            case SEG_CUBICTO:
2552                npoints = 3;
2553                serialtype = (isdbl
2554                              ? SERIAL_SEG_DBL_CUBICTO
2555                              : SERIAL_SEG_FLT_CUBICTO);
2556                break;
2557            case SEG_CLOSE:
2558                npoints = 0;
2559                serialtype = SERIAL_SEG_CLOSE;
2560                break;
2561
2562            default:
2563                // Should never happen
2564                throw new InternalError("unrecognized path type");
2565            }
2566            s.writeByte(serialtype);
2567            while (--npoints >= 0) {
2568                if (isdbl) {
2569                    s.writeDouble(dCoords[cindex++]);
2570                    s.writeDouble(dCoords[cindex++]);
2571                } else {
2572                    s.writeFloat(fCoords[cindex++]);
2573                    s.writeFloat(fCoords[cindex++]);
2574                }
2575            }
2576        }
2577        s.writeByte(SERIAL_PATH_END);
2578    }
2579
2580    final void readObject(java.io.ObjectInputStream s, boolean storedbl)
2581        throws java.lang.ClassNotFoundException, java.io.IOException
2582    {
2583        s.defaultReadObject();
2584
2585        // The subclass calls this method with the storage type that
2586        // they want us to use (storedbl) so we ignore the storage
2587        // method hint from the stream.
2588        s.readByte();
2589        int nT = s.readInt();
2590        int nC = s.readInt();
2591        try {
2592            setWindingRule(s.readByte());
2593        } catch (IllegalArgumentException iae) {
2594            throw new java.io.InvalidObjectException(iae.getMessage());
2595        }
2596
2597        pointTypes = new byte[(nT < 0) ? INIT_SIZE : nT];
2598        if (nC < 0) {
2599            nC = INIT_SIZE * 2;
2600        }
2601        if (storedbl) {
2602            ((Path2D.Double) this).doubleCoords = new double[nC];
2603        } else {
2604            ((Path2D.Float) this).floatCoords = new float[nC];
2605        }
2606
2607    PATHDONE:
2608        for (int i = 0; nT < 0 || i < nT; i++) {
2609            boolean isdbl;
2610            int npoints;
2611            byte segtype;
2612
2613            byte serialtype = s.readByte();
2614            switch (serialtype) {
2615            case SERIAL_SEG_FLT_MOVETO:
2616                isdbl = false;
2617                npoints = 1;
2618                segtype = SEG_MOVETO;
2619                break;
2620            case SERIAL_SEG_FLT_LINETO:
2621                isdbl = false;
2622                npoints = 1;
2623                segtype = SEG_LINETO;
2624                break;
2625            case SERIAL_SEG_FLT_QUADTO:
2626                isdbl = false;
2627                npoints = 2;
2628                segtype = SEG_QUADTO;
2629                break;
2630            case SERIAL_SEG_FLT_CUBICTO:
2631                isdbl = false;
2632                npoints = 3;
2633                segtype = SEG_CUBICTO;
2634                break;
2635
2636            case SERIAL_SEG_DBL_MOVETO:
2637                isdbl = true;
2638                npoints = 1;
2639                segtype = SEG_MOVETO;
2640                break;
2641            case SERIAL_SEG_DBL_LINETO:
2642                isdbl = true;
2643                npoints = 1;
2644                segtype = SEG_LINETO;
2645                break;
2646            case SERIAL_SEG_DBL_QUADTO:
2647                isdbl = true;
2648                npoints = 2;
2649                segtype = SEG_QUADTO;
2650                break;
2651            case SERIAL_SEG_DBL_CUBICTO:
2652                isdbl = true;
2653                npoints = 3;
2654                segtype = SEG_CUBICTO;
2655                break;
2656
2657            case SERIAL_SEG_CLOSE:
2658                isdbl = false;
2659                npoints = 0;
2660                segtype = SEG_CLOSE;
2661                break;
2662
2663            case SERIAL_PATH_END:
2664                if (nT < 0) {
2665                    break PATHDONE;
2666                }
2667                throw new StreamCorruptedException("unexpected PATH_END");
2668
2669            default:
2670                throw new StreamCorruptedException("unrecognized path type");
2671            }
2672            needRoom(segtype != SEG_MOVETO, npoints * 2);
2673            if (isdbl) {
2674                while (--npoints >= 0) {
2675                    append(s.readDouble(), s.readDouble());
2676                }
2677            } else {
2678                while (--npoints >= 0) {
2679                    append(s.readFloat(), s.readFloat());
2680                }
2681            }
2682            pointTypes[numTypes++] = segtype;
2683        }
2684        if (nT >= 0 && s.readByte() != SERIAL_PATH_END) {
2685            throw new StreamCorruptedException("missing PATH_END");
2686        }
2687    }
2688
2689    abstract static class Iterator implements PathIterator {
2690        int typeIdx;
2691        int pointIdx;
2692        Path2D path;
2693
2694        static final int curvecoords[] = {2, 2, 4, 6, 0};
2695
2696        Iterator(Path2D path) {
2697            this.path = path;
2698        }
2699
2700        public int getWindingRule() {
2701            return path.getWindingRule();
2702        }
2703
2704        public boolean isDone() {
2705            return (typeIdx >= path.numTypes);
2706        }
2707
2708        public void next() {
2709            int type = path.pointTypes[typeIdx++];
2710            pointIdx += curvecoords[type];
2711        }
2712    }
2713}
2714