home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / geom / CubicCurve2D.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  28.5 KB  |  1,019 lines

  1. /*
  2.  * @(#)CubicCurve2D.java    1.10 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.awt.geom;
  16.  
  17. import java.awt.Shape;
  18. import java.awt.Rectangle;
  19.  
  20. /**
  21.  * A cubic parametric curve segment in (x, y) coordinate space.
  22.  * <p>
  23.  * This class is only the abstract superclass for all objects which
  24.  * store a 2D cubic curve segment.
  25.  * The actual storage representation of the coordinates is left to
  26.  * the subclass.
  27.  *
  28.  * @version 10 Feb 1997
  29.  * @author    Jim Graham
  30.  */
  31. public abstract class CubicCurve2D implements Shape, Cloneable {
  32.     /**
  33.      * A cubic parametric curve segment specified with float coordinates.
  34.      */
  35.     public static class Float extends CubicCurve2D {
  36.     /**
  37.      * The X coordinate of the start point
  38.      * of the cubic curve segment.
  39.      */
  40.     public float x1;
  41.  
  42.     /**
  43.      * The Y coordinate of the start point
  44.      * of the cubic curve segment.
  45.      */
  46.     public float y1;
  47.  
  48.     /**
  49.      * The X coordinate of the first control point
  50.      * of the cubic curve segment.
  51.      */
  52.     public float ctrlx1;
  53.  
  54.     /**
  55.      * The Y coordinate of the first control point
  56.      * of the cubic curve segment.
  57.      */
  58.     public float ctrly1;
  59.  
  60.     /**
  61.      * The X coordinate of the second control point
  62.      * of the cubic curve segment.
  63.      */
  64.     public float ctrlx2;
  65.  
  66.     /**
  67.      * The Y coordinate of the second control point
  68.      * of the cubic curve segment.
  69.      */
  70.     public float ctrly2;
  71.  
  72.     /**
  73.      * The X coordinate of the end point
  74.      * of the cubic curve segment.
  75.      */
  76.     public float x2;
  77.  
  78.     /**
  79.      * The Y coordinate of the end point
  80.      * of the cubic curve segment.
  81.      */
  82.     public float y2;
  83.  
  84.     /**
  85.      * Constructs and initializes a CubicCurve with coordinates
  86.      * (0, 0, 0, 0, 0, 0).
  87.      */
  88.     public Float() {
  89.     }
  90.  
  91.     /**
  92.      * Constructs and initializes a CubicCurve from
  93.      * the specified coordinates.
  94.      */
  95.     public Float(float x1, float y1,
  96.                    float ctrlx1, float ctrly1,
  97.                    float ctrlx2, float ctrly2,
  98.                    float x2, float y2) {
  99.         setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
  100.     }
  101.  
  102.     /**
  103.      * Returns the X coordinate of the start point
  104.      * in double precision.
  105.      */
  106.     public double getX1() {
  107.         return (double) x1;
  108.     }
  109.  
  110.     /**
  111.      * Returns the Y coordinate of the start point 
  112.      * in double precision.
  113.      */
  114.     public double getY1() {
  115.         return (double) y1;
  116.     }
  117.  
  118.     /**
  119.      * Returns the X coordinate of the first control point 
  120.      * in double precision.
  121.      */
  122.     public double getCtrlX1() {
  123.         return (double) ctrlx1;
  124.     }
  125.  
  126.     /**
  127.      * Returns the Y coordinate of the first control point 
  128.      * in double precision.
  129.      */
  130.     public double getCtrlY1() {
  131.         return (double) ctrly1;
  132.     }
  133.  
  134.     /**
  135.      * Returns the X coordinate of the second control point
  136.      * in double precision.
  137.      */
  138.     public double getCtrlX2() {
  139.         return (double) ctrlx2;
  140.     }
  141.  
  142.     /**
  143.      * Returns the Y coordinate of the second control point
  144.      * in double precision.
  145.      */
  146.     public double getCtrlY2() {
  147.         return (double) ctrly2;
  148.     }
  149.  
  150.     /**
  151.      * Returns the X coordinate of the end point
  152.      * in double precision.
  153.      */
  154.     public double getX2() {
  155.         return (double) x2;
  156.     }
  157.  
  158.     /**
  159.      * Returns the Y coordinate of the end point 
  160.      * in double precision.
  161.      */
  162.     public double getY2() {
  163.         return (double) y2;
  164.     }
  165.  
  166.     /**
  167.      * Sets the location of the endpoints and controlpoints
  168.      * of this curve to the specified double coordinates.
  169.      */
  170.     public void setCurve(double x1, double y1,
  171.                  double ctrlx1, double ctrly1,
  172.                  double ctrlx2, double ctrly2,
  173.                  double x2, double y2) {
  174.         this.x1     = (float) x1;
  175.         this.y1     = (float) y1;
  176.         this.ctrlx1 = (float) ctrlx1;
  177.         this.ctrly1 = (float) ctrly1;
  178.         this.ctrlx2 = (float) ctrlx2;
  179.         this.ctrly2 = (float) ctrly2;
  180.         this.x2     = (float) x2;
  181.         this.y2     = (float) y2;
  182.     }
  183.  
  184.     /**
  185.      * Sets the location of the endpoints and controlpoints
  186.      * of this curve to the specified float coordinates.
  187.      */
  188.     public void setCurve(float x1, float y1,
  189.                  float ctrlx1, float ctrly1,
  190.                  float ctrlx2, float ctrly2,
  191.                  float x2, float y2) {
  192.         this.x1     = x1;
  193.         this.y1     = y1;
  194.         this.ctrlx1 = ctrlx1;
  195.         this.ctrly1 = ctrly1;
  196.         this.ctrlx2 = ctrlx2;
  197.         this.ctrly2 = ctrly2;
  198.         this.x2     = x2;
  199.         this.y2     = y2;
  200.     }
  201.  
  202.     /**
  203.      * Return the bounding box of the shape.
  204.      */
  205.     public Rectangle2D getBounds2D() {
  206.         float left   = Math.min(Math.min(x1, x2),
  207.                     Math.min(ctrlx1, ctrlx2));
  208.         float top    = Math.min(Math.min(y1, y2),
  209.                     Math.min(ctrly1, ctrly2));
  210.         float right  = Math.max(Math.max(x1, x2),
  211.                     Math.max(ctrlx1, ctrlx2));
  212.         float bottom = Math.max(Math.max(y1, y2),
  213.                     Math.max(ctrly1, ctrly2));
  214.         return new Rectangle2D.Float(left, top,
  215.                      right - left, bottom - top);
  216.     }
  217.     }
  218.  
  219.     /**
  220.      * A cubic parametric curve segment specified with double coordinates.
  221.      */
  222.     public static class Double extends CubicCurve2D {
  223.     /**
  224.      * The X coordinate of the start point
  225.      * of the cubic curve segment.
  226.      */
  227.     public double x1;
  228.  
  229.     /**
  230.      * The Y coordinate of the start point
  231.      * of the cubic curve segment.
  232.      */
  233.     public double y1;
  234.  
  235.     /**
  236.      * The X coordinate of the first control point
  237.      * of the cubic curve segment.
  238.      */
  239.     public double ctrlx1;
  240.  
  241.     /**
  242.      * The Y coordinate of the first control point
  243.      * of the cubic curve segment.
  244.      */
  245.     public double ctrly1;
  246.  
  247.     /**
  248.      * The X coordinate of the second control point
  249.      * of the cubic curve segment.
  250.      */
  251.     public double ctrlx2;
  252.  
  253.     /**
  254.      * The Y coordinate of the second control point
  255.      * of the cubic curve segment.
  256.      */
  257.     public double ctrly2;
  258.  
  259.     /**
  260.      * The X coordinate of the end point
  261.      * of the cubic curve segment.
  262.      */
  263.     public double x2;
  264.  
  265.     /**
  266.      * The Y coordinate of the end point
  267.      * of the cubic curve segment.
  268.      */
  269.     public double y2;
  270.  
  271.     /**
  272.      * Constructs and initializes a CubicCurve with coordinates
  273.      * (0, 0, 0, 0, 0, 0).
  274.      */
  275.     public Double() {
  276.     }
  277.  
  278.     /**
  279.      * Constructs and initializes a CubicCurve from
  280.      * the specified coordinates.
  281.      */
  282.     public Double(double x1, double y1,
  283.               double ctrlx1, double ctrly1,
  284.               double ctrlx2, double ctrly2,
  285.               double x2, double y2) {
  286.         setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
  287.     }
  288.  
  289.     /**
  290.      * Returns the X coordinate of the start point
  291.      * in double precision.
  292.      */
  293.     public double getX1() {
  294.         return x1;
  295.     }
  296.  
  297.     /**
  298.      * Returns the Y coordinate of the start point 
  299.      * in double precision.
  300.      */
  301.     public double getY1() {
  302.         return y1;
  303.     }
  304.  
  305.     /**
  306.      * Returns the X coordinate of the first control point 
  307.      * in double precision.
  308.      */
  309.     public double getCtrlX1() {
  310.         return ctrlx1;
  311.     }
  312.  
  313.     /**
  314.      * Returns the Y coordinate of the first control point 
  315.      * in double precision.
  316.      */
  317.     public double getCtrlY1() {
  318.         return ctrly1;
  319.     }
  320.  
  321.     /**
  322.      * Returns the X coordinate of the second control point
  323.      * in double precision.
  324.      */
  325.     public double getCtrlX2() {
  326.         return ctrlx2;
  327.     }
  328.  
  329.     /**
  330.      * Returns the Y coordinate of the second control point
  331.      * in double precision.
  332.      */
  333.     public double getCtrlY2() {
  334.         return ctrly2;
  335.     }
  336.  
  337.     /**
  338.      * Returns the X coordinate of the end point
  339.      * in double precision.
  340.      */
  341.     public double getX2() {
  342.         return x2;
  343.     }
  344.  
  345.     /**
  346.      * Returns the Y coordinate of the end point 
  347.      * in double precision.
  348.      */
  349.     public double getY2() {
  350.         return y2;
  351.     }
  352.  
  353.     /**
  354.      * Sets the location of the endpoints and controlpoints
  355.      * of this curve to the specified double coordinates.
  356.      */
  357.     public void setCurve(double x1, double y1,
  358.                  double ctrlx1, double ctrly1,
  359.                  double ctrlx2, double ctrly2,
  360.                  double x2, double y2) {
  361.         this.x1     = x1;
  362.         this.y1     = y1;
  363.         this.ctrlx1 = ctrlx1;
  364.         this.ctrly1 = ctrly1;
  365.         this.ctrlx2 = ctrlx2;
  366.         this.ctrly2 = ctrly2;
  367.         this.x2     = x2;
  368.         this.y2     = y2;
  369.     }
  370.  
  371.     /**
  372.      * Return the bounding box of the shape.
  373.      */
  374.     public Rectangle2D getBounds2D() {
  375.         double left   = Math.min(Math.min(x1, x2),
  376.                      Math.min(ctrlx1, ctrlx2));
  377.         double top    = Math.min(Math.min(y1, y2),
  378.                      Math.min(ctrly1, ctrly2));
  379.         double right  = Math.max(Math.max(x1, x2),
  380.                      Math.max(ctrlx1, ctrlx2));
  381.         double bottom = Math.max(Math.max(y1, y2),
  382.                      Math.max(ctrly1, ctrly2));
  383.         return new Rectangle2D.Double(left, top,
  384.                       right - left, bottom - top);
  385.     }
  386.     }
  387.  
  388.     protected CubicCurve2D() {
  389.     }
  390.  
  391.     /**
  392.      * Returns the X coordinate of the start point in double precision.
  393.      */
  394.     public abstract double getX1();
  395.  
  396.     /**
  397.      * Returns the Y coordinate of the start point in double precision.
  398.      */
  399.     public abstract double getY1();
  400.  
  401.     /**
  402.      * Returns the X coordinate of the first control point in double precision.
  403.      */
  404.     public abstract double getCtrlX1();
  405.  
  406.     /**
  407.      * Returns the Y coordinate of the first control point in double precision.
  408.      */
  409.     public abstract double getCtrlY1();
  410.  
  411.     /**
  412.      * Returns the X coordinate of the second control point
  413.      * in double precision.
  414.      */
  415.     public abstract double getCtrlX2();
  416.  
  417.     /**
  418.      * Returns the Y coordinate of the second control point
  419.      * in double precision.
  420.      */
  421.     public abstract double getCtrlY2();
  422.  
  423.     /**
  424.      * Returns the X coordinate of the end point in double precision.
  425.      */
  426.     public abstract double getX2();
  427.  
  428.     /**
  429.      * Returns the Y coordinate of the end point in double precision.
  430.      */
  431.     public abstract double getY2();
  432.  
  433.     /**
  434.      * Sets the location of the endpoints and controlpoints of this curve
  435.      * to the specified double coordinates.
  436.      */
  437.     public abstract void setCurve(double x1, double y1,
  438.                   double ctrlx1, double ctrly1,
  439.                   double ctrlx2, double ctrly2,
  440.                   double x2, double y2);
  441.  
  442.     /**
  443.      * Sets the location of the endpoints and controlpoints of this curve
  444.      * to the double coordinates at the specified offset in the specified
  445.      * array.
  446.      */
  447.     public void setCurve(double[] coords, int offset) {
  448.     setCurve(coords[offset + 0], coords[offset + 1],
  449.          coords[offset + 2], coords[offset + 3],
  450.          coords[offset + 4], coords[offset + 5],
  451.          coords[offset + 6], coords[offset + 7]);
  452.     }
  453.  
  454.     /**
  455.      * Sets the location of the endpoints and controlpoints of this curve
  456.      * to the specified Point coordinates.
  457.      */
  458.     public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) {
  459.     setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(),
  460.          cp2.getX(), cp2.getY(), p2.getX(), p2.getY());
  461.     }
  462.  
  463.     /**
  464.      * Sets the location of the endpoints and controlpoints of this curve
  465.      * to the coordinates of the Point objects at the specified offset in
  466.      * the specified array.
  467.      */
  468.     public void setCurve(Point2D[] pts, int offset) {
  469.     setCurve(pts[offset + 0].getX(), pts[offset + 0].getY(),
  470.          pts[offset + 1].getX(), pts[offset + 1].getY(),
  471.          pts[offset + 2].getX(), pts[offset + 2].getY(),
  472.          pts[offset + 3].getX(), pts[offset + 3].getY());
  473.     }
  474.  
  475.     /**
  476.      * Sets the location of the endpoints and controlpoints of this curve
  477.      * to the same as those in the specified CubicCurve.
  478.      */
  479.     public void setCurve(CubicCurve2D c) {
  480.     setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(),
  481.          c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2());
  482.     }
  483.  
  484.     /**
  485.      * Returns the square of the flatness, or maximum distance of a
  486.      * controlpoint from the line connecting the endpoints, of the
  487.      * cubic curve specified by the indicated controlpoints.
  488.      */
  489.     public static double getFlatnessSq(double x1, double y1,
  490.                        double ctrlx1, double ctrly1,
  491.                        double ctrlx2, double ctrly2,
  492.                        double x2, double y2) {
  493.     return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1, ctrly1),
  494.             Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx2, ctrly2));
  495.             
  496.     }
  497.  
  498.     /**
  499.      * Returns the flatness, or maximum distance of a
  500.      * controlpoint from the line connecting the endpoints, of the
  501.      * cubic curve specified by the indicated controlpoints.
  502.      */
  503.     public static double getFlatness(double x1, double y1,
  504.                      double ctrlx1, double ctrly1,
  505.                      double ctrlx2, double ctrly2,
  506.                      double x2, double y2) {
  507.     return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1,
  508.                        ctrlx2, ctrly2, x2, y2));
  509.     }
  510.  
  511.     /**
  512.      * Returns the square of the flatness, or maximum distance of a
  513.      * controlpoint from the line connecting the endpoints, of the
  514.      * cubic curve specified by the controlpoints stored in the
  515.      * indicated array at the indicated index.
  516.      */
  517.     public static double getFlatnessSq(double coords[], int offset) {
  518.     return getFlatnessSq(coords[offset + 0], coords[offset + 1],
  519.                  coords[offset + 2], coords[offset + 3],
  520.                  coords[offset + 4], coords[offset + 5],
  521.                  coords[offset + 6], coords[offset + 7]);
  522.     }
  523.  
  524.     /**
  525.      * Returns the flatness, or maximum distance of a
  526.      * controlpoint from the line connecting the endpoints, of the
  527.      * cubic curve specified by the controlpoints stored in the
  528.      * indicated array at the indicated index.
  529.      */
  530.     public static double getFlatness(double coords[], int offset) {
  531.     return getFlatness(coords[offset + 0], coords[offset + 1],
  532.                coords[offset + 2], coords[offset + 3],
  533.                coords[offset + 4], coords[offset + 5],
  534.                coords[offset + 6], coords[offset + 7]);
  535.     }
  536.  
  537.     /**
  538.      * Returns the square of the flatness, or maximum distance of a
  539.      * controlpoint from the line connecting the endpoints, of this curve.
  540.      */
  541.     public double getFlatnessSq() {
  542.     return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
  543.                  getCtrlX2(), getCtrlY2(), getX2(), getY2());
  544.     }
  545.  
  546.     /**
  547.      * Returns the flatness, or maximum distance of a
  548.      * controlpoint from the line connecting the endpoints, of this curve.
  549.      */
  550.     public double getFlatness() {
  551.     return getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
  552.                getCtrlX2(), getCtrlY2(), getX2(), getY2());
  553.     }
  554.  
  555.     /**
  556.      * Subdivides this cubic curve and stores the resulting two
  557.      * subdivided curves into the left and right curve parameters.
  558.      * Either or both of the left and right objects may be the same
  559.      * as this object or null.
  560.      * @param left the cubic curve object for storing for the left or
  561.      * first half of the subdivided curve
  562.      * @param right the cubic curve object for storing for the right or
  563.      * second half of the subdivided curve
  564.      */
  565.     public void subdivide(CubicCurve2D left, CubicCurve2D right) {
  566.     subdivide(this, left, right);
  567.     }
  568.  
  569.     /**
  570.      * Subdivides the cubic curve specified by the src parameter
  571.      * and stores the resulting two subdivided curves into the left
  572.      * and right curve parameters.
  573.      * Either or both of the left and right objects may be the same
  574.      * as the src object or null.
  575.      * @param src the cubic curve to be subdivided
  576.      * @param left the cubic curve object for storing for the left or
  577.      * first half of the subdivided curve
  578.      * @param right the cubic curve object for storing for the right or
  579.      * second half of the subdivided curve
  580.      */
  581.     public static void subdivide(CubicCurve2D src,
  582.                  CubicCurve2D left,
  583.                  CubicCurve2D right) {
  584.     double x1 = src.getX1();
  585.     double y1 = src.getY1();
  586.     double ctrlx1 = src.getCtrlX1();
  587.     double ctrly1 = src.getCtrlY1();
  588.     double ctrlx2 = src.getCtrlX2();
  589.     double ctrly2 = src.getCtrlY2();
  590.     double x2 = src.getX2();
  591.     double y2 = src.getY2();
  592.     double centerx = (ctrlx1 + ctrlx2) / 2.0;
  593.     double centery = (ctrly1 + ctrly2) / 2.0;
  594.     ctrlx1 = (x1 + ctrlx1) / 2.0;
  595.     ctrly1 = (y1 + ctrly1) / 2.0;
  596.     ctrlx2 = (x2 + ctrlx2) / 2.0;
  597.     ctrly2 = (y2 + ctrly2) / 2.0;
  598.     double ctrlx12 = (ctrlx1 + centerx) / 2.0;
  599.     double ctrly12 = (ctrly1 + centery) / 2.0;
  600.     double ctrlx21 = (ctrlx2 + centerx) / 2.0;
  601.     double ctrly21 = (ctrly2 + centery) / 2.0;
  602.     centerx = (ctrlx12 + ctrlx21) / 2.0;
  603.     centery = (ctrly12 + ctrly21) / 2.0;
  604.     if (left != null) {
  605.         left.setCurve(x1, y1, ctrlx1, ctrly1,
  606.               ctrlx12, ctrly12, centerx, centery);
  607.     }
  608.     if (right != null) {
  609.         right.setCurve(centerx, centery, ctrlx21, ctrly21,
  610.                ctrlx2, ctrly2, x2, y2);
  611.     }
  612.     }
  613.  
  614.     /**
  615.      * Subdivides the cubic curve specified by the the coordinates
  616.      * stored in the src array at indices (srcoff) through (srcoff + 7)
  617.      * and stores the resulting two subdivided curves into the two
  618.      * result arrays at the corresponding indices.
  619.      * Either or both of the left and right arrays may be null or a
  620.      * reference to the same array as the src array.
  621.      * Note that the last point in the first subdivided curve is the
  622.      * same as the first point in the second subdivided curve and thus
  623.      * it is possible to pass the same array for left and right and
  624.      * to use offsets such that rightoff equals (leftoff + 6) in order
  625.      * to avoid allocating extra storage for this common point.
  626.      * @param src the array holding the coordinates for the source curve
  627.      * @param srcoff the offset into the array of the beginning of the
  628.      * the 6 source coordinates
  629.      * @param left the array for storing the coordinates for the first
  630.      * half of the subdivided curve
  631.      * @param leftoff the offset into the array of the beginning of the
  632.      * the 6 left coordinates
  633.      * @param right the array for storing the coordinates for the second
  634.      * half of the subdivided curve
  635.      * @param rightoff the offset into the array of the beginning of the
  636.      * the 6 right coordinates
  637.      */
  638.     public static void subdivide(double src[], int srcoff,
  639.                  double left[], int leftoff,
  640.                  double right[], int rightoff) {
  641.     double x1 = src[srcoff + 0];
  642.     double y1 = src[srcoff + 1];
  643.     double ctrlx1 = src[srcoff + 2];
  644.     double ctrly1 = src[srcoff + 3];
  645.     double ctrlx2 = src[srcoff + 4];
  646.     double ctrly2 = src[srcoff + 5];
  647.     double x2 = src[srcoff + 6];
  648.     double y2 = src[srcoff + 7];
  649.     if (left != null) {
  650.         left[leftoff + 0] = x1;
  651.         left[leftoff + 1] = y1;
  652.     }
  653.     if (right != null) {
  654.         right[rightoff + 6] = x2;
  655.         right[rightoff + 7] = y2;
  656.     }
  657.     x1 = (x1 + ctrlx1) / 2.0;
  658.     y1 = (y1 + ctrly1) / 2.0;
  659.     x2 = (x2 + ctrlx2) / 2.0;
  660.     y2 = (y2 + ctrly2) / 2.0;
  661.     double centerx = (ctrlx1 + ctrlx2) / 2.0;
  662.     double centery = (ctrly1 + ctrly2) / 2.0;
  663.     ctrlx1 = (x1 + centerx) / 2.0;
  664.     ctrly1 = (y1 + centery) / 2.0;
  665.     ctrlx2 = (x2 + centerx) / 2.0;
  666.     ctrly2 = (y2 + centery) / 2.0;
  667.     centerx = (ctrlx1 + ctrlx2) / 2.0;
  668.     centery = (ctrly1 + ctrly2) / 2.0;
  669.     if (left != null) {
  670.         left[leftoff + 2] = x1;
  671.         left[leftoff + 3] = y1;
  672.         left[leftoff + 4] = ctrlx1;
  673.         left[leftoff + 5] = ctrly1;
  674.         left[leftoff + 6] = centerx;
  675.         left[leftoff + 7] = centery;
  676.     }
  677.     if (right != null) {
  678.         right[rightoff + 0] = centerx;
  679.         right[rightoff + 1] = centery;
  680.         right[rightoff + 2] = ctrlx2;
  681.         right[rightoff + 3] = ctrly2;
  682.         right[rightoff + 4] = x2;
  683.         right[rightoff + 5] = y2;
  684.     }
  685.     }
  686.  
  687.     /**
  688.      * Solve the cubic whose coefficients are in the eqn array and
  689.      * place the non-complex roots back into the array, returning the
  690.      * number of roots.  The quadratic solved is represented by the
  691.      * equation:
  692.      *     eqn = {c, b, a, d}
  693.      *     dx^3 + ax^2 + bx + c = 0
  694.      * A return value of -1 is used to distinguish a constant equation,
  695.      * which may be always 0 or never 0, from an equation which has no
  696.      * zeroes.
  697.      * @return the number of roots, or -1 if the equation is a constant
  698.      */
  699.     public static int solveCubic(double eqn[]) {
  700.     // From Numerical Recipes, 5.6, Quadratic and Cubic Equations
  701.     double d = eqn[3];
  702.     if (d == 0.0) {
  703.         // The cubic has degenerated to quadratic (or line or ...).
  704.         return QuadCurve2D.solveQuadratic(eqn);
  705.     }
  706.     double a = eqn[2] / d;
  707.     double b = eqn[1] / d;
  708.     double c = eqn[0] / d;
  709.     int roots = 0;
  710.     double Q = (a * a - 3.0 * b) / 9.0;
  711.     double R = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0;
  712.     double R2 = R * R;
  713.     double Q3 = Q * Q * Q;
  714.     a = a / 3.0;
  715.     if (R2 < Q3) {
  716.         double theta = Math.acos(R / Math.sqrt(Q3));
  717.         Q = -2.0 * Math.sqrt(Q);
  718.         eqn[roots++] = Q * Math.cos(theta / 3.0) - a;
  719.         eqn[roots++] = Q * Math.cos((theta + Math.PI * 2.0)/ 3.0) - a;
  720.         eqn[roots++] = Q * Math.cos((theta - Math.PI * 2.0)/ 3.0) - a;
  721.     } else {
  722.         boolean neg = (R < 0.0);
  723.         double S = Math.sqrt(R2 - Q3);
  724.         if (neg) {
  725.         R = -R;
  726.         }
  727.         double A = Math.pow(R + S, 1.0 / 3.0);
  728.         if (!neg) {
  729.         A = -A;
  730.         }
  731.         double B = (A == 0.0) ? 0.0 : (Q / A);
  732.         eqn[roots++] = (A + B) - a;
  733.     }
  734.     return roots;
  735.     }
  736.  
  737.     /**
  738.      * Test if a given coordinate is inside the boundary of the shape.
  739.      */
  740.     public boolean contains(double x, double y) {
  741.     // We count the "Y" crossings to determine if the point is
  742.     // inside the curve bounded by its closing line.
  743.     int crossings = 0;
  744.     double x1 = getX1();
  745.     double y1 = getY1();
  746.     double x2 = getX2();
  747.     double y2 = getY2();
  748.     // First check for a crossing of the line connecting the endpoints
  749.     double dy = y2 - y1;
  750.     if ((dy > 0.0 && y >= y1 && y <= y2) ||
  751.         (dy < 0.0 && y <= y1 && y >= y2))
  752.     {
  753.         if (x <= x1 + (y - y1) * (x2 - x1) / dy) {
  754.         crossings++;
  755.         }
  756.     }
  757.     // Solve the Y parametric equation for intersections with y
  758.     // Since the points at t = 0.0 and t = 1.0 were already
  759.     // checked by the line test above, we are only interested
  760.     // in solutions in the range (0,1)
  761.     // We currently have:
  762.     //     y = Py(t) = y1(1-t)^3 + 3cy1 t(1-t)^2 + 3cy2 t^2(1-t) + y2 t^3
  763.     //               = y1 - 3y1t + 3y1t^2 - y1t^3 +
  764.     //                 3cy1t - 6cy1t^2 + 3cy1t^3 +
  765.     //                 3cy2t^2 - 3cy2t^3 +
  766.     //                 y2t^3
  767.     //             0 = (y1 - y) +
  768.     //                 (3cy1 - 3y1) t +
  769.     //                 (3y1 - 6cy1 + 3cy2) t^2 +
  770.     //                 (y2 - 3cy2 + 3cy1 - y1) t^3
  771.     //             0 = C + Bt + At^2 + Dt^3
  772.     double ctrlx1 = getCtrlX1();
  773.     double ctrly1 = getCtrlY1();
  774.     double ctrlx2 = getCtrlX2();
  775.     double ctrly2 = getCtrlY2();
  776.     double eqn[] = {y1 - y,
  777.             (ctrly1 - y1) * 3.0,
  778.             (y1 - ctrly1 - ctrly1 + ctrly2) * 3.0,
  779.             y2 + 3.0 * (ctrly1 - ctrly2) - y1};
  780.     int roots = solveCubic(eqn);
  781.     while (--roots >= 0) {
  782.         double t = eqn[roots];
  783.         if (t > 0.0 && t < 1.0) {
  784.         double u = 1.0 - t;
  785.         if (x <= (x1 * u * u * u
  786.               + 3.0 * ctrlx1 * t * u * u
  787.               + 3.0 * ctrlx2 * t * t * u
  788.               + x2 * t * t * t)) {
  789.             crossings++;
  790.         }
  791.         }
  792.     }
  793.     return ((crossings & 1) == 1);
  794.     }
  795.  
  796.     /**
  797.      * Test if a given Point is inside the boundary of the shape.
  798.      */
  799.     public boolean contains(Point2D p) {
  800.     return contains(p.getX(), p.getY());
  801.     }
  802.  
  803.     /**
  804.      * Test if the Shape intersects the interior of a given
  805.      * set of rectangular coordinates.
  806.      */
  807.     public boolean intersects(double x, double y, double w, double h) {
  808.  
  809.       double temp;
  810.       double count = 0;
  811.  
  812.       double[] eqn = new double[4];
  813.       double[] backup = new double[4];
  814.       int result = 0;
  815.  
  816.       /*
  817.         The first test is fast and so in certain instances 
  818.         will return an answer very quickly
  819.         It can be dispensed with if need be, 
  820.         as the second test will always return the correct result
  821.         */
  822.  
  823.       if ((getX1() >= x) && (getY1() >= y) && (getX1() <= (x+w)) 
  824.           && (getY1() <= (y+h))) {
  825.     count++;
  826.       }
  827.       if ((getCtrlX1() >= x) && (getCtrlY1() >= y) && (getCtrlX1() < (x+w)) 
  828.           && (getCtrlY1() < (y+h))) {
  829.     count++;
  830.       }
  831.       if ((getX2() >= x) && (getY2() >= y) && (getX2() < (x+w)) 
  832.           && (getY2() < (y+h))) {
  833.     count++;
  834.       }
  835.       if ((getCtrlX2() >= x) && (getCtrlY2() >= y) && (getCtrlX2() < (x+w)) 
  836.           && (getCtrlY2() < (y+h))) {
  837.     count ++;
  838.       }
  839.       if (count > 1) {
  840.     return true;
  841.       }
  842.  
  843.       /*
  844.         Solve the cubic with the 0th number being our rect line segment
  845.         returns -1 if not intersection, else return true
  846.         make sure that the intersection occurs between the two endpoints
  847.         */
  848.  
  849.       eqn[0] = getX1() - x;
  850.       eqn[1] = (3 * getCtrlX1()) - (3 * getX1());
  851.       eqn[2] = (3 * getX1()) + (3 * getCtrlX2()) - (6 * getCtrlX1());
  852.       eqn[3] = (3 * getCtrlX1()) + getX2() - ( 3 * getCtrlX2()) - getX1();
  853.  
  854.       System.arraycopy(eqn, 0, backup, 0, 4);
  855.  
  856.       result = solveCubic(eqn);
  857.  
  858.       for (int i = 0; i < result; i++) {
  859.     if ((eqn[i] >= 0) && (eqn[i] <= 1)) {
  860.  
  861.         temp = (getY1() * Math.pow((1-eqn[i]),3)) 
  862.                 + (getCtrlY1() * 3 * eqn[i] * Math.pow((1-eqn[i]), 2)) 
  863.                 + (getCtrlY2() * 3 * Math.pow(eqn[i], 2) * (1 - eqn[i])) 
  864.                 + (getY2() * Math.pow(eqn[i], 3)); 
  865.  
  866.       double temp2 = 0;
  867.       temp2 = (getX1() * Math.pow((1-eqn[i]),3)) 
  868.               + (getCtrlX1() * 3 * eqn[i] * Math.pow((1-eqn[i]), 2)) 
  869.               + (getCtrlX2() * 3 * Math.pow(eqn[i], 2) * (1 - eqn[i])) 
  870.               + (getX2() * Math.pow(eqn[i], 3));
  871.  
  872.       if ((temp >= y) && (temp <= (y+h))) {
  873.         return true;
  874.           }
  875.     }
  876.       }
  877.  
  878.       System.arraycopy(backup, 0, eqn, 0, 4);
  879.       eqn[0] = getX1() - (x + w);
  880.       System.arraycopy(eqn, 0, backup, 0, 4);
  881.  
  882.       result = solveCubic(eqn);
  883.  
  884.       for (int i = 0; i < result; i++) {
  885.     if ((eqn[i] >= 0) && (eqn[i] <= 1)) {
  886.       temp = (getY1() * Math.pow((1-eqn[i]),3)) 
  887.               + (getCtrlY1() * 3 * eqn[i] * Math.pow((1-eqn[i]), 2)) 
  888.               + (getCtrlY2() * 3 * Math.pow(eqn[i], 2) * (1 - eqn[i])) 
  889.               + (getY2() * Math.pow(eqn[i], 3));
  890.  
  891.       if ((temp >= y) && (temp <= (y+h))) {
  892.         return true;
  893.           }
  894.     }
  895.       }
  896.       
  897.       eqn[0] = getY1() - y;
  898.       eqn[1] = (3 * getCtrlY1()) - (3 * getY1());
  899.       eqn[2] = (3 * getY1()) + (3 * getCtrlY2()) - (6 * getCtrlY1());
  900.       eqn[3] = (3 * getCtrlY1()) + getY2() - ( 3 * getCtrlY2()) - getY1();
  901.  
  902.       System.arraycopy(eqn, 0, backup, 0, 4);
  903.  
  904.       result = solveCubic(eqn);
  905.  
  906.       for (int i = 0; i < result; i++) {
  907.     if ((eqn[i] >= 0) && (eqn[i] <= 1)) {
  908.       temp = (getX1() * Math.pow((1-eqn[i]),3)) 
  909.               + (getCtrlX1() * 3 * eqn[i] * Math.pow((1-eqn[i]), 2)) 
  910.               + (getCtrlX2() * 3 * Math.pow(eqn[i], 2) * (1 - eqn[i])) 
  911.               + (getX2() * Math.pow(eqn[i], 3));
  912.  
  913.       if ((temp >= x) && (temp <= (x+w))) {
  914.         return true;
  915.           }
  916.     }
  917.       }
  918.  
  919.       System.arraycopy(backup, 0, eqn, 0, 4);
  920.       eqn[0] = getY1() - (y + h);
  921.       System.arraycopy(eqn, 0, backup, 0, 4);
  922.  
  923.       result = solveCubic(eqn);
  924.  
  925.       for (int i = 0; i < result; i++) {
  926.     if ((eqn[i] >= 0) && (eqn[i] <= 1)) {
  927.             temp = (getX1() * Math.pow((1-eqn[i]),3)) 
  928.                 + (getCtrlX1() * 3 * eqn[i] * Math.pow((1-eqn[i]), 2)) 
  929.                 + (getCtrlX2() * 3 * Math.pow(eqn[i], 2) * (1 - eqn[i])) 
  930.                 + (getX2() * Math.pow(eqn[i], 3));
  931.  
  932.             if ((temp >= x) && (temp <= (x+w))) {
  933.                 return true;
  934.             }
  935.     }
  936.       }
  937.  
  938.       return false;
  939.     }
  940.  
  941.     /**
  942.      * Test if the Shape intersects the interior of a given
  943.      * Rectangle.
  944.      */
  945.     public boolean intersects(Rectangle2D r) {
  946.     return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
  947.     }
  948.  
  949.     /**
  950.      * Test if the interior of the Shape entirely contains the given
  951.      * set of rectangular coordinates.
  952.      */
  953.  
  954.     public boolean contains(double x, double y, double w, double h) {
  955.     // Assertion: Cubic curves closed by connecting their
  956.     // endpoints form either one or two convex halves with
  957.     // the closing line segment as an edge of both sides.
  958.     if (!(contains(x, y) &&
  959.           contains(x + w, y) &&
  960.           contains(x + w, y + h) &&
  961.           contains(x, y + h))) {
  962.         return false;
  963.     }
  964.     // Either the rectangle is entirely inside one of the convex
  965.     // halves or it crosses from one to the other, in which case
  966.     // it must intersect the closing line segment.
  967.     Rectangle2D rect = new Rectangle2D.Double(x, y, w, h);
  968.     return !rect.intersectsLine(getX1(), getY1(), getX2(), getY2());
  969.     }
  970.  
  971.     /**
  972.      * Test if the interior of the Shape entirely contains the given
  973.      * Rectangle.
  974.      */
  975.     public boolean contains(Rectangle2D r) {
  976.     return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
  977.     }
  978.  
  979.     /**
  980.      * Return the bounding box of the shape.
  981.      */
  982.     public Rectangle getBounds() {
  983.     return getBounds2D().getBounds();
  984.     }
  985.  
  986.     /**
  987.      * Return an iteration object that defines the boundary of the
  988.      * shape.
  989.      */
  990.     public PathIterator getPathIterator(AffineTransform at) {
  991.     return new CubicIterator(this, at);
  992.     }
  993.  
  994.     /**
  995.      * Return an iteration object that defines the boundary of the
  996.      * flattened shape.
  997.      */
  998.     public PathIterator getPathIterator(AffineTransform at, double flatness) {
  999.     return new FlatteningPathIterator(getPathIterator(at), flatness);
  1000.     }
  1001.  
  1002.     /**
  1003.      * Creates a new object of the same class as this object.
  1004.      *
  1005.      * @return     a clone of this instance.
  1006.      * @exception  OutOfMemoryError            if there is not enough memory.
  1007.      * @see        java.lang.Cloneable
  1008.      * @since      JDK1.2
  1009.      */
  1010.     public Object clone() {
  1011.     try {
  1012.         return super.clone();
  1013.     } catch (CloneNotSupportedException e) {
  1014.         // this shouldn't happen, since we are Cloneable
  1015.         throw new InternalError();
  1016.     }
  1017.     }
  1018. }
  1019.