19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.awt.geom;
27
28 import java.awt.Shape;
29 import java.awt.Rectangle;
30 import java.util.Arrays;
31 import java.io.Serializable;
32 import sun.awt.geom.Curve;
33
34 import static java.lang.Math.abs;
35 import static java.lang.Math.max;
36 import static java.lang.Math.ulp;
37
38 /**
39 * The <code>CubicCurve2D</code> class defines a cubic parametric curve
40 * segment in {@code (x,y)} coordinate space.
41 * <p>
42 * This class is only the abstract superclass for all objects which
43 * store a 2D cubic curve segment.
44 * The actual storage representation of the coordinates is left to
45 * the subclass.
46 *
47 * @author Jim Graham
48 * @since 1.2
49 */
50 public abstract class CubicCurve2D implements Shape, Cloneable {
51
52 /**
53 * A cubic parametric curve segment specified with
54 * {@code float} coordinates.
55 * @since 1.2
56 */
57 public static class Float extends CubicCurve2D implements Serializable {
58 /**
59 * The X coordinate of the start point
705 * @param ctrlx2 the X coordinate used to set the second control point
706 * of this {@code CubicCurve2D}
707 * @param ctrly2 the Y coordinate used to set the second control point
708 * of this {@code CubicCurve2D}
709 * @param x2 the X coordinate used to set the end point
710 * of this {@code CubicCurve2D}
711 * @param y2 the Y coordinate used to set the end point
712 * of this {@code CubicCurve2D}
713 * @since 1.2
714 */
715 public abstract void setCurve(double x1, double y1,
716 double ctrlx1, double ctrly1,
717 double ctrlx2, double ctrly2,
718 double x2, double y2);
719
720 /**
721 * Sets the location of the end points and control points of this curve
722 * to the double coordinates at the specified offset in the specified
723 * array.
724 * @param coords a double array containing coordinates
725 * @param offset the index of <code>coords</code> from which to begin
726 * setting the end points and control points of this curve
727 * to the coordinates contained in <code>coords</code>
728 * @since 1.2
729 */
730 public void setCurve(double[] coords, int offset) {
731 setCurve(coords[offset + 0], coords[offset + 1],
732 coords[offset + 2], coords[offset + 3],
733 coords[offset + 4], coords[offset + 5],
734 coords[offset + 6], coords[offset + 7]);
735 }
736
737 /**
738 * Sets the location of the end points and control points of this curve
739 * to the specified <code>Point2D</code> coordinates.
740 * @param p1 the first specified <code>Point2D</code> used to set the
741 * start point of this curve
742 * @param cp1 the second specified <code>Point2D</code> used to set the
743 * first control point of this curve
744 * @param cp2 the third specified <code>Point2D</code> used to set the
745 * second control point of this curve
746 * @param p2 the fourth specified <code>Point2D</code> used to set the
747 * end point of this curve
748 * @since 1.2
749 */
750 public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) {
751 setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(),
752 cp2.getX(), cp2.getY(), p2.getX(), p2.getY());
753 }
754
755 /**
756 * Sets the location of the end points and control points of this curve
757 * to the coordinates of the <code>Point2D</code> objects at the specified
758 * offset in the specified array.
759 * @param pts an array of <code>Point2D</code> objects
760 * @param offset the index of <code>pts</code> from which to begin setting
761 * the end points and control points of this curve to the
762 * points contained in <code>pts</code>
763 * @since 1.2
764 */
765 public void setCurve(Point2D[] pts, int offset) {
766 setCurve(pts[offset + 0].getX(), pts[offset + 0].getY(),
767 pts[offset + 1].getX(), pts[offset + 1].getY(),
768 pts[offset + 2].getX(), pts[offset + 2].getY(),
769 pts[offset + 3].getX(), pts[offset + 3].getY());
770 }
771
772 /**
773 * Sets the location of the end points and control points of this curve
774 * to the same as those in the specified <code>CubicCurve2D</code>.
775 * @param c the specified <code>CubicCurve2D</code>
776 * @since 1.2
777 */
778 public void setCurve(CubicCurve2D c) {
779 setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(),
780 c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2());
781 }
782
783 /**
784 * Returns the square of the flatness of the cubic curve specified
785 * by the indicated control points. The flatness is the maximum distance
786 * of a control point from the line connecting the end points.
787 *
788 * @param x1 the X coordinate that specifies the start point
789 * of a {@code CubicCurve2D}
790 * @param y1 the Y coordinate that specifies the start point
791 * of a {@code CubicCurve2D}
792 * @param ctrlx1 the X coordinate that specifies the first control point
793 * of a {@code CubicCurve2D}
794 * @param ctrly1 the Y coordinate that specifies the first control point
795 * of a {@code CubicCurve2D}
836 * @param y2 the Y coordinate that specifies the end point
837 * of a {@code CubicCurve2D}
838 * @return the flatness of the {@code CubicCurve2D}
839 * represented by the specified coordinates.
840 * @since 1.2
841 */
842 public static double getFlatness(double x1, double y1,
843 double ctrlx1, double ctrly1,
844 double ctrlx2, double ctrly2,
845 double x2, double y2) {
846 return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1,
847 ctrlx2, ctrly2, x2, y2));
848 }
849
850 /**
851 * Returns the square of the flatness of the cubic curve specified
852 * by the control points stored in the indicated array at the
853 * indicated index. The flatness is the maximum distance
854 * of a control point from the line connecting the end points.
855 * @param coords an array containing coordinates
856 * @param offset the index of <code>coords</code> from which to begin
857 * getting the end points and control points of the curve
858 * @return the square of the flatness of the <code>CubicCurve2D</code>
859 * specified by the coordinates in <code>coords</code> at
860 * the specified offset.
861 * @since 1.2
862 */
863 public static double getFlatnessSq(double coords[], int offset) {
864 return getFlatnessSq(coords[offset + 0], coords[offset + 1],
865 coords[offset + 2], coords[offset + 3],
866 coords[offset + 4], coords[offset + 5],
867 coords[offset + 6], coords[offset + 7]);
868 }
869
870 /**
871 * Returns the flatness of the cubic curve specified
872 * by the control points stored in the indicated array at the
873 * indicated index. The flatness is the maximum distance
874 * of a control point from the line connecting the end points.
875 * @param coords an array containing coordinates
876 * @param offset the index of <code>coords</code> from which to begin
877 * getting the end points and control points of the curve
878 * @return the flatness of the <code>CubicCurve2D</code>
879 * specified by the coordinates in <code>coords</code> at
880 * the specified offset.
881 * @since 1.2
882 */
883 public static double getFlatness(double coords[], int offset) {
884 return getFlatness(coords[offset + 0], coords[offset + 1],
885 coords[offset + 2], coords[offset + 3],
886 coords[offset + 4], coords[offset + 5],
887 coords[offset + 6], coords[offset + 7]);
888 }
889
890 /**
891 * Returns the square of the flatness of this curve. The flatness is the
892 * maximum distance of a control point from the line connecting the
893 * end points.
894 * @return the square of the flatness of this curve.
895 * @since 1.2
896 */
897 public double getFlatnessSq() {
898 return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
899 getCtrlX2(), getCtrlY2(), getX2(), getY2());
910 return getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
911 getCtrlX2(), getCtrlY2(), getX2(), getY2());
912 }
913
914 /**
915 * Subdivides this cubic curve and stores the resulting two
916 * subdivided curves into the left and right curve parameters.
917 * Either or both of the left and right objects may be the same
918 * as this object or null.
919 * @param left the cubic curve object for storing for the left or
920 * first half of the subdivided curve
921 * @param right the cubic curve object for storing for the right or
922 * second half of the subdivided curve
923 * @since 1.2
924 */
925 public void subdivide(CubicCurve2D left, CubicCurve2D right) {
926 subdivide(this, left, right);
927 }
928
929 /**
930 * Subdivides the cubic curve specified by the <code>src</code> parameter
931 * and stores the resulting two subdivided curves into the
932 * <code>left</code> and <code>right</code> curve parameters.
933 * Either or both of the <code>left</code> and <code>right</code> objects
934 * may be the same as the <code>src</code> object or <code>null</code>.
935 * @param src the cubic curve to be subdivided
936 * @param left the cubic curve object for storing the left or
937 * first half of the subdivided curve
938 * @param right the cubic curve object for storing the right or
939 * second half of the subdivided curve
940 * @since 1.2
941 */
942 public static void subdivide(CubicCurve2D src,
943 CubicCurve2D left,
944 CubicCurve2D right) {
945 double x1 = src.getX1();
946 double y1 = src.getY1();
947 double ctrlx1 = src.getCtrlX1();
948 double ctrly1 = src.getCtrlY1();
949 double ctrlx2 = src.getCtrlX2();
950 double ctrly2 = src.getCtrlY2();
951 double x2 = src.getX2();
952 double y2 = src.getY2();
953 double centerx = (ctrlx1 + ctrlx2) / 2.0;
954 double centery = (ctrly1 + ctrly2) / 2.0;
957 ctrlx2 = (x2 + ctrlx2) / 2.0;
958 ctrly2 = (y2 + ctrly2) / 2.0;
959 double ctrlx12 = (ctrlx1 + centerx) / 2.0;
960 double ctrly12 = (ctrly1 + centery) / 2.0;
961 double ctrlx21 = (ctrlx2 + centerx) / 2.0;
962 double ctrly21 = (ctrly2 + centery) / 2.0;
963 centerx = (ctrlx12 + ctrlx21) / 2.0;
964 centery = (ctrly12 + ctrly21) / 2.0;
965 if (left != null) {
966 left.setCurve(x1, y1, ctrlx1, ctrly1,
967 ctrlx12, ctrly12, centerx, centery);
968 }
969 if (right != null) {
970 right.setCurve(centerx, centery, ctrlx21, ctrly21,
971 ctrlx2, ctrly2, x2, y2);
972 }
973 }
974
975 /**
976 * Subdivides the cubic curve specified by the coordinates
977 * stored in the <code>src</code> array at indices <code>srcoff</code>
978 * through (<code>srcoff</code> + 7) and stores the
979 * resulting two subdivided curves into the two result arrays at the
980 * corresponding indices.
981 * Either or both of the <code>left</code> and <code>right</code>
982 * arrays may be <code>null</code> or a reference to the same array
983 * as the <code>src</code> array.
984 * Note that the last point in the first subdivided curve is the
985 * same as the first point in the second subdivided curve. Thus,
986 * it is possible to pass the same array for <code>left</code>
987 * and <code>right</code> and to use offsets, such as <code>rightoff</code>
988 * equals (<code>leftoff</code> + 6), in order
989 * to avoid allocating extra storage for this common point.
990 * @param src the array holding the coordinates for the source curve
991 * @param srcoff the offset into the array of the beginning of the
992 * the 6 source coordinates
993 * @param left the array for storing the coordinates for the first
994 * half of the subdivided curve
995 * @param leftoff the offset into the array of the beginning of the
996 * the 6 left coordinates
997 * @param right the array for storing the coordinates for the second
998 * half of the subdivided curve
999 * @param rightoff the offset into the array of the beginning of the
1000 * the 6 right coordinates
1001 * @since 1.2
1002 */
1003 public static void subdivide(double src[], int srcoff,
1004 double left[], int leftoff,
1005 double right[], int rightoff) {
1006 double x1 = src[srcoff + 0];
1007 double y1 = src[srcoff + 1];
1008 double ctrlx1 = src[srcoff + 2];
1033 centery = (ctrly1 + ctrly2) / 2.0;
1034 if (left != null) {
1035 left[leftoff + 2] = x1;
1036 left[leftoff + 3] = y1;
1037 left[leftoff + 4] = ctrlx1;
1038 left[leftoff + 5] = ctrly1;
1039 left[leftoff + 6] = centerx;
1040 left[leftoff + 7] = centery;
1041 }
1042 if (right != null) {
1043 right[rightoff + 0] = centerx;
1044 right[rightoff + 1] = centery;
1045 right[rightoff + 2] = ctrlx2;
1046 right[rightoff + 3] = ctrly2;
1047 right[rightoff + 4] = x2;
1048 right[rightoff + 5] = y2;
1049 }
1050 }
1051
1052 /**
1053 * Solves the cubic whose coefficients are in the <code>eqn</code>
1054 * array and places the non-complex roots back into the same array,
1055 * returning the number of roots. The solved cubic is represented
1056 * by the equation:
1057 * <pre>
1058 * eqn = {c, b, a, d}
1059 * dx^3 + ax^2 + bx + c = 0
1060 * </pre>
1061 * A return value of -1 is used to distinguish a constant equation
1062 * that might be always 0 or never 0 from an equation that has no
1063 * zeroes.
1064 * @param eqn an array containing coefficients for a cubic
1065 * @return the number of roots, or -1 if the equation is a constant.
1066 * @since 1.2
1067 */
1068 public static int solveCubic(double eqn[]) {
1069 return solveCubic(eqn, eqn);
1070 }
1071
1072 /**
1073 * Solve the cubic whose coefficients are in the <code>eqn</code>
1074 * array and place the non-complex roots into the <code>res</code>
1075 * array, returning the number of roots.
1076 * The cubic solved is represented by the equation:
1077 * eqn = {c, b, a, d}
1078 * dx^3 + ax^2 + bx + c = 0
1079 * A return value of -1 is used to distinguish a constant equation,
1080 * which may be always 0 or never 0, from an equation which has no
1081 * zeroes.
1082 * @param eqn the specified array of coefficients to use to solve
1083 * the cubic equation
1084 * @param res the array that contains the non-complex roots
1085 * resulting from the solution of the cubic equation
1086 * @return the number of roots, or -1 if the equation is a constant
1087 * @since 1.3
1088 */
1089 public static int solveCubic(double eqn[], double res[]) {
1090 // From Graphics Gems:
1091 // http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
1092 final double d = eqn[3];
1093 if (d == 0) {
1094 return QuadCurve2D.solveQuadratic(eqn, res);
1500 /**
1501 * {@inheritDoc}
1502 * @since 1.2
1503 */
1504 public boolean contains(Rectangle2D r) {
1505 return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
1506 }
1507
1508 /**
1509 * {@inheritDoc}
1510 * @since 1.2
1511 */
1512 public Rectangle getBounds() {
1513 return getBounds2D().getBounds();
1514 }
1515
1516 /**
1517 * Returns an iteration object that defines the boundary of the
1518 * shape.
1519 * The iterator for this class is not multi-threaded safe,
1520 * which means that this <code>CubicCurve2D</code> class does not
1521 * guarantee that modifications to the geometry of this
1522 * <code>CubicCurve2D</code> object do not affect any iterations of
1523 * that geometry that are already in process.
1524 * @param at an optional <code>AffineTransform</code> to be applied to the
1525 * coordinates as they are returned in the iteration, or <code>null</code>
1526 * if untransformed coordinates are desired
1527 * @return the <code>PathIterator</code> object that returns the
1528 * geometry of the outline of this <code>CubicCurve2D</code>, one
1529 * segment at a time.
1530 * @since 1.2
1531 */
1532 public PathIterator getPathIterator(AffineTransform at) {
1533 return new CubicIterator(this, at);
1534 }
1535
1536 /**
1537 * Return an iteration object that defines the boundary of the
1538 * flattened shape.
1539 * The iterator for this class is not multi-threaded safe,
1540 * which means that this <code>CubicCurve2D</code> class does not
1541 * guarantee that modifications to the geometry of this
1542 * <code>CubicCurve2D</code> object do not affect any iterations of
1543 * that geometry that are already in process.
1544 * @param at an optional <code>AffineTransform</code> to be applied to the
1545 * coordinates as they are returned in the iteration, or <code>null</code>
1546 * if untransformed coordinates are desired
1547 * @param flatness the maximum amount that the control points
1548 * for a given curve can vary from colinear before a subdivided
1549 * curve is replaced by a straight line connecting the end points
1550 * @return the <code>PathIterator</code> object that returns the
1551 * geometry of the outline of this <code>CubicCurve2D</code>,
1552 * one segment at a time.
1553 * @since 1.2
1554 */
1555 public PathIterator getPathIterator(AffineTransform at, double flatness) {
1556 return new FlatteningPathIterator(getPathIterator(at), flatness);
1557 }
1558
1559 /**
1560 * Creates a new object of the same class as this object.
1561 *
1562 * @return a clone of this instance.
1563 * @exception OutOfMemoryError if there is not enough memory.
1564 * @see java.lang.Cloneable
1565 * @since 1.2
1566 */
1567 public Object clone() {
1568 try {
1569 return super.clone();
1570 } catch (CloneNotSupportedException e) {
1571 // this shouldn't happen, since we are Cloneable
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.awt.geom;
27
28 import java.awt.Shape;
29 import java.awt.Rectangle;
30 import java.util.Arrays;
31 import java.io.Serializable;
32 import sun.awt.geom.Curve;
33
34 import static java.lang.Math.abs;
35 import static java.lang.Math.max;
36 import static java.lang.Math.ulp;
37
38 /**
39 * The {@code CubicCurve2D} class defines a cubic parametric curve
40 * segment in {@code (x,y)} coordinate space.
41 * <p>
42 * This class is only the abstract superclass for all objects which
43 * store a 2D cubic curve segment.
44 * The actual storage representation of the coordinates is left to
45 * the subclass.
46 *
47 * @author Jim Graham
48 * @since 1.2
49 */
50 public abstract class CubicCurve2D implements Shape, Cloneable {
51
52 /**
53 * A cubic parametric curve segment specified with
54 * {@code float} coordinates.
55 * @since 1.2
56 */
57 public static class Float extends CubicCurve2D implements Serializable {
58 /**
59 * The X coordinate of the start point
705 * @param ctrlx2 the X coordinate used to set the second control point
706 * of this {@code CubicCurve2D}
707 * @param ctrly2 the Y coordinate used to set the second control point
708 * of this {@code CubicCurve2D}
709 * @param x2 the X coordinate used to set the end point
710 * of this {@code CubicCurve2D}
711 * @param y2 the Y coordinate used to set the end point
712 * of this {@code CubicCurve2D}
713 * @since 1.2
714 */
715 public abstract void setCurve(double x1, double y1,
716 double ctrlx1, double ctrly1,
717 double ctrlx2, double ctrly2,
718 double x2, double y2);
719
720 /**
721 * Sets the location of the end points and control points of this curve
722 * to the double coordinates at the specified offset in the specified
723 * array.
724 * @param coords a double array containing coordinates
725 * @param offset the index of {@code coords} from which to begin
726 * setting the end points and control points of this curve
727 * to the coordinates contained in {@code coords}
728 * @since 1.2
729 */
730 public void setCurve(double[] coords, int offset) {
731 setCurve(coords[offset + 0], coords[offset + 1],
732 coords[offset + 2], coords[offset + 3],
733 coords[offset + 4], coords[offset + 5],
734 coords[offset + 6], coords[offset + 7]);
735 }
736
737 /**
738 * Sets the location of the end points and control points of this curve
739 * to the specified {@code Point2D} coordinates.
740 * @param p1 the first specified {@code Point2D} used to set the
741 * start point of this curve
742 * @param cp1 the second specified {@code Point2D} used to set the
743 * first control point of this curve
744 * @param cp2 the third specified {@code Point2D} used to set the
745 * second control point of this curve
746 * @param p2 the fourth specified {@code Point2D} used to set the
747 * end point of this curve
748 * @since 1.2
749 */
750 public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) {
751 setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(),
752 cp2.getX(), cp2.getY(), p2.getX(), p2.getY());
753 }
754
755 /**
756 * Sets the location of the end points and control points of this curve
757 * to the coordinates of the {@code Point2D} objects at the specified
758 * offset in the specified array.
759 * @param pts an array of {@code Point2D} objects
760 * @param offset the index of {@code pts} from which to begin setting
761 * the end points and control points of this curve to the
762 * points contained in {@code pts}
763 * @since 1.2
764 */
765 public void setCurve(Point2D[] pts, int offset) {
766 setCurve(pts[offset + 0].getX(), pts[offset + 0].getY(),
767 pts[offset + 1].getX(), pts[offset + 1].getY(),
768 pts[offset + 2].getX(), pts[offset + 2].getY(),
769 pts[offset + 3].getX(), pts[offset + 3].getY());
770 }
771
772 /**
773 * Sets the location of the end points and control points of this curve
774 * to the same as those in the specified {@code CubicCurve2D}.
775 * @param c the specified {@code CubicCurve2D}
776 * @since 1.2
777 */
778 public void setCurve(CubicCurve2D c) {
779 setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(),
780 c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2());
781 }
782
783 /**
784 * Returns the square of the flatness of the cubic curve specified
785 * by the indicated control points. The flatness is the maximum distance
786 * of a control point from the line connecting the end points.
787 *
788 * @param x1 the X coordinate that specifies the start point
789 * of a {@code CubicCurve2D}
790 * @param y1 the Y coordinate that specifies the start point
791 * of a {@code CubicCurve2D}
792 * @param ctrlx1 the X coordinate that specifies the first control point
793 * of a {@code CubicCurve2D}
794 * @param ctrly1 the Y coordinate that specifies the first control point
795 * of a {@code CubicCurve2D}
836 * @param y2 the Y coordinate that specifies the end point
837 * of a {@code CubicCurve2D}
838 * @return the flatness of the {@code CubicCurve2D}
839 * represented by the specified coordinates.
840 * @since 1.2
841 */
842 public static double getFlatness(double x1, double y1,
843 double ctrlx1, double ctrly1,
844 double ctrlx2, double ctrly2,
845 double x2, double y2) {
846 return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1,
847 ctrlx2, ctrly2, x2, y2));
848 }
849
850 /**
851 * Returns the square of the flatness of the cubic curve specified
852 * by the control points stored in the indicated array at the
853 * indicated index. The flatness is the maximum distance
854 * of a control point from the line connecting the end points.
855 * @param coords an array containing coordinates
856 * @param offset the index of {@code coords} from which to begin
857 * getting the end points and control points of the curve
858 * @return the square of the flatness of the {@code CubicCurve2D}
859 * specified by the coordinates in {@code coords} at
860 * the specified offset.
861 * @since 1.2
862 */
863 public static double getFlatnessSq(double coords[], int offset) {
864 return getFlatnessSq(coords[offset + 0], coords[offset + 1],
865 coords[offset + 2], coords[offset + 3],
866 coords[offset + 4], coords[offset + 5],
867 coords[offset + 6], coords[offset + 7]);
868 }
869
870 /**
871 * Returns the flatness of the cubic curve specified
872 * by the control points stored in the indicated array at the
873 * indicated index. The flatness is the maximum distance
874 * of a control point from the line connecting the end points.
875 * @param coords an array containing coordinates
876 * @param offset the index of {@code coords} from which to begin
877 * getting the end points and control points of the curve
878 * @return the flatness of the {@code CubicCurve2D}
879 * specified by the coordinates in {@code coords} at
880 * the specified offset.
881 * @since 1.2
882 */
883 public static double getFlatness(double coords[], int offset) {
884 return getFlatness(coords[offset + 0], coords[offset + 1],
885 coords[offset + 2], coords[offset + 3],
886 coords[offset + 4], coords[offset + 5],
887 coords[offset + 6], coords[offset + 7]);
888 }
889
890 /**
891 * Returns the square of the flatness of this curve. The flatness is the
892 * maximum distance of a control point from the line connecting the
893 * end points.
894 * @return the square of the flatness of this curve.
895 * @since 1.2
896 */
897 public double getFlatnessSq() {
898 return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
899 getCtrlX2(), getCtrlY2(), getX2(), getY2());
910 return getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
911 getCtrlX2(), getCtrlY2(), getX2(), getY2());
912 }
913
914 /**
915 * Subdivides this cubic curve and stores the resulting two
916 * subdivided curves into the left and right curve parameters.
917 * Either or both of the left and right objects may be the same
918 * as this object or null.
919 * @param left the cubic curve object for storing for the left or
920 * first half of the subdivided curve
921 * @param right the cubic curve object for storing for the right or
922 * second half of the subdivided curve
923 * @since 1.2
924 */
925 public void subdivide(CubicCurve2D left, CubicCurve2D right) {
926 subdivide(this, left, right);
927 }
928
929 /**
930 * Subdivides the cubic curve specified by the {@code src} parameter
931 * and stores the resulting two subdivided curves into the
932 * {@code left} and {@code right} curve parameters.
933 * Either or both of the {@code left} and {@code right} objects
934 * may be the same as the {@code src} object or {@code null}.
935 * @param src the cubic curve to be subdivided
936 * @param left the cubic curve object for storing the left or
937 * first half of the subdivided curve
938 * @param right the cubic curve object for storing the right or
939 * second half of the subdivided curve
940 * @since 1.2
941 */
942 public static void subdivide(CubicCurve2D src,
943 CubicCurve2D left,
944 CubicCurve2D right) {
945 double x1 = src.getX1();
946 double y1 = src.getY1();
947 double ctrlx1 = src.getCtrlX1();
948 double ctrly1 = src.getCtrlY1();
949 double ctrlx2 = src.getCtrlX2();
950 double ctrly2 = src.getCtrlY2();
951 double x2 = src.getX2();
952 double y2 = src.getY2();
953 double centerx = (ctrlx1 + ctrlx2) / 2.0;
954 double centery = (ctrly1 + ctrly2) / 2.0;
957 ctrlx2 = (x2 + ctrlx2) / 2.0;
958 ctrly2 = (y2 + ctrly2) / 2.0;
959 double ctrlx12 = (ctrlx1 + centerx) / 2.0;
960 double ctrly12 = (ctrly1 + centery) / 2.0;
961 double ctrlx21 = (ctrlx2 + centerx) / 2.0;
962 double ctrly21 = (ctrly2 + centery) / 2.0;
963 centerx = (ctrlx12 + ctrlx21) / 2.0;
964 centery = (ctrly12 + ctrly21) / 2.0;
965 if (left != null) {
966 left.setCurve(x1, y1, ctrlx1, ctrly1,
967 ctrlx12, ctrly12, centerx, centery);
968 }
969 if (right != null) {
970 right.setCurve(centerx, centery, ctrlx21, ctrly21,
971 ctrlx2, ctrly2, x2, y2);
972 }
973 }
974
975 /**
976 * Subdivides the cubic curve specified by the coordinates
977 * stored in the {@code src} array at indices {@code srcoff}
978 * through ({@code srcoff} + 7) and stores the
979 * resulting two subdivided curves into the two result arrays at the
980 * corresponding indices.
981 * Either or both of the {@code left} and {@code right}
982 * arrays may be {@code null} or a reference to the same array
983 * as the {@code src} array.
984 * Note that the last point in the first subdivided curve is the
985 * same as the first point in the second subdivided curve. Thus,
986 * it is possible to pass the same array for {@code left}
987 * and {@code right} and to use offsets, such as {@code rightoff}
988 * equals ({@code leftoff} + 6), in order
989 * to avoid allocating extra storage for this common point.
990 * @param src the array holding the coordinates for the source curve
991 * @param srcoff the offset into the array of the beginning of the
992 * the 6 source coordinates
993 * @param left the array for storing the coordinates for the first
994 * half of the subdivided curve
995 * @param leftoff the offset into the array of the beginning of the
996 * the 6 left coordinates
997 * @param right the array for storing the coordinates for the second
998 * half of the subdivided curve
999 * @param rightoff the offset into the array of the beginning of the
1000 * the 6 right coordinates
1001 * @since 1.2
1002 */
1003 public static void subdivide(double src[], int srcoff,
1004 double left[], int leftoff,
1005 double right[], int rightoff) {
1006 double x1 = src[srcoff + 0];
1007 double y1 = src[srcoff + 1];
1008 double ctrlx1 = src[srcoff + 2];
1033 centery = (ctrly1 + ctrly2) / 2.0;
1034 if (left != null) {
1035 left[leftoff + 2] = x1;
1036 left[leftoff + 3] = y1;
1037 left[leftoff + 4] = ctrlx1;
1038 left[leftoff + 5] = ctrly1;
1039 left[leftoff + 6] = centerx;
1040 left[leftoff + 7] = centery;
1041 }
1042 if (right != null) {
1043 right[rightoff + 0] = centerx;
1044 right[rightoff + 1] = centery;
1045 right[rightoff + 2] = ctrlx2;
1046 right[rightoff + 3] = ctrly2;
1047 right[rightoff + 4] = x2;
1048 right[rightoff + 5] = y2;
1049 }
1050 }
1051
1052 /**
1053 * Solves the cubic whose coefficients are in the {@code eqn}
1054 * array and places the non-complex roots back into the same array,
1055 * returning the number of roots. The solved cubic is represented
1056 * by the equation:
1057 * <pre>
1058 * eqn = {c, b, a, d}
1059 * dx^3 + ax^2 + bx + c = 0
1060 * </pre>
1061 * A return value of -1 is used to distinguish a constant equation
1062 * that might be always 0 or never 0 from an equation that has no
1063 * zeroes.
1064 * @param eqn an array containing coefficients for a cubic
1065 * @return the number of roots, or -1 if the equation is a constant.
1066 * @since 1.2
1067 */
1068 public static int solveCubic(double eqn[]) {
1069 return solveCubic(eqn, eqn);
1070 }
1071
1072 /**
1073 * Solve the cubic whose coefficients are in the {@code eqn}
1074 * array and place the non-complex roots into the {@code res}
1075 * array, returning the number of roots.
1076 * The cubic solved is represented by the equation:
1077 * eqn = {c, b, a, d}
1078 * dx^3 + ax^2 + bx + c = 0
1079 * A return value of -1 is used to distinguish a constant equation,
1080 * which may be always 0 or never 0, from an equation which has no
1081 * zeroes.
1082 * @param eqn the specified array of coefficients to use to solve
1083 * the cubic equation
1084 * @param res the array that contains the non-complex roots
1085 * resulting from the solution of the cubic equation
1086 * @return the number of roots, or -1 if the equation is a constant
1087 * @since 1.3
1088 */
1089 public static int solveCubic(double eqn[], double res[]) {
1090 // From Graphics Gems:
1091 // http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
1092 final double d = eqn[3];
1093 if (d == 0) {
1094 return QuadCurve2D.solveQuadratic(eqn, res);
1500 /**
1501 * {@inheritDoc}
1502 * @since 1.2
1503 */
1504 public boolean contains(Rectangle2D r) {
1505 return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
1506 }
1507
1508 /**
1509 * {@inheritDoc}
1510 * @since 1.2
1511 */
1512 public Rectangle getBounds() {
1513 return getBounds2D().getBounds();
1514 }
1515
1516 /**
1517 * Returns an iteration object that defines the boundary of the
1518 * shape.
1519 * The iterator for this class is not multi-threaded safe,
1520 * which means that this {@code CubicCurve2D} class does not
1521 * guarantee that modifications to the geometry of this
1522 * {@code CubicCurve2D} object do not affect any iterations of
1523 * that geometry that are already in process.
1524 * @param at an optional {@code AffineTransform} to be applied to the
1525 * coordinates as they are returned in the iteration, or {@code null}
1526 * if untransformed coordinates are desired
1527 * @return the {@code PathIterator} object that returns the
1528 * geometry of the outline of this {@code CubicCurve2D}, one
1529 * segment at a time.
1530 * @since 1.2
1531 */
1532 public PathIterator getPathIterator(AffineTransform at) {
1533 return new CubicIterator(this, at);
1534 }
1535
1536 /**
1537 * Return an iteration object that defines the boundary of the
1538 * flattened shape.
1539 * The iterator for this class is not multi-threaded safe,
1540 * which means that this {@code CubicCurve2D} class does not
1541 * guarantee that modifications to the geometry of this
1542 * {@code CubicCurve2D} object do not affect any iterations of
1543 * that geometry that are already in process.
1544 * @param at an optional {@code AffineTransform} to be applied to the
1545 * coordinates as they are returned in the iteration, or {@code null}
1546 * if untransformed coordinates are desired
1547 * @param flatness the maximum amount that the control points
1548 * for a given curve can vary from colinear before a subdivided
1549 * curve is replaced by a straight line connecting the end points
1550 * @return the {@code PathIterator} object that returns the
1551 * geometry of the outline of this {@code CubicCurve2D},
1552 * one segment at a time.
1553 * @since 1.2
1554 */
1555 public PathIterator getPathIterator(AffineTransform at, double flatness) {
1556 return new FlatteningPathIterator(getPathIterator(at), flatness);
1557 }
1558
1559 /**
1560 * Creates a new object of the same class as this object.
1561 *
1562 * @return a clone of this instance.
1563 * @exception OutOfMemoryError if there is not enough memory.
1564 * @see java.lang.Cloneable
1565 * @since 1.2
1566 */
1567 public Object clone() {
1568 try {
1569 return super.clone();
1570 } catch (CloneNotSupportedException e) {
1571 // this shouldn't happen, since we are Cloneable
|