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