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