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:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Java Source
|
1998-03-20
|
28.5 KB
|
1,019 lines
/*
* @(#)CubicCurve2D.java 1.10 98/03/18
*
* Copyright 1997, 1998 by Sun Microsystems, Inc.,
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
* All rights reserved.
*
* This software is the confidential and proprietary information
* of Sun Microsystems, Inc. ("Confidential Information"). You
* shall not disclose such Confidential Information and shall use
* it only in accordance with the terms of the license agreement
* you entered into with Sun.
*/
package java.awt.geom;
import java.awt.Shape;
import java.awt.Rectangle;
/**
* A cubic parametric curve segment in (x, y) coordinate space.
* <p>
* This class is only the abstract superclass for all objects which
* store a 2D cubic curve segment.
* The actual storage representation of the coordinates is left to
* the subclass.
*
* @version 10 Feb 1997
* @author Jim Graham
*/
public abstract class CubicCurve2D implements Shape, Cloneable {
/**
* A cubic parametric curve segment specified with float coordinates.
*/
public static class Float extends CubicCurve2D {
/**
* The X coordinate of the start point
* of the cubic curve segment.
*/
public float x1;
/**
* The Y coordinate of the start point
* of the cubic curve segment.
*/
public float y1;
/**
* The X coordinate of the first control point
* of the cubic curve segment.
*/
public float ctrlx1;
/**
* The Y coordinate of the first control point
* of the cubic curve segment.
*/
public float ctrly1;
/**
* The X coordinate of the second control point
* of the cubic curve segment.
*/
public float ctrlx2;
/**
* The Y coordinate of the second control point
* of the cubic curve segment.
*/
public float ctrly2;
/**
* The X coordinate of the end point
* of the cubic curve segment.
*/
public float x2;
/**
* The Y coordinate of the end point
* of the cubic curve segment.
*/
public float y2;
/**
* Constructs and initializes a CubicCurve with coordinates
* (0, 0, 0, 0, 0, 0).
*/
public Float() {
}
/**
* Constructs and initializes a CubicCurve from
* the specified coordinates.
*/
public Float(float x1, float y1,
float ctrlx1, float ctrly1,
float ctrlx2, float ctrly2,
float x2, float y2) {
setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
}
/**
* Returns the X coordinate of the start point
* in double precision.
*/
public double getX1() {
return (double) x1;
}
/**
* Returns the Y coordinate of the start point
* in double precision.
*/
public double getY1() {
return (double) y1;
}
/**
* Returns the X coordinate of the first control point
* in double precision.
*/
public double getCtrlX1() {
return (double) ctrlx1;
}
/**
* Returns the Y coordinate of the first control point
* in double precision.
*/
public double getCtrlY1() {
return (double) ctrly1;
}
/**
* Returns the X coordinate of the second control point
* in double precision.
*/
public double getCtrlX2() {
return (double) ctrlx2;
}
/**
* Returns the Y coordinate of the second control point
* in double precision.
*/
public double getCtrlY2() {
return (double) ctrly2;
}
/**
* Returns the X coordinate of the end point
* in double precision.
*/
public double getX2() {
return (double) x2;
}
/**
* Returns the Y coordinate of the end point
* in double precision.
*/
public double getY2() {
return (double) y2;
}
/**
* Sets the location of the endpoints and controlpoints
* of this curve to the specified double coordinates.
*/
public void setCurve(double x1, double y1,
double ctrlx1, double ctrly1,
double ctrlx2, double ctrly2,
double x2, double y2) {
this.x1 = (float) x1;
this.y1 = (float) y1;
this.ctrlx1 = (float) ctrlx1;
this.ctrly1 = (float) ctrly1;
this.ctrlx2 = (float) ctrlx2;
this.ctrly2 = (float) ctrly2;
this.x2 = (float) x2;
this.y2 = (float) y2;
}
/**
* Sets the location of the endpoints and controlpoints
* of this curve to the specified float coordinates.
*/
public void setCurve(float x1, float y1,
float ctrlx1, float ctrly1,
float ctrlx2, float ctrly2,
float x2, float y2) {
this.x1 = x1;
this.y1 = y1;
this.ctrlx1 = ctrlx1;
this.ctrly1 = ctrly1;
this.ctrlx2 = ctrlx2;
this.ctrly2 = ctrly2;
this.x2 = x2;
this.y2 = y2;
}
/**
* Return the bounding box of the shape.
*/
public Rectangle2D getBounds2D() {
float left = Math.min(Math.min(x1, x2),
Math.min(ctrlx1, ctrlx2));
float top = Math.min(Math.min(y1, y2),
Math.min(ctrly1, ctrly2));
float right = Math.max(Math.max(x1, x2),
Math.max(ctrlx1, ctrlx2));
float bottom = Math.max(Math.max(y1, y2),
Math.max(ctrly1, ctrly2));
return new Rectangle2D.Float(left, top,
right - left, bottom - top);
}
}
/**
* A cubic parametric curve segment specified with double coordinates.
*/
public static class Double extends CubicCurve2D {
/**
* The X coordinate of the start point
* of the cubic curve segment.
*/
public double x1;
/**
* The Y coordinate of the start point
* of the cubic curve segment.
*/
public double y1;
/**
* The X coordinate of the first control point
* of the cubic curve segment.
*/
public double ctrlx1;
/**
* The Y coordinate of the first control point
* of the cubic curve segment.
*/
public double ctrly1;
/**
* The X coordinate of the second control point
* of the cubic curve segment.
*/
public double ctrlx2;
/**
* The Y coordinate of the second control point
* of the cubic curve segment.
*/
public double ctrly2;
/**
* The X coordinate of the end point
* of the cubic curve segment.
*/
public double x2;
/**
* The Y coordinate of the end point
* of the cubic curve segment.
*/
public double y2;
/**
* Constructs and initializes a CubicCurve with coordinates
* (0, 0, 0, 0, 0, 0).
*/
public Double() {
}
/**
* Constructs and initializes a CubicCurve from
* the specified coordinates.
*/
public Double(double x1, double y1,
double ctrlx1, double ctrly1,
double ctrlx2, double ctrly2,
double x2, double y2) {
setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
}
/**
* Returns the X coordinate of the start point
* in double precision.
*/
public double getX1() {
return x1;
}
/**
* Returns the Y coordinate of the start point
* in double precision.
*/
public double getY1() {
return y1;
}
/**
* Returns the X coordinate of the first control point
* in double precision.
*/
public double getCtrlX1() {
return ctrlx1;
}
/**
* Returns the Y coordinate of the first control point
* in double precision.
*/
public double getCtrlY1() {
return ctrly1;
}
/**
* Returns the X coordinate of the second control point
* in double precision.
*/
public double getCtrlX2() {
return ctrlx2;
}
/**
* Returns the Y coordinate of the second control point
* in double precision.
*/
public double getCtrlY2() {
return ctrly2;
}
/**
* Returns the X coordinate of the end point
* in double precision.
*/
public double getX2() {
return x2;
}
/**
* Returns the Y coordinate of the end point
* in double precision.
*/
public double getY2() {
return y2;
}
/**
* Sets the location of the endpoints and controlpoints
* of this curve to the specified double coordinates.
*/
public void setCurve(double x1, double y1,
double ctrlx1, double ctrly1,
double ctrlx2, double ctrly2,
double x2, double y2) {
this.x1 = x1;
this.y1 = y1;
this.ctrlx1 = ctrlx1;
this.ctrly1 = ctrly1;
this.ctrlx2 = ctrlx2;
this.ctrly2 = ctrly2;
this.x2 = x2;
this.y2 = y2;
}
/**
* Return the bounding box of the shape.
*/
public Rectangle2D getBounds2D() {
double left = Math.min(Math.min(x1, x2),
Math.min(ctrlx1, ctrlx2));
double top = Math.min(Math.min(y1, y2),
Math.min(ctrly1, ctrly2));
double right = Math.max(Math.max(x1, x2),
Math.max(ctrlx1, ctrlx2));
double bottom = Math.max(Math.max(y1, y2),
Math.max(ctrly1, ctrly2));
return new Rectangle2D.Double(left, top,
right - left, bottom - top);
}
}
protected CubicCurve2D() {
}
/**
* Returns the X coordinate of the start point in double precision.
*/
public abstract double getX1();
/**
* Returns the Y coordinate of the start point in double precision.
*/
public abstract double getY1();
/**
* Returns the X coordinate of the first control point in double precision.
*/
public abstract double getCtrlX1();
/**
* Returns the Y coordinate of the first control point in double precision.
*/
public abstract double getCtrlY1();
/**
* Returns the X coordinate of the second control point
* in double precision.
*/
public abstract double getCtrlX2();
/**
* Returns the Y coordinate of the second control point
* in double precision.
*/
public abstract double getCtrlY2();
/**
* Returns the X coordinate of the end point in double precision.
*/
public abstract double getX2();
/**
* Returns the Y coordinate of the end point in double precision.
*/
public abstract double getY2();
/**
* Sets the location of the endpoints and controlpoints of this curve
* to the specified double coordinates.
*/
public abstract void setCurve(double x1, double y1,
double ctrlx1, double ctrly1,
double ctrlx2, double ctrly2,
double x2, double y2);
/**
* Sets the location of the endpoints and controlpoints of this curve
* to the double coordinates at the specified offset in the specified
* array.
*/
public void setCurve(double[] coords, int offset) {
setCurve(coords[offset + 0], coords[offset + 1],
coords[offset + 2], coords[offset + 3],
coords[offset + 4], coords[offset + 5],
coords[offset + 6], coords[offset + 7]);
}
/**
* Sets the location of the endpoints and controlpoints of this curve
* to the specified Point coordinates.
*/
public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) {
setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(),
cp2.getX(), cp2.getY(), p2.getX(), p2.getY());
}
/**
* Sets the location of the endpoints and controlpoints of this curve
* to the coordinates of the Point objects at the specified offset in
* the specified array.
*/
public void setCurve(Point2D[] pts, int offset) {
setCurve(pts[offset + 0].getX(), pts[offset + 0].getY(),
pts[offset + 1].getX(), pts[offset + 1].getY(),
pts[offset + 2].getX(), pts[offset + 2].getY(),
pts[offset + 3].getX(), pts[offset + 3].getY());
}
/**
* Sets the location of the endpoints and controlpoints of this curve
* to the same as those in the specified CubicCurve.
*/
public void setCurve(CubicCurve2D c) {
setCurve(c.getX1(), c.getY1(), c.getCtrlX1(), c.getCtrlY1(),
c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2());
}
/**
* Returns the square of the flatness, or maximum distance of a
* controlpoint from the line connecting the endpoints, of the
* cubic curve specified by the indicated controlpoints.
*/
public static double getFlatnessSq(double x1, double y1,
double ctrlx1, double ctrly1,
double ctrlx2, double ctrly2,
double x2, double y2) {
return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1, ctrly1),
Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx2, ctrly2));
}
/**
* Returns the flatness, or maximum distance of a
* controlpoint from the line connecting the endpoints, of the
* cubic curve specified by the indicated controlpoints.
*/
public static double getFlatness(double x1, double y1,
double ctrlx1, double ctrly1,
double ctrlx2, double ctrly2,
double x2, double y2) {
return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1,
ctrlx2, ctrly2, x2, y2));
}
/**
* Returns the square of the flatness, or maximum distance of a
* controlpoint from the line connecting the endpoints, of the
* cubic curve specified by the controlpoints stored in the
* indicated array at the indicated index.
*/
public static double getFlatnessSq(double coords[], int offset) {
return getFlatnessSq(coords[offset + 0], coords[offset + 1],
coords[offset + 2], coords[offset + 3],
coords[offset + 4], coords[offset + 5],
coords[offset + 6], coords[offset + 7]);
}
/**
* Returns the flatness, or maximum distance of a
* controlpoint from the line connecting the endpoints, of the
* cubic curve specified by the controlpoints stored in the
* indicated array at the indicated index.
*/
public static double getFlatness(double coords[], int offset) {
return getFlatness(coords[offset + 0], coords[offset + 1],
coords[offset + 2], coords[offset + 3],
coords[offset + 4], coords[offset + 5],
coords[offset + 6], coords[offset + 7]);
}
/**
* Returns the square of the flatness, or maximum distance of a
* controlpoint from the line connecting the endpoints, of this curve.
*/
public double getFlatnessSq() {
return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
getCtrlX2(), getCtrlY2(), getX2(), getY2());
}
/**
* Returns the flatness, or maximum distance of a
* controlpoint from the line connecting the endpoints, of this curve.
*/
public double getFlatness() {
return getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
getCtrlX2(), getCtrlY2(), getX2(), getY2());
}
/**
* Subdivides this cubic curve and stores the resulting two
* subdivided curves into the left and right curve parameters.
* Either or both of the left and right objects may be the same
* as this object or null.
* @param left the cubic curve object for storing for the left or
* first half of the subdivided curve
* @param right the cubic curve object for storing for the right or
* second half of the subdivided curve
*/
public void subdivide(CubicCurve2D left, CubicCurve2D right) {
subdivide(this, left, right);
}
/**
* Subdivides the cubic curve specified by the src parameter
* and stores the resulting two subdivided curves into the left
* and right curve parameters.
* Either or both of the left and right objects may be the same
* as the src object or null.
* @param src the cubic curve to be subdivided
* @param left the cubic curve object for storing for the left or
* first half of the subdivided curve
* @param right the cubic curve object for storing for the right or
* second half of the subdivided curve
*/
public static void subdivide(CubicCurve2D src,
CubicCurve2D left,
CubicCurve2D right) {
double x1 = src.getX1();
double y1 = src.getY1();
double ctrlx1 = src.getCtrlX1();
double ctrly1 = src.getCtrlY1();
double ctrlx2 = src.getCtrlX2();
double ctrly2 = src.getCtrlY2();
double x2 = src.getX2();
double y2 = src.getY2();
double centerx = (ctrlx1 + ctrlx2) / 2.0;
double centery = (ctrly1 + ctrly2) / 2.0;
ctrlx1 = (x1 + ctrlx1) / 2.0;
ctrly1 = (y1 + ctrly1) / 2.0;
ctrlx2 = (x2 + ctrlx2) / 2.0;
ctrly2 = (y2 + ctrly2) / 2.0;
double ctrlx12 = (ctrlx1 + centerx) / 2.0;
double ctrly12 = (ctrly1 + centery) / 2.0;
double ctrlx21 = (ctrlx2 + centerx) / 2.0;
double ctrly21 = (ctrly2 + centery) / 2.0;
centerx = (ctrlx12 + ctrlx21) / 2.0;
centery = (ctrly12 + ctrly21) / 2.0;
if (left != null) {
left.setCurve(x1, y1, ctrlx1, ctrly1,
ctrlx12, ctrly12, centerx, centery);
}
if (right != null) {
right.setCurve(centerx, centery, ctrlx21, ctrly21,
ctrlx2, ctrly2, x2, y2);
}
}
/**
* Subdivides the cubic curve specified by the the coordinates
* stored in the src array at indices (srcoff) through (srcoff + 7)
* and stores the resulting two subdivided curves into the two
* result arrays at the corresponding indices.
* Either or both of the left and right arrays may be null or a
* reference to the same array as the src array.
* Note that the last point in the first subdivided curve is the
* same as the first point in the second subdivided curve and thus
* it is possible to pass the same array for left and right and
* to use offsets such that rightoff equals (leftoff + 6) in order
* to avoid allocating extra storage for this common point.
* @param src the array holding the coordinates for the source curve
* @param srcoff the offset into the array of the beginning of the
* the 6 source coordinates
* @param left the array for storing the coordinates for the first
* half of the subdivided curve
* @param leftoff the offset into the array of the beginning of the
* the 6 left coordinates
* @param right the array for storing the coordinates for the second
* half of the subdivided curve
* @param rightoff the offset into the array of the beginning of the
* the 6 right coordinates
*/
public static void subdivide(double src[], int srcoff,
double left[], int leftoff,
double right[], int rightoff) {
double x1 = src[srcoff + 0];
double y1 = src[srcoff + 1];
double ctrlx1 = src[srcoff + 2];
double ctrly1 = src[srcoff + 3];
double ctrlx2 = src[srcoff + 4];
double ctrly2 = src[srcoff + 5];
double x2 = src[srcoff + 6];
double y2 = src[srcoff + 7];
if (left != null) {
left[leftoff + 0] = x1;
left[leftoff + 1] = y1;
}
if (right != null) {
right[rightoff + 6] = x2;
right[rightoff + 7] = y2;
}
x1 = (x1 + ctrlx1) / 2.0;
y1 = (y1 + ctrly1) / 2.0;
x2 = (x2 + ctrlx2) / 2.0;
y2 = (y2 + ctrly2) / 2.0;
double centerx = (ctrlx1 + ctrlx2) / 2.0;
double centery = (ctrly1 + ctrly2) / 2.0;
ctrlx1 = (x1 + centerx) / 2.0;
ctrly1 = (y1 + centery) / 2.0;
ctrlx2 = (x2 + centerx) / 2.0;
ctrly2 = (y2 + centery) / 2.0;
centerx = (ctrlx1 + ctrlx2) / 2.0;
centery = (ctrly1 + ctrly2) / 2.0;
if (left != null) {
left[leftoff + 2] = x1;
left[leftoff + 3] = y1;
left[leftoff + 4] = ctrlx1;
left[leftoff + 5] = ctrly1;
left[leftoff + 6] = centerx;
left[leftoff + 7] = centery;
}
if (right != null) {
right[rightoff + 0] = centerx;
right[rightoff + 1] = centery;
right[rightoff + 2] = ctrlx2;
right[rightoff + 3] = ctrly2;
right[rightoff + 4] = x2;
right[rightoff + 5] = y2;
}
}
/**
* Solve the cubic whose coefficients are in the eqn array and
* place the non-complex roots back into the array, returning the
* number of roots. The quadratic solved is represented by the
* equation:
* eqn = {c, b, a, d}
* dx^3 + ax^2 + bx + c = 0
* A return value of -1 is used to distinguish a constant equation,
* which may be always 0 or never 0, from an equation which has no
* zeroes.
* @return the number of roots, or -1 if the equation is a constant
*/
public static int solveCubic(double eqn[]) {
// From Numerical Recipes, 5.6, Quadratic and Cubic Equations
double d = eqn[3];
if (d == 0.0) {
// The cubic has degenerated to quadratic (or line or ...).
return QuadCurve2D.solveQuadratic(eqn);
}
double a = eqn[2] / d;
double b = eqn[1] / d;
double c = eqn[0] / d;
int roots = 0;
double Q = (a * a - 3.0 * b) / 9.0;
double R = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0;
double R2 = R * R;
double Q3 = Q * Q * Q;
a = a / 3.0;
if (R2 < Q3) {
double theta = Math.acos(R / Math.sqrt(Q3));
Q = -2.0 * Math.sqrt(Q);
eqn[roots++] = Q * Math.cos(theta / 3.0) - a;
eqn[roots++] = Q * Math.cos((theta + Math.PI * 2.0)/ 3.0) - a;
eqn[roots++] = Q * Math.cos((theta - Math.PI * 2.0)/ 3.0) - a;
} else {
boolean neg = (R < 0.0);
double S = Math.sqrt(R2 - Q3);
if (neg) {
R = -R;
}
double A = Math.pow(R + S, 1.0 / 3.0);
if (!neg) {
A = -A;
}
double B = (A == 0.0) ? 0.0 : (Q / A);
eqn[roots++] = (A + B) - a;
}
return roots;
}
/**
* Test if a given coordinate is inside the boundary of the shape.
*/
public boolean contains(double x, double y) {
// We count the "Y" crossings to determine if the point is
// inside the curve bounded by its closing line.
int crossings = 0;
double x1 = getX1();
double y1 = getY1();
double x2 = getX2();
double y2 = getY2();
// First check for a crossing of the line connecting the endpoints
double dy = y2 - y1;
if ((dy > 0.0 && y >= y1 && y <= y2) ||
(dy < 0.0 && y <= y1 && y >= y2))
{
if (x <= x1 + (y - y1) * (x2 - x1) / dy) {
crossings++;
}
}
// Solve the Y parametric equation for intersections with y
// Since the points at t = 0.0 and t = 1.0 were already
// checked by the line test above, we are only interested
// in solutions in the range (0,1)
// We currently have:
// y = Py(t) = y1(1-t)^3 + 3cy1 t(1-t)^2 + 3cy2 t^2(1-t) + y2 t^3
// = y1 - 3y1t + 3y1t^2 - y1t^3 +
// 3cy1t - 6cy1t^2 + 3cy1t^3 +
// 3cy2t^2 - 3cy2t^3 +
// y2t^3
// 0 = (y1 - y) +
// (3cy1 - 3y1) t +
// (3y1 - 6cy1 + 3cy2) t^2 +
// (y2 - 3cy2 + 3cy1 - y1) t^3
// 0 = C + Bt + At^2 + Dt^3
double ctrlx1 = getCtrlX1();
double ctrly1 = getCtrlY1();
double ctrlx2 = getCtrlX2();
double ctrly2 = getCtrlY2();
double eqn[] = {y1 - y,
(ctrly1 - y1) * 3.0,
(y1 - ctrly1 - ctrly1 + ctrly2) * 3.0,
y2 + 3.0 * (ctrly1 - ctrly2) - y1};
int roots = solveCubic(eqn);
while (--roots >= 0) {
double t = eqn[roots];
if (t > 0.0 && t < 1.0) {
double u = 1.0 - t;
if (x <= (x1 * u * u * u
+ 3.0 * ctrlx1 * t * u * u
+ 3.0 * ctrlx2 * t * t * u
+ x2 * t * t * t)) {
crossings++;
}
}
}
return ((crossings & 1) == 1);
}
/**
* Test if a given Point is inside the boundary of the shape.
*/
public boolean contains(Point2D p) {
return contains(p.getX(), p.getY());
}
/**
* Test if the Shape intersects the interior of a given
* set of rectangular coordinates.
*/
public boolean intersects(double x, double y, double w, double h) {
double temp;
double count = 0;
double[] eqn = new double[4];
double[] backup = new double[4];
int result = 0;
/*
The first test is fast and so in certain instances
will return an answer very quickly
It can be dispensed with if need be,
as the second test will always return the correct result
*/
if ((getX1() >= x) && (getY1() >= y) && (getX1() <= (x+w))
&& (getY1() <= (y+h))) {
count++;
}
if ((getCtrlX1() >= x) && (getCtrlY1() >= y) && (getCtrlX1() < (x+w))
&& (getCtrlY1() < (y+h))) {
count++;
}
if ((getX2() >= x) && (getY2() >= y) && (getX2() < (x+w))
&& (getY2() < (y+h))) {
count++;
}
if ((getCtrlX2() >= x) && (getCtrlY2() >= y) && (getCtrlX2() < (x+w))
&& (getCtrlY2() < (y+h))) {
count ++;
}
if (count > 1) {
return true;
}
/*
Solve the cubic with the 0th number being our rect line segment
returns -1 if not intersection, else return true
make sure that the intersection occurs between the two endpoints
*/
eqn[0] = getX1() - x;
eqn[1] = (3 * getCtrlX1()) - (3 * getX1());
eqn[2] = (3 * getX1()) + (3 * getCtrlX2()) - (6 * getCtrlX1());
eqn[3] = (3 * getCtrlX1()) + getX2() - ( 3 * getCtrlX2()) - getX1();
System.arraycopy(eqn, 0, backup, 0, 4);
result = solveCubic(eqn);
for (int i = 0; i < result; i++) {
if ((eqn[i] >= 0) && (eqn[i] <= 1)) {
temp = (getY1() * Math.pow((1-eqn[i]),3))
+ (getCtrlY1() * 3 * eqn[i] * Math.pow((1-eqn[i]), 2))
+ (getCtrlY2() * 3 * Math.pow(eqn[i], 2) * (1 - eqn[i]))
+ (getY2() * Math.pow(eqn[i], 3));
double temp2 = 0;
temp2 = (getX1() * Math.pow((1-eqn[i]),3))
+ (getCtrlX1() * 3 * eqn[i] * Math.pow((1-eqn[i]), 2))
+ (getCtrlX2() * 3 * Math.pow(eqn[i], 2) * (1 - eqn[i]))
+ (getX2() * Math.pow(eqn[i], 3));
if ((temp >= y) && (temp <= (y+h))) {
return true;
}
}
}
System.arraycopy(backup, 0, eqn, 0, 4);
eqn[0] = getX1() - (x + w);
System.arraycopy(eqn, 0, backup, 0, 4);
result = solveCubic(eqn);
for (int i = 0; i < result; i++) {
if ((eqn[i] >= 0) && (eqn[i] <= 1)) {
temp = (getY1() * Math.pow((1-eqn[i]),3))
+ (getCtrlY1() * 3 * eqn[i] * Math.pow((1-eqn[i]), 2))
+ (getCtrlY2() * 3 * Math.pow(eqn[i], 2) * (1 - eqn[i]))
+ (getY2() * Math.pow(eqn[i], 3));
if ((temp >= y) && (temp <= (y+h))) {
return true;
}
}
}
eqn[0] = getY1() - y;
eqn[1] = (3 * getCtrlY1()) - (3 * getY1());
eqn[2] = (3 * getY1()) + (3 * getCtrlY2()) - (6 * getCtrlY1());
eqn[3] = (3 * getCtrlY1()) + getY2() - ( 3 * getCtrlY2()) - getY1();
System.arraycopy(eqn, 0, backup, 0, 4);
result = solveCubic(eqn);
for (int i = 0; i < result; i++) {
if ((eqn[i] >= 0) && (eqn[i] <= 1)) {
temp = (getX1() * Math.pow((1-eqn[i]),3))
+ (getCtrlX1() * 3 * eqn[i] * Math.pow((1-eqn[i]), 2))
+ (getCtrlX2() * 3 * Math.pow(eqn[i], 2) * (1 - eqn[i]))
+ (getX2() * Math.pow(eqn[i], 3));
if ((temp >= x) && (temp <= (x+w))) {
return true;
}
}
}
System.arraycopy(backup, 0, eqn, 0, 4);
eqn[0] = getY1() - (y + h);
System.arraycopy(eqn, 0, backup, 0, 4);
result = solveCubic(eqn);
for (int i = 0; i < result; i++) {
if ((eqn[i] >= 0) && (eqn[i] <= 1)) {
temp = (getX1() * Math.pow((1-eqn[i]),3))
+ (getCtrlX1() * 3 * eqn[i] * Math.pow((1-eqn[i]), 2))
+ (getCtrlX2() * 3 * Math.pow(eqn[i], 2) * (1 - eqn[i]))
+ (getX2() * Math.pow(eqn[i], 3));
if ((temp >= x) && (temp <= (x+w))) {
return true;
}
}
}
return false;
}
/**
* Test if the Shape intersects the interior of a given
* Rectangle.
*/
public boolean intersects(Rectangle2D r) {
return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
/**
* Test if the interior of the Shape entirely contains the given
* set of rectangular coordinates.
*/
public boolean contains(double x, double y, double w, double h) {
// Assertion: Cubic curves closed by connecting their
// endpoints form either one or two convex halves with
// the closing line segment as an edge of both sides.
if (!(contains(x, y) &&
contains(x + w, y) &&
contains(x + w, y + h) &&
contains(x, y + h))) {
return false;
}
// Either the rectangle is entirely inside one of the convex
// halves or it crosses from one to the other, in which case
// it must intersect the closing line segment.
Rectangle2D rect = new Rectangle2D.Double(x, y, w, h);
return !rect.intersectsLine(getX1(), getY1(), getX2(), getY2());
}
/**
* Test if the interior of the Shape entirely contains the given
* Rectangle.
*/
public boolean contains(Rectangle2D r) {
return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
/**
* Return the bounding box of the shape.
*/
public Rectangle getBounds() {
return getBounds2D().getBounds();
}
/**
* Return an iteration object that defines the boundary of the
* shape.
*/
public PathIterator getPathIterator(AffineTransform at) {
return new CubicIterator(this, at);
}
/**
* Return an iteration object that defines the boundary of the
* flattened shape.
*/
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return new FlatteningPathIterator(getPathIterator(at), flatness);
}
/**
* Creates a new object of the same class as this object.
*
* @return a clone of this instance.
* @exception OutOfMemoryError if there is not enough memory.
* @see java.lang.Cloneable
* @since JDK1.2
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
}