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