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