Save This Page
Home » openjdk-7 » java » awt » geom » [javadoc | source]
    1   /*
    2    * Copyright 1997-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 java.util.Arrays;
   31   import java.io.Serializable;
   32   import sun.awt.geom.Curve;
   33   
   34   /**
   35    * The <code>CubicCurve2D</code> class defines a cubic parametric curve
   36    * segment in {@code (x,y)} coordinate space.
   37    * <p>
   38    * This class is only the abstract superclass for all objects which
   39    * store a 2D cubic curve segment.
   40    * The actual storage representation of the coordinates is left to
   41    * the subclass.
   42    *
   43    * @author      Jim Graham
   44    * @since 1.2
   45    */
   46   public abstract class CubicCurve2D implements Shape, Cloneable {
   47   
   48       /**
   49        * A cubic parametric curve segment specified with
   50        * {@code float} coordinates.
   51        * @since 1.2
   52        */
   53       public static class Float extends CubicCurve2D implements Serializable {
   54           /**
   55            * The X coordinate of the start point
   56            * of the cubic curve segment.
   57            * @since 1.2
   58            * @serial
   59            */
   60           public float x1;
   61   
   62           /**
   63            * The Y coordinate of the start point
   64            * of the cubic curve segment.
   65            * @since 1.2
   66            * @serial
   67            */
   68           public float y1;
   69   
   70           /**
   71            * The X coordinate of the first control point
   72            * of the cubic curve segment.
   73            * @since 1.2
   74            * @serial
   75            */
   76           public float ctrlx1;
   77   
   78           /**
   79            * The Y coordinate of the first control point
   80            * of the cubic curve segment.
   81            * @since 1.2
   82            * @serial
   83            */
   84           public float ctrly1;
   85   
   86           /**
   87            * The X coordinate of the second control point
   88            * of the cubic curve segment.
   89            * @since 1.2
   90            * @serial
   91            */
   92           public float ctrlx2;
   93   
   94           /**
   95            * The Y coordinate of the second control point
   96            * of the cubic curve segment.
   97            * @since 1.2
   98            * @serial
   99            */
  100           public float ctrly2;
  101   
  102           /**
  103            * The X coordinate of the end point
  104            * of the cubic curve segment.
  105            * @since 1.2
  106            * @serial
  107            */
  108           public float x2;
  109   
  110           /**
  111            * The Y coordinate of the end point
  112            * of the cubic curve segment.
  113            * @since 1.2
  114            * @serial
  115            */
  116           public float y2;
  117   
  118           /**
  119            * Constructs and initializes a CubicCurve with coordinates
  120            * (0, 0, 0, 0, 0, 0, 0, 0).
  121            * @since 1.2
  122            */
  123           public Float() {
  124           }
  125   
  126           /**
  127            * Constructs and initializes a {@code CubicCurve2D} from
  128            * the specified {@code float} coordinates.
  129            *
  130            * @param x1 the X coordinate for the start point
  131            *           of the resulting {@code CubicCurve2D}
  132            * @param y1 the Y coordinate for the start point
  133            *           of the resulting {@code CubicCurve2D}
  134            * @param ctrlx1 the X coordinate for the first control point
  135            *               of the resulting {@code CubicCurve2D}
  136            * @param ctrly1 the Y coordinate for the first control point
  137            *               of the resulting {@code CubicCurve2D}
  138            * @param ctrlx2 the X coordinate for the second control point
  139            *               of the resulting {@code CubicCurve2D}
  140            * @param ctrly2 the Y coordinate for the second control point
  141            *               of the resulting {@code CubicCurve2D}
  142            * @param x2 the X coordinate for the end point
  143            *           of the resulting {@code CubicCurve2D}
  144            * @param y2 the Y coordinate for the end point
  145            *           of the resulting {@code CubicCurve2D}
  146            * @since 1.2
  147            */
  148           public Float(float x1, float y1,
  149                        float ctrlx1, float ctrly1,
  150                        float ctrlx2, float ctrly2,
  151                        float x2, float y2)
  152           {
  153               setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
  154           }
  155   
  156           /**
  157            * {@inheritDoc}
  158            * @since 1.2
  159            */
  160           public double getX1() {
  161               return (double) x1;
  162           }
  163   
  164           /**
  165            * {@inheritDoc}
  166            * @since 1.2
  167            */
  168           public double getY1() {
  169               return (double) y1;
  170           }
  171   
  172           /**
  173            * {@inheritDoc}
  174            * @since 1.2
  175            */
  176           public Point2D getP1() {
  177               return new Point2D.Float(x1, y1);
  178           }
  179   
  180           /**
  181            * {@inheritDoc}
  182            * @since 1.2
  183            */
  184           public double getCtrlX1() {
  185               return (double) ctrlx1;
  186           }
  187   
  188           /**
  189            * {@inheritDoc}
  190            * @since 1.2
  191            */
  192           public double getCtrlY1() {
  193               return (double) ctrly1;
  194           }
  195   
  196           /**
  197            * {@inheritDoc}
  198            * @since 1.2
  199            */
  200           public Point2D getCtrlP1() {
  201               return new Point2D.Float(ctrlx1, ctrly1);
  202           }
  203   
  204           /**
  205            * {@inheritDoc}
  206            * @since 1.2
  207            */
  208           public double getCtrlX2() {
  209               return (double) ctrlx2;
  210           }
  211   
  212           /**
  213            * {@inheritDoc}
  214            * @since 1.2
  215            */
  216           public double getCtrlY2() {
  217               return (double) ctrly2;
  218           }
  219   
  220           /**
  221            * {@inheritDoc}
  222            * @since 1.2
  223            */
  224           public Point2D getCtrlP2() {
  225               return new Point2D.Float(ctrlx2, ctrly2);
  226           }
  227   
  228           /**
  229            * {@inheritDoc}
  230            * @since 1.2
  231            */
  232           public double getX2() {
  233               return (double) x2;
  234           }
  235   
  236           /**
  237            * {@inheritDoc}
  238            * @since 1.2
  239            */
  240           public double getY2() {
  241               return (double) y2;
  242           }
  243   
  244           /**
  245            * {@inheritDoc}
  246            * @since 1.2
  247            */
  248           public Point2D getP2() {
  249               return new Point2D.Float(x2, y2);
  250           }
  251   
  252           /**
  253            * {@inheritDoc}
  254            * @since 1.2
  255            */
  256           public void setCurve(double x1, double y1,
  257                                double ctrlx1, double ctrly1,
  258                                double ctrlx2, double ctrly2,
  259                                double x2, double y2)
  260           {
  261               this.x1     = (float) x1;
  262               this.y1     = (float) y1;
  263               this.ctrlx1 = (float) ctrlx1;
  264               this.ctrly1 = (float) ctrly1;
  265               this.ctrlx2 = (float) ctrlx2;
  266               this.ctrly2 = (float) ctrly2;
  267               this.x2     = (float) x2;
  268               this.y2     = (float) y2;
  269           }
  270   
  271           /**
  272            * Sets the location of the end points and control points
  273            * of this curve to the specified {@code float} coordinates.
  274            *
  275            * @param x1 the X coordinate used to set the start point
  276            *           of this {@code CubicCurve2D}
  277            * @param y1 the Y coordinate used to set the start point
  278            *           of this {@code CubicCurve2D}
  279            * @param ctrlx1 the X coordinate used to set the first control point
  280            *               of this {@code CubicCurve2D}
  281            * @param ctrly1 the Y coordinate used to set the first control point
  282            *               of this {@code CubicCurve2D}
  283            * @param ctrlx2 the X coordinate used to set the second control point
  284            *               of this {@code CubicCurve2D}
  285            * @param ctrly2 the Y coordinate used to set the second control point
  286            *               of this {@code CubicCurve2D}
  287            * @param x2 the X coordinate used to set the end point
  288            *           of this {@code CubicCurve2D}
  289            * @param y2 the Y coordinate used to set the end point
  290            *           of this {@code CubicCurve2D}
  291            * @since 1.2
  292            */
  293           public void setCurve(float x1, float y1,
  294                                float ctrlx1, float ctrly1,
  295                                float ctrlx2, float ctrly2,
  296                                float x2, float y2)
  297           {
  298               this.x1     = x1;
  299               this.y1     = y1;
  300               this.ctrlx1 = ctrlx1;
  301               this.ctrly1 = ctrly1;
  302               this.ctrlx2 = ctrlx2;
  303               this.ctrly2 = ctrly2;
  304               this.x2     = x2;
  305               this.y2     = y2;
  306           }
  307   
  308           /**
  309            * {@inheritDoc}
  310            * @since 1.2
  311            */
  312           public Rectangle2D getBounds2D() {
  313               float left   = Math.min(Math.min(x1, x2),
  314                                       Math.min(ctrlx1, ctrlx2));
  315               float top    = Math.min(Math.min(y1, y2),
  316                                       Math.min(ctrly1, ctrly2));
  317               float right  = Math.max(Math.max(x1, x2),
  318                                       Math.max(ctrlx1, ctrlx2));
  319               float bottom = Math.max(Math.max(y1, y2),
  320                                       Math.max(ctrly1, ctrly2));
  321               return new Rectangle2D.Float(left, top,
  322                                            right - left, bottom - top);
  323           }
  324   
  325           /*
  326            * JDK 1.6 serialVersionUID
  327            */
  328           private static final long serialVersionUID = -1272015596714244385L;
  329       }
  330   
  331       /**
  332        * A cubic parametric curve segment specified with
  333        * {@code double} coordinates.
  334        * @since 1.2
  335        */
  336       public static class Double extends CubicCurve2D implements Serializable {
  337           /**
  338            * The X coordinate of the start point
  339            * of the cubic curve segment.
  340            * @since 1.2
  341            * @serial
  342            */
  343           public double x1;
  344   
  345           /**
  346            * The Y coordinate of the start point
  347            * of the cubic curve segment.
  348            * @since 1.2
  349            * @serial
  350            */
  351           public double y1;
  352   
  353           /**
  354            * The X coordinate of the first control point
  355            * of the cubic curve segment.
  356            * @since 1.2
  357            * @serial
  358            */
  359           public double ctrlx1;
  360   
  361           /**
  362            * The Y coordinate of the first control point
  363            * of the cubic curve segment.
  364            * @since 1.2
  365            * @serial
  366            */
  367           public double ctrly1;
  368   
  369           /**
  370            * The X coordinate of the second control point
  371            * of the cubic curve segment.
  372            * @since 1.2
  373            * @serial
  374            */
  375           public double ctrlx2;
  376   
  377           /**
  378            * The Y coordinate of the second control point
  379            * of the cubic curve segment.
  380            * @since 1.2
  381            * @serial
  382            */
  383           public double ctrly2;
  384   
  385           /**
  386            * The X coordinate of the end point
  387            * of the cubic curve segment.
  388            * @since 1.2
  389            * @serial
  390            */
  391           public double x2;
  392   
  393           /**
  394            * The Y coordinate of the end point
  395            * of the cubic curve segment.
  396            * @since 1.2
  397            * @serial
  398            */
  399           public double y2;
  400   
  401           /**
  402            * Constructs and initializes a CubicCurve with coordinates
  403            * (0, 0, 0, 0, 0, 0, 0, 0).
  404            * @since 1.2
  405            */
  406           public Double() {
  407           }
  408   
  409           /**
  410            * Constructs and initializes a {@code CubicCurve2D} from
  411            * the specified {@code double} coordinates.
  412            *
  413            * @param x1 the X coordinate for the start point
  414            *           of the resulting {@code CubicCurve2D}
  415            * @param y1 the Y coordinate for the start point
  416            *           of the resulting {@code CubicCurve2D}
  417            * @param ctrlx1 the X coordinate for the first control point
  418            *               of the resulting {@code CubicCurve2D}
  419            * @param ctrly1 the Y coordinate for the first control point
  420            *               of the resulting {@code CubicCurve2D}
  421            * @param ctrlx2 the X coordinate for the second control point
  422            *               of the resulting {@code CubicCurve2D}
  423            * @param ctrly2 the Y coordinate for the second control point
  424            *               of the resulting {@code CubicCurve2D}
  425            * @param x2 the X coordinate for the end point
  426            *           of the resulting {@code CubicCurve2D}
  427            * @param y2 the Y coordinate for the end point
  428            *           of the resulting {@code CubicCurve2D}
  429            * @since 1.2
  430            */
  431           public Double(double x1, double y1,
  432                         double ctrlx1, double ctrly1,
  433                         double ctrlx2, double ctrly2,
  434                         double x2, double y2)
  435           {
  436               setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
  437           }
  438   
  439           /**
  440            * {@inheritDoc}
  441            * @since 1.2
  442            */
  443           public double getX1() {
  444               return x1;
  445           }
  446   
  447           /**
  448            * {@inheritDoc}
  449            * @since 1.2
  450            */
  451           public double getY1() {
  452               return y1;
  453           }
  454   
  455           /**
  456            * {@inheritDoc}
  457            * @since 1.2
  458            */
  459           public Point2D getP1() {
  460               return new Point2D.Double(x1, y1);
  461           }
  462   
  463           /**
  464            * {@inheritDoc}
  465            * @since 1.2
  466            */
  467           public double getCtrlX1() {
  468               return ctrlx1;
  469           }
  470   
  471           /**
  472            * {@inheritDoc}
  473            * @since 1.2
  474            */
  475           public double getCtrlY1() {
  476               return ctrly1;
  477           }
  478   
  479           /**
  480            * {@inheritDoc}
  481            * @since 1.2
  482            */
  483           public Point2D getCtrlP1() {
  484               return new Point2D.Double(ctrlx1, ctrly1);
  485           }
  486   
  487           /**
  488            * {@inheritDoc}
  489            * @since 1.2
  490            */
  491           public double getCtrlX2() {
  492               return ctrlx2;
  493           }
  494   
  495           /**
  496            * {@inheritDoc}
  497            * @since 1.2
  498            */
  499           public double getCtrlY2() {
  500               return ctrly2;
  501           }
  502   
  503           /**
  504            * {@inheritDoc}
  505            * @since 1.2
  506            */
  507           public Point2D getCtrlP2() {
  508               return new Point2D.Double(ctrlx2, ctrly2);
  509           }
  510   
  511           /**
  512            * {@inheritDoc}
  513            * @since 1.2
  514            */
  515           public double getX2() {
  516               return x2;
  517           }
  518   
  519           /**
  520            * {@inheritDoc}
  521            * @since 1.2
  522            */
  523           public double getY2() {
  524               return y2;
  525           }
  526   
  527           /**
  528            * {@inheritDoc}
  529            * @since 1.2
  530            */
  531           public Point2D getP2() {
  532               return new Point2D.Double(x2, y2);
  533           }
  534   
  535           /**
  536            * {@inheritDoc}
  537            * @since 1.2
  538            */
  539           public void setCurve(double x1, double y1,
  540                                double ctrlx1, double ctrly1,
  541                                double ctrlx2, double ctrly2,
  542                                double x2, double y2)
  543           {
  544               this.x1     = x1;
  545               this.y1     = y1;
  546               this.ctrlx1 = ctrlx1;
  547               this.ctrly1 = ctrly1;
  548               this.ctrlx2 = ctrlx2;
  549               this.ctrly2 = ctrly2;
  550               this.x2     = x2;
  551               this.y2     = y2;
  552           }
  553   
  554           /**
  555            * {@inheritDoc}
  556            * @since 1.2
  557            */
  558           public Rectangle2D getBounds2D() {
  559               double left   = Math.min(Math.min(x1, x2),
  560                                        Math.min(ctrlx1, ctrlx2));
  561               double top    = Math.min(Math.min(y1, y2),
  562                                        Math.min(ctrly1, ctrly2));
  563               double right  = Math.max(Math.max(x1, x2),
  564                                        Math.max(ctrlx1, ctrlx2));
  565               double bottom = Math.max(Math.max(y1, y2),
  566                                        Math.max(ctrly1, ctrly2));
  567               return new Rectangle2D.Double(left, top,
  568                                             right - left, bottom - top);
  569           }
  570   
  571           /*
  572            * JDK 1.6 serialVersionUID
  573            */
  574           private static final long serialVersionUID = -4202960122839707295L;
  575       }
  576   
  577       /**
  578        * This is an abstract class that cannot be instantiated directly.
  579        * Type-specific implementation subclasses are available for
  580        * instantiation and provide a number of formats for storing
  581        * the information necessary to satisfy the various accessor
  582        * methods below.
  583        *
  584        * @see java.awt.geom.CubicCurve2D.Float
  585        * @see java.awt.geom.CubicCurve2D.Double
  586        * @since 1.2
  587        */
  588       protected CubicCurve2D() {
  589       }
  590   
  591       /**
  592        * Returns the X coordinate of the start point in double precision.
  593        * @return the X coordinate of the start point of the
  594        *         {@code CubicCurve2D}.
  595        * @since 1.2
  596        */
  597       public abstract double getX1();
  598   
  599       /**
  600        * Returns the Y coordinate of the start point in double precision.
  601        * @return the Y coordinate of the start point of the
  602        *         {@code CubicCurve2D}.
  603        * @since 1.2
  604        */
  605       public abstract double getY1();
  606   
  607       /**
  608        * Returns the start point.
  609        * @return a {@code Point2D} that is the start point of
  610        *         the {@code CubicCurve2D}.
  611        * @since 1.2
  612        */
  613       public abstract Point2D getP1();
  614   
  615       /**
  616        * Returns the X coordinate of the first control point in double precision.
  617        * @return the X coordinate of the first control point of the
  618        *         {@code CubicCurve2D}.
  619        * @since 1.2
  620        */
  621       public abstract double getCtrlX1();
  622   
  623       /**
  624        * Returns the Y coordinate of the first control point in double precision.
  625        * @return the Y coordinate of the first control point of the
  626        *         {@code CubicCurve2D}.
  627        * @since 1.2
  628        */
  629       public abstract double getCtrlY1();
  630   
  631       /**
  632        * Returns the first control point.
  633        * @return a {@code Point2D} that is the first control point of
  634        *         the {@code CubicCurve2D}.
  635        * @since 1.2
  636        */
  637       public abstract Point2D getCtrlP1();
  638   
  639       /**
  640        * Returns the X coordinate of the second control point
  641        * in double precision.
  642        * @return the X coordinate of the second control point of the
  643        *         {@code CubicCurve2D}.
  644        * @since 1.2
  645        */
  646       public abstract double getCtrlX2();
  647   
  648       /**
  649        * Returns the Y coordinate of the second control point
  650        * in double precision.
  651        * @return the Y coordinate of the second control point of the
  652        *         {@code CubicCurve2D}.
  653        * @since 1.2
  654        */
  655       public abstract double getCtrlY2();
  656   
  657       /**
  658        * Returns the second control point.
  659        * @return a {@code Point2D} that is the second control point of
  660        *         the {@code CubicCurve2D}.
  661        * @since 1.2
  662        */
  663       public abstract Point2D getCtrlP2();
  664   
  665       /**
  666        * Returns the X coordinate of the end point in double precision.
  667        * @return the X coordinate of the end point of the
  668        *         {@code CubicCurve2D}.
  669        * @since 1.2
  670        */
  671       public abstract double getX2();
  672   
  673       /**
  674        * Returns the Y coordinate of the end point in double precision.
  675        * @return the Y coordinate of the end point of the
  676        *         {@code CubicCurve2D}.
  677        * @since 1.2
  678        */
  679       public abstract double getY2();
  680   
  681       /**
  682        * Returns the end point.
  683        * @return a {@code Point2D} that is the end point of
  684        *         the {@code CubicCurve2D}.
  685        * @since 1.2
  686        */
  687       public abstract Point2D getP2();
  688   
  689       /**
  690        * Sets the location of the end points and control points of this curve
  691        * to the specified double coordinates.
  692        *
  693        * @param x1 the X coordinate used to set the start point
  694        *           of this {@code CubicCurve2D}
  695        * @param y1 the Y coordinate used to set the start point
  696        *           of this {@code CubicCurve2D}
  697        * @param ctrlx1 the X coordinate used to set the first control point
  698        *               of this {@code CubicCurve2D}
  699        * @param ctrly1 the Y coordinate used to set the first control point
  700        *               of this {@code CubicCurve2D}
  701        * @param ctrlx2 the X coordinate used to set the second control point
  702        *               of this {@code CubicCurve2D}
  703        * @param ctrly2 the Y coordinate used to set the second control point
  704        *               of this {@code CubicCurve2D}
  705        * @param x2 the X coordinate used to set the end point
  706        *           of this {@code CubicCurve2D}
  707        * @param y2 the Y coordinate used to set the end point
  708        *           of this {@code CubicCurve2D}
  709        * @since 1.2
  710        */
  711       public abstract void setCurve(double x1, double y1,
  712                                     double ctrlx1, double ctrly1,
  713                                     double ctrlx2, double ctrly2,
  714                                     double x2, double y2);
  715   
  716       /**
  717        * Sets the location of the end points and control points of this curve
  718        * to the double coordinates at the specified offset in the specified
  719        * array.
  720        * @param coords a double array containing coordinates
  721        * @param offset the index of <code>coords</code> from which to begin
  722        *          setting the end points and control points of this curve
  723        *          to the coordinates contained in <code>coords</code>
  724        * @since 1.2
  725        */
  726       public void setCurve(double[] coords, int offset) {
  727           setCurve(coords[offset + 0], coords[offset + 1],
  728                    coords[offset + 2], coords[offset + 3],
  729                    coords[offset + 4], coords[offset + 5],
  730                    coords[offset + 6], coords[offset + 7]);
  731       }
  732   
  733       /**
  734        * Sets the location of the end points and control points of this curve
  735        * to the specified <code>Point2D</code> coordinates.
  736        * @param p1 the first specified <code>Point2D</code> used to set the
  737        *          start point of this curve
  738        * @param cp1 the second specified <code>Point2D</code> used to set the
  739        *          first control point of this curve
  740        * @param cp2 the third specified <code>Point2D</code> used to set the
  741        *          second control point of this curve
  742        * @param p2 the fourth specified <code>Point2D</code> used to set the
  743        *          end point of this curve
  744        * @since 1.2
  745        */
  746       public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) {
  747           setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(),
  748                    cp2.getX(), cp2.getY(), p2.getX(), p2.getY());
  749       }
  750   
  751       /**
  752        * Sets the location of the end points and control points of this curve
  753        * to the coordinates of the <code>Point2D</code> objects at the specified
  754        * offset in the specified array.
  755        * @param pts an array of <code>Point2D</code> objects
  756        * @param offset  the index of <code>pts</code> from which to begin setting
  757        *          the end points and control points of this curve to the
  758        *          points contained in <code>pts</code>
  759        * @since 1.2
  760        */
  761       public void setCurve(Point2D[] pts, int offset) {
  762           setCurve(pts[offset + 0].getX(), pts[offset + 0].getY(),
  763                    pts[offset + 1].getX(), pts[offset + 1].getY(),
  764                    pts[offset + 2].getX(), pts[offset + 2].getY(),
  765                    pts[offset + 3].getX(), pts[offset + 3].getY());
  766       }
  767   
  768       /**
  769        * Sets the location of the end points and control points of this curve
  770        * to the same as those in the specified <code>CubicCurve2D</code>.
  771        * @param c the specified <code>CubicCurve2D</code>
  772        * @since 1.2
  773        */
  774       public void setCurve(CubicCurve2D c) {
  775           setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(),
  776                    c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2());
  777       }
  778   
  779       /**
  780        * Returns the square of the flatness of the cubic curve specified
  781        * by the indicated control points. The flatness is the maximum distance
  782        * of a control point from the line connecting the end points.
  783        *
  784        * @param x1 the X coordinate that specifies the start point
  785        *           of a {@code CubicCurve2D}
  786        * @param y1 the Y coordinate that specifies the start point
  787        *           of a {@code CubicCurve2D}
  788        * @param ctrlx1 the X coordinate that specifies the first control point
  789        *               of a {@code CubicCurve2D}
  790        * @param ctrly1 the Y coordinate that specifies the first control point
  791        *               of a {@code CubicCurve2D}
  792        * @param ctrlx2 the X coordinate that specifies the second control point
  793        *               of a {@code CubicCurve2D}
  794        * @param ctrly2 the Y coordinate that specifies the second control point
  795        *               of a {@code CubicCurve2D}
  796        * @param x2 the X coordinate that specifies the end point
  797        *           of a {@code CubicCurve2D}
  798        * @param y2 the Y coordinate that specifies the end point
  799        *           of a {@code CubicCurve2D}
  800        * @return the square of the flatness of the {@code CubicCurve2D}
  801        *          represented by the specified coordinates.
  802        * @since 1.2
  803        */
  804       public static double getFlatnessSq(double x1, double y1,
  805                                          double ctrlx1, double ctrly1,
  806                                          double ctrlx2, double ctrly2,
  807                                          double x2, double y2) {
  808           return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1, ctrly1),
  809                           Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx2, ctrly2));
  810   
  811       }
  812   
  813       /**
  814        * Returns the flatness of the cubic curve specified
  815        * by the indicated control points. The flatness is the maximum distance
  816        * of a control point from the line connecting the end points.
  817        *
  818        * @param x1 the X coordinate that specifies the start point
  819        *           of a {@code CubicCurve2D}
  820        * @param y1 the Y coordinate that specifies the start point
  821        *           of a {@code CubicCurve2D}
  822        * @param ctrlx1 the X coordinate that specifies the first control point
  823        *               of a {@code CubicCurve2D}
  824        * @param ctrly1 the Y coordinate that specifies the first control point
  825        *               of a {@code CubicCurve2D}
  826        * @param ctrlx2 the X coordinate that specifies the second control point
  827        *               of a {@code CubicCurve2D}
  828        * @param ctrly2 the Y coordinate that specifies the second control point
  829        *               of a {@code CubicCurve2D}
  830        * @param x2 the X coordinate that specifies the end point
  831        *           of a {@code CubicCurve2D}
  832        * @param y2 the Y coordinate that specifies the end point
  833        *           of a {@code CubicCurve2D}
  834        * @return the flatness of the {@code CubicCurve2D}
  835        *          represented by the specified coordinates.
  836        * @since 1.2
  837        */
  838       public static double getFlatness(double x1, double y1,
  839                                        double ctrlx1, double ctrly1,
  840                                        double ctrlx2, double ctrly2,
  841                                        double x2, double y2) {
  842           return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1,
  843                                          ctrlx2, ctrly2, x2, y2));
  844       }
  845   
  846       /**
  847        * Returns the square of the flatness of the cubic curve specified
  848        * by the control points stored in the indicated array at the
  849        * indicated index. The flatness is the maximum distance
  850        * of a control point from the line connecting the end points.
  851        * @param coords an array containing coordinates
  852        * @param offset the index of <code>coords</code> from which to begin
  853        *          getting the end points and control points of the curve
  854        * @return the square of the flatness of the <code>CubicCurve2D</code>
  855        *          specified by the coordinates in <code>coords</code> at
  856        *          the specified offset.
  857        * @since 1.2
  858        */
  859       public static double getFlatnessSq(double coords[], int offset) {
  860           return getFlatnessSq(coords[offset + 0], coords[offset + 1],
  861                                coords[offset + 2], coords[offset + 3],
  862                                coords[offset + 4], coords[offset + 5],
  863                                coords[offset + 6], coords[offset + 7]);
  864       }
  865   
  866       /**
  867        * Returns the flatness of the cubic curve specified
  868        * by the control points stored in the indicated array at the
  869        * indicated index.  The flatness is the maximum distance
  870        * of a control point from the line connecting the end points.
  871        * @param coords an array containing coordinates
  872        * @param offset the index of <code>coords</code> from which to begin
  873        *          getting the end points and control points of the curve
  874        * @return the flatness of the <code>CubicCurve2D</code>
  875        *          specified by the coordinates in <code>coords</code> at
  876        *          the specified offset.
  877        * @since 1.2
  878        */
  879       public static double getFlatness(double coords[], int offset) {
  880           return getFlatness(coords[offset + 0], coords[offset + 1],
  881                              coords[offset + 2], coords[offset + 3],
  882                              coords[offset + 4], coords[offset + 5],
  883                              coords[offset + 6], coords[offset + 7]);
  884       }
  885   
  886       /**
  887        * Returns the square of the flatness of this curve.  The flatness is the
  888        * maximum distance of a control point from the line connecting the
  889        * end points.
  890        * @return the square of the flatness of this curve.
  891        * @since 1.2
  892        */
  893       public double getFlatnessSq() {
  894           return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
  895                                getCtrlX2(), getCtrlY2(), getX2(), getY2());
  896       }
  897   
  898       /**
  899        * Returns the flatness of this curve.  The flatness is the
  900        * maximum distance of a control point from the line connecting the
  901        * end points.
  902        * @return the flatness of this curve.
  903        * @since 1.2
  904        */
  905       public double getFlatness() {
  906           return getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
  907                              getCtrlX2(), getCtrlY2(), getX2(), getY2());
  908       }
  909   
  910       /**
  911        * Subdivides this cubic curve and stores the resulting two
  912        * subdivided curves into the left and right curve parameters.
  913        * Either or both of the left and right objects may be the same
  914        * as this object or null.
  915        * @param left the cubic curve object for storing for the left or
  916        * first half of the subdivided curve
  917        * @param right the cubic curve object for storing for the right or
  918        * second half of the subdivided curve
  919        * @since 1.2
  920        */
  921       public void subdivide(CubicCurve2D left, CubicCurve2D right) {
  922           subdivide(this, left, right);
  923       }
  924   
  925       /**
  926        * Subdivides the cubic curve specified by the <code>src</code> parameter
  927        * and stores the resulting two subdivided curves into the
  928        * <code>left</code> and <code>right</code> curve parameters.
  929        * Either or both of the <code>left</code> and <code>right</code> objects
  930        * may be the same as the <code>src</code> object or <code>null</code>.
  931        * @param src the cubic curve to be subdivided
  932        * @param left the cubic curve object for storing the left or
  933        * first half of the subdivided curve
  934        * @param right the cubic curve object for storing the right or
  935        * second half of the subdivided curve
  936        * @since 1.2
  937        */
  938       public static void subdivide(CubicCurve2D src,
  939                                    CubicCurve2D left,
  940                                    CubicCurve2D right) {
  941           double x1 = src.getX1();
  942           double y1 = src.getY1();
  943           double ctrlx1 = src.getCtrlX1();
  944           double ctrly1 = src.getCtrlY1();
  945           double ctrlx2 = src.getCtrlX2();
  946           double ctrly2 = src.getCtrlY2();
  947           double x2 = src.getX2();
  948           double y2 = src.getY2();
  949           double centerx = (ctrlx1 + ctrlx2) / 2.0;
  950           double centery = (ctrly1 + ctrly2) / 2.0;
  951           ctrlx1 = (x1 + ctrlx1) / 2.0;
  952           ctrly1 = (y1 + ctrly1) / 2.0;
  953           ctrlx2 = (x2 + ctrlx2) / 2.0;
  954           ctrly2 = (y2 + ctrly2) / 2.0;
  955           double ctrlx12 = (ctrlx1 + centerx) / 2.0;
  956           double ctrly12 = (ctrly1 + centery) / 2.0;
  957           double ctrlx21 = (ctrlx2 + centerx) / 2.0;
  958           double ctrly21 = (ctrly2 + centery) / 2.0;
  959           centerx = (ctrlx12 + ctrlx21) / 2.0;
  960           centery = (ctrly12 + ctrly21) / 2.0;
  961           if (left != null) {
  962               left.setCurve(x1, y1, ctrlx1, ctrly1,
  963                             ctrlx12, ctrly12, centerx, centery);
  964           }
  965           if (right != null) {
  966               right.setCurve(centerx, centery, ctrlx21, ctrly21,
  967                              ctrlx2, ctrly2, x2, y2);
  968           }
  969       }
  970   
  971       /**
  972        * Subdivides the cubic curve specified by the coordinates
  973        * stored in the <code>src</code> array at indices <code>srcoff</code>
  974        * through (<code>srcoff</code>&nbsp;+&nbsp;7) and stores the
  975        * resulting two subdivided curves into the two result arrays at the
  976        * corresponding indices.
  977        * Either or both of the <code>left</code> and <code>right</code>
  978        * arrays may be <code>null</code> or a reference to the same array
  979        * as the <code>src</code> array.
  980        * Note that the last point in the first subdivided curve is the
  981        * same as the first point in the second subdivided curve. Thus,
  982        * it is possible to pass the same array for <code>left</code>
  983        * and <code>right</code> and to use offsets, such as <code>rightoff</code>
  984        * equals (<code>leftoff</code> + 6), in order
  985        * to avoid allocating extra storage for this common point.
  986        * @param src the array holding the coordinates for the source curve
  987        * @param srcoff the offset into the array of the beginning of the
  988        * the 6 source coordinates
  989        * @param left the array for storing the coordinates for the first
  990        * half of the subdivided curve
  991        * @param leftoff the offset into the array of the beginning of the
  992        * the 6 left coordinates
  993        * @param right the array for storing the coordinates for the second
  994        * half of the subdivided curve
  995        * @param rightoff the offset into the array of the beginning of the
  996        * the 6 right coordinates
  997        * @since 1.2
  998        */
  999       public static void subdivide(double src[], int srcoff,
 1000                                    double left[], int leftoff,
 1001                                    double right[], int rightoff) {
 1002           double x1 = src[srcoff + 0];
 1003           double y1 = src[srcoff + 1];
 1004           double ctrlx1 = src[srcoff + 2];
 1005           double ctrly1 = src[srcoff + 3];
 1006           double ctrlx2 = src[srcoff + 4];
 1007           double ctrly2 = src[srcoff + 5];
 1008           double x2 = src[srcoff + 6];
 1009           double y2 = src[srcoff + 7];
 1010           if (left != null) {
 1011               left[leftoff + 0] = x1;
 1012               left[leftoff + 1] = y1;
 1013           }
 1014           if (right != null) {
 1015               right[rightoff + 6] = x2;
 1016               right[rightoff + 7] = y2;
 1017           }
 1018           x1 = (x1 + ctrlx1) / 2.0;
 1019           y1 = (y1 + ctrly1) / 2.0;
 1020           x2 = (x2 + ctrlx2) / 2.0;
 1021           y2 = (y2 + ctrly2) / 2.0;
 1022           double centerx = (ctrlx1 + ctrlx2) / 2.0;
 1023           double centery = (ctrly1 + ctrly2) / 2.0;
 1024           ctrlx1 = (x1 + centerx) / 2.0;
 1025           ctrly1 = (y1 + centery) / 2.0;
 1026           ctrlx2 = (x2 + centerx) / 2.0;
 1027           ctrly2 = (y2 + centery) / 2.0;
 1028           centerx = (ctrlx1 + ctrlx2) / 2.0;
 1029           centery = (ctrly1 + ctrly2) / 2.0;
 1030           if (left != null) {
 1031               left[leftoff + 2] = x1;
 1032               left[leftoff + 3] = y1;
 1033               left[leftoff + 4] = ctrlx1;
 1034               left[leftoff + 5] = ctrly1;
 1035               left[leftoff + 6] = centerx;
 1036               left[leftoff + 7] = centery;
 1037           }
 1038           if (right != null) {
 1039               right[rightoff + 0] = centerx;
 1040               right[rightoff + 1] = centery;
 1041               right[rightoff + 2] = ctrlx2;
 1042               right[rightoff + 3] = ctrly2;
 1043               right[rightoff + 4] = x2;
 1044               right[rightoff + 5] = y2;
 1045           }
 1046       }
 1047   
 1048       /**
 1049        * Solves the cubic whose coefficients are in the <code>eqn</code>
 1050        * array and places the non-complex roots back into the same array,
 1051        * returning the number of roots.  The solved cubic is represented
 1052        * by the equation:
 1053        * <pre>
 1054        *     eqn = {c, b, a, d}
 1055        *     dx^3 + ax^2 + bx + c = 0
 1056        * </pre>
 1057        * A return value of -1 is used to distinguish a constant equation
 1058        * that might be always 0 or never 0 from an equation that has no
 1059        * zeroes.
 1060        * @param eqn an array containing coefficients for a cubic
 1061        * @return the number of roots, or -1 if the equation is a constant.
 1062        * @since 1.2
 1063        */
 1064       public static int solveCubic(double eqn[]) {
 1065           return solveCubic(eqn, eqn);
 1066       }
 1067   
 1068       /**
 1069        * Solve the cubic whose coefficients are in the <code>eqn</code>
 1070        * array and place the non-complex roots into the <code>res</code>
 1071        * array, returning the number of roots.
 1072        * The cubic solved is represented by the equation:
 1073        *     eqn = {c, b, a, d}
 1074        *     dx^3 + ax^2 + bx + c = 0
 1075        * A return value of -1 is used to distinguish a constant equation,
 1076        * which may be always 0 or never 0, from an equation which has no
 1077        * zeroes.
 1078        * @param eqn the specified array of coefficients to use to solve
 1079        *        the cubic equation
 1080        * @param res the array that contains the non-complex roots
 1081        *        resulting from the solution of the cubic equation
 1082        * @return the number of roots, or -1 if the equation is a constant
 1083        * @since 1.3
 1084        */
 1085       public static int solveCubic(double eqn[], double res[]) {
 1086           // From Numerical Recipes, 5.6, Quadratic and Cubic Equations
 1087           double d = eqn[3];
 1088           if (d == 0.0) {
 1089               // The cubic has degenerated to quadratic (or line or ...).
 1090               return QuadCurve2D.solveQuadratic(eqn, res);
 1091           }
 1092           double a = eqn[2] / d;
 1093           double b = eqn[1] / d;
 1094           double c = eqn[0] / d;
 1095           int roots = 0;
 1096           double Q = (a * a - 3.0 * b) / 9.0;
 1097           double R = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0;
 1098           double R2 = R * R;
 1099           double Q3 = Q * Q * Q;
 1100           a = a / 3.0;
 1101           if (R2 < Q3) {
 1102               double theta = Math.acos(R / Math.sqrt(Q3));
 1103               Q = -2.0 * Math.sqrt(Q);
 1104               if (res == eqn) {
 1105                   // Copy the eqn so that we don't clobber it with the
 1106                   // roots.  This is needed so that fixRoots can do its
 1107                   // work with the original equation.
 1108                   eqn = new double[4];
 1109                   System.arraycopy(res, 0, eqn, 0, 4);
 1110               }
 1111               res[roots++] = Q * Math.cos(theta / 3.0) - a;
 1112               res[roots++] = Q * Math.cos((theta + Math.PI * 2.0)/ 3.0) - a;
 1113               res[roots++] = Q * Math.cos((theta - Math.PI * 2.0)/ 3.0) - a;
 1114               fixRoots(res, eqn);
 1115           } else {
 1116               boolean neg = (R < 0.0);
 1117               double S = Math.sqrt(R2 - Q3);
 1118               if (neg) {
 1119                   R = -R;
 1120               }
 1121               double A = Math.pow(R + S, 1.0 / 3.0);
 1122               if (!neg) {
 1123                   A = -A;
 1124               }
 1125               double B = (A == 0.0) ? 0.0 : (Q / A);
 1126               res[roots++] = (A + B) - a;
 1127           }
 1128           return roots;
 1129       }
 1130   
 1131       /*
 1132        * This pruning step is necessary since solveCubic uses the
 1133        * cosine function to calculate the roots when there are 3
 1134        * of them.  Since the cosine method can have an error of
 1135        * +/- 1E-14 we need to make sure that we don't make any
 1136        * bad decisions due to an error.
 1137        *
 1138        * If the root is not near one of the endpoints, then we will
 1139        * only have a slight inaccuracy in calculating the x intercept
 1140        * which will only cause a slightly wrong answer for some
 1141        * points very close to the curve.  While the results in that
 1142        * case are not as accurate as they could be, they are not
 1143        * disastrously inaccurate either.
 1144        *
 1145        * On the other hand, if the error happens near one end of
 1146        * the curve, then our processing to reject values outside
 1147        * of the t=[0,1] range will fail and the results of that
 1148        * failure will be disastrous since for an entire horizontal
 1149        * range of test points, we will either overcount or undercount
 1150        * the crossings and get a wrong answer for all of them, even
 1151        * when they are clearly and obviously inside or outside the
 1152        * curve.
 1153        *
 1154        * To work around this problem, we try a couple of Newton-Raphson
 1155        * iterations to see if the true root is closer to the endpoint
 1156        * or further away.  If it is further away, then we can stop
 1157        * since we know we are on the right side of the endpoint.  If
 1158        * we change direction, then either we are now being dragged away
 1159        * from the endpoint in which case the first condition will cause
 1160        * us to stop, or we have passed the endpoint and are headed back.
 1161        * In the second case, we simply evaluate the slope at the
 1162        * endpoint itself and place ourselves on the appropriate side
 1163        * of it or on it depending on that result.
 1164        */
 1165       private static void fixRoots(double res[], double eqn[]) {
 1166           final double EPSILON = 1E-5;
 1167           for (int i = 0; i < 3; i++) {
 1168               double t = res[i];
 1169               if (Math.abs(t) < EPSILON) {
 1170                   res[i] = findZero(t, 0, eqn);
 1171               } else if (Math.abs(t - 1) < EPSILON) {
 1172                   res[i] = findZero(t, 1, eqn);
 1173               }
 1174           }
 1175       }
 1176   
 1177       private static double solveEqn(double eqn[], int order, double t) {
 1178           double v = eqn[order];
 1179           while (--order >= 0) {
 1180               v = v * t + eqn[order];
 1181           }
 1182           return v;
 1183       }
 1184   
 1185       private static double findZero(double t, double target, double eqn[]) {
 1186           double slopeqn[] = {eqn[1], 2*eqn[2], 3*eqn[3]};
 1187           double slope;
 1188           double origdelta = 0;
 1189           double origt = t;
 1190           while (true) {
 1191               slope = solveEqn(slopeqn, 2, t);
 1192               if (slope == 0) {
 1193                   // At a local minima - must return
 1194                   return t;
 1195               }
 1196               double y = solveEqn(eqn, 3, t);
 1197               if (y == 0) {
 1198                   // Found it! - return it
 1199                   return t;
 1200               }
 1201               // assert(slope != 0 && y != 0);
 1202               double delta = - (y / slope);
 1203               // assert(delta != 0);
 1204               if (origdelta == 0) {
 1205                   origdelta = delta;
 1206               }
 1207               if (t < target) {
 1208                   if (delta < 0) return t;
 1209               } else if (t > target) {
 1210                   if (delta > 0) return t;
 1211               } else { /* t == target */
 1212                   return (delta > 0
 1213                           ? (target + java.lang.Double.MIN_VALUE)
 1214                           : (target - java.lang.Double.MIN_VALUE));
 1215               }
 1216               double newt = t + delta;
 1217               if (t == newt) {
 1218                   // The deltas are so small that we aren't moving...
 1219                   return t;
 1220               }
 1221               if (delta * origdelta < 0) {
 1222                   // We have reversed our path.
 1223                   int tag = (origt < t
 1224                              ? getTag(target, origt, t)
 1225                              : getTag(target, t, origt));
 1226                   if (tag != INSIDE) {
 1227                       // Local minima found away from target - return the middle
 1228                       return (origt + t) / 2;
 1229                   }
 1230                   // Local minima somewhere near target - move to target
 1231                   // and let the slope determine the resulting t.
 1232                   t = target;
 1233               } else {
 1234                   t = newt;
 1235               }
 1236           }
 1237       }
 1238   
 1239       /**
 1240        * {@inheritDoc}
 1241        * @since 1.2
 1242        */
 1243       public boolean contains(double x, double y) {
 1244           if (!(x * 0.0 + y * 0.0 == 0.0)) {
 1245               /* Either x or y was infinite or NaN.
 1246                * A NaN always produces a negative response to any test
 1247                * and Infinity values cannot be "inside" any path so
 1248                * they should return false as well.
 1249                */
 1250               return false;
 1251           }
 1252           // We count the "Y" crossings to determine if the point is
 1253           // inside the curve bounded by its closing line.
 1254           double x1 = getX1();
 1255           double y1 = getY1();
 1256           double x2 = getX2();
 1257           double y2 = getY2();
 1258           int crossings =
 1259               (Curve.pointCrossingsForLine(x, y, x1, y1, x2, y2) +
 1260                Curve.pointCrossingsForCubic(x, y,
 1261                                             x1, y1,
 1262                                             getCtrlX1(), getCtrlY1(),
 1263                                             getCtrlX2(), getCtrlY2(),
 1264                                             x2, y2, 0));
 1265           return ((crossings & 1) == 1);
 1266       }
 1267   
 1268       /**
 1269        * {@inheritDoc}
 1270        * @since 1.2
 1271        */
 1272       public boolean contains(Point2D p) {
 1273           return contains(p.getX(), p.getY());
 1274       }
 1275   
 1276       /*
 1277        * Fill an array with the coefficients of the parametric equation
 1278        * in t, ready for solving against val with solveCubic.
 1279        * We currently have:
 1280        * <pre>
 1281        *   val = P(t) = C1(1-t)^3 + 3CP1 t(1-t)^2 + 3CP2 t^2(1-t) + C2 t^3
 1282        *              = C1 - 3C1t + 3C1t^2 - C1t^3 +
 1283        *                3CP1t - 6CP1t^2 + 3CP1t^3 +
 1284        *                3CP2t^2 - 3CP2t^3 +
 1285        *                C2t^3
 1286        *            0 = (C1 - val) +
 1287        *                (3CP1 - 3C1) t +
 1288        *                (3C1 - 6CP1 + 3CP2) t^2 +
 1289        *                (C2 - 3CP2 + 3CP1 - C1) t^3
 1290        *            0 = C + Bt + At^2 + Dt^3
 1291        *     C = C1 - val
 1292        *     B = 3*CP1 - 3*C1
 1293        *     A = 3*CP2 - 6*CP1 + 3*C1
 1294        *     D = C2 - 3*CP2 + 3*CP1 - C1
 1295        * </pre>
 1296        */
 1297       private static void fillEqn(double eqn[], double val,
 1298                                   double c1, double cp1, double cp2, double c2) {
 1299           eqn[0] = c1 - val;
 1300           eqn[1] = (cp1 - c1) * 3.0;
 1301           eqn[2] = (cp2 - cp1 - cp1 + c1) * 3.0;
 1302           eqn[3] = c2 + (cp1 - cp2) * 3.0 - c1;
 1303           return;
 1304       }
 1305   
 1306       /*
 1307        * Evaluate the t values in the first num slots of the vals[] array
 1308        * and place the evaluated values back into the same array.  Only
 1309        * evaluate t values that are within the range <0, 1>, including
 1310        * the 0 and 1 ends of the range iff the include0 or include1
 1311        * booleans are true.  If an "inflection" equation is handed in,
 1312        * then any points which represent a point of inflection for that
 1313        * cubic equation are also ignored.
 1314        */
 1315       private static int evalCubic(double vals[], int num,
 1316                                    boolean include0,
 1317                                    boolean include1,
 1318                                    double inflect[],
 1319                                    double c1, double cp1,
 1320                                    double cp2, double c2) {
 1321           int j = 0;
 1322           for (int i = 0; i < num; i++) {
 1323               double t = vals[i];
 1324               if ((include0 ? t >= 0 : t > 0) &&
 1325                   (include1 ? t <= 1 : t < 1) &&
 1326                   (inflect == null ||
 1327                    inflect[1] + (2*inflect[2] + 3*inflect[3]*t)*t != 0))
 1328               {
 1329                   double u = 1 - t;
 1330                   vals[j++] = c1*u*u*u + 3*cp1*t*u*u + 3*cp2*t*t*u + c2*t*t*t;
 1331               }
 1332           }
 1333           return j;
 1334       }
 1335   
 1336       private static final int BELOW = -2;
 1337       private static final int LOWEDGE = -1;
 1338       private static final int INSIDE = 0;
 1339       private static final int HIGHEDGE = 1;
 1340       private static final int ABOVE = 2;
 1341   
 1342       /*
 1343        * Determine where coord lies with respect to the range from
 1344        * low to high.  It is assumed that low <= high.  The return
 1345        * value is one of the 5 values BELOW, LOWEDGE, INSIDE, HIGHEDGE,
 1346        * or ABOVE.
 1347        */
 1348       private static int getTag(double coord, double low, double high) {
 1349           if (coord <= low) {
 1350               return (coord < low ? BELOW : LOWEDGE);
 1351           }
 1352           if (coord >= high) {
 1353               return (coord > high ? ABOVE : HIGHEDGE);
 1354           }
 1355           return INSIDE;
 1356       }
 1357   
 1358       /*
 1359        * Determine if the pttag represents a coordinate that is already
 1360        * in its test range, or is on the border with either of the two
 1361        * opttags representing another coordinate that is "towards the
 1362        * inside" of that test range.  In other words, are either of the
 1363        * two "opt" points "drawing the pt inward"?
 1364        */
 1365       private static boolean inwards(int pttag, int opt1tag, int opt2tag) {
 1366           switch (pttag) {
 1367           case BELOW:
 1368           case ABOVE:
 1369           default:
 1370               return false;
 1371           case LOWEDGE:
 1372               return (opt1tag >= INSIDE || opt2tag >= INSIDE);
 1373           case INSIDE:
 1374               return true;
 1375           case HIGHEDGE:
 1376               return (opt1tag <= INSIDE || opt2tag <= INSIDE);
 1377           }
 1378       }
 1379   
 1380       /**
 1381        * {@inheritDoc}
 1382        * @since 1.2
 1383        */
 1384       public boolean intersects(double x, double y, double w, double h) {
 1385           // Trivially reject non-existant rectangles
 1386           if (w <= 0 || h <= 0) {
 1387               return false;
 1388           }
 1389   
 1390           // Trivially accept if either endpoint is inside the rectangle
 1391           // (not on its border since it may end there and not go inside)
 1392           // Record where they lie with respect to the rectangle.
 1393           //     -1 => left, 0 => inside, 1 => right
 1394           double x1 = getX1();
 1395           double y1 = getY1();
 1396           int x1tag = getTag(x1, x, x+w);
 1397           int y1tag = getTag(y1, y, y+h);
 1398           if (x1tag == INSIDE && y1tag == INSIDE) {
 1399               return true;
 1400           }
 1401           double x2 = getX2();
 1402           double y2 = getY2();
 1403           int x2tag = getTag(x2, x, x+w);
 1404           int y2tag = getTag(y2, y, y+h);
 1405           if (x2tag == INSIDE && y2tag == INSIDE) {
 1406               return true;
 1407           }
 1408   
 1409           double ctrlx1 = getCtrlX1();
 1410           double ctrly1 = getCtrlY1();
 1411           double ctrlx2 = getCtrlX2();
 1412           double ctrly2 = getCtrlY2();
 1413           int ctrlx1tag = getTag(ctrlx1, x, x+w);
 1414           int ctrly1tag = getTag(ctrly1, y, y+h);
 1415           int ctrlx2tag = getTag(ctrlx2, x, x+w);
 1416           int ctrly2tag = getTag(ctrly2, y, y+h);
 1417   
 1418           // Trivially reject if all points are entirely to one side of
 1419           // the rectangle.
 1420           if (x1tag < INSIDE && x2tag < INSIDE &&
 1421               ctrlx1tag < INSIDE && ctrlx2tag < INSIDE)
 1422           {
 1423               return false;       // All points left
 1424           }
 1425           if (y1tag < INSIDE && y2tag < INSIDE &&
 1426               ctrly1tag < INSIDE && ctrly2tag < INSIDE)
 1427           {
 1428               return false;       // All points above
 1429           }
 1430           if (x1tag > INSIDE && x2tag > INSIDE &&
 1431               ctrlx1tag > INSIDE && ctrlx2tag > INSIDE)
 1432           {
 1433               return false;       // All points right
 1434           }
 1435           if (y1tag > INSIDE && y2tag > INSIDE &&
 1436               ctrly1tag > INSIDE && ctrly2tag > INSIDE)
 1437           {
 1438               return false;       // All points below
 1439           }
 1440   
 1441           // Test for endpoints on the edge where either the segment
 1442           // or the curve is headed "inwards" from them
 1443           // Note: These tests are a superset of the fast endpoint tests
 1444           //       above and thus repeat those tests, but take more time
 1445           //       and cover more cases
 1446           if (inwards(x1tag, x2tag, ctrlx1tag) &&
 1447               inwards(y1tag, y2tag, ctrly1tag))
 1448           {
 1449               // First endpoint on border with either edge moving inside
 1450               return true;
 1451           }
 1452           if (inwards(x2tag, x1tag, ctrlx2tag) &&
 1453               inwards(y2tag, y1tag, ctrly2tag))
 1454           {
 1455               // Second endpoint on border with either edge moving inside
 1456               return true;
 1457           }
 1458   
 1459           // Trivially accept if endpoints span directly across the rectangle
 1460           boolean xoverlap = (x1tag * x2tag <= 0);
 1461           boolean yoverlap = (y1tag * y2tag <= 0);
 1462           if (x1tag == INSIDE && x2tag == INSIDE && yoverlap) {
 1463               return true;
 1464           }
 1465           if (y1tag == INSIDE && y2tag == INSIDE && xoverlap) {
 1466               return true;
 1467           }
 1468   
 1469           // We now know that both endpoints are outside the rectangle
 1470           // but the 4 points are not all on one side of the rectangle.
 1471           // Therefore the curve cannot be contained inside the rectangle,
 1472           // but the rectangle might be contained inside the curve, or
 1473           // the curve might intersect the boundary of the rectangle.
 1474   
 1475           double[] eqn = new double[4];
 1476           double[] res = new double[4];
 1477           if (!yoverlap) {
 1478               // Both y coordinates for the closing segment are above or
 1479               // below the rectangle which means that we can only intersect
 1480               // if the curve crosses the top (or bottom) of the rectangle
 1481               // in more than one place and if those crossing locations
 1482               // span the horizontal range of the rectangle.
 1483               fillEqn(eqn, (y1tag < INSIDE ? y : y+h), y1, ctrly1, ctrly2, y2);
 1484               int num = solveCubic(eqn, res);
 1485               num = evalCubic(res, num, true, true, null,
 1486                               x1, ctrlx1, ctrlx2, x2);
 1487               // odd counts imply the crossing was out of [0,1] bounds
 1488               // otherwise there is no way for that part of the curve to
 1489               // "return" to meet its endpoint
 1490               return (num == 2 &&
 1491                       getTag(res[0], x, x+w) * getTag(res[1], x, x+w) <= 0);
 1492           }
 1493   
 1494           // Y ranges overlap.  Now we examine the X ranges
 1495           if (!xoverlap) {
 1496               // Both x coordinates for the closing segment are left of
 1497               // or right of the rectangle which means that we can only
 1498               // intersect if the curve crosses the left (or right) edge
 1499               // of the rectangle in more than one place and if those
 1500               // crossing locations span the vertical range of the rectangle.
 1501               fillEqn(eqn, (x1tag < INSIDE ? x : x+w), x1, ctrlx1, ctrlx2, x2);
 1502               int num = solveCubic(eqn, res);
 1503               num = evalCubic(res, num, true, true, null,
 1504                               y1, ctrly1, ctrly2, y2);
 1505               // odd counts imply the crossing was out of [0,1] bounds
 1506               // otherwise there is no way for that part of the curve to
 1507               // "return" to meet its endpoint
 1508               return (num == 2 &&
 1509                       getTag(res[0], y, y+h) * getTag(res[1], y, y+h) <= 0);
 1510           }
 1511   
 1512           // The X and Y ranges of the endpoints overlap the X and Y
 1513           // ranges of the rectangle, now find out how the endpoint
 1514           // line segment intersects the Y range of the rectangle
 1515           double dx = x2 - x1;
 1516           double dy = y2 - y1;
 1517           double k = y2 * x1 - x2 * y1;
 1518           int c1tag, c2tag;
 1519           if (y1tag == INSIDE) {
 1520               c1tag = x1tag;
 1521           } else {
 1522               c1tag = getTag((k + dx * (y1tag < INSIDE ? y : y+h)) / dy, x, x+w);
 1523           }
 1524           if (y2tag == INSIDE) {
 1525               c2tag = x2tag;
 1526           } else {
 1527               c2tag = getTag((k + dx * (y2tag < INSIDE ? y : y+h)) / dy, x, x+w);
 1528           }
 1529           // If the part of the line segment that intersects the Y range
 1530           // of the rectangle crosses it horizontally - trivially accept
 1531           if (c1tag * c2tag <= 0) {
 1532               return true;
 1533           }
 1534   
 1535           // Now we know that both the X and Y ranges intersect and that
 1536           // the endpoint line segment does not directly cross the rectangle.
 1537           //
 1538           // We can almost treat this case like one of the cases above
 1539           // where both endpoints are to one side, except that we may
 1540           // get one or three intersections of the curve with the vertical
 1541           // side of the rectangle.  This is because the endpoint segment
 1542           // accounts for the other intersection in an even pairing.  Thus,
 1543           // with the endpoint crossing we end up with 2 or 4 total crossings.
 1544           //
 1545           // (Remember there is overlap in both the X and Y ranges which
 1546           //  means that the segment itself must cross at least one vertical
 1547           //  edge of the rectangle - in particular, the "near vertical side"
 1548           //  - leaving an odd number of intersections for the curve.)
 1549           //
 1550           // Now we calculate the y tags of all the intersections on the
 1551           // "near vertical side" of the rectangle.  We will have one with
 1552           // the endpoint segment, and one or three with the curve.  If
 1553           // any pair of those vertical intersections overlap the Y range
 1554           // of the rectangle, we have an intersection.  Otherwise, we don't.
 1555   
 1556           // c1tag = vertical intersection class of the endpoint segment
 1557           //
 1558           // Choose the y tag of the endpoint that was not on the same
 1559           // side of the rectangle as the subsegment calculated above.
 1560           // Note that we can "steal" the existing Y tag of that endpoint
 1561           // since it will be provably the same as the vertical intersection.
 1562           c1tag = ((c1tag * x1tag <= 0) ? y1tag : y2tag);
 1563   
 1564           // Now we have to calculate an array of solutions of the curve
 1565           // with the "near vertical side" of the rectangle.  Then we
 1566           // need to sort the tags and do a pairwise range test to see
 1567           // if either of the pairs of crossings spans the Y range of
 1568           // the rectangle.
 1569           //
 1570           // Note that the c2tag can still tell us which vertical edge
 1571           // to test against.
 1572           fillEqn(eqn, (c2tag < INSIDE ? x : x+w), x1, ctrlx1, ctrlx2, x2);
 1573           int num = solveCubic(eqn, res);
 1574           num = evalCubic(res, num, true, true, null, y1, ctrly1, ctrly2, y2);
 1575   
 1576           // Now put all of the tags into a bucket and sort them.  There
 1577           // is an intersection iff one of the pairs of tags "spans" the
 1578           // Y range of the rectangle.
 1579           int tags[] = new int[num+1];
 1580           for (int i = 0; i < num; i++) {
 1581               tags[i] = getTag(res[i], y, y+h);
 1582           }
 1583           tags[num] = c1tag;
 1584           Arrays.sort(tags);
 1585           return ((num >= 1 && tags[0] * tags[1] <= 0) ||
 1586                   (num >= 3 && tags[2] * tags[3] <= 0));
 1587       }
 1588   
 1589       /**
 1590        * {@inheritDoc}
 1591        * @since 1.2
 1592        */
 1593       public boolean intersects(Rectangle2D r) {
 1594           return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
 1595       }
 1596   
 1597       /**
 1598        * {@inheritDoc}
 1599        * @since 1.2
 1600        */
 1601       public boolean contains(double x, double y, double w, double h) {
 1602           if (w <= 0 || h <= 0) {
 1603               return false;
 1604           }
 1605           // Assertion: Cubic curves closed by connecting their
 1606           // endpoints form either one or two convex halves with
 1607           // the closing line segment as an edge of both sides.
 1608           if (!(contains(x, y) &&
 1609                 contains(x + w, y) &&
 1610                 contains(x + w, y + h) &&
 1611                 contains(x, y + h))) {
 1612               return false;
 1613           }
 1614           // Either the rectangle is entirely inside one of the convex
 1615           // halves or it crosses from one to the other, in which case
 1616           // it must intersect the closing line segment.
 1617           Rectangle2D rect = new Rectangle2D.Double(x, y, w, h);
 1618           return !rect.intersectsLine(getX1(), getY1(), getX2(), getY2());
 1619       }
 1620   
 1621       /**
 1622        * {@inheritDoc}
 1623        * @since 1.2
 1624        */
 1625       public boolean contains(Rectangle2D r) {
 1626           return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
 1627       }
 1628   
 1629       /**
 1630        * {@inheritDoc}
 1631        * @since 1.2
 1632        */
 1633       public Rectangle getBounds() {
 1634           return getBounds2D().getBounds();
 1635       }
 1636   
 1637       /**
 1638        * Returns an iteration object that defines the boundary of the
 1639        * shape.
 1640        * The iterator for this class is not multi-threaded safe,
 1641        * which means that this <code>CubicCurve2D</code> class does not
 1642        * guarantee that modifications to the geometry of this
 1643        * <code>CubicCurve2D</code> object do not affect any iterations of
 1644        * that geometry that are already in process.
 1645        * @param at an optional <code>AffineTransform</code> to be applied to the
 1646        * coordinates as they are returned in the iteration, or <code>null</code>
 1647        * if untransformed coordinates are desired
 1648        * @return    the <code>PathIterator</code> object that returns the
 1649        *          geometry of the outline of this <code>CubicCurve2D</code>, one
 1650        *          segment at a time.
 1651        * @since 1.2
 1652        */
 1653       public PathIterator getPathIterator(AffineTransform at) {
 1654           return new CubicIterator(this, at);
 1655       }
 1656   
 1657       /**
 1658        * Return an iteration object that defines the boundary of the
 1659        * flattened shape.
 1660        * The iterator for this class is not multi-threaded safe,
 1661        * which means that this <code>CubicCurve2D</code> class does not
 1662        * guarantee that modifications to the geometry of this
 1663        * <code>CubicCurve2D</code> object do not affect any iterations of
 1664        * that geometry that are already in process.
 1665        * @param at an optional <code>AffineTransform</code> to be applied to the
 1666        * coordinates as they are returned in the iteration, or <code>null</code>
 1667        * if untransformed coordinates are desired
 1668        * @param flatness the maximum amount that the control points
 1669        * for a given curve can vary from colinear before a subdivided
 1670        * curve is replaced by a straight line connecting the end points
 1671        * @return    the <code>PathIterator</code> object that returns the
 1672        * geometry of the outline of this <code>CubicCurve2D</code>,
 1673        * one segment at a time.
 1674        * @since 1.2
 1675        */
 1676       public PathIterator getPathIterator(AffineTransform at, double flatness) {
 1677           return new FlatteningPathIterator(getPathIterator(at), flatness);
 1678       }
 1679   
 1680       /**
 1681        * Creates a new object of the same class as this object.
 1682        *
 1683        * @return     a clone of this instance.
 1684        * @exception  OutOfMemoryError            if there is not enough memory.
 1685        * @see        java.lang.Cloneable
 1686        * @since      1.2
 1687        */
 1688       public Object clone() {
 1689           try {
 1690               return super.clone();
 1691           } catch (CloneNotSupportedException e) {
 1692               // this shouldn't happen, since we are Cloneable
 1693               throw new InternalError();
 1694           }
 1695       }
 1696   }

Save This Page
Home » openjdk-7 » java » awt » geom » [javadoc | source]