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