This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Hi, This merges in the work done by Sven de Marothy on java.awt.geom. 2004-08-08 Mark Wielaard <mark@klomp.org> * java/awt/geom/CubicCurve2D.java (solveCubic): Removed duplicate comments. 2004-08-01 Sven de Marothy <sven@physto.se> * java/awt/geom/CubicCurve2D.java: Reindent. (contains): Implemented. (intersects): Implemented. * java/awt/geom/QuadCurve2D.java: Likewise. * java/awt/geom/GeneralPath.java: Reindent and document. Fully (re)implemented using separate xpoints and ypoints float[] coords. * java/awt/geom/RoundRectangle2D.java: Several bugfixes (Bug #6007). Committed to the gui branch. Cheers, Mark
Index: java/awt/geom/CubicCurve2D.java =================================================================== RCS file: /cvs/gcc/gcc/libjava/java/awt/geom/CubicCurve2D.java,v retrieving revision 1.4 diff -u -r1.4 CubicCurve2D.java --- java/awt/geom/CubicCurve2D.java 5 Jan 2004 19:19:29 -0000 1.4 +++ java/awt/geom/CubicCurve2D.java 8 Aug 2004 19:38:26 -0000 @@ -1,5 +1,5 @@ /* CubicCurve2D.java -- represents a parameterized cubic curve in 2-D space - Copyright (C) 2002, 2003 Free Software Foundation + Copyright (C) 2002, 2003, 2004 Free Software Foundation This file is part of GNU Classpath. @@ -35,7 +35,6 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package java.awt.geom; import java.awt.Rectangle; @@ -53,12 +52,14 @@ * @author Eric Blake (ebb9@email.byu.edu) * @author Graydon Hoare (graydon@redhat.com) * @author Sascha Brawer (brawer@dandelis.ch) + * @author Sven de Marothy (sven@physto.se) * * @since 1.2 */ -public abstract class CubicCurve2D - implements Shape, Cloneable +public abstract class CubicCurve2D implements Shape, Cloneable { + private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0; + /** * Constructs a new CubicCurve2D. Typical users will want to * construct instances of a subclass, such as {@link @@ -68,87 +69,74 @@ { } - /** * Returns the <i>x</i> coordinate of the curve’s start * point. */ public abstract double getX1(); - /** * Returns the <i>y</i> coordinate of the curve’s start * point. */ public abstract double getY1(); - /** * Returns the curve’s start point. */ public abstract Point2D getP1(); - /** * Returns the <i>x</i> coordinate of the curve’s first * control point. */ public abstract double getCtrlX1(); - /** * Returns the <i>y</i> coordinate of the curve’s first * control point. */ public abstract double getCtrlY1(); - /** * Returns the curve’s first control point. */ public abstract Point2D getCtrlP1(); - /** * Returns the <i>x</i> coordinate of the curve’s second * control point. */ public abstract double getCtrlX2(); - /** * Returns the <i>y</i> coordinate of the curve’s second * control point. */ public abstract double getCtrlY2(); - /** * Returns the curve’s second control point. */ public abstract Point2D getCtrlP2(); - /** * Returns the <i>x</i> coordinate of the curve’s end * point. */ public abstract double getX2(); - /** * Returns the <i>y</i> coordinate of the curve’s end * point. */ public abstract double getY2(); - /** * Returns the curve’s end point. */ public abstract Point2D getP2(); - /** * Changes the curve geometry, separately specifying each coordinate * value. @@ -183,7 +171,6 @@ public abstract void setCurve(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2); - /** * Changes the curve geometry, specifying coordinate values in an * array. @@ -206,13 +193,11 @@ */ public void setCurve(double[] coords, int offset) { - setCurve(coords[offset++], coords[offset++], - coords[offset++], coords[offset++], - coords[offset++], coords[offset++], + setCurve(coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++], coords[offset++], coords[offset++], coords[offset++]); } - /** * Changes the curve geometry, specifying coordinate values in * separate Point objects. @@ -232,11 +217,10 @@ */ public void setCurve(Point2D p1, Point2D c1, Point2D c2, Point2D p2) { - setCurve(p1.getX(), p1.getY(), c1.getX(), c1.getY(), - c2.getX(), c2.getY(), p2.getX(), p2.getY()); + setCurve(p1.getX(), p1.getY(), c1.getX(), c1.getY(), c2.getX(), c2.getY(), + p2.getX(), p2.getY()); } - /** * Changes the curve geometry, specifying coordinate values in an * array of Point objects. @@ -258,12 +242,10 @@ */ public void setCurve(Point2D[] pts, int offset) { - setCurve(pts[offset].getX(), pts[offset++].getY(), - pts[offset].getX(), pts[offset++].getY(), - pts[offset].getX(), pts[offset++].getY(), + setCurve(pts[offset].getX(), pts[offset++].getY(), pts[offset].getX(), + pts[offset++].getY(), pts[offset].getX(), pts[offset++].getY(), pts[offset].getX(), pts[offset++].getY()); } - /** * Changes the curve geometry to that of another curve. @@ -276,7 +258,6 @@ c.getCtrlX2(), c.getCtrlY2(), c.getX2(), c.getY2()); } - /** * Calculates the squared flatness of a cubic curve, directly * specifying each coordinate value. The flatness is the maximal @@ -309,7 +290,6 @@ Line2D.ptSegDistSq(x1, y1, x2, y2, cx2, cy2)); } - /** * Calculates the flatness of a cubic curve, directly specifying * each coordinate value. The flatness is the maximal distance of a @@ -340,7 +320,6 @@ return Math.sqrt(getFlatnessSq(x1, y1, cx1, cy1, cx2, cy2, x2, y2)); } - /** * Calculates the squared flatness of a cubic curve, specifying the * coordinate values in an array. The flatness is the maximal @@ -374,13 +353,11 @@ */ public static double getFlatnessSq(double[] coords, int offset) { - return getFlatnessSq(coords[offset++], coords[offset++], - coords[offset++], coords[offset++], - coords[offset++], coords[offset++], + return getFlatnessSq(coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++], coords[offset++], coords[offset++], coords[offset++]); } - /** * Calculates the flatness of a cubic curve, specifying the * coordinate values in an array. The flatness is the maximal @@ -420,7 +397,6 @@ coords[offset++], coords[offset++])); } - /** * Calculates the squared flatness of this curve. The flatness is * the maximal distance of a control point to the line between start @@ -441,7 +417,6 @@ getCtrlX2(), getCtrlY2(), getX2(), getY2()); } - /** * Calculates the flatness of this curve. The flatness is the * maximal distance of a control point to the line between start and @@ -458,12 +433,10 @@ */ public double getFlatness() { - return Math.sqrt(getFlatnessSq(getX1(), getY1(), getCtrlX1(), - getCtrlY1(), getCtrlX2(), getCtrlY2(), - getX2(), getY2())); + return Math.sqrt(getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(), + getCtrlX2(), getCtrlY2(), getX2(), getY2())); } - /** * Subdivides this curve into two halves. * @@ -482,9 +455,11 @@ public void subdivide(CubicCurve2D left, CubicCurve2D right) { // Use empty slots at end to share single array. - double[] d = new double[] { getX1(), getY1(), getCtrlX1(), getCtrlY1(), - getCtrlX2(), getCtrlY2(), getX2(), getY2(), - 0, 0, 0, 0, 0, 0 }; + double[] d = new double[] + { + getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(), + getCtrlY2(), getX2(), getY2(), 0, 0, 0, 0, 0, 0 + }; subdivide(d, 0, d, 0, d, 6); if (left != null) left.setCurve(d, 0); @@ -492,7 +467,6 @@ right.setCurve(d, 6); } - /** * Subdivides a cubic curve into two halves. * @@ -510,13 +484,12 @@ * of <code>src</code>, or <code>null</code> if the caller is not * interested in the right half. */ - public static void subdivide(CubicCurve2D src, - CubicCurve2D left, CubicCurve2D right) + public static void subdivide(CubicCurve2D src, CubicCurve2D left, + CubicCurve2D right) { src.subdivide(left, right); } - /** * Subdivides a cubic curve into two halves, passing all coordinates * in an array. @@ -563,18 +536,29 @@ * index where the start point’s <i>x</i> coordinate will be * stored. */ - public static void subdivide(double[] src, int srcOff, - double[] left, int leftOff, - double[] right, int rightOff) + public static void subdivide(double[] src, int srcOff, double[] left, + int leftOff, double[] right, int rightOff) { // To understand this code, please have a look at the image // "CubicCurve2D-3.png" in the sub-directory "doc-files". - double src_C1_x, src_C1_y, src_C2_x, src_C2_y; - double left_P1_x, left_P1_y; - double left_C1_x, left_C1_y, left_C2_x, left_C2_y; - double right_C1_x, right_C1_y, right_C2_x, right_C2_y; - double right_P2_x, right_P2_y; - double Mid_x, Mid_y; // Mid = left.P2 = right.P1 + double src_C1_x; + double src_C1_y; + double src_C2_x; + double src_C2_y; + double left_P1_x; + double left_P1_y; + double left_C1_x; + double left_C1_y; + double left_C2_x; + double left_C2_y; + double right_C1_x; + double right_C1_y; + double right_C2_x; + double right_C2_y; + double right_P2_x; + double right_P2_y; + double Mid_x; // Mid = left.P2 = right.P1 + double Mid_y; // Mid = left.P2 = right.P1 left_P1_x = src[srcOff]; left_P1_y = src[srcOff + 1]; @@ -599,31 +583,30 @@ Mid_y = (left_C2_y + right_C1_y) / 2; if (left != null) - { - left[leftOff] = left_P1_x; - left[leftOff + 1] = left_P1_y; - left[leftOff + 2] = left_C1_x; - left[leftOff + 3] = left_C1_y; - left[leftOff + 4] = left_C2_x; - left[leftOff + 5] = left_C2_y; - left[leftOff + 6] = Mid_x; - left[leftOff + 7] = Mid_y; - } + { + left[leftOff] = left_P1_x; + left[leftOff + 1] = left_P1_y; + left[leftOff + 2] = left_C1_x; + left[leftOff + 3] = left_C1_y; + left[leftOff + 4] = left_C2_x; + left[leftOff + 5] = left_C2_y; + left[leftOff + 6] = Mid_x; + left[leftOff + 7] = Mid_y; + } if (right != null) - { - right[rightOff] = Mid_x; - right[rightOff + 1] = Mid_y; - right[rightOff + 2] = right_C1_x; - right[rightOff + 3] = right_C1_y; - right[rightOff + 4] = right_C2_x; - right[rightOff + 5] = right_C2_y; - right[rightOff + 6] = right_P2_x; - right[rightOff + 7] = right_P2_y; - } + { + right[rightOff] = Mid_x; + right[rightOff + 1] = Mid_y; + right[rightOff + 2] = right_C1_x; + right[rightOff + 3] = right_C1_y; + right[rightOff + 4] = right_C2_x; + right[rightOff + 5] = right_C2_y; + right[rightOff + 6] = right_P2_x; + right[rightOff + 7] = right_P2_y; + } } - /** * Finds the non-complex roots of a cubic equation, placing the * results into the same array as the equation coefficients. The @@ -670,7 +653,6 @@ return solveCubic(eqn, eqn); } - /** * Finds the non-complex roots of a cubic equation. The following * equation is being solved: @@ -727,9 +709,19 @@ // The Java implementation is very similar to the GSL code, but // not a strict one-to-one copy. For example, GSL would sort the // result. - - double a, b, c, q, r, Q, R; - double c3, Q3, R2, CR2, CQ3; + + double a; + double b; + double c; + double q; + double r; + double Q; + double R; + double c3; + double Q3; + double R2; + double CR2; + double CQ3; // If the cubic coefficient is zero, we have a quadratic equation. c3 = eqn[3]; @@ -755,219 +747,267 @@ CQ3 = 2916 * q * q * q; if (R == 0 && Q == 0) - { - // The GNU Scientific Library would return three identical - // solutions in this case. - res[0] = -a/3; - return 1; - } - - if (CR2 == CQ3) - { - /* this test is actually R2 == Q3, written in a form suitable - for exact computation with integers */ - - /* Due to finite precision some double roots may be missed, and - considered to be a pair of complex roots z = x +/- epsilon i - close to the real axis. */ - - double sqrtQ = Math.sqrt(Q); - - if (R > 0) { - res[0] = -2 * sqrtQ - a/3; - res[1] = sqrtQ - a/3; + // The GNU Scientific Library would return three identical + // solutions in this case. + res[0] = -a / 3; + return 1; } - else + + if (CR2 == CQ3) { - res[0] = -sqrtQ - a/3; - res[1] = 2 * sqrtQ - a/3; + /* this test is actually R2 == Q3, written in a form suitable + for exact computation with integers */ + /* Due to finite precision some double roots may be missed, and + considered to be a pair of complex roots z = x +/- epsilon i + close to the real axis. */ + double sqrtQ = Math.sqrt(Q); + + if (R > 0) + { + res[0] = -2 * sqrtQ - a / 3; + res[1] = sqrtQ - a / 3; + } + else + { + res[0] = -sqrtQ - a / 3; + res[1] = 2 * sqrtQ - a / 3; + } + return 2; } - return 2; - } if (CR2 < CQ3) /* equivalent to R2 < Q3 */ - { - double sqrtQ = Math.sqrt(Q); - double sqrtQ3 = sqrtQ * sqrtQ * sqrtQ; - double theta = Math.acos(R / sqrtQ3); - double norm = -2 * sqrtQ; - res[0] = norm * Math.cos(theta / 3) - a / 3; - res[1] = norm * Math.cos((theta + 2.0 * Math.PI) / 3) - a/3; - res[2] = norm * Math.cos((theta - 2.0 * Math.PI) / 3) - a/3; + { + double sqrtQ = Math.sqrt(Q); + double sqrtQ3 = sqrtQ * sqrtQ * sqrtQ; + double theta = Math.acos(R / sqrtQ3); + double norm = -2 * sqrtQ; + res[0] = norm * Math.cos(theta / 3) - a / 3; + res[1] = norm * Math.cos((theta + 2.0 * Math.PI) / 3) - a / 3; + res[2] = norm * Math.cos((theta - 2.0 * Math.PI) / 3) - a / 3; - // The GNU Scientific Library sorts the results. We don't. - return 3; - } + // The GNU Scientific Library sorts the results. We don't. + return 3; + } double sgnR = (R >= 0 ? 1 : -1); - double A = -sgnR * Math.pow(Math.abs(R) + Math.sqrt(R2 - Q3), 1.0/3.0); - double B = Q / A ; - res[0] = A + B - a/3; + double A = -sgnR * Math.pow(Math.abs(R) + Math.sqrt(R2 - Q3), 1.0 / 3.0); + double B = Q / A; + res[0] = A + B - a / 3; return 1; } - /** - * Determines whether a position lies inside the area that is bounded + * Determines whether a position lies inside the area bounded * by the curve and the straight line connecting its end points. * * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" * alt="A drawing of the area spanned by the curve" /> * * <p>The above drawing illustrates in which area points are - * considered “contained” in a CubicCurve2D. + * considered “inside” a CubicCurve2D. */ public boolean contains(double x, double y) { - // XXX Implement. - throw new Error("not implemented"); - } + if (! getBounds2D().contains(x, y)) + return false; + return ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0); + } /** - * Determines whether a point lies inside the area that is bounded + * Determines whether a point lies inside the area bounded * by the curve and the straight line connecting its end points. * * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" * alt="A drawing of the area spanned by the curve" /> * * <p>The above drawing illustrates in which area points are - * considered “contained” in a CubicCurve2D. + * considered “inside” a CubicCurve2D. */ public boolean contains(Point2D p) { return contains(p.getX(), p.getY()); } - + /** + * Determines whether any part of a rectangle is inside the area bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” in a CubicCurve2D. + * @see #contains(double, double) + */ public boolean intersects(double x, double y, double w, double h) { - // XXX Implement. - throw new Error("not implemented"); - } + if (! getBounds2D().contains(x, y, w, h)) + return false; + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return true; + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + + /** + * Determines whether any part of a Rectangle2D is inside the area bounded + * by the curve and the straight line connecting its end points. + * @see #intersects(double, double, double, double) + */ public boolean intersects(Rectangle2D r) { return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } - + /** + * Determine whether a rectangle is entirely inside the area that is bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” a CubicCurve2D. + * @see #contains(double, double) + */ public boolean contains(double x, double y, double w, double h) { - // XXX Implement. - throw new Error("not implemented"); - } + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return false; + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + return false; + } + + /** + * Determine whether a Rectangle2D is entirely inside the area that is + * bounded by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/CubicCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” a CubicCurve2D. + * @see #contains(double, double) + */ public boolean contains(Rectangle2D r) { return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } - /** * Determines the smallest rectangle that encloses the - * curve’s start, end and control points. As the illustration - * below shows, the invisible control points may cause the bounds to - * be much larger than the area that is actually covered by the - * curve. - * - * <p><img src="doc-files/CubicCurve2D-2.png" width="350" height="180" - * alt="An illustration of the bounds of a CubicCurve2D" /> + * curve’s start, end and control points. */ public Rectangle getBounds() { return getBounds2D().getBounds(); } - public PathIterator getPathIterator(final AffineTransform at) { return new PathIterator() - { - /** Current coordinate. */ - private int current = 0; - - public int getWindingRule() - { - return WIND_NON_ZERO; - } - - public boolean isDone() { - return current >= 2; - } - - public void next() - { - current++; - } + /** Current coordinate. */ + private int current = 0; - public int currentSegment(float[] coords) - { - int result; - switch (current) - { - case 0: - coords[0] = (float) getX1(); - coords[1] = (float) getY1(); - result = SEG_MOVETO; - break; - case 1: - coords[0] = (float) getCtrlX1(); - coords[1] = (float) getCtrlY1(); - coords[2] = (float) getCtrlX2(); - coords[3] = (float) getCtrlY2(); - coords[4] = (float) getX2(); - coords[5] = (float) getY2(); - result = SEG_CUBICTO; - break; - default: - throw new NoSuchElementException("cubic iterator out of bounds"); - } - if (at != null) - at.transform(coords, 0, coords, 0, 3); - return result; - } - - public int currentSegment(double[] coords) - { - int result; - switch (current) - { - case 0: - coords[0] = getX1(); - coords[1] = getY1(); - result = SEG_MOVETO; - break; - case 1: - coords[0] = getCtrlX1(); - coords[1] = getCtrlY1(); - coords[2] = getCtrlX2(); - coords[3] = getCtrlY2(); - coords[4] = getX2(); - coords[5] = getY2(); - result = SEG_CUBICTO; - break; - default: - throw new NoSuchElementException("cubic iterator out of bounds"); - } - if (at != null) - at.transform(coords, 0, coords, 0, 3); - return result; - } - }; + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current >= 2; + } + + public void next() + { + current++; + } + + public int currentSegment(float[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = (float) getX1(); + coords[1] = (float) getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = (float) getCtrlX1(); + coords[1] = (float) getCtrlY1(); + coords[2] = (float) getCtrlX2(); + coords[3] = (float) getCtrlY2(); + coords[4] = (float) getX2(); + coords[5] = (float) getY2(); + result = SEG_CUBICTO; + break; + default: + throw new NoSuchElementException("cubic iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 3); + return result; + } + + public int currentSegment(double[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = getX1(); + coords[1] = getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = getCtrlX1(); + coords[1] = getCtrlY1(); + coords[2] = getCtrlX2(); + coords[3] = getCtrlY2(); + coords[4] = getX2(); + coords[5] = getY2(); + result = SEG_CUBICTO; + break; + default: + throw new NoSuchElementException("cubic iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 3); + return result; + } + }; } - public PathIterator getPathIterator(AffineTransform at, double flatness) { return new FlatteningPathIterator(getPathIterator(at), flatness); } - /** * Create a new curve with the same contents as this one. * @@ -976,15 +1016,118 @@ public Object clone() { try - { - return super.clone(); - } + { + return super.clone(); + } catch (CloneNotSupportedException e) - { - throw (Error) new InternalError().initCause(e); // Impossible - } + { + throw (Error) new InternalError().initCause(e); // Impossible + } } + /** + * Helper method used by contains() and intersects() methods, that + * returns the number of curve/line intersections on a given axis + * extending from a certain point. + * + * @param x x coordinate of the origin point + * @param y y coordinate of the origin point + * @param useYaxis axis used, if true the positive Y axis is used, + * false uses the positive X axis. + * + * This is an implementation of the line-crossings algorithm, + * Detailed in an article on Eric Haines' page: + * http://www.acm.org/tog/editors/erich/ptinpoly/ + * + * A special-case not adressed in this code is self-intersections + * of the curve, e.g. if the axis intersects the self-itersection, + * the degenerate roots of the polynomial will erroneously count as + * a single intersection of the curve, and not two. + */ + private int getAxisIntersections(double x, double y, boolean useYaxis, + double distance) + { + int nCrossings = 0; + double a0; + double a1; + double a2; + double a3; + double b0; + double b1; + double b2; + double b3; + double[] r = new double[4]; + int nRoots; + + a0 = a3 = 0.0; + + if (useYaxis) + { + a0 = getY1() - y; + a1 = getCtrlY1() - y; + a2 = getCtrlY2() - y; + a3 = getY2() - y; + b0 = getX1() - x; + b1 = getCtrlX1() - x; + b2 = getCtrlX2() - x; + b3 = getX2() - x; + } + else + { + a0 = getX1() - x; + a1 = getCtrlX1() - x; + a2 = getCtrlX2() - x; + a3 = getX2() - x; + b0 = getY1() - y; + b1 = getCtrlY1() - y; + b2 = getCtrlY2() - y; + b3 = getY2() - y; + } + + /* If the axis intersects a start/endpoint, shift it up by some small + amount to guarantee the line is 'inside' + If this is not done, bad behaviour may result for points on that axis.*/ + if (a0 == 0.0 || a3 == 0.0) + { + double small = getFlatness() * (1E-10); + if (a0 == 0.0) + a0 += small; + if (a3 == 0.0) + a3 += small; + } + + if (useYaxis) + { + if (Line2D.linesIntersect(b0, a0, b3, a3, 0.0, 0.0, distance, 0.0)) + nCrossings++; + } + else + { + if (Line2D.linesIntersect(a0, b0, a3, b3, 0.0, 0.0, 0.0, distance)) + nCrossings++; + } + + r[0] = a0; + r[1] = 3 * (a1 - a0); + r[2] = 3 * (a2 + a0 - 2 * a1); + r[3] = a3 - 3 * a2 + 3 * a1 - a0; + + if ((nRoots = solveCubic(r)) != 0) + for (int i = 0; i < nRoots; i++) + { + double t = r[i]; + if (t >= 0.0 && t <= 1.0) + { + double crossing = -(t * t * t) * (b0 - 3 * b1 + 3 * b2 - b3) + + 3 * t * t * (b0 - 2 * b1 + b2) + + 3 * t * (b1 - b0) + b0; + if (crossing > 0.0 && crossing <= distance) + nCrossings++; + } + } + + return (nCrossings); + } /** * A two-dimensional curve that is parameterized with a cubic @@ -996,57 +1139,48 @@ * @author Eric Blake (ebb9@email.byu.edu) * @author Sascha Brawer (brawer@dandelis.ch) */ - public static class Double - extends CubicCurve2D + public static class Double extends CubicCurve2D { /** * The <i>x</i> coordinate of the curve’s start point. */ public double x1; - /** * The <i>y</i> coordinate of the curve’s start point. */ public double y1; - /** * The <i>x</i> coordinate of the curve’s first control point. */ public double ctrlx1; - /** * The <i>y</i> coordinate of the curve’s first control point. */ public double ctrly1; - /** * The <i>x</i> coordinate of the curve’s second control point. */ public double ctrlx2; - /** * The <i>y</i> coordinate of the curve’s second control point. */ public double ctrly2; - /** * The <i>x</i> coordinate of the curve’s end point. */ public double x2; - /** * The <i>y</i> coordinate of the curve’s end point. */ public double y2; - /** * Constructs a new CubicCurve2D that stores its coordinate values * in double-precision floating-point format. All points are @@ -1056,7 +1190,6 @@ { } - /** * Constructs a new CubicCurve2D that stores its coordinate values * in double-precision floating-point format, specifying the @@ -1089,8 +1222,8 @@ * @param y2 the <i>y</i> coordinate of the curve’s end * point. */ - public Double(double x1, double y1, double cx1, double cy1, - double cx2, double cy2, double x2, double y2) + public Double(double x1, double y1, double cx1, double cy1, double cx2, + double cy2, double x2, double y2) { this.x1 = x1; this.y1 = y1; @@ -1102,7 +1235,6 @@ this.y2 = y2; } - /** * Returns the <i>x</i> coordinate of the curve’s start * point. @@ -1112,7 +1244,6 @@ return x1; } - /** * Returns the <i>y</i> coordinate of the curve’s start * point. @@ -1122,7 +1253,6 @@ return y1; } - /** * Returns the curve’s start point. */ @@ -1131,7 +1261,6 @@ return new Point2D.Double(x1, y1); } - /** * Returns the <i>x</i> coordinate of the curve’s first * control point. @@ -1141,7 +1270,6 @@ return ctrlx1; } - /** * Returns the <i>y</i> coordinate of the curve’s first * control point. @@ -1151,7 +1279,6 @@ return ctrly1; } - /** * Returns the curve’s first control point. */ @@ -1160,7 +1287,6 @@ return new Point2D.Double(ctrlx1, ctrly1); } - /** * Returns the <i>x</i> coordinate of the curve’s second * control point. @@ -1170,7 +1296,6 @@ return ctrlx2; } - /** * Returns the <i>y</i> coordinate of the curve’s second * control point. @@ -1180,7 +1305,6 @@ return ctrly2; } - /** * Returns the curve’s second control point. */ @@ -1189,7 +1313,6 @@ return new Point2D.Double(ctrlx2, ctrly2); } - /** * Returns the <i>x</i> coordinate of the curve’s end * point. @@ -1199,7 +1322,6 @@ return x2; } - /** * Returns the <i>y</i> coordinate of the curve’s end * point. @@ -1209,7 +1331,6 @@ return y2; } - /** * Returns the curve’s end point. */ @@ -1218,7 +1339,6 @@ return new Point2D.Double(x2, y2); } - /** * Changes the curve geometry, separately specifying each coordinate * value. @@ -1263,7 +1383,6 @@ this.y2 = y2; } - /** * Determines the smallest rectangle that encloses the * curve’s start, end and control points. As the @@ -1284,7 +1403,6 @@ } } - /** * A two-dimensional curve that is parameterized with a cubic * function and stores coordinate values in single-precision @@ -1295,57 +1413,48 @@ * @author Eric Blake (ebb9@email.byu.edu) * @author Sascha Brawer (brawer@dandelis.ch) */ - public static class Float - extends CubicCurve2D + public static class Float extends CubicCurve2D { /** * The <i>x</i> coordinate of the curve’s start point. */ public float x1; - /** * The <i>y</i> coordinate of the curve’s start point. */ public float y1; - /** * The <i>x</i> coordinate of the curve’s first control point. */ public float ctrlx1; - /** * The <i>y</i> coordinate of the curve’s first control point. */ public float ctrly1; - /** * The <i>x</i> coordinate of the curve’s second control point. */ public float ctrlx2; - /** * The <i>y</i> coordinate of the curve’s second control point. */ public float ctrly2; - /** * The <i>x</i> coordinate of the curve’s end point. */ public float x2; - /** * The <i>y</i> coordinate of the curve’s end point. */ public float y2; - /** * Constructs a new CubicCurve2D that stores its coordinate values * in single-precision floating-point format. All points are @@ -1355,7 +1464,6 @@ { } - /** * Constructs a new CubicCurve2D that stores its coordinate values * in single-precision floating-point format, specifying the @@ -1388,8 +1496,8 @@ * @param y2 the <i>y</i> coordinate of the curve’s end * point. */ - public Float(float x1, float y1, float cx1, float cy1, - float cx2, float cy2, float x2, float y2) + public Float(float x1, float y1, float cx1, float cy1, float cx2, + float cy2, float x2, float y2) { this.x1 = x1; this.y1 = y1; @@ -1401,7 +1509,6 @@ this.y2 = y2; } - /** * Returns the <i>x</i> coordinate of the curve’s start * point. @@ -1411,7 +1518,6 @@ return x1; } - /** * Returns the <i>y</i> coordinate of the curve’s start * point. @@ -1421,7 +1527,6 @@ return y1; } - /** * Returns the curve’s start point. */ @@ -1430,7 +1535,6 @@ return new Point2D.Float(x1, y1); } - /** * Returns the <i>x</i> coordinate of the curve’s first * control point. @@ -1440,7 +1544,6 @@ return ctrlx1; } - /** * Returns the <i>y</i> coordinate of the curve’s first * control point. @@ -1450,7 +1553,6 @@ return ctrly1; } - /** * Returns the curve’s first control point. */ @@ -1459,7 +1561,6 @@ return new Point2D.Float(ctrlx1, ctrly1); } - /** * Returns the <i>s</i> coordinate of the curve’s second * control point. @@ -1469,7 +1570,6 @@ return ctrlx2; } - /** * Returns the <i>y</i> coordinate of the curve’s second * control point. @@ -1479,7 +1579,6 @@ return ctrly2; } - /** * Returns the curve’s second control point. */ @@ -1488,7 +1587,6 @@ return new Point2D.Float(ctrlx2, ctrly2); } - /** * Returns the <i>x</i> coordinate of the curve’s end * point. @@ -1498,7 +1596,6 @@ return x2; } - /** * Returns the <i>y</i> coordinate of the curve’s end * point. @@ -1508,7 +1605,6 @@ return y2; } - /** * Returns the curve’s end point. */ @@ -1517,7 +1613,6 @@ return new Point2D.Float(x2, y2); } - /** * Changes the curve geometry, separately specifying each coordinate * value as a double-precision floating-point number. @@ -1562,7 +1657,6 @@ this.y2 = (float) y2; } - /** * Changes the curve geometry, separately specifying each coordinate * value as a single-precision floating-point number. @@ -1594,8 +1688,8 @@ * @param y2 the <i>y</i> coordinate of the curve’s new end * point. */ - public void setCurve(float x1, float y1, float cx1, float cy1, - float cx2, float cy2, float x2, float y2) + public void setCurve(float x1, float y1, float cx1, float cy1, float cx2, + float cy2, float x2, float y2) { this.x1 = x1; this.y1 = y1; @@ -1607,7 +1701,6 @@ this.y2 = y2; } - /** * Determines the smallest rectangle that encloses the * curve’s start, end and control points. As the Index: java/awt/geom/GeneralPath.java =================================================================== RCS file: /cvs/gcc/gcc/libjava/java/awt/geom/GeneralPath.java,v retrieving revision 1.3 diff -u -r1.3 GeneralPath.java --- java/awt/geom/GeneralPath.java 21 Oct 2003 13:18:22 -0000 1.3 +++ java/awt/geom/GeneralPath.java 8 Aug 2004 19:38:26 -0000 @@ -1,50 +1,80 @@ /* GeneralPath.java -- represents a shape built from subpaths - Copyright (C) 2002, 2003 Free Software Foundation + Copyright (C) 2002, 2003, 2004 Free Software Foundation -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -02111-1307 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ + This file is part of GNU Classpath. + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ package java.awt.geom; import java.awt.Rectangle; import java.awt.Shape; + /** - * STUBS ONLY - * XXX Implement and document. Note that Sun's implementation only expects - * float precision, not double. + * A general geometric path, consisting of any number of subpaths + * constructed out of straight lines and cubic or quadratic Bezier + * curves. + * + * <p>The inside of the curve is defined for drawing purposes by a winding + * rule. Either the WIND_EVEN_ODD or WIND_NON_ZERO winding rule can be chosen. + * + * <p><img src="doc-files/GeneralPath-1.png" width="300" height="210" + * alt="A drawing of a GeneralPath" /> + * <p>The EVEN_ODD winding rule defines a point as inside a path if: + * A ray from the point towards infinity in an arbitrary direction + * intersects the path an odd number of times. Points <b>A</b> and + * <b>C</b> in the image are considered to be outside the path. + * (both intersect twice) + * Point <b>B</b> intersects once, and is inside. + * + * <p>The NON_ZERO winding rule defines a point as inside a path if: + * The path intersects the ray in an equal number of opposite directions. + * Point <b>A</b> in the image is outside (one intersection in the + * ’up’ + * direction, one in the ’down’ direction) Point <b>B</b> in + * the image is inside (one intersection ’down’) + * Point <b>C</b> in the image is outside (two intersections + * ’down’) + * + * @see Line2D + * @see CubicCurve2D + * @see QuadCurve2D + * + * @author Sascha Brawer (brawer@dandelis.ch) + * @author Sven de Marothy (sven@physto.se) + * + * @since 1.2 */ public final class GeneralPath implements Shape, Cloneable { @@ -52,35 +82,63 @@ public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO; /** Initial size if not specified. */ - private static final int INIT_SIZE = 20; + private static final int INIT_SIZE = 10; + + /** A big number, but not so big it can't survive a few float operations */ + private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0; /** The winding rule. */ private int rule; + /** - * The path type in points. Note that points[index] maps to - * types[index >> 1]; the control points of quad and cubic paths map as + * The path type in points. Note that xpoints[index] and ypoints[index] maps + * to types[index]; the control points of quad and cubic paths map as * well but are ignored. */ private byte[] types; + /** * The list of all points seen. Since you can only append floats, it makes - * sense for this to be a float[]. I have no idea why Sun didn't choose to + * sense for these to be float[]. I have no idea why Sun didn't choose to * allow a general path of double precision points. + * Note: Storing x and y coords seperately makes for a slower transforms, + * But it speeds up and simplifies box-intersection checking a lot. */ - private float[] points; + private float[] xpoints; + private float[] ypoints; + /** The index of the most recent moveto point, or null. */ private int subpath = -1; + /** The next available index into points. */ private int index; + /** + * Constructs a GeneralPath with the default (NON_ZERO) + * winding rule and initial capacity (20). + */ public GeneralPath() { this(WIND_NON_ZERO, INIT_SIZE); } + + /** + * Constructs a GeneralPath with a specific winding rule + * and the default initial capacity (20). + * @param rule the winding rule (WIND_NON_ZERO or WIND_EVEN_ODD) + */ public GeneralPath(int rule) { this(rule, INIT_SIZE); } + + /** + * Constructs a GeneralPath with a specific winding rule + * and the initial capacity. The initial capacity should be + * the approximate number of path segments to be used. + * @param rule the winding rule (WIND_NON_ZERO or WIND_EVEN_ODD) + * @param capacity the inital capacity, in path segments + */ public GeneralPath(int rule, int capacity) { if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) @@ -88,68 +146,112 @@ this.rule = rule; if (capacity < INIT_SIZE) capacity = INIT_SIZE; - types = new byte[capacity >> 1]; - points = new float[capacity]; + types = new byte[capacity]; + xpoints = new float[capacity]; + ypoints = new float[capacity]; } + + /** + * Constructs a GeneralPath from an arbitrary shape object. + * The Shapes PathIterator path and winding rule will be used. + * @param s the shape + */ public GeneralPath(Shape s) { - types = new byte[INIT_SIZE >> 1]; - points = new float[INIT_SIZE]; + types = new byte[INIT_SIZE]; + xpoints = new float[INIT_SIZE]; + ypoints = new float[INIT_SIZE]; PathIterator pi = s.getPathIterator(null); setWindingRule(pi.getWindingRule()); append(pi, false); } + /** + * Adds a new point to a path. + */ public void moveTo(float x, float y) { subpath = index; - ensureSize(index + 2); - types[index >> 1] = PathIterator.SEG_MOVETO; - points[index++] = x; - points[index++] = y; + ensureSize(index + 1); + types[index] = PathIterator.SEG_MOVETO; + xpoints[index] = x; + ypoints[index++] = y; } + + /** + * Appends a straight line to the current path. + * @param x x coordinate of the line endpoint. + * @param y y coordinate of the line endpoint. + */ public void lineTo(float x, float y) { - ensureSize(index + 2); - types[index >> 1] = PathIterator.SEG_LINETO; - points[index++] = x; - points[index++] = y; + ensureSize(index + 1); + types[index] = PathIterator.SEG_LINETO; + xpoints[index] = x; + ypoints[index++] = y; } + + /** + * Appends a quadratic Bezier curve to the current path. + * @param x1 x coordinate of the control point + * @param y1 y coordinate of the control point + * @param x2 x coordinate of the curve endpoint. + * @param y2 y coordinate of the curve endpoint. + */ public void quadTo(float x1, float y1, float x2, float y2) { - ensureSize(index + 4); - types[index >> 1] = PathIterator.SEG_QUADTO; - points[index++] = x1; - points[index++] = y1; - points[index++] = x2; - points[index++] = y2; - } - public void curveTo(float x1, float y1, float x2, float y2, - float x3, float y3) - { - ensureSize(index + 6); - types[index >> 1] = PathIterator.SEG_CUBICTO; - points[index++] = x1; - points[index++] = y1; - points[index++] = x2; - points[index++] = y2; - points[index++] = x3; - points[index++] = y3; + ensureSize(index + 2); + types[index] = PathIterator.SEG_QUADTO; + xpoints[index] = x1; + ypoints[index++] = y1; + xpoints[index] = x2; + ypoints[index++] = y2; } + + /** + * Appends a cubic Bezier curve to the current path. + * @param x1 x coordinate of the first control point + * @param y1 y coordinate of the first control point + * @param x2 x coordinate of the second control point + * @param y2 y coordinate of the second control point + * @param x3 x coordinate of the curve endpoint. + * @param y3 y coordinate of the curve endpoint. + */ + public void curveTo(float x1, float y1, float x2, float y2, float x3, + float y3) + { + ensureSize(index + 3); + types[index] = PathIterator.SEG_CUBICTO; + xpoints[index] = x1; + ypoints[index++] = y1; + xpoints[index] = x2; + ypoints[index++] = y2; + xpoints[index] = x3; + ypoints[index++] = y3; + } + + /** + * Closes the current subpath by drawing a line + * back to the point of the last moveTo. + */ public void closePath() { - ensureSize(index + 2); - types[index >> 1] = PathIterator.SEG_CLOSE; - points[index++] = points[subpath]; - points[index++] = points[subpath + 1]; + ensureSize(index + 1); + types[index] = PathIterator.SEG_CLOSE; + xpoints[index] = xpoints[subpath]; + ypoints[index++] = ypoints[subpath]; } + /** + * Appends the segments of a Shape to the path. If <code>connect</code> is + * true, the new path segments are connected to the existing one with a line. + * The winding rule of the Shape is ignored. + */ public void append(Shape s, boolean connect) { append(s.getPathIterator(null), connect); } - /** * Appends the segments of a PathIterator to this GeneralPath. * Optionally, the initial {@link PathIterator#SEG_MOVETO} segment @@ -158,7 +260,7 @@ * * @param iter the PathIterator specifying which segments shall be * appended. - * + * * @param connect <code>true</code> for substituting the initial * {@link PathIterator#SEG_MOVETO} segment by a {@link * PathIterator#SEG_LINETO}, or <code>false</code> for not @@ -171,50 +273,55 @@ { // A bad implementation of this method had caused Classpath bug #6076. float[] f = new float[6]; - while (!iter.isDone()) - { - switch (iter.currentSegment(f)) + while (! iter.isDone()) { - case PathIterator.SEG_MOVETO: - if (!connect || (index == 0)) - { - moveTo(f[0], f[1]); - break; - } + switch (iter.currentSegment(f)) + { + case PathIterator.SEG_MOVETO: + if (! connect || (index == 0)) + { + moveTo(f[0], f[1]); + break; + } + if ((index >= 1) && (types[index - 1] == PathIterator.SEG_CLOSE) + && (f[0] == xpoints[index - 1]) + && (f[1] == ypoints[index - 1])) + break; + + // Fall through. + case PathIterator.SEG_LINETO: + lineTo(f[0], f[1]); + break; + case PathIterator.SEG_QUADTO: + quadTo(f[0], f[1], f[2], f[3]); + break; + case PathIterator.SEG_CUBICTO: + curveTo(f[0], f[1], f[2], f[3], f[4], f[5]); + break; + case PathIterator.SEG_CLOSE: + closePath(); + break; + } - if ((index >= 2) && (types[(index - 2) >> 2] == PathIterator.SEG_CLOSE) - && (f[0] == points[index - 2]) && (f[1] == points[index - 1])) - break; - - // Fall through. - - case PathIterator.SEG_LINETO: - lineTo(f[0], f[1]); - break; - - case PathIterator.SEG_QUADTO: - quadTo(f[0], f[1], f[2], f[3]); - break; - - case PathIterator.SEG_CUBICTO: - curveTo(f[0], f[1], f[2], f[3], f[4], f[5]); - break; - - case PathIterator.SEG_CLOSE: - closePath(); - break; + connect = false; + iter.next(); } - - connect = false; - iter.next(); - } } - + /** + * Returns the path’s current winding rule. + */ public int getWindingRule() { return rule; } + + /** + * Sets the path’s winding rule, which controls which areas are + * considered ’inside’ or ’outside’ the path + * on drawing. Valid rules are WIND_EVEN_ODD for an even-odd winding rule, + * or WIND_NON_ZERO for a non-zero winding rule. + */ public void setWindingRule(int rule) { if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) @@ -222,22 +329,48 @@ this.rule = rule; } + /** + * Returns the current appending point of the path. + */ public Point2D getCurrentPoint() { if (subpath < 0) return null; - return new Point2D.Float(points[index - 2], points[index - 1]); + return new Point2D.Float(xpoints[index - 1], ypoints[index - 1]); } + + /** + * Resets the path. All points and segments are destroyed. + */ public void reset() { subpath = -1; index = 0; } + /** + * Applies a transform to the path. + */ public void transform(AffineTransform xform) { - xform.transform(points, 0, points, 0, index >> 1); + double nx; + double ny; + double[] m = new double[6]; + xform.getMatrix(m); + for (int i = 0; i < index; i++) + { + nx = m[0] * xpoints[i] + m[2] * ypoints[i] + m[4]; + ny = m[1] * xpoints[i] + m[3] * ypoints[i] + m[5]; + xpoints[i] = (float) nx; + ypoints[i] = (float) ny; + } } + + /** + * Creates a transformed version of the path. + * @param xform the transform to apply + * @return a new transformed GeneralPath + */ public Shape createTransformedShape(AffineTransform xform) { GeneralPath p = new GeneralPath(this); @@ -245,85 +378,174 @@ return p; } + /** + * Returns the path’s bounding box. + */ public Rectangle getBounds() { return getBounds2D().getBounds(); } + + /** + * Returns the path’s bounding box, in <code>float</code> precision + */ public Rectangle2D getBounds2D() { - // XXX Implement. - throw new Error("not implemented"); + float x1; + float y1; + float x2; + float y2; + + if (index > 0) + { + x1 = x2 = xpoints[0]; + y1 = y2 = ypoints[0]; + } + else + x1 = x2 = y1 = y2 = 0.0f; + + for (int i = 0; i < index; i++) + { + x1 = Math.min(xpoints[i], x1); + y1 = Math.min(ypoints[i], y1); + x2 = Math.max(xpoints[i], x2); + y2 = Math.max(ypoints[i], y2); + } + return (new Rectangle2D.Float(x1, y1, x2 - x1, y2 - y1)); } + /** + * Evaluates if a point is within the GeneralPath, + * The NON_ZERO winding rule is used, regardless of the + * set winding rule. + * @param x x coordinate of the point to evaluate + * @param y y coordinate of the point to evaluate + * @return true if the point is within the path, false otherwise + */ public boolean contains(double x, double y) { - // XXX Implement. - throw new Error("not implemented"); + return (getWindingNumber(x, y) != 0); } + + /** + * Evaluates if a Point2D is within the GeneralPath, + * The NON_ZERO winding rule is used, regardless of the + * set winding rule. + * @param p The Point2D to evaluate + * @return true if the point is within the path, false otherwise + */ public boolean contains(Point2D p) { return contains(p.getX(), p.getY()); } + + /** + * Evaluates if a rectangle is completely contained within the path. + * This method will return false in the cases when the box + * intersects an inner segment of the path. + * (i.e.: The method is accurate for the EVEN_ODD winding rule) + */ public boolean contains(double x, double y, double w, double h) { - // XXX Implement. - throw new Error("not implemented"); + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, false, w) != 0 /* top */ + || getAxisIntersections(x, y + h, false, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, true, h) != 0 /* right */ + || getAxisIntersections(x, y, true, h) != 0) /* left */ + return false; + + /* No intersections, is any point inside? */ + if (getWindingNumber(x, y) != 0) + return true; + + return false; } + + /** + * Evaluates if a rectangle is completely contained within the path. + * This method will return false in the cases when the box + * intersects an inner segment of the path. + * (i.e.: The method is accurate for the EVEN_ODD winding rule) + * @param r the rectangle + * @return <code>true</code> if the rectangle is completely contained + * within the path, <code>false</code> otherwise + */ public boolean contains(Rectangle2D r) { return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } + /** + * Evaluates if a rectangle intersects the path. + * @param x x coordinate of the rectangle + * @param y y coordinate of the rectangle + * @param w width of the rectangle + * @param h height of the rectangle + * @return <code>true</code> if the rectangle intersects the path, + * <code>false</code> otherwise + */ public boolean intersects(double x, double y, double w, double h) { - // XXX Implement. - throw new Error("not implemented"); + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, false, w) != 0 /* top */ + || getAxisIntersections(x, y + h, false, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, true, h) != 0 /* right */ + || getAxisIntersections(x, y, true, h) != 0) /* left */ + return true; + + /* No intersections, is any point inside? */ + if (getWindingNumber(x, y) != 0) + return true; + + return false; } + + /** + * Evaluates if a Rectangle2D intersects the path. + * @param r The rectangle + * @return <code>true</code> if the rectangle intersects the path, + * <code>false</code> otherwise + */ public boolean intersects(Rectangle2D r) { return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } - /** * A PathIterator that iterates over the segments of a GeneralPath. * * @author Sascha Brawer (brawer@dandelis.ch) */ - private static class GeneralPathIterator - implements PathIterator + private static class GeneralPathIterator implements PathIterator { /** * The number of coordinate values for each segment type. */ - private static final int[] NUM_COORDS = - { - /* 0: SEG_MOVETO */ 2, - /* 1: SEG_LINETO */ 2, - /* 2: SEG_QUADTO */ 4, - /* 3: SEG_CUBICTO */ 6, - /* 4: SEG_CLOSE */ 0 - }; - + private static final int[] NUM_COORDS = { + /* 0: SEG_MOVETO */ 1, + /* 1: SEG_LINETO */ 1, + /* 2: SEG_QUADTO */ 2, + /* 3: SEG_CUBICTO */ 3, + /* 4: SEG_CLOSE */ 0}; /** * The GeneralPath whose segments are being iterated. */ private final GeneralPath path; - /** * The affine transformation used to transform coordinates. */ private final AffineTransform transform; - /** * The current position of the iterator. */ private int pos; - /** * Constructs a new iterator for enumerating the segments of a * GeneralPath. @@ -338,7 +560,6 @@ this.transform = transform; } - /** * Returns the current winding rule of the GeneralPath. */ @@ -347,7 +568,6 @@ return path.rule; } - /** * Determines whether the iterator has reached the last segment in * the path. @@ -357,7 +577,6 @@ return pos >= path.index; } - /** * Advances the iterator position by one segment. */ @@ -365,70 +584,72 @@ { int seg; - /* Increment pos by the number of coordinate values. Note that - * we store two values even for a SEG_CLOSE segment, which is - * why we increment pos at least by 2. + /* + * Increment pos by the number of coordinate pairs. */ - seg = path.types[pos >> 1]; + seg = path.types[pos]; if (seg == SEG_CLOSE) - pos += 2; + pos++; else - pos += NUM_COORDS[seg]; + pos += NUM_COORDS[seg]; } - /** * Returns the current segment in float coordinates. */ public int currentSegment(float[] coords) { - int seg, numCoords; + int seg; + int numCoords; - seg = path.types[pos >> 1]; + seg = path.types[pos]; numCoords = NUM_COORDS[seg]; if (numCoords > 0) - { - if (transform == null) - System.arraycopy(path.points, pos, coords, 0, numCoords); - else - transform.transform(/* src */ path.points, /* srcOffset */ pos, - /* dest */ coords, /* destOffset */ 0, - /* numPoints */ numCoords >> 1); - } + { + for (int i = 0; i < numCoords; i++) + { + coords[i << 1] = path.xpoints[pos + i]; + coords[(i << 1) + 1] = path.ypoints[pos + i]; + } + + if (transform != null) + transform.transform( /* src */ + coords, /* srcOffset */ + 0, /* dest */ coords, /* destOffset */ + 0, /* numPoints */ numCoords); + } return seg; } - /** * Returns the current segment in double coordinates. */ public int currentSegment(double[] coords) { - int seg, numCoords; + int seg; + int numCoords; - seg = path.types[pos >> 1]; + seg = path.types[pos]; numCoords = NUM_COORDS[seg]; if (numCoords > 0) - { - if (transform == null) { - // System.arraycopy throws an exception if the source and destination - // array are not of the same primitive type. - for (int i = 0; i < numCoords; i++) - coords[i] = (double) path.points[pos + i]; + for (int i = 0; i < numCoords; i++) + { + coords[i << 1] = (double) path.xpoints[pos + i]; + coords[(i << 1) + 1] = (double) path.ypoints[pos + i]; + } + if (transform != null) + transform.transform( /* src */ + coords, /* srcOffset */ + pos, /* dest */ coords, /* destOffset */ + 0, /* numPoints */ numCoords); } - else - transform.transform(/* src */ path.points, /* srcOffset */ pos, - /* dest */ coords, /* destOffset */ 0, - /* numPoints */ numCoords >> 1); - } return seg; } } - /** - * Creates a PathIterator for iterating along the segments of this path. + * Creates a PathIterator for iterating along the segments of the path. * * @param at an affine transformation for projecting the returned * points, or <code>null</code> to let the created iterator return @@ -439,15 +660,17 @@ return new GeneralPathIterator(this, at); } - + /** + * Creates a new FlatteningPathIterator for the path + */ public PathIterator getPathIterator(AffineTransform at, double flatness) { return new FlatteningPathIterator(getPathIterator(at), flatness); } /** - * Create a new shape of the same run-time type with the same contents as - * this one. + * Creates a new shape of the same run-time type with the same contents + * as this one. * * @return the clone * @@ -461,17 +684,261 @@ return new GeneralPath(this); } + /** + * Helper method - ensure the size of the data arrays, + * otherwise, reallocate new ones twice the size + */ private void ensureSize(int size) { if (subpath < 0) throw new IllegalPathStateException("need initial moveto"); - if (size <= points.length) + if (size <= xpoints.length) return; - byte[] b = new byte[points.length]; - System.arraycopy(types, 0, b, 0, index >> 1); + byte[] b = new byte[types.length << 1]; + System.arraycopy(types, 0, b, 0, index); types = b; - float[] f = new float[points.length << 1]; - System.arraycopy(points, 0, f, 0, index); - points = f; + float[] f = new float[xpoints.length << 1]; + System.arraycopy(xpoints, 0, f, 0, index); + xpoints = f; + f = new float[ypoints.length << 1]; + System.arraycopy(ypoints, 0, f, 0, index); + ypoints = f; + } + + /** + * Helper method - Get the total number of intersections from (x,y) along + * a given axis, within a given distance. + */ + private int getAxisIntersections(double x, double y, boolean useYaxis, + double distance) + { + return (evaluateCrossings(x, y, false, useYaxis, distance)); + } + + /** + * Helper method - returns the winding number of a point. + */ + private int getWindingNumber(double x, double y) + { + /* Evaluate the crossings from x,y to infinity on the y axis (arbitrary + choice). Note that we don't actually use Double.INFINITY, since that's + slower, and may cause problems. */ + return (evaluateCrossings(x, y, true, true, BIG_VALUE)); + } + + /** + * Helper method - evaluates the number of intersections on an axis from + * the point (x,y) to the point (x,y+distance) or (x+distance,y). + * @param x x coordinate. + * @param y y coordinate. + * @param neg True if opposite-directed intersections should cancel, + * false to sum all intersections. + * @param useYaxis Use the Y axis, false uses the X axis. + * @param distance Interval from (x,y) on the selected axis to find + * intersections. + */ + private int evaluateCrossings(double x, double y, boolean neg, + boolean useYaxis, double distance) + { + float cx = 0.0f; + float cy = 0.0f; + float firstx = 0.0f; + float firsty = 0.0f; + + int negative = (neg) ? -1 : 1; + double x0; + double x1; + double x2; + double x3; + double y0; + double y1; + double y2; + double y3; + double[] r = new double[4]; + int nRoots; + double epsilon = 0.0; + int pos = 0; + int windingNumber = 0; + boolean pathStarted = false; + + if (index == 0) + return (0); + if (useYaxis) + { + float[] swap1; + swap1 = ypoints; + ypoints = xpoints; + xpoints = swap1; + double swap2; + swap2 = y; + y = x; + x = swap2; + } + + /* Get a value which is hopefully small but not insignificant relative + the path. */ + epsilon = ypoints[0] * 1E-9; + + pos = 0; + while (pos < index) + { + switch (types[pos]) + { + case PathIterator.SEG_MOVETO: + if (pathStarted) // close old path + { + x0 = cx; + y0 = cy; + x1 = firstx; + y1 = firsty; + + if (y0 == 0.0) + y0 += epsilon; + if (y1 == 0.0) + y1 += epsilon; + if (Line2D.linesIntersect(x0, y0, x1, y1, 0.0, 0.0, distance, + 0.0)) + windingNumber += (y1 < y0) ? 1 : negative; + + cx = firstx; + cy = firsty; + } + cx = firstx = xpoints[pos] - (float) x; + cy = firsty = ypoints[pos++] - (float) y; + pathStarted = true; + break; + case PathIterator.SEG_CLOSE: + x0 = cx; + y0 = cy; + x1 = firstx; + y1 = firsty; + + if (y0 == 0.0) + y0 += epsilon; + if (y1 == 0.0) + y1 += epsilon; + if (Line2D.linesIntersect(x0, y0, x1, y1, 0.0, 0.0, distance, 0.0)) + windingNumber += (y1 < y0) ? 1 : negative; + + cx = firstx; + cy = firsty; + pos++; + pathStarted = false; + break; + case PathIterator.SEG_LINETO: + x0 = cx; + y0 = cy; + x1 = xpoints[pos] - (float) x; + y1 = ypoints[pos++] - (float) y; + + if (y0 == 0.0) + y0 += epsilon; + if (y1 == 0.0) + y1 += epsilon; + if (Line2D.linesIntersect(x0, y0, x1, y1, 0.0, 0.0, distance, 0.0)) + windingNumber += (y1 < y0) ? 1 : negative; + + cx = xpoints[pos - 1] - (float) x; + cy = ypoints[pos - 1] - (float) y; + break; + case PathIterator.SEG_QUADTO: + x0 = cx; + y0 = cy; + x1 = xpoints[pos] - x; + y1 = ypoints[pos++] - y; + x2 = xpoints[pos] - x; + y2 = ypoints[pos++] - y; + + /* check if curve may intersect X+ axis. */ + if ((x0 > 0.0 || x1 > 0.0 || x2 > 0.0) + && (y0 * y1 <= 0 || y1 * y2 <= 0)) + { + if (y0 == 0.0) + y0 += epsilon; + if (y2 == 0.0) + y2 += epsilon; + + r[0] = y0; + r[1] = 2 * (y1 - y0); + r[2] = (y2 - 2 * y1 + y0); + + /* degenerate roots (=tangent points) do not + contribute to the winding number. */ + if ((nRoots = QuadCurve2D.solveQuadratic(r)) == 2) + for (int i = 0; i < nRoots; i++) + { + float t = (float) r[i]; + if (t > 0.0f && t < 1.0f) + { + double crossing = t * t * (x2 - 2 * x1 + x0) + + 2 * t * (x1 - x0) + x0; + if (crossing >= 0.0 && crossing <= distance) + windingNumber += (2 * t * (y2 - 2 * y1 + y0) + + 2 * (y1 - y0) < 0) ? 1 : negative; + } + } + } + + cx = xpoints[pos - 1] - (float) x; + cy = ypoints[pos - 1] - (float) y; + break; + case PathIterator.SEG_CUBICTO: + x0 = cx; + y0 = cy; + x1 = xpoints[pos] - x; + y1 = ypoints[pos++] - y; + x2 = xpoints[pos] - x; + y2 = ypoints[pos++] - y; + x3 = xpoints[pos] - x; + y3 = ypoints[pos++] - y; + + /* check if curve may intersect X+ axis. */ + if ((x0 > 0.0 || x1 > 0.0 || x2 > 0.0 || x3 > 0.0) + && (y0 * y1 <= 0 || y1 * y2 <= 0 || y2 * y3 <= 0)) + { + if (y0 == 0.0) + y0 += epsilon; + if (y3 == 0.0) + y3 += epsilon; + + r[0] = y0; + r[1] = 3 * (y1 - y0); + r[2] = 3 * (y2 + y0 - 2 * y1); + r[3] = y3 - 3 * y2 + 3 * y1 - y0; + + if ((nRoots = CubicCurve2D.solveCubic(r)) != 0) + for (int i = 0; i < nRoots; i++) + { + float t = (float) r[i]; + if (t > 0.0 && t < 1.0) + { + double crossing = -(t * t * t) * (x0 - 3 * x1 + + 3 * x2 - x3) + + 3 * t * t * (x0 - 2 * x1 + x2) + + 3 * t * (x1 - x0) + x0; + if (crossing >= 0 && crossing <= distance) + windingNumber += (3 * t * t * (y3 + 3 * y1 + - 3 * y2 - y0) + + 6 * t * (y0 - 2 * y1 + y2) + + 3 * (y1 - y0) < 0) ? 1 : negative; + } + } + } + + cx = xpoints[pos - 1] - (float) x; + cy = ypoints[pos - 1] - (float) y; + break; + } + } + + // swap coordinates back + if (useYaxis) + { + float[] swap; + swap = ypoints; + ypoints = xpoints; + xpoints = swap; + } + return (windingNumber); } } // class GeneralPath Index: java/awt/geom/QuadCurve2D.java =================================================================== RCS file: /cvs/gcc/gcc/libjava/java/awt/geom/QuadCurve2D.java,v retrieving revision 1.6 diff -u -r1.6 QuadCurve2D.java --- java/awt/geom/QuadCurve2D.java 5 Jan 2004 19:19:29 -0000 1.6 +++ java/awt/geom/QuadCurve2D.java 8 Aug 2004 19:38:26 -0000 @@ -1,5 +1,5 @@ /* QuadCurve2D.java -- represents a parameterized quadratic curve in 2-D space - Copyright (C) 2002, 2003 Free Software Foundation + Copyright (C) 2002, 2003, 2004 Free Software Foundation This file is part of GNU Classpath. @@ -35,7 +35,6 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package java.awt.geom; import java.awt.Rectangle; @@ -53,12 +52,14 @@ * @author Eric Blake (ebb9@email.byu.edu) * @author Graydon Hoare (graydon@redhat.com) * @author Sascha Brawer (brawer@dandelis.ch) + * @author Sven de Marothy (sven@physto.se) * * @since 1.2 */ -public abstract class QuadCurve2D - implements Shape, Cloneable +public abstract class QuadCurve2D implements Shape, Cloneable { + private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0; + /** * Constructs a new QuadCurve2D. Typical users will want to * construct instances of a subclass, such as {@link @@ -68,67 +69,57 @@ { } - /** * Returns the <i>x</i> coordinate of the curve’s start * point. */ public abstract double getX1(); - /** * Returns the <i>y</i> coordinate of the curve’s start * point. */ public abstract double getY1(); - /** * Returns the curve’s start point. */ public abstract Point2D getP1(); - /** * Returns the <i>x</i> coordinate of the curve’s control * point. */ public abstract double getCtrlX(); - /** * Returns the <i>y</i> coordinate of the curve’s control * point. */ public abstract double getCtrlY(); - /** * Returns the curve’s control point. */ public abstract Point2D getCtrlPt(); - /** * Returns the <i>x</i> coordinate of the curve’s end * point. */ public abstract double getX2(); - /** * Returns the <i>y</i> coordinate of the curve’s end * point. */ public abstract double getY2(); - /** * Returns the curve’s end point. */ public abstract Point2D getP2(); - /** * Changes the curve geometry, separately specifying each coordinate * value. @@ -154,7 +145,6 @@ public abstract void setCurve(double x1, double y1, double cx, double cy, double x2, double y2); - /** * Changes the curve geometry, passing coordinate values in an * array. @@ -174,12 +164,10 @@ */ public void setCurve(double[] coords, int offset) { - setCurve(coords[offset++], coords[offset++], - coords[offset++], coords[offset++], - coords[offset++], coords[offset++]); + setCurve(coords[offset++], coords[offset++], coords[offset++], + coords[offset++], coords[offset++], coords[offset++]); } - /** * Changes the curve geometry, specifying coordinate values in * separate Point objects. @@ -198,11 +186,9 @@ */ public void setCurve(Point2D p1, Point2D c, Point2D p2) { - setCurve(p1.getX(), p1.getY(), c.getX(), c.getY(), - p2.getX(), p2.getY()); + setCurve(p1.getX(), p1.getY(), c.getX(), c.getY(), p2.getX(), p2.getY()); } - /** * Changes the curve geometry, specifying coordinate values in an * array of Point objects. @@ -223,12 +209,11 @@ */ public void setCurve(Point2D[] pts, int offset) { - setCurve(pts[offset].getX(), pts[offset].getY(), - pts[offset + 1].getX(), pts[offset + 1].getY(), - pts[offset + 2].getX(), pts[offset + 2].getY()); + setCurve(pts[offset].getX(), pts[offset].getY(), pts[offset + 1].getX(), + pts[offset + 1].getY(), pts[offset + 2].getX(), + pts[offset + 2].getY()); } - /** * Changes the geometry of the curve to that of another curve. * @@ -236,11 +221,10 @@ */ public void setCurve(QuadCurve2D c) { - setCurve(c.getX1(), c.getY1(), c.getCtrlX(), c.getCtrlY(), - c.getX2(), c.getY2()); + setCurve(c.getX1(), c.getY1(), c.getCtrlX(), c.getCtrlY(), c.getX2(), + c.getY2()); } - /** * Calculates the squared flatness of a quadratic curve, directly * specifying each coordinate value. The flatness is the distance of @@ -267,7 +251,6 @@ return Line2D.ptSegDistSq(x1, y1, x2, y2, cx, cy); } - /** * Calculates the flatness of a quadratic curve, directly specifying * each coordinate value. The flatness is the distance of the @@ -294,7 +277,6 @@ return Line2D.ptSegDist(x1, y1, x2, y2, cx, cy); } - /** * Calculates the squared flatness of a quadratic curve, specifying * the coordinate values in an array. The flatness is the distance @@ -328,7 +310,6 @@ coords[offset + 2], coords[offset + 3]); } - /** * Calculates the flatness of a quadratic curve, specifying the * coordinate values in an array. The flatness is the distance of @@ -362,7 +343,6 @@ coords[offset + 2], coords[offset + 3]); } - /** * Calculates the squared flatness of this curve. The flatness is * the distance of the control point to the line between start and @@ -378,12 +358,10 @@ */ public double getFlatnessSq() { - return Line2D.ptSegDistSq(getX1(), getY1(), - getX2(), getY2(), - getCtrlX(), getCtrlY()); + return Line2D.ptSegDistSq(getX1(), getY1(), getX2(), getY2(), getCtrlX(), + getCtrlY()); } - /** * Calculates the flatness of this curve. The flatness is the * distance of the control point to the line between start and end @@ -399,12 +377,10 @@ */ public double getFlatness() { - return Line2D.ptSegDist(getX1(), getY1(), - getX2(), getY2(), - getCtrlX(), getCtrlY()); + return Line2D.ptSegDist(getX1(), getY1(), getX2(), getY2(), getCtrlX(), + getCtrlY()); } - /** * Subdivides this curve into two halves. * @@ -423,8 +399,11 @@ public void subdivide(QuadCurve2D left, QuadCurve2D right) { // Use empty slots at end to share single array. - double[] d = new double[] { getX1(), getY1(), getCtrlX(), getCtrlY(), - getX2(), getY2(), 0, 0, 0, 0 }; + double[] d = new double[] + { + getX1(), getY1(), getCtrlX(), getCtrlY(), getX2(), getY2(), + 0, 0, 0, 0 + }; subdivide(d, 0, d, 0, d, 4); if (left != null) left.setCurve(d, 0); @@ -432,7 +411,6 @@ right.setCurve(d, 4); } - /** * Subdivides a quadratic curve into two halves. * @@ -456,7 +434,6 @@ src.subdivide(left, right); } - /** * Subdivides a quadratic curve into two halves, passing all * coordinates in an array. @@ -500,11 +477,15 @@ * index where the start point’s <i>x</i> coordinate will be * stored. */ - public static void subdivide(double[] src, int srcOff, - double[] left, int leftOff, - double[] right, int rightOff) + public static void subdivide(double[] src, int srcOff, double[] left, + int leftOff, double[] right, int rightOff) { - double x1, y1, xc, yc, x2, y2; + double x1; + double y1; + double xc; + double yc; + double x2; + double y2; x1 = src[srcOff]; y1 = src[srcOff + 1]; @@ -514,16 +495,16 @@ y2 = src[srcOff + 5]; if (left != null) - { - left[leftOff] = x1; - left[leftOff + 1] = y1; - } + { + left[leftOff] = x1; + left[leftOff + 1] = y1; + } if (right != null) - { - right[rightOff + 4] = x2; - right[rightOff + 5] = y2; - } + { + right[rightOff + 4] = x2; + right[rightOff + 5] = y2; + } x1 = (x1 + xc) / 2; x2 = (xc + x2) / 2; @@ -533,23 +514,22 @@ yc = (y1 + y2) / 2; if (left != null) - { - left[leftOff + 2] = x1; - left[leftOff + 3] = y1; - left[leftOff + 4] = xc; - left[leftOff + 5] = yc; - } + { + left[leftOff + 2] = x1; + left[leftOff + 3] = y1; + left[leftOff + 4] = xc; + left[leftOff + 5] = yc; + } if (right != null) - { - right[rightOff] = xc; - right[rightOff + 1] = yc; - right[rightOff + 2] = x2; - right[rightOff + 3] = y2; - } + { + right[rightOff] = xc; + right[rightOff + 1] = yc; + right[rightOff + 2] = x2; + right[rightOff + 3] = y2; + } } - /** * Finds the non-complex roots of a quadratic equation, placing the * results into the same array as the equation coefficients. The @@ -594,7 +574,6 @@ return solveQuadratic(eqn, eqn); } - /** * Finds the non-complex roots of a quadratic equation. The * following equation is being solved: @@ -649,8 +628,10 @@ // The Java implementation is very similar to the GSL code, but // not a strict one-to-one copy. For example, GSL would sort the // result. - - double a, b, c, disc; + double a; + double b; + double c; + double disc; c = eqn[0]; b = eqn[1]; @@ -661,13 +642,13 @@ // wouldn't return -1 for constant functions, and 2 instead of 1 // for linear functions. if (a == 0) - { - if (b == 0) - return -1; - - res[0] = -c / b; - return 1; - } + { + if (b == 0) + return -1; + + res[0] = -c / b; + return 1; + } disc = b * b - 4 * a * c; @@ -675,96 +656,149 @@ return 0; if (disc == 0) - { - // The GNU Scientific Library returns two identical results here. - // We just return one. - res[0] = -0.5 * b / a ; - return 1; - } + { + // The GNU Scientific Library returns two identical results here. + // We just return one. + res[0] = -0.5 * b / a; + return 1; + } // disc > 0 if (b == 0) - { - double r; + { + double r; - r = Math.abs(0.5 * Math.sqrt(disc) / a); - res[0] = -r; - res[1] = r; - } + r = Math.abs(0.5 * Math.sqrt(disc) / a); + res[0] = -r; + res[1] = r; + } else - { - double sgnb, temp; - - sgnb = (b > 0 ? 1 : -1); - temp = -0.5 * (b + sgnb * Math.sqrt(disc)); - - // The GNU Scientific Library sorts the result here. We don't. - res[0] = temp / a; - res[1] = c / temp; - } + { + double sgnb; + double temp; + + sgnb = (b > 0 ? 1 : -1); + temp = -0.5 * (b + sgnb * Math.sqrt(disc)); + + // The GNU Scientific Library sorts the result here. We don't. + res[0] = temp / a; + res[1] = c / temp; + } return 2; } - /** - * Determines whether a point lies inside the area that is bounded + * Determines whether a point is inside the area bounded * by the curve and the straight line connecting its end points. * * <p><img src="doc-files/QuadCurve2D-5.png" width="350" height="180" * alt="A drawing of the area spanned by the curve" /> * * <p>The above drawing illustrates in which area points are - * considered “contained” in a QuadCurve2D. + * considered “inside” a QuadCurve2D. */ public boolean contains(double x, double y) { - // XXX Implement. - throw new Error("not implemented"); - } + if (! getBounds2D().contains(x, y)) + return false; + return ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0); + } /** - * Determines whether a point lies inside the area that is bounded + * Determines whether a point is inside the area bounded * by the curve and the straight line connecting its end points. * * <p><img src="doc-files/QuadCurve2D-5.png" width="350" height="180" * alt="A drawing of the area spanned by the curve" /> * * <p>The above drawing illustrates in which area points are - * considered “contained” in a QuadCurve2D. + * considered “inside” a QuadCurve2D. */ public boolean contains(Point2D p) { return contains(p.getX(), p.getY()); } - + /** + * Determines whether any part of a rectangle is inside the area bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/QuadCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” in a CubicCurve2D. + */ public boolean intersects(double x, double y, double w, double h) { - // XXX Implement. - throw new Error("not implemented"); - } + if (! getBounds2D().contains(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return true; + + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + return false; + } + /** + * Determines whether any part of a Rectangle2D is inside the area bounded + * by the curve and the straight line connecting its end points. + * @see #intersects(double, double, double, double) + */ public boolean intersects(Rectangle2D r) { return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } - + /** + * Determines whether a rectangle is entirely inside the area bounded + * by the curve and the straight line connecting its end points. + * + * <p><img src="doc-files/QuadCurve2D-5.png" width="350" height="180" + * alt="A drawing of the area spanned by the curve" /> + * + * <p>The above drawing illustrates in which area points are + * considered “inside” a QuadCurve2D. + * @see #contains(double, double) + */ public boolean contains(double x, double y, double w, double h) { - // XXX Implement. - throw new Error("not implemented"); - } + if (! getBounds2D().intersects(x, y, w, h)) + return false; + + /* Does any edge intersect? */ + if (getAxisIntersections(x, y, true, w) != 0 /* top */ + || getAxisIntersections(x, y + h, true, w) != 0 /* bottom */ + || getAxisIntersections(x + w, y, false, h) != 0 /* right */ + || getAxisIntersections(x, y, false, h) != 0) /* left */ + return false; + /* No intersections, is any point inside? */ + if ((getAxisIntersections(x, y, true, BIG_VALUE) & 1) != 0) + return true; + + return false; + } + /** + * Determines whether a Rectangle2D is entirely inside the area that is + * bounded by the curve and the straight line connecting its end points. + * @see #contains(double, double, double, double) + */ public boolean contains(Rectangle2D r) { return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } - /** * Determines the smallest rectangle that encloses the * curve’s start, end and control point. As the illustration @@ -780,97 +814,85 @@ return getBounds2D().getBounds(); } - public PathIterator getPathIterator(final AffineTransform at) { return new PathIterator() - { - /** Current coordinate. */ - private int current = 0; - - - public int getWindingRule() - { - return WIND_NON_ZERO; - } - - - public boolean isDone() - { - return current >= 2; - } - - - public void next() - { - current++; - } - - - public int currentSegment(float[] coords) { - int result; - switch (current) - { - case 0: - coords[0] = (float) getX1(); - coords[1] = (float) getY1(); - result = SEG_MOVETO; - break; - - case 1: - coords[0] = (float) getCtrlX(); - coords[1] = (float) getCtrlY(); - coords[2] = (float) getX2(); - coords[3] = (float) getY2(); - result = SEG_QUADTO; - break; - - default: - throw new NoSuchElementException("quad iterator out of bounds"); - } - if (at != null) - at.transform(coords, 0, coords, 0, 2); - return result; - } - + /** Current coordinate. */ + private int current = 0; - public int currentSegment(double[] coords) - { - int result; - switch (current) - { - case 0: - coords[0] = getX1(); - coords[1] = getY1(); - result = SEG_MOVETO; - break; - - case 1: - coords[0] = getCtrlX(); - coords[1] = getCtrlY(); - coords[2] = getX2(); - coords[3] = getY2(); - result = SEG_QUADTO; - break; - - default: - throw new NoSuchElementException("quad iterator out of bounds"); - } - if (at != null) - at.transform(coords, 0, coords, 0, 2); - return result; - } - }; + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current >= 2; + } + + public void next() + { + current++; + } + + public int currentSegment(float[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = (float) getX1(); + coords[1] = (float) getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = (float) getCtrlX(); + coords[1] = (float) getCtrlY(); + coords[2] = (float) getX2(); + coords[3] = (float) getY2(); + result = SEG_QUADTO; + break; + default: + throw new NoSuchElementException("quad iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 2); + return result; + } + + public int currentSegment(double[] coords) + { + int result; + switch (current) + { + case 0: + coords[0] = getX1(); + coords[1] = getY1(); + result = SEG_MOVETO; + break; + case 1: + coords[0] = getCtrlX(); + coords[1] = getCtrlY(); + coords[2] = getX2(); + coords[3] = getY2(); + result = SEG_QUADTO; + break; + default: + throw new NoSuchElementException("quad iterator out of bounds"); + } + if (at != null) + at.transform(coords, 0, coords, 0, 2); + return result; + } + }; } - public PathIterator getPathIterator(AffineTransform at, double flatness) { return new FlatteningPathIterator(getPathIterator(at), flatness); } - /** * Creates a new curve with the same contents as this one. * @@ -879,15 +901,106 @@ public Object clone() { try - { - return super.clone(); - } + { + return super.clone(); + } catch (CloneNotSupportedException e) - { - throw (Error) new InternalError().initCause(e); // Impossible - } + { + throw (Error) new InternalError().initCause(e); // Impossible + } } + /** + * Helper method used by contains() and intersects() methods + * Return the number of curve/line intersections on a given axis + * extending from a certain point. useYaxis is true for using the Y axis, + * @param x x coordinate of the origin point + * @param y y coordinate of the origin point + * @param useYaxis axis to follow, if true the positive Y axis is used, + * false uses the positive X axis. + * + * This is an implementation of the line-crossings algorithm, + * Detailed in an article on Eric Haines' page: + * http://www.acm.org/tog/editors/erich/ptinpoly/ + */ + private int getAxisIntersections(double x, double y, boolean useYaxis, + double distance) + { + int nCrossings = 0; + double a0; + double a1; + double a2; + double b0; + double b1; + double b2; + double[] r = new double[3]; + int nRoots; + + a0 = a2 = 0.0; + + if (useYaxis) + { + a0 = getY1() - y; + a1 = getCtrlY() - y; + a2 = getY2() - y; + b0 = getX1() - x; + b1 = getCtrlX() - x; + b2 = getX2() - x; + } + else + { + a0 = getX1() - x; + a1 = getCtrlX() - x; + a2 = getX2() - x; + b0 = getY1() - y; + b1 = getCtrlY() - y; + b2 = getY2() - y; + } + + /* If the axis intersects a start/endpoint, shift it up by some small + amount to guarantee the line is 'inside' + If this is not done,bad behaviour may result for points on that axis. */ + if (a0 == 0.0 || a2 == 0.0) + { + double small = getFlatness() * (1E-10); + if (a0 == 0.0) + a0 += small; + + if (a2 == 0.0) + a2 += small; + } + + r[0] = a0; + r[1] = 2 * (a1 - a0); + r[2] = (a2 - 2 * a1 + a0); + + nRoots = solveQuadratic(r); + for (int i = 0; i < nRoots; i++) + { + double t = r[i]; + if (t >= 0.0 && t <= 1.0) + { + double crossing = t * t * (b2 - 2 * b1 + b0) + 2 * t * (b1 - b0) + + b0; + /* single root is always doubly degenerate in quads */ + if (crossing > 0 && crossing < distance) + nCrossings += (nRoots == 1) ? 2 : 1; + } + } + + if (useYaxis) + { + if (Line2D.linesIntersect(b0, a0, b2, a2, 0.0, 0.0, distance, 0.0)) + nCrossings++; + } + else + { + if (Line2D.linesIntersect(a0, b0, a2, b2, 0.0, 0.0, 0.0, distance)) + nCrossings++; + } + + return (nCrossings); + } /** * A two-dimensional curve that is parameterized with a quadratic @@ -899,45 +1012,38 @@ * @author Eric Blake (ebb9@email.byu.edu) * @author Sascha Brawer (brawer@dandelis.ch) */ - public static class Double - extends QuadCurve2D + public static class Double extends QuadCurve2D { /** * The <i>x</i> coordinate of the curve’s start point. */ public double x1; - /** * The <i>y</i> coordinate of the curve’s start point. */ public double y1; - /** * The <i>x</i> coordinate of the curve’s control point. */ public double ctrlx; - /** * The <i>y</i> coordinate of the curve’s control point. */ public double ctrly; - /** * The <i>x</i> coordinate of the curve’s end point. */ public double x2; - /** * The <i>y</i> coordinate of the curve’s end point. */ public double y2; - /** * Constructs a new QuadCurve2D that stores its coordinate values * in double-precision floating-point format. All points are @@ -947,7 +1053,6 @@ { } - /** * Constructs a new QuadCurve2D that stores its coordinate values * in double-precision floating-point format, specifying the @@ -971,8 +1076,8 @@ * @param y2 the <i>y</i> coordinate of the curve’s end * point. */ - public Double(double x1, double y1, double cx, double cy, - double x2, double y2) + public Double(double x1, double y1, double cx, double cy, double x2, + double y2) { this.x1 = x1; this.y1 = y1; @@ -982,7 +1087,6 @@ this.y2 = y2; } - /** * Returns the <i>x</i> coordinate of the curve’s start * point. @@ -992,7 +1096,6 @@ return x1; } - /** * Returns the <i>y</i> coordinate of the curve’s start * point. @@ -1002,7 +1105,6 @@ return y1; } - /** * Returns the curve’s start point. */ @@ -1011,7 +1113,6 @@ return new Point2D.Double(x1, y1); } - /** * Returns the <i>x</i> coordinate of the curve’s control * point. @@ -1021,7 +1122,6 @@ return ctrlx; } - /** * Returns the <i>y</i> coordinate of the curve’s control * point. @@ -1031,7 +1131,6 @@ return ctrly; } - /** * Returns the curve’s control point. */ @@ -1040,7 +1139,6 @@ return new Point2D.Double(ctrlx, ctrly); } - /** * Returns the <i>x</i> coordinate of the curve’s end * point. @@ -1050,7 +1148,6 @@ return x2; } - /** * Returns the <i>y</i> coordinate of the curve’s end * point. @@ -1060,7 +1157,6 @@ return y2; } - /** * Returns the curve’s end point. */ @@ -1069,7 +1165,6 @@ return new Point2D.Double(x2, y2); } - /** * Changes the geometry of the curve. * @@ -1102,7 +1197,6 @@ this.y2 = y2; } - /** * Determines the smallest rectangle that encloses the * curve’s start, end and control point. As the @@ -1123,7 +1217,6 @@ } } - /** * A two-dimensional curve that is parameterized with a quadratic * function and stores coordinate values in single-precision @@ -1134,45 +1227,38 @@ * @author Eric Blake (ebb9@email.byu.edu) * @author Sascha Brawer (brawer@dandelis.ch) */ - public static class Float - extends QuadCurve2D + public static class Float extends QuadCurve2D { /** * The <i>x</i> coordinate of the curve’s start point. */ public float x1; - /** * The <i>y</i> coordinate of the curve’s start point. */ public float y1; - /** * The <i>x</i> coordinate of the curve’s control point. */ public float ctrlx; - /** * The <i>y</i> coordinate of the curve’s control point. */ public float ctrly; - /** * The <i>x</i> coordinate of the curve’s end point. */ public float x2; - /** * The <i>y</i> coordinate of the curve’s end point. */ public float y2; - /** * Constructs a new QuadCurve2D that stores its coordinate values * in single-precision floating-point format. All points are @@ -1182,7 +1268,6 @@ { } - /** * Constructs a new QuadCurve2D that stores its coordinate values * in single-precision floating-point format, specifying the @@ -1206,8 +1291,7 @@ * @param y2 the <i>y</i> coordinate of the curve’s end * point. */ - public Float(float x1, float y1, float cx, float cy, - float x2, float y2) + public Float(float x1, float y1, float cx, float cy, float x2, float y2) { this.x1 = x1; this.y1 = y1; @@ -1217,7 +1301,6 @@ this.y2 = y2; } - /** * Returns the <i>x</i> coordinate of the curve’s start * point. @@ -1227,7 +1310,6 @@ return x1; } - /** * Returns the <i>y</i> coordinate of the curve’s start * point. @@ -1237,7 +1319,6 @@ return y1; } - /** * Returns the curve’s start point. */ @@ -1246,7 +1327,6 @@ return new Point2D.Float(x1, y1); } - /** * Returns the <i>x</i> coordinate of the curve’s control * point. @@ -1256,7 +1336,6 @@ return ctrlx; } - /** * Returns the <i>y</i> coordinate of the curve’s control * point. @@ -1266,7 +1345,6 @@ return ctrly; } - /** * Returns the curve’s control point. */ @@ -1275,7 +1353,6 @@ return new Point2D.Float(ctrlx, ctrly); } - /** * Returns the <i>x</i> coordinate of the curve’s end * point. @@ -1285,7 +1362,6 @@ return x2; } - /** * Returns the <i>y</i> coordinate of the curve’s end * point. @@ -1295,7 +1371,6 @@ return y2; } - /** * Returns the curve’s end point. */ @@ -1304,7 +1379,6 @@ return new Point2D.Float(x2, y2); } - /** * Changes the geometry of the curve, specifying coordinate values * as double-precision floating-point numbers. @@ -1338,7 +1412,6 @@ this.y2 = (float) y2; } - /** * Changes the geometry of the curve, specifying coordinate values * as single-precision floating-point numbers. @@ -1361,8 +1434,8 @@ * @param y2 the <i>y</i> coordinate of the curve’s new * end point. */ - public void setCurve(float x1, float y1, float cx, float cy, - float x2, float y2) + public void setCurve(float x1, float y1, float cx, float cy, float x2, + float y2) { this.x1 = x1; this.y1 = y1; @@ -1372,7 +1445,6 @@ this.y2 = y2; } - /** * Determines the smallest rectangle that encloses the * curve’s start, end and control point. As the Index: java/awt/geom/RoundRectangle2D.java =================================================================== RCS file: /cvs/gcc/gcc/libjava/java/awt/geom/RoundRectangle2D.java,v retrieving revision 1.5 diff -u -r1.5 RoundRectangle2D.java --- java/awt/geom/RoundRectangle2D.java 26 Sep 2003 15:14:21 -0000 1.5 +++ java/awt/geom/RoundRectangle2D.java 8 Aug 2004 19:38:26 -0000 @@ -1,5 +1,5 @@ /* RoundRectangle2D.java -- represents a rectangle with rounded corners - Copyright (C) 2000, 2002, 2003 Free Software Foundation + Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation This file is part of GNU Classpath. @@ -39,6 +39,7 @@ import java.util.NoSuchElementException; + /** This class implements a rectangle with rounded corners. * @author Tom Tromey <tromey@cygnus.com> * @date December 3, 2000 @@ -60,12 +61,12 @@ * @param arcHeight The arc height */ public abstract void setRoundRect(double x, double y, double w, double h, - double arcWidth, double arcHeight); + double arcWidth, double arcHeight); /** Create a RoundRectangle2D. This is protected because this class * is abstract and cannot be instantiated. */ - protected RoundRectangle2D() + protected RoundRectangle2D() { } @@ -87,8 +88,11 @@ // Now check to see if the point is in range of an arc. double dy = Math.min(Math.abs(my - y), Math.abs(my + mh - y)); double dx = Math.min(Math.abs(mx - x), Math.abs(mx + mw - x)); - double aw = getArcWidth(); - double ah = getArcHeight(); + + // The arc dimensions are that of the corresponding ellipse + // thus a 90 degree segment is half of that. + double aw = getArcWidth() / 2.0; + double ah = getArcHeight() / 2.0; if (dx > aw || dy > ah) return true; @@ -112,8 +116,8 @@ { // We have to check all four points here (for ordinary rectangles // we can just check opposing corners). - return (contains(x, y) && contains(x + w, h) - && contains(x, y + h) && contains(x + w, y + h)); + return (contains(x, y) && contains(x, y + h) && contains(x + w, y + h) + && contains(x + w, y)); } /** Return a new path iterator which iterates over this rectangle. @@ -128,154 +132,161 @@ final double arcwidth = getArcWidth(); final double archeight = getArcHeight(); return new PathIterator() - { - /** We iterate clockwise around the rectangle, starting in the - * upper left. This variable tracks our current point, which - * can be on either side of a given corner. */ - private int current = 0; - - /** Child path iterator, used for corners. */ - private PathIterator corner; - - /** This is used when rendering the corners. We re-use the arc - * for each corner. */ - private Arc2D arc = new Arc2D.Double(); - - /** Temporary array used by getPoint. */ - private double[] temp = new double[2]; - - public int getWindingRule() - { - return WIND_NON_ZERO; - } - - public boolean isDone() - { - return current > 9; - } - - private void getPoint(int val) - { - switch (val) - { - case 0: - case 8: - temp[0] = minx; - temp[1] = miny + archeight; - break; - case 1: - temp[0] = minx + arcwidth; - temp[1] = miny; - break; - case 2: - temp[0] = maxx - arcwidth; - temp[1] = maxy; - break; - case 3: - temp[0] = maxx; - temp[1] = miny + archeight; - break; - case 4: - temp[0] = maxx; - temp[1] = maxy - archeight; - break; - case 5: - temp[0] = maxx - arcwidth; - temp[1] = maxy; - break; - case 6: - temp[0] = minx + arcwidth; - temp[1] = maxy; - break; - case 7: - temp[0] = minx; - temp[1] = maxy - archeight; - break; - } - } - - public void next() - { - if (current >= 8) - ++current; - else if (corner != null) - { - // We're iterating through the corner. Work on the child - // iterator; if it finishes, reset and move to the next - // point along the rectangle. - corner.next(); - if (corner.isDone()) - { - corner = null; - ++current; - } - } - else - { - // Make an arc between this point on the rectangle and - // the next one, and then iterate over this arc. - getPoint(current); - double x1 = temp[0]; - double y1 = temp[1]; - getPoint(current + 1); - arc.setFrameFromDiagonal(x1, y1, temp[0], temp[1]); - arc.setAngles(x1, y1, temp[0], temp[1]); - corner = arc.getPathIterator(at); - } - } - - public int currentSegment(float[] coords) - { - if (corner != null) - { - int r = corner.currentSegment(coords); - if (r == SEG_MOVETO) - r = SEG_LINETO; - return r; - } - - if (current < 9) - { - getPoint(current); - coords[0] = (float) temp[0]; - coords[1] = (float) temp[1]; - } - else if (current == 9) - return SEG_CLOSE; - else - throw new NoSuchElementException("rect iterator out of bounds"); - - if (at != null) - at.transform(coords, 0, coords, 0, 1); - return current == 0 ? SEG_MOVETO : SEG_LINETO; - } - - public int currentSegment(double[] coords) { - if (corner != null) - { - int r = corner.currentSegment(coords); - if (r == SEG_MOVETO) - r = SEG_LINETO; - return r; - } - - if (current < 9) - { - getPoint(current); - coords[0] = temp[0]; - coords[1] = temp[1]; - } - else if (current == 9) - return SEG_CLOSE; - else - throw new NoSuchElementException("rect iterator out of bounds"); - - if (at != null) - at.transform(coords, 0, coords, 0, 1); - return current == 0 ? SEG_MOVETO : SEG_LINETO; - } - }; + /** We iterate counterclockwise around the rectangle, starting in the + * upper right. This variable tracks our current point, which + * can be on either side of a given corner. */ + private int current = 0; + + /** Child path iterator, used for corners. */ + private PathIterator corner; + + /** This is used when rendering the corners. We re-use the arc + * for each corner. */ + private Arc2D arc = new Arc2D.Double(); + + /** Temporary array used by getPoint. */ + private double[] temp = new double[2]; + + public int getWindingRule() + { + return WIND_NON_ZERO; + } + + public boolean isDone() + { + return current > 9; + } + + private void getPoint(int val) + { + switch (val) + { + case 0: + case 8: + temp[0] = maxx; + temp[1] = miny + archeight; + break; + case 7: + temp[0] = maxx; + temp[1] = maxy - archeight; + break; + case 6: + temp[0] = maxx - arcwidth; + temp[1] = maxy; + break; + case 5: + temp[0] = minx + arcwidth; + temp[1] = maxy; + break; + case 4: + temp[0] = minx; + temp[1] = maxy - archeight; + break; + case 3: + temp[0] = minx; + temp[1] = miny + archeight; + break; + case 2: + temp[0] = minx + arcwidth; + temp[1] = miny; + break; + case 1: + temp[0] = maxx - arcwidth; + temp[1] = miny; + break; + } + } + + public void next() + { + if (current >= 8) + ++current; + else if (corner != null) + { + // We're iterating through the corner. Work on the child + // iterator; if it finishes, reset and move to the next + // point along the rectangle. + corner.next(); + if (corner.isDone()) + { + corner = null; + ++current; + } + } + else + { + // Make an arc between this point on the rectangle and + // the next one, and then iterate over this arc. + getPoint(current); + double x1 = temp[0]; + double y1 = temp[1]; + getPoint(current + 1); + Rectangle2D.Double r = new Rectangle2D.Double(Math.min(x1, + temp[0]), + Math.min(y1, + temp[1]), + Math.abs(x1 + - temp[0]), + Math.abs(y1 + - temp[1])); + arc.setArc(r, (current >> 1) * 90.0, 90.0, Arc2D.OPEN); + corner = arc.getPathIterator(at); + } + } + + public int currentSegment(float[] coords) + { + if (corner != null) + { + int r = corner.currentSegment(coords); + if (r == SEG_MOVETO) + r = SEG_LINETO; + return r; + } + + if (current < 9) + { + getPoint(current); + coords[0] = (float) temp[0]; + coords[1] = (float) temp[1]; + } + else if (current == 9) + return SEG_CLOSE; + else + throw new NoSuchElementException("rect iterator out of bounds"); + + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return current == 0 ? SEG_MOVETO : SEG_LINETO; + } + + public int currentSegment(double[] coords) + { + if (corner != null) + { + int r = corner.currentSegment(coords); + if (r == SEG_MOVETO) + r = SEG_LINETO; + return r; + } + + if (current < 9) + { + getPoint(current); + coords[0] = temp[0]; + coords[1] = temp[1]; + } + else if (current == 9) + return SEG_CLOSE; + else + throw new NoSuchElementException("rect iterator out of bounds"); + + if (at != null) + at.transform(coords, 0, coords, 0, 1); + return current == 0 ? SEG_MOVETO : SEG_LINETO; + } + }; } /** Return true if the given rectangle intersects this shape. @@ -286,14 +297,9 @@ */ public boolean intersects(double x, double y, double w, double h) { - // Here we can use the same code we use for an ordinary rectangle. - double mx = getX(); - double mw = getWidth(); - if (x < mx || x >= mx + mw || x + w < mx || x + w >= mx + mw) - return false; - double my = getY(); - double mh = getHeight(); - return y >= my && y < my + mh && y + h >= my && y + h < my + mh; + // Check if any corner is within the rectangle + return (contains(x, y) || contains(x, y + h) || contains(x + w, y + h) + || contains(x + w, y)); } /** Set the boundary of this round rectangle. @@ -315,7 +321,7 @@ public void setRoundRect(RoundRectangle2D rr) { setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(), - rr.getArcWidth(), rr.getArcHeight()); + rr.getArcWidth(), rr.getArcHeight()); } /** A subclass of RoundRectangle which keeps its parameters as @@ -353,8 +359,8 @@ * @param arcWidth The arc width * @param arcHeight The arc height */ - public Double(double x, double y, double w, double h, - double arcWidth, double arcHeight) + public Double(double x, double y, double w, double h, double arcWidth, + double arcHeight) { this.x = x; this.y = y; @@ -405,7 +411,7 @@ } public void setRoundRect(double x, double y, double w, double h, - double arcWidth, double arcHeight) + double arcWidth, double arcHeight) { this.x = x; this.y = y; @@ -451,8 +457,8 @@ * @param arcWidth The arc width * @param arcHeight The arc height */ - public Float(float x, float y, float w, float h, - float arcWidth, float arcHeight) + public Float(float x, float y, float w, float h, float arcWidth, + float arcHeight) { this.x = x; this.y = y; @@ -503,7 +509,7 @@ } public void setRoundRect(float x, float y, float w, float h, - float arcWidth, float arcHeight) + float arcWidth, float arcHeight) { this.x = x; this.y = y; @@ -514,7 +520,7 @@ } public void setRoundRect(double x, double y, double w, double h, - double arcWidth, double arcHeight) + double arcWidth, double arcHeight) { this.x = (float) x; this.y = (float) y;
Attachment:
signature.asc
Description: This is a digitally signed message part
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |