Eliminated views of location, size and bounds. They would be crazy expensive to

keep up to date for shapes like Path and they're probably not that useful.
Added instead methods to obtain said values by copying the data into a supplied
object, which allows the caller to avoid garbage generation when desired. Also
finished up quad and cubic curves.
This commit is contained in:
Michael Bayne
2011-06-10 12:23:19 -07:00
parent b8572dd82f
commit c7d31b9ea3
21 changed files with 1054 additions and 348 deletions
@@ -0,0 +1,173 @@
//
// $Id$
package pythagoras.f;
import java.util.NoSuchElementException;
/**
* Provides most of the implementation of {@link ICubicCurve}, obtaining only the start, end and
* control points from the derived class.
*/
public abstract class AbstractCubicCurve implements ICubicCurve
{
@Override // from interface ICubicCurve
public Point getP1 () {
return new Point(getX1(), getY1());
}
@Override // from interface ICubicCurve
public Point getCtrlP1 () {
return new Point(getCtrlX1(), getCtrlY1());
}
@Override // from interface ICubicCurve
public Point getCtrlP2 () {
return new Point(getCtrlX2(), getCtrlY2());
}
@Override // from interface ICubicCurve
public Point getP2 () {
return new Point(getX2(), getY2());
}
@Override // from interface ICubicCurve
public double getFlatnessSq () {
return CubicCurves.getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
getCtrlX2(), getCtrlY2(), getX2(), getY2());
}
@Override // from interface ICubicCurve
public double getFlatness () {
return CubicCurves.getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
getCtrlX2(), getCtrlY2(), getX2(), getY2());
}
@Override // from interface ICubicCurve
public void subdivide (CubicCurve left, CubicCurve right) {
CubicCurves.subdivide(this, left, right);
}
@Override // from interface ICubicCurve
public CubicCurve clone () {
return new CubicCurve(getX1(), getY1(), getCtrlX1(), getCtrlY1(),
getCtrlX2(), getCtrlY2(), getX2(), getY2());
}
@Override // from interface IShape
public boolean isEmpty () {
return true; // curves contain no space
}
@Override // from interface IShape
public boolean contains (float px, float py) {
return Crossing.isInsideEvenOdd(Crossing.crossShape(this, px, py));
}
@Override // from interface IShape
public boolean contains (float rx, float ry, float rw, float rh) {
int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
return (cross != Crossing.CROSSING) && Crossing.isInsideEvenOdd(cross);
}
@Override // from interface IShape
public boolean contains (IPoint p) {
return contains(p.getX(), p.getY());
}
@Override // from interface IShape
public boolean contains (IRectangle r) {
return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
@Override // from interface IShape
public boolean intersects (float rx, float ry, float rw, float rh) {
int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
return (cross == Crossing.CROSSING) || Crossing.isInsideEvenOdd(cross);
}
@Override // from interface IShape
public boolean intersects (IRectangle r) {
return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
@Override // from interface IShape
public Rectangle getBounds () {
return getBounds(new Rectangle());
}
@Override // from interface IShape
public Rectangle getBounds (Rectangle target) {
float x1 = getX1(), y1 = getY1(), x2 = getX2(), y2 = getY2();
float ctrlx1 = getCtrlX1(), ctrly1 = getCtrlY1();
float ctrlx2 = getCtrlX2(), ctrly2 = getCtrlY2();
float rx1 = Math.min(Math.min(x1, x2), Math.min(ctrlx1, ctrlx2));
float ry1 = Math.min(Math.min(y1, y2), Math.min(ctrly1, ctrly2));
float rx2 = Math.max(Math.max(x1, x2), Math.max(ctrlx1, ctrlx2));
float ry2 = Math.max(Math.max(y1, y2), Math.max(ctrly1, ctrly2));
target.setBounds(rx1, ry1, rx2 - rx1, ry2 - ry1);
return target;
}
@Override // from interface IShape
public PathIterator getPathIterator (AffineTransform t) {
return new Iterator(this, t);
}
@Override // from interface IShape
public PathIterator getPathIterator (AffineTransform at, float flatness) {
return new FlatteningPathIterator(getPathIterator(at), flatness);
}
/** An iterator over an {@link ICubicCurve}. */
protected static class Iterator implements PathIterator
{
private ICubicCurve c;
private AffineTransform t;
private int index;
Iterator (ICubicCurve c, AffineTransform t) {
this.c = c;
this.t = t;
}
@Override public int getWindingRule () {
return WIND_NON_ZERO;
}
@Override public boolean isDone () {
return index > 1;
}
@Override public void next () {
index++;
}
@Override public int currentSegment (float[] coords) {
if (isDone()) {
throw new NoSuchElementException("Iterator out of bounds");
}
int type;
int count;
if (index == 0) {
type = SEG_MOVETO;
coords[0] = c.getX1();
coords[1] = c.getY1();
count = 1;
} else {
type = SEG_CUBICTO;
coords[0] = c.getCtrlX1();
coords[1] = c.getCtrlY1();
coords[2] = c.getCtrlX2();
coords[3] = c.getCtrlY2();
coords[4] = c.getX2();
coords[5] = c.getY2();
count = 3;
}
if (t != null) {
t.transform(coords, 0, coords, 0, count);
}
return type;
}
}
}
+16 -46
View File
@@ -11,38 +11,26 @@ import java.util.NoSuchElementException;
*/ */
public abstract class AbstractLine implements ILine public abstract class AbstractLine implements ILine
{ {
@Override // from interface ILine
public IPoint p1 () {
return new AbstractPoint() {
@Override public float getX () {
return getX1();
}
@Override public float getY () {
return getY1();
}
};
}
@Override // from interface ILine @Override // from interface ILine
public Point getP1 () { public Point getP1 () {
return new Point(getX1(), getY1()); return getP1(new Point());
} }
@Override // from interface ILine @Override // from interface ILine
public IPoint p2 () { public Point getP1 (Point target) {
return new AbstractPoint() { target.setLocation(getX1(), getY1());
@Override public float getX () { return target;
return getX2();
}
@Override public float getY () {
return getY2();
}
};
} }
@Override // from interface ILine @Override // from interface ILine
public Point getP2 () { public Point getP2 () {
return new Point(getX2(), getY2()); return getP2(new Point());
}
@Override // from interface ILine
public Point getP2 (Point target) {
target.setLocation(getX2(), getY2());
return target;
} }
@Override // from interface ILine @Override // from interface ILine
@@ -126,31 +114,12 @@ public abstract class AbstractLine implements ILine
} }
@Override // from interface IShape @Override // from interface IShape
public IRectangle bounds () { public Rectangle getBounds () {
return new AbstractRectangle() { return getBounds(new Rectangle());
@Override public float getX () {
return Math.min(getX1(), getX2());
}
@Override public float getY () {
return Math.min(getY1(), getY2());
}
@Override public float getWidth () {
float x1 = getX1(), x2 = getX2();
return (x1 < x2) ? (x2 - x1) : (x1 - x2);
}
@Override public float getHeight () {
float y1 = getY1(), y2 = getY2();
return (y1 < y2) ? (y2 - y1) : (y1 - y2);
}
// this isn't visible in the type, so won't be called by non-combatants
@Override public void setFrame (float x, float y, float w, float h) {
throw new UnsupportedOperationException();
}
};
} }
@Override // from interface IShape @Override // from interface IShape
public Rectangle getBounds () { public Rectangle getBounds (Rectangle target) {
float x1 = getX1(), x2 = getX2(), y1 = getY1(), y2 = getY2(); float x1 = getX1(), x2 = getX2(), y1 = getY1(), y2 = getY2();
float rx, ry, rw, rh; float rx, ry, rw, rh;
if (x1 < x2) { if (x1 < x2) {
@@ -167,7 +136,8 @@ public abstract class AbstractLine implements ILine
ry = y2; ry = y2;
rh = y1 - y2; rh = y1 - y2;
} }
return new Rectangle(rx, ry, rw, rh); target.setBounds(rx, ry, rw, rh);
return target;
} }
@Override // from interface IShape @Override // from interface IShape
@@ -0,0 +1,162 @@
//
// $Id$
package pythagoras.f;
import java.util.NoSuchElementException;
/**
* Provides most of the implementation of {@link IQuadCurve}, obtaining only the start, end and
* control point from the derived class.
*/
public abstract class AbstractQuadCurve implements IQuadCurve
{
@Override // from interface IQuadCurve
public Point getP1 () {
return new Point(getX1(), getY1());
}
@Override // from interface IQuadCurve
public Point getCtrlP () {
return new Point(getCtrlX(), getCtrlY());
}
@Override // from interface IQuadCurve
public Point getP2 () {
return new Point(getX2(), getY2());
}
@Override // from interface IQuadCurve
public float getFlatnessSq () {
return Lines.pointSegDistSq(getCtrlX(), getCtrlY(), getX1(), getY1(), getX2(), getY2());
}
@Override // from interface IQuadCurve
public float getFlatness () {
return Lines.pointSegDist(getCtrlX(), getCtrlY(), getX1(), getY1(), getX2(), getY2());
}
@Override // from interface IQuadCurve
public void subdivide (QuadCurve left, QuadCurve right) {
QuadCurves.subdivide(this, left, right);
}
@Override // from interface IQuadCurve
public QuadCurve clone () {
return new QuadCurve(getX1(), getY1(), getCtrlX(), getCtrlY(), getX2(), getY2());
}
@Override // from interface IShape
public boolean isEmpty () {
return true; // curves contain no space
}
@Override // from interface IShape
public boolean contains (float px, float py) {
return Crossing.isInsideEvenOdd(Crossing.crossShape(this, px, py));
}
@Override // from interface IShape
public boolean contains (float rx, float ry, float rw, float rh) {
int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
}
@Override // from interface IShape
public boolean contains (IPoint p) {
return contains(p.getX(), p.getY());
}
@Override // from interface IShape
public boolean contains (IRectangle r) {
return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
@Override // from interface IShape
public boolean intersects (float rx, float ry, float rw, float rh) {
int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
}
@Override // from interface IShape
public boolean intersects (IRectangle r) {
return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
@Override // from interface IShape
public Rectangle getBounds () {
return getBounds(new Rectangle());
}
@Override // from interface IShape
public Rectangle getBounds (Rectangle target) {
float x1 = getX1(), y1 = getY1(), x2 = getX2(), y2 = getY2();
float ctrlx = getCtrlX(), ctrly = getCtrlY();
float rx0 = Math.min(Math.min(x1, x2), ctrlx);
float ry0 = Math.min(Math.min(y1, y2), ctrly);
float rx1 = Math.max(Math.max(x1, x2), ctrlx);
float ry1 = Math.max(Math.max(y1, y2), ctrly);
target.setBounds(rx0, ry0, rx1 - rx0, ry1 - ry0);
return target;
}
@Override // from interface IShape
public PathIterator getPathIterator (AffineTransform t) {
return new Iterator(this, t);
}
@Override // from interface IShape
public PathIterator getPathIterator (AffineTransform t, float flatness) {
return new FlatteningPathIterator(getPathIterator(t), flatness);
}
/** An iterator over an {@link IQuadCurve}. */
protected static class Iterator implements PathIterator
{
private IQuadCurve c;
private AffineTransform t;
private int index;
Iterator (IQuadCurve q, AffineTransform t) {
this.c = q;
this.t = t;
}
@Override public int getWindingRule () {
return WIND_NON_ZERO;
}
@Override public boolean isDone () {
return (index > 1);
}
@Override public void next () {
index++;
}
@Override public int currentSegment (float[] coords) {
if (isDone()) {
throw new NoSuchElementException("Iterator out of bounds");
}
int type;
int count;
if (index == 0) {
type = SEG_MOVETO;
coords[0] = c.getX1();
coords[1] = c.getY1();
count = 1;
} else {
type = SEG_QUADTO;
coords[0] = c.getCtrlX();
coords[1] = c.getCtrlY();
coords[2] = c.getX2();
coords[3] = c.getY2();
count = 2;
}
if (t != null) {
t.transform(coords, 0, coords, 0, count);
}
return type;
}
}
}
@@ -11,38 +11,26 @@ import java.util.NoSuchElementException;
*/ */
public abstract class AbstractRectangle extends RectangularShape implements IRectangle public abstract class AbstractRectangle extends RectangularShape implements IRectangle
{ {
@Override // from interface IRectangle
public IPoint location () {
return new AbstractPoint() {
@Override public float getX () {
return AbstractRectangle.this.getX();
}
@Override public float getY () {
return AbstractRectangle.this.getY();
}
};
}
@Override // from interface IRectangle @Override // from interface IRectangle
public Point getLocation () { public Point getLocation () {
return new Point(getX(), getY()); return getLocation(new Point());
} }
@Override // from interface IRectangle @Override // from interface IRectangle
public IDimension size () { public Point getLocation (Point target) {
return new AbstractDimension() { target.setLocation(getX(), getY());
@Override public float getWidth () { return target;
return AbstractRectangle.this.getWidth();
}
@Override public float getHeight () {
return AbstractRectangle.this.getHeight();
}
};
} }
@Override // from interface IRectangle @Override // from interface IRectangle
public Dimension getSize () { public Dimension getSize () {
return new Dimension(getWidth(), getHeight()); return getSize(new Dimension());
}
@Override // from interface IRectangle
public Dimension getSize (Dimension target) {
target.setSize(getWidth(), getHeight());
return target;
} }
@Override // from interface IRectangle @Override // from interface IRectangle
@@ -147,16 +135,6 @@ public abstract class AbstractRectangle extends RectangularShape implements IRec
return new Iterator(this, t); return new Iterator(this, t);
} }
@Override // from RectangularShape
public IRectangle frame () {
return this;
}
@Override // from RectangularShape
public IRectangle bounds () {
return this;
}
@Override // from Object @Override // from Object
public boolean equals (Object obj) { public boolean equals (Object obj) {
if (obj == this) { if (obj == this) {
+8 -10
View File
@@ -218,17 +218,15 @@ class Crossing
} }
} }
/** /** CubicCurve helper for finding curve crossing and calculating bounds. */
* CubicCurve class provides basic functionality to find curve crossing and calculating bounds public static class CubicCurveH
*/
public static class CubicCurve
{ {
float ax, ay, bx, by, cx, cy; float ax, ay, bx, by, cx, cy;
float Ax, Ay, Bx, By, Cx, Cy; float Ax, Ay, Bx, By, Cx, Cy;
float Ax3, Bx2; float Ax3, Bx2;
public CubicCurve (float x1, float y1, float cx1, float cy1, float cx2, float cy2, public CubicCurveH (float x1, float y1, float cx1, float cy1, float cx2, float cy2,
float x2, float y2) { float x2, float y2) {
ax = x2 - x1; ax = x2 - x1;
ay = y2 - y1; ay = y2 - y1;
bx = cx1 - x1; bx = cx1 - x1;
@@ -410,7 +408,7 @@ class Crossing
} }
// INSIDE // INSIDE
CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2); CubicCurveH c = new CubicCurveH(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
float px = x - x1, py = y - y1; float px = x - x1, py = y - y1;
float[] res = new float[3]; float[] res = new float[3];
int rc = c.solvePoint(res, px); int rc = c.solvePoint(res, px);
@@ -471,7 +469,7 @@ class Crossing
* Returns how many times a ray from point (x,y) crosses a shape. * Returns how many times a ray from point (x,y) crosses a shape.
*/ */
public static int crossShape (IShape s, float x, float y) { public static int crossShape (IShape s, float x, float y) {
if (!s.bounds().contains(x, y)) { if (!s.getBounds().contains(x, y)) {
return 0; return 0;
} }
return crossPath(s.getPathIterator(null), x, y); return crossPath(s.getPathIterator(null), x, y);
@@ -642,7 +640,7 @@ class Crossing
} }
// INSIDE // INSIDE
CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2); CubicCurveH c = new CubicCurveH(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
float px1 = rx1 - x1; float px1 = rx1 - x1;
float py1 = ry1 - y1; float py1 = ry1 - y1;
float px2 = rx2 - x1; float px2 = rx2 - x1;
@@ -758,7 +756,7 @@ class Crossing
* Returns how many times rectangle stripe cross shape or the are intersect * Returns how many times rectangle stripe cross shape or the are intersect
*/ */
public static int intersectShape (IShape s, float x, float y, float w, float h) { public static int intersectShape (IShape s, float x, float y, float w, float h) {
if (!s.bounds().intersects(x, y, w, h)) { if (!s.getBounds().intersects(x, y, w, h)) {
return 0; return 0;
} }
return intersectPath(s.getPathIterator(null), x, y, w, h); return intersectPath(s.getPathIterator(null), x, y, w, h);
+142
View File
@@ -0,0 +1,142 @@
//
// $Id$
package pythagoras.f;
import java.io.Serializable;
/**
* Represents a cubic curve.
*/
public class CubicCurve extends AbstractCubicCurve implements Serializable
{
/** The x-coordinate of the start of this curve. */
public float x1;
/** The y-coordinate of the start of this curve. */
public float y1;
/** The x-coordinate of the first control point. */
public float ctrlx1;
/** The y-coordinate of the first control point. */
public float ctrly1;
/** The x-coordinate of the second control point. */
public float ctrlx2;
/** The x-coordinate of the second control point. */
public float ctrly2;
/** The x-coordinate of the end of this curve. */
public float x2;
/** The y-coordinate of the end of this curve. */
public float y2;
/**
* Creates a cubic curve with all points at (0,0).
*/
public CubicCurve () {
}
/**
* Creates a cubic curve with the specified start, control, and end points.
*/
public CubicCurve (float x1, float y1, float ctrlx1, float ctrly1,
float ctrlx2, float ctrly2, float x2, float y2) {
setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
}
/**
* Configures the start, control and end points for this curve.
*/
public void setCurve (float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2,
float ctrly2, float x2, float y2) {
this.x1 = x1;
this.y1 = y1;
this.ctrlx1 = ctrlx1;
this.ctrly1 = ctrly1;
this.ctrlx2 = ctrlx2;
this.ctrly2 = ctrly2;
this.x2 = x2;
this.y2 = y2;
}
/**
* Configures the start, control and end points for this curve.
*/
public void setCurve (IPoint p1, IPoint cp1, IPoint cp2, IPoint p2) {
setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(),
cp2.getX(), cp2.getY(), p2.getX(), p2.getY());
}
/**
* Configures the start, control and end points for this curve, using the values at the
* specified offset in the {@link coords} array.
*/
public void setCurve (float[] coords, int offset) {
setCurve(coords[offset + 0], coords[offset + 1], coords[offset + 2], coords[offset + 3],
coords[offset + 4], coords[offset + 5], coords[offset + 6], coords[offset + 7]);
}
/**
* Configures the start, control and end points for this curve, using the values at the
* specified offset in the {@link points} array.
*/
public void setCurve (IPoint[] points, int offset) {
setCurve(points[offset + 0].getX(), points[offset + 0].getY(),
points[offset + 1].getX(), points[offset + 1].getY(),
points[offset + 2].getX(), points[offset + 2].getY(),
points[offset + 3].getX(), points[offset + 3].getY());
}
/**
* Configures the start, control and end points for this curve to be the same as the supplied
* curve.
*/
public void setCurve (ICubicCurve curve) {
setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX1(), curve.getCtrlY1(),
curve.getCtrlX2(), curve.getCtrlY2(), curve.getX2(), curve.getY2());
}
@Override // from interface ICubicCurve
public float getX1 () {
return x1;
}
@Override // from interface ICubicCurve
public float getY1 () {
return y1;
}
@Override // from interface ICubicCurve
public float getCtrlX1 () {
return ctrlx1;
}
@Override // from interface ICubicCurve
public float getCtrlY1 () {
return ctrly1;
}
@Override // from interface ICubicCurve
public float getCtrlX2 () {
return ctrlx2;
}
@Override // from interface ICubicCurve
public float getCtrlY2 () {
return ctrly2;
}
@Override // from interface ICubicCurve
public float getX2 () {
return x2;
}
@Override // from interface ICubicCurve
public float getY2 () {
return y2;
}
}
+100
View File
@@ -0,0 +1,100 @@
//
// $Id$
package pythagoras.f;
/**
* Cubic curve-related utility methods.
*/
public class CubicCurves
{
public static float getFlatnessSq (float x1, float y1, float ctrlx1, float ctrly1,
float ctrlx2, float ctrly2, float x2, float y2) {
return Math.max(Lines.pointSegDistSq(ctrlx1, ctrly1, x1, y1, x2, y2),
Lines.pointSegDistSq(ctrlx2, ctrly2, x1, y1, x2, y2));
}
public static float getFlatnessSq (float coords[], int offset) {
return getFlatnessSq(coords[offset + 0], coords[offset + 1], coords[offset + 2],
coords[offset + 3], coords[offset + 4], coords[offset + 5],
coords[offset + 6], coords[offset + 7]);
}
public static float getFlatness (float x1, float y1, float ctrlx1, float ctrly1,
float ctrlx2, float ctrly2, float x2, float y2) {
return (float)Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2));
}
public static float getFlatness (float coords[], int offset) {
return getFlatness(coords[offset + 0], coords[offset + 1], coords[offset + 2],
coords[offset + 3], coords[offset + 4], coords[offset + 5],
coords[offset + 6], coords[offset + 7]);
}
public static void subdivide (ICubicCurve src, CubicCurve left, CubicCurve right) {
float x1 = src.getX1(), y1 = src.getY1();
float cx1 = src.getCtrlX1(), cy1 = src.getCtrlY1();
float cx2 = src.getCtrlX2(), cy2 = src.getCtrlY2();
float x2 = src.getX2(), y2 = src.getY2();
float cx = (cx1 + cx2) / 2f, cy = (cy1 + cy2) / 2f;
cx1 = (x1 + cx1) / 2f;
cy1 = (y1 + cy1) / 2f;
cx2 = (x2 + cx2) / 2f;
cy2 = (y2 + cy2) / 2f;
float ax = (cx1 + cx) / 2f, ay = (cy1 + cy) / 2f;
float bx = (cx2 + cx) / 2f, by = (cy2 + cy) / 2f;
cx = (ax + bx) / 2f;
cy = (ay + by) / 2f;
if (left != null) {
left.setCurve(x1, y1, cx1, cy1, ax, ay, cx, cy);
}
if (right != null) {
right.setCurve(cx, cy, bx, by, cx2, cy2, x2, y2);
}
}
public static void subdivide (float src[], int srcOff, float left[], int leftOff,
float right[], int rightOff) {
float x1 = src[srcOff + 0], y1 = src[srcOff + 1];
float cx1 = src[srcOff + 2], cy1 = src[srcOff + 3];
float cx2 = src[srcOff + 4], cy2 = src[srcOff + 5];
float x2 = src[srcOff + 6], y2 = src[srcOff + 7];
float cx = (cx1 + cx2) / 2f, cy = (cy1 + cy2) / 2f;
cx1 = (x1 + cx1) / 2f;
cy1 = (y1 + cy1) / 2f;
cx2 = (x2 + cx2) / 2f;
cy2 = (y2 + cy2) / 2f;
float ax = (cx1 + cx) / 2f, ay = (cy1 + cy) / 2f;
float bx = (cx2 + cx) / 2f, by = (cy2 + cy) / 2f;
cx = (ax + bx) / 2f;
cy = (ay + by) / 2f;
if (left != null) {
left[leftOff + 0] = x1;
left[leftOff + 1] = y1;
left[leftOff + 2] = cx1;
left[leftOff + 3] = cy1;
left[leftOff + 4] = ax;
left[leftOff + 5] = ay;
left[leftOff + 6] = cx;
left[leftOff + 7] = cy;
}
if (right != null) {
right[rightOff + 0] = cx;
right[rightOff + 1] = cy;
right[rightOff + 2] = bx;
right[rightOff + 3] = by;
right[rightOff + 4] = cx2;
right[rightOff + 5] = cy2;
right[rightOff + 6] = x2;
right[rightOff + 7] = y2;
}
}
public static int solveCubic (float[] eqn) {
return solveCubic(eqn, eqn);
}
public static int solveCubic (float[] eqn, float[] res) {
return Crossing.solveCubic(eqn, res);
}
}
@@ -128,17 +128,15 @@ public class FlatteningPathIterator implements PathIterator
} }
/** /**
* Calculates flat path points for current segment of the source shape. * Calculates flat path points for the current segment of the source shape. Line segment is
* * flat by itself. Flatness of quad and cubic curves are evaluated by the getFlatnessSq()
* Line segment is flat by itself. Flatness of quad and cubic curves * method. Curves are subdivided until current flatness is bigger than user defined value and
* evaluated by getFlatnessSq() method. Curves subdivided until current * subdivision limit isn't exhausted. Single source segments are translated to a series of
* flatness is bigger than user defined and subdivision limit isn't * buffer points. The smaller the flatness the bigger the series. Every currentSegment() call
* exhausted. Single source segment translated to series of buffer points. * extracts one point from the buffer. When a series is completed, evaluate() takes the next
* The less flatness the bigger serries. Every currentSegment() call extract
* one point from the buffer. When series completed evaluate() takes next
* source shape segment. * source shape segment.
*/ */
void evaluate () { protected void evaluate () {
if (bufEmpty) { if (bufEmpty) {
bufType = p.currentSegment(coords); bufType = p.currentSegment(coords);
} }
@@ -149,6 +147,7 @@ public class FlatteningPathIterator implements PathIterator
px = coords[0]; px = coords[0];
py = coords[1]; py = coords[1];
break; break;
case SEG_QUADTO: case SEG_QUADTO:
if (bufEmpty) { if (bufEmpty) {
bufIndex -= 6; bufIndex -= 6;
@@ -159,7 +158,7 @@ public class FlatteningPathIterator implements PathIterator
} }
while (bufSubdiv < bufLimit) { while (bufSubdiv < bufLimit) {
if (QuadCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) { if (QuadCurves.getFlatnessSq(buf, bufIndex) < flatness2) {
break; break;
} }
@@ -173,7 +172,7 @@ public class FlatteningPathIterator implements PathIterator
bufIndex += BUFFER_CAPACITY; bufIndex += BUFFER_CAPACITY;
} }
QuadCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 4, buf, bufIndex); QuadCurves.subdivide(buf, bufIndex, buf, bufIndex - 4, buf, bufIndex);
bufIndex -= 4; bufIndex -= 4;
bufSubdiv++; bufSubdiv++;
@@ -189,6 +188,7 @@ public class FlatteningPathIterator implements PathIterator
bufType = SEG_LINETO; bufType = SEG_LINETO;
} }
break; break;
case SEG_CUBICTO: case SEG_CUBICTO:
if (bufEmpty) { if (bufEmpty) {
bufIndex -= 8; bufIndex -= 8;
@@ -199,7 +199,7 @@ public class FlatteningPathIterator implements PathIterator
} }
while (bufSubdiv < bufLimit) { while (bufSubdiv < bufLimit) {
if (CubicCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) { if (CubicCurves.getFlatnessSq(buf, bufIndex) < flatness2) {
break; break;
} }
@@ -213,7 +213,7 @@ public class FlatteningPathIterator implements PathIterator
bufIndex += BUFFER_CAPACITY; bufIndex += BUFFER_CAPACITY;
} }
CubicCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 6, buf, bufIndex); CubicCurves.subdivide(buf, bufIndex, buf, bufIndex - 6, buf, bufIndex);
bufIndex -= 6; bufIndex -= 6;
bufSubdiv++; bufSubdiv++;
@@ -230,7 +230,6 @@ public class FlatteningPathIterator implements PathIterator
} }
break; break;
} }
} }
public void next () { public void next () {
@@ -0,0 +1,60 @@
//
// $Id$
package pythagoras.f;
/**
* Provides read-only access to a {@link CubicCurve}.
*/
public interface ICubicCurve extends IShape, Cloneable
{
/** Returns the x-coordinate of the start of this curve. */
float getX1 ();
/** Returns the y-coordinate of the start of this curve. */
float getY1 ();
/** Returns the x-coordinate of the first control point. */
float getCtrlX1 ();
/** Returns the y-coordinate of the first control point. */
float getCtrlY1 ();
/** Returns the x-coordinate of the second control point. */
float getCtrlX2 ();
/** Returns the y-coordinate of the second control point. */
float getCtrlY2 ();
/** Returns the x-coordinate of the end of this curve. */
float getX2 ();
/** Returns the y-coordinate of the end of this curve. */
float getY2 ();
/** Returns a copy of the starting point of this curve. */
Point getP1 ();
/** Returns a copy of the first control point of this curve. */
Point getCtrlP1 ();
/** Returns a copy of the second control point of this curve. */
Point getCtrlP2 ();
/** Returns a copy of the ending point of this curve. */
Point getP2 ();
/** Returns the square of the flatness (maximum distance of a control point from the line
* connecting the end points) of this curve. */
double getFlatnessSq ();
/** Returns the flatness (maximum distance of a control point from the line connecting the end
* points) of this curve. */
double getFlatness ();
/** Subdivides this curve and stores the results into {@code left} and {@code right}. */
void subdivide (CubicCurve left, CubicCurve right);
/** Returns a mutable copy of this curve. */
CubicCurve clone ();
}
+24 -60
View File
@@ -8,94 +8,58 @@ package pythagoras.f;
*/ */
public interface ILine extends IShape, Cloneable public interface ILine extends IShape, Cloneable
{ {
/** /** Returns the x-coordinate of the start of this line. */
* Returns the x-coordinate of the start of this line.
*/
float getX1 (); float getX1 ();
/** /** Returns the y-coordinate of the start of this line. */
* Returns the y-coordinate of the start of this line.
*/
float getY1 (); float getY1 ();
/** /** Returns the x-coordinate of the end of this line. */
* Returns the x-coordinate of the end of this line.
*/
float getX2 (); float getX2 ();
/** /** Returns the y-coordinate of the end of this line. */
* Returns the y-coordinate of the end of this line.
*/
float getY2 (); float getY2 ();
/** /** Returns a copy of the starting point of this line. */
* Returns a view of the starting point of this line. Subsequent changes to the starting point
* will be visible in the returned point.
*/
IPoint p1 ();
/**
* Returns a copy of the starting point of this line. Subsequent changes to the starting point
* will not be visible in the returned point.
*/
Point getP1 (); Point getP1 ();
/** /** Initializes the supplied point with this line's starting point.
* Returns a view of the ending point of this line. Subsequent changes to the ending point will * @return the supplied point. */
* be visible in the returned point. Point getP1 (Point target);
*/
IPoint p2 ();
/** /** Returns a copy of the ending point of this line. */
* Returns a copy of the ending point of this line. Subsequent changes to the ending point will
* not be visible in the returned point.
*/
Point getP2 (); Point getP2 ();
/** /** Initializes the supplied point with this line's ending point.
* Returns the square of the distance from the specified point to the line defined by this line * @return the supplied point. */
* segment. Point getP2 (Point target);
*/
/** Returns the square of the distance from the specified point to the line defined by this
* line segment. */
float pointLineDistSq (float px, float py); float pointLineDistSq (float px, float py);
/** /** Returns the square of the distance from the supplied point to the line defined by this line
* Returns the square of the distance from the supplied point to the line defined by this line * segment. */
* segment.
*/
float pointLineDistSq (IPoint p); float pointLineDistSq (IPoint p);
/** /** Returns the distance from the specified point to the line defined by this line segment. */
* Returns the distance from the specified point to the line defined by this line segment.
*/
float pointLineDist (float px, float py); float pointLineDist (float px, float py);
/** /** Returns the distance from the supplied point to the line defined by this line segment. */
* Returns the distance from the supplied point to the line defined by this line segment.
*/
float pointLineDist (IPoint p); float pointLineDist (IPoint p);
/** /** Returns the square of the distance from the specified point this line segment. */
* Returns the square of the distance from the specified point this line segment.
*/
float pointSegDistSq (float px, float py); float pointSegDistSq (float px, float py);
/** /** Returns the square of the distance from the supplied point this line segment. */
* Returns the square of the distance from the supplied point this line segment.
*/
float pointSegDistSq (IPoint p); float pointSegDistSq (IPoint p);
/** /** Returns the distance from the specified point this line segment. */
* Returns the distance from the specified point this line segment.
*/
float pointSegDist (float px, float py); float pointSegDist (float px, float py);
/** /** Returns the distance from the supplied point this line segment. */
* Returns the distance from the supplied point this line segment.
*/
float pointSegDist (IPoint p); float pointSegDist (IPoint p);
/** /** Returns a mutable copy of this line. */
* Returns a mutable copy of this line.
*/
Line clone (); Line clone ();
} }
+7 -21
View File
@@ -9,38 +9,24 @@ package pythagoras.f;
*/ */
public interface IPoint extends Cloneable public interface IPoint extends Cloneable
{ {
/** /** Returns this point's x-coordinate. */
* Returns this point's x-coordinate.
*/
float getX (); float getX ();
/** /** Returns this point's y-coordinate. */
* Returns this point's y-coordinate.
*/
float getY (); float getY ();
/** /** Returns the squared Euclidian distance between this point and the specified point. */
* Returns the squared Euclidian distance between this point and the specified point.
*/
float distanceSq (float px, float py); float distanceSq (float px, float py);
/** /** Returns the squared Euclidian distance between this point and the supplied point. */
* Returns the squared Euclidian distance between this point and the supplied point.
*/
float distanceSq (IPoint p); float distanceSq (IPoint p);
/** /** Returns the Euclidian distance between this point and the specified point. */
* Returns the Euclidian distance between this point and the specified point.
*/
float distance (float px, float py); float distance (float px, float py);
/** /** Returns the Euclidian distance between this point and the supplied point. */
* Returns the Euclidian distance between this point and the supplied point.
*/
float distance (IPoint p); float distance (IPoint p);
/** /** Returns a mutable copy of this point. */
* Returns a mutable copy of this point.
*/
Point clone (); Point clone ();
} }
@@ -0,0 +1,51 @@
//
// $Id$
package pythagoras.f;
/**
* Provides read-only access to a {@link QuadCurve}.
*/
public interface IQuadCurve extends IShape, Cloneable
{
/** Returns the x-coordinate of the start of this curve. */
float getX1 ();
/** Returns the y-coordinate of the start of this curve. */
float getY1 ();
/** Returns the x-coordinate of the control point. */
float getCtrlX ();
/** Returns the y-coordinate of the control point. */
float getCtrlY ();
/** Returns the x-coordinate of the end of this curve. */
float getX2 ();
/** Returns the y-coordinate of the end of this curve. */
float getY2 ();
/** Returns a copy of the starting point of this curve. */
Point getP1 ();
/** Returns a copy of the control point of this curve. */
Point getCtrlP ();
/** Returns a copy of the ending point of this curve. */
Point getP2 ();
/** Returns the square of the flatness (maximum distance of a control point from the line
* connecting the end points) of this curve. */
float getFlatnessSq ();
/** Returns the flatness (maximum distance of a control point from the line connecting the end
* points) of this curve. */
float getFlatness ();
/** Subdivides this curve and stores the results into {@code left} and {@code right}. */
void subdivide (QuadCurve left, QuadCurve right);
/** Returns a mutable copy of this curve. */
QuadCurve clone ();
}
+26 -52
View File
@@ -9,86 +9,60 @@ package pythagoras.f;
*/ */
public interface IRectangle extends IRectangularShape, Cloneable public interface IRectangle extends IRectangularShape, Cloneable
{ {
/** The bitmask that indicates that a point lies to the left of this rectangle. /** The bitmask that indicates that a point lies to the left of this rectangle. See
* See {@link #outcode}. */ * {@link #outcode}. */
int OUT_LEFT = 1; int OUT_LEFT = 1;
/** The bitmask that indicates that a point lies above this rectangle. See {@link #outcode}. */ /** The bitmask that indicates that a point lies above this rectangle. See {@link #outcode}. */
int OUT_TOP = 2; int OUT_TOP = 2;
/** The bitmask that indicates that a point lies to the right of this rectangle. /** The bitmask that indicates that a point lies to the right of this rectangle. See
* See {@link #outcode}. */ * {@link #outcode}. */
int OUT_RIGHT = 4; int OUT_RIGHT = 4;
/** The bitmask that indicates that a point lies below this rectangle. See {@link #outcode}. */ /** The bitmask that indicates that a point lies below this rectangle. See {@link #outcode}. */
int OUT_BOTTOM = 8; int OUT_BOTTOM = 8;
/** /** Returns a copy of this rectangle's upper-left corner. */
* Returns a view of this rectangle's upper-left corner. Subsequent changes to this rectangle's
* location will be reflected in the returned point.
*/
IPoint location ();
/**
* Returns a copy of this rectangle's upper-left corner. Subsequent changes to this rectangle's
* location will not be reflected in the returned point.
*/
Point getLocation (); Point getLocation ();
/** /** Initializes the supplied point with this rectangle's upper-left corner.
* Returns a view of this rectangle's size. Subsequent changes to this rectangle's size will be * @return the supplied point. */
* reflected in the returned dimension. Point getLocation (Point target);
*/
IDimension size ();
/** /** Returns a copy of this rectangle's size. */
* Returns a copy of this rectangle's size. Subsequent changes to this rectangle's size will
* not be reflected in the returned dimension.
*/
Dimension getSize (); Dimension getSize ();
/** /** Initializes the supplied dimension with this rectangle's size.
* Returns the intersection of the specified rectangle and this rectangle (i.e. the largest * @return the supplied dimension. */
* rectangle contained in both this and the specified rectangle). Dimension getSize (Dimension target);
*/
/** Returns the intersection of the specified rectangle and this rectangle (i.e. the largest
* rectangle contained in both this and the specified rectangle). */
Rectangle intersection (float rx, float ry, float rw, float rh); Rectangle intersection (float rx, float ry, float rw, float rh);
/** /** Returns the intersection of the supplied rectangle and this rectangle (i.e. the largest
* Returns the intersection of the supplied rectangle and this rectangle (i.e. the largest * rectangle contained in both this and the supplied rectangle). */
* rectangle contained in both this and the supplied rectangle).
*/
Rectangle intersection (IRectangle r); Rectangle intersection (IRectangle r);
/** /** Returns the union of the supplied rectangle and this rectangle (i.e. the smallest rectangle
* Returns the union of the supplied rectangle and this rectangle (i.e. the smallest rectangle * that contains both this and the supplied rectangle). */
* that contains both this and the supplied rectangle).
*/
Rectangle union (IRectangle r); Rectangle union (IRectangle r);
/** /** Returns true if the specified line segment intersects this rectangle. */
* Returns true if the specified line segment intersects this rectangle.
*/
boolean intersectsLine (float x1, float y1, float x2, float y2); boolean intersectsLine (float x1, float y1, float x2, float y2);
/** /** Returns true if the supplied line segment intersects this rectangle. */
* Returns true if the supplied line segment intersects this rectangle.
*/
boolean intersectsLine (ILine l); boolean intersectsLine (ILine l);
/** /** Returns a set of flags indicating where the specified point lies in relation to the bounds
* Returns a set of flags indicating where the specified point lies in relation to the bounds * of this rectangle. See {@link #OUT_LEFT}, etc. */
* of this rectangle. See {@link #OUT_LEFT}, etc.
*/
int outcode (float px, float py); int outcode (float px, float py);
/** /** Returns a set of flags indicating where the supplied point lies in relation to the bounds of
* Returns a set of flags indicating where the supplied point lies in relation to the bounds of * this rectangle. See {@link #OUT_LEFT}, etc. */
* this rectangle. See {@link #OUT_LEFT}, etc.
*/
int outcode (IPoint point); int outcode (IPoint point);
/** /** Returns a mutable copy of this rectangle. */
* Returns a mutable copy of this rectangle.
*/
Rectangle clone (); Rectangle clone ();
} }
@@ -11,65 +11,40 @@ package pythagoras.f;
*/ */
public interface IRectangularShape extends IShape public interface IRectangularShape extends IShape
{ {
/** /** Returns the x-coordinate of the upper-left corner of the framing rectangle. */
* Returns the x-coordinate of the upper-left corner of the framing rectangle.
*/
float getX (); float getX ();
/** /** Returns the y-coordinate of the upper-left corner of the framing rectangle. */
* Returns the y-coordinate of the upper-left corner of the framing rectangle.
*/
float getY (); float getY ();
/** /** Returns the width of the framing rectangle. */
* Returns the width of the framing rectangle.
*/
float getWidth (); float getWidth ();
/** /** Returns the height of the framing rectangle. */
* Returns the height of the framing rectangle.
*/
float getHeight (); float getHeight ();
/** /** Returns the minimum x-coordinate of the framing rectangle. */
* Returns the minimum x-coordinate of the framing rectangle.
*/
float getMinX (); float getMinX ();
/** /** Returns the minimum y-coordinate of the framing rectangle. */
* Returns the minimum y-coordinate of the framing rectangle.
*/
float getMinY (); float getMinY ();
/** /** Returns the maximum x-coordinate of the framing rectangle. */
* Returns the maximum x-coordinate of the framing rectangle.
*/
float getMaxX (); float getMaxX ();
/** /** Returns the maximum y-coordinate of the framing rectangle. */
* Returns the maximum y-coordinate of the framing rectangle.
*/
float getMaxY (); float getMaxY ();
/** /** Returns the x-coordinate of the center of the framing rectangle. */
* Returns the x-coordinate of the center of the framing rectangle.
*/
float getCenterX (); float getCenterX ();
/** /** Returns the y-coordinate of the center of the framing rectangle. */
* Returns the y-coordinate of the center of the framing rectangle.
*/
float getCenterY (); float getCenterY ();
/** /** Returns a copy of this shape's framing rectangle. */
* Returns a view of this shape's framing rectangle. Subsequent changes to the shape will be
* reflected in the returned rectangle.
*/
IRectangle frame ();
/**
* Returns a copy of this shape's framing rectangle. Subsequent changes to the shape will be
* reflected in the returned rectangle.
*/
Rectangle getFrame (); Rectangle getFrame ();
/** Initializes the supplied rectangle with this shape's framing rectangle.
* @return the supplied rectangle. */
Rectangle getFrame (Rectangle target);
} }
+16 -35
View File
@@ -9,67 +9,48 @@ package pythagoras.f;
*/ */
public interface IShape public interface IShape
{ {
/** /** Returns true if this shape encloses no area. */
* Returns true if this shape encloses no area.
*/
boolean isEmpty (); boolean isEmpty ();
/** /** Returns true if this shape contains the specified point. */
* Returns true if this shape contains the specified point.
*/
boolean contains (float x, float y); boolean contains (float x, float y);
/** /** Returns true if this shape contains the supplied point. */
* Returns true if this shape contains the supplied point.
*/
boolean contains (IPoint point); boolean contains (IPoint point);
/** /** Returns true if this shape completely contains the specified rectangle. */
* Returns true if this shape completely contains the specified rectangle.
*/
boolean contains (float x, float y, float w, float h); boolean contains (float x, float y, float w, float h);
/** /** Returns true if this shape completely contains the supplied rectangle. */
* Returns true if this shape completely contains the supplied rectangle.
*/
boolean contains (IRectangle r); boolean contains (IRectangle r);
/** /** Returns true if this shape intersects the specified rectangle. */
* Returns true if this shape intersects the specified rectangle.
*/
boolean intersects (float x, float y, float w, float h); boolean intersects (float x, float y, float w, float h);
/** /** Returns true if this shape intersects the supplied rectangle. */
* Returns true if this shape intersects the supplied rectangle.
*/
boolean intersects (IRectangle r); boolean intersects (IRectangle r);
/** /** Returns a copy of the bounding rectangle for this shape. */
* Returns a view of the bounding rectangle for this shape. Subsequent changes to the bounding
* rectangle will be reflected in the returned rectangle.
*/
IRectangle bounds();
/**
* Returns a copy of the bounding rectangle for this shape. Subsequent changes to the bounding
* rectangle will not be reflected in the returned rectangle.
*/
Rectangle getBounds (); Rectangle getBounds ();
/** Initializes the supplied rectangle with this shape's bounding rectangle.
* @return the supplied rectangle. */
Rectangle getBounds (Rectangle target);
/** /**
* Returns an iterator over the path described by this shape. * Returns an iterator over the path described by this shape.
* *
* @param at if supplied, the points in the path are transformed using this. * @param at if supplied, the points in the path are transformed using this.
*/ */
PathIterator getPathIterator (AffineTransform at); PathIterator getPathIterator (AffineTransform at);
/** /**
* Returns an iterator over the path described by this shape. * Returns an iterator over the path described by this shape.
* *
* @param at if supplied, the points in the path are transformed using this. * @param at if supplied, the points in the path are transformed using this.
* @param flatness when approximating curved segments with lines, this controls the maximum * @param flatness when approximating curved segments with lines, this controls the maximum
* distance the lines are allowed to deviate from the approximated curve, thus a higher * distance the lines are allowed to deviate from the approximated curve, thus a higher
* flatness value generally allows for a path with fewer segments. * flatness value generally allows for a path with fewer segments.
*/ */
PathIterator getPathIterator (AffineTransform at, float flatness); PathIterator getPathIterator (AffineTransform at, float flatness);
} }
+6 -10
View File
@@ -167,18 +167,13 @@ public final class Path implements IShape, Cloneable
return p; return p;
} }
/** @Override // from interface IShape
* {@inheritDoc} public Rectangle getBounds () {
* return getBounds(new Rectangle());
* <em>Note:</em> this method violates the contract in that the bounds returned will
* <em>not</em> reflect subsequent changes to this path. Doing so is prohibitively expensive.
*/
@Override public IRectangle bounds () {
return getBounds();
} }
@Override // from interface IShape @Override // from interface IShape
public Rectangle getBounds () { public Rectangle getBounds (Rectangle target) {
float rx1, ry1, rx2, ry2; float rx1, ry1, rx2, ry2;
if (pointSize == 0) { if (pointSize == 0) {
rx1 = ry1 = rx2 = ry2 = 0f; rx1 = ry1 = rx2 = ry2 = 0f;
@@ -201,7 +196,8 @@ public final class Path implements IShape, Cloneable
} }
} }
} }
return new Rectangle(rx1, ry1, rx2 - rx1, ry2 - ry1); target.setBounds(rx1, ry1, rx2 - rx1, ry2 - ry1);
return target;
} }
@Override // from interface IShape @Override // from interface IShape
-1
View File
@@ -21,7 +21,6 @@ public class Point extends AbstractPoint implements Serializable
* Constructs a point at (0, 0). * Constructs a point at (0, 0).
*/ */
public Point () { public Point () {
setLocation(0, 0);
} }
/** /**
+121
View File
@@ -0,0 +1,121 @@
//
// $Id$
package pythagoras.f;
import java.io.Serializable;
/**
* Represents a quadratic curve.
*/
public class QuadCurve extends AbstractQuadCurve implements Serializable
{
/** The x-coordinate of the start of this curve. */
public float x1;
/** The y-coordinate of the start of this curve. */
public float y1;
/** The x-coordinate of the control point. */
public float ctrlx;
/** The y-coordinate of the control point. */
public float ctrly;
/** The x-coordinate of the end of this curve. */
public float x2;
/** The y-coordinate of the end of this curve. */
public float y2;
/**
* Creates a quad curve with all points at (0,0).
*/
public QuadCurve () {
}
/**
* Creates a quad curve with the specified start, control, and end points.
*/
public QuadCurve (float x1, float y1, float ctrlx, float ctrly, float x2, float y2) {
setCurve(x1, y1, ctrlx, ctrly, x2, y2);
}
/**
* Configures the start, control, and end points for this curve.
*/
public void setCurve (float x1, float y1, float ctrlx, float ctrly, float x2, float y2) {
this.x1 = x1;
this.y1 = y1;
this.ctrlx = ctrlx;
this.ctrly = ctrly;
this.x2 = x2;
this.y2 = y2;
}
/**
* Configures the start, control, and end points for this curve.
*/
public void setCurve (IPoint p1, IPoint cp, IPoint p2) {
setCurve(p1.getX(), p1.getY(), cp.getX(), cp.getY(), p2.getX(), p2.getY());
}
/**
* Configures the start, control, and end points for this curve, using the values at the
* specified offset in the {@link coords} array.
*/
public void setCurve (float[] coords, int offset) {
setCurve(coords[offset + 0], coords[offset + 1],
coords[offset + 2], coords[offset + 3],
coords[offset + 4], coords[offset + 5]);
}
/**
* Configures the start, control, and end points for this curve, using the values at the
* specified offset in the {@link points} array.
*/
public void setCurve (IPoint[] points, int offset) {
setCurve(points[offset + 0].getX(), points[offset + 0].getY(),
points[offset + 1].getX(), points[offset + 1].getY(),
points[offset + 2].getX(), points[offset + 2].getY());
}
/**
* Configures the start, control, and end points for this curve to be the same as the supplied
* curve.
*/
public void setCurve (IQuadCurve curve) {
setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX(), curve.getCtrlY(),
curve.getX2(), curve.getY2());
}
@Override // from interface IQuadCurve
public float getX1 () {
return x1;
}
@Override // from interface IQuadCurve
public float getY1 () {
return y1;
}
@Override // from interface IQuadCurve
public float getCtrlX () {
return ctrlx;
}
@Override // from interface IQuadCurve
public float getCtrlY () {
return ctrly;
}
@Override // from interface IQuadCurve
public float getX2 () {
return x2;
}
@Override // from interface IQuadCurve
public float getY2 () {
return y2;
}
}
@@ -0,0 +1,93 @@
//
// $Id$
package pythagoras.f;
/**
* Quad curve-related utility methods.
*/
public class QuadCurves
{
public static float getFlatnessSq (float x1, float y1, float ctrlx, float ctrly,
float x2, float y2) {
return Lines.pointSegDistSq(ctrlx, ctrly, x1, y1, x2, y2);
}
public static float getFlatnessSq (float coords[], int offset) {
return Lines.pointSegDistSq(coords[offset + 2], coords[offset + 3],
coords[offset + 0], coords[offset + 1],
coords[offset + 4], coords[offset + 5]);
}
public static float getFlatness (float x1, float y1, float ctrlx, float ctrly,
float x2, float y2) {
return Lines.pointSegDist(ctrlx, ctrly, x1, y1, x2, y2);
}
public static float getFlatness (float[] coords, int offset) {
return Lines.pointSegDist(coords[offset + 2], coords[offset + 3],
coords[offset + 0], coords[offset + 1],
coords[offset + 4], coords[offset + 5]);
}
public static void subdivide (IQuadCurve src, QuadCurve left, QuadCurve right) {
float x1 = src.getX1();
float y1 = src.getY1();
float cx = src.getCtrlX();
float cy = src.getCtrlY();
float x2 = src.getX2();
float y2 = src.getY2();
float cx1 = (x1 + cx) / 2f;
float cy1 = (y1 + cy) / 2f;
float cx2 = (x2 + cx) / 2f;
float cy2 = (y2 + cy) / 2f;
cx = (cx1 + cx2) / 2f;
cy = (cy1 + cy2) / 2f;
if (left != null) {
left.setCurve(x1, y1, cx1, cy1, cx, cy);
}
if (right != null) {
right.setCurve(cx, cy, cx2, cy2, x2, y2);
}
}
public static void subdivide (float[] src, int srcoff,
float left[], int leftOff, float[] right, int rightOff) {
float x1 = src[srcoff + 0];
float y1 = src[srcoff + 1];
float cx = src[srcoff + 2];
float cy = src[srcoff + 3];
float x2 = src[srcoff + 4];
float y2 = src[srcoff + 5];
float cx1 = (x1 + cx) / 2f;
float cy1 = (y1 + cy) / 2f;
float cx2 = (x2 + cx) / 2f;
float cy2 = (y2 + cy) / 2f;
cx = (cx1 + cx2) / 2f;
cy = (cy1 + cy2) / 2f;
if (left != null) {
left[leftOff + 0] = x1;
left[leftOff + 1] = y1;
left[leftOff + 2] = cx1;
left[leftOff + 3] = cy1;
left[leftOff + 4] = cx;
left[leftOff + 5] = cy;
}
if (right != null) {
right[rightOff + 0] = cx;
right[rightOff + 1] = cy;
right[rightOff + 2] = cx2;
right[rightOff + 3] = cy2;
right[rightOff + 4] = x2;
right[rightOff + 5] = y2;
}
}
public static int solveQuadratic (float[] eqn) {
return solveQuadratic(eqn, eqn);
}
public static int solveQuadratic (float[] eqn, float[] res) {
return Crossing.solveQuad(eqn, res);
}
}
@@ -27,7 +27,6 @@ public class Rectangle extends AbstractRectangle implements Serializable
* Constructs a rectangle at (0,0) and with dimensions (0,0). * Constructs a rectangle at (0,0) and with dimensions (0,0).
*/ */
public Rectangle () { public Rectangle () {
setBounds(0, 0, 0, 0);
} }
/** /**
@@ -111,13 +111,13 @@ public abstract class RectangularShape implements IRectangularShape
} }
@Override // from IRectangularShape @Override // from IRectangularShape
public IRectangle frame () { public Rectangle getFrame () {
return bounds(); return getBounds();
} }
@Override // from IRectangularShape @Override // from IRectangularShape
public Rectangle getFrame () { public Rectangle getFrame (Rectangle target) {
return getBounds(); return getBounds(target);
} }
@Override // from interface IShape @Override // from interface IShape
@@ -141,32 +141,17 @@ public abstract class RectangularShape implements IRectangularShape
} }
@Override // from interface IShape @Override // from interface IShape
public IRectangle bounds () { public Rectangle getBounds () {
return new AbstractRectangle() { return getBounds(new Rectangle());
@Override public float getX () {
return RectangularShape.this.getX();
}
@Override public float getY () {
return RectangularShape.this.getY();
}
@Override public float getWidth () {
return RectangularShape.this.getWidth();
}
@Override public float getHeight () {
return RectangularShape.this.getHeight();
}
// this isn't visible in the type, so won't be called by non-combatants
@Override public void setFrame (float x, float y, float w, float h) {
throw new UnsupportedOperationException();
}
};
} }
@Override // from interface IShape @Override // from interface IShape
public Rectangle getBounds () { public Rectangle getBounds (Rectangle target) {
return new Rectangle(getX(), getY(), getWidth(), getHeight()); target.setBounds(getX(), getY(), getWidth(), getHeight());
return target;
} }
// @Override // from interface IShape
// public PathIterator getPathIterator (AffineTransform t, float flatness) { // public PathIterator getPathIterator (AffineTransform t, float flatness) {
// return new FlatteningPathIterator(getPathIterator(t), flatness); // return new FlatteningPathIterator(getPathIterator(t), flatness);
// } // }