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