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