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