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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,38 +11,26 @@ import java.util.NoSuchElementException;
|
||||
*/
|
||||
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
|
||||
public Point getP1 () {
|
||||
return new Point(getX1(), getY1());
|
||||
return getP1(new Point());
|
||||
}
|
||||
|
||||
@Override // from interface ILine
|
||||
public IPoint p2 () {
|
||||
return new AbstractPoint() {
|
||||
@Override public float getX () {
|
||||
return getX2();
|
||||
}
|
||||
@Override public float getY () {
|
||||
return getY2();
|
||||
}
|
||||
};
|
||||
public Point getP1 (Point target) {
|
||||
target.setLocation(getX1(), getY1());
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override // from interface ILine
|
||||
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
|
||||
@@ -126,31 +114,12 @@ public abstract class AbstractLine implements ILine
|
||||
}
|
||||
|
||||
@Override // from interface IShape
|
||||
public IRectangle bounds () {
|
||||
return new AbstractRectangle() {
|
||||
@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();
|
||||
}
|
||||
};
|
||||
public Rectangle getBounds () {
|
||||
return getBounds(new Rectangle());
|
||||
}
|
||||
|
||||
@Override // from interface IShape
|
||||
public Rectangle getBounds () {
|
||||
public Rectangle getBounds (Rectangle target) {
|
||||
float x1 = getX1(), x2 = getX2(), y1 = getY1(), y2 = getY2();
|
||||
float rx, ry, rw, rh;
|
||||
if (x1 < x2) {
|
||||
@@ -167,7 +136,8 @@ public abstract class AbstractLine implements ILine
|
||||
ry = y2;
|
||||
rh = y1 - y2;
|
||||
}
|
||||
return new Rectangle(rx, ry, rw, rh);
|
||||
target.setBounds(rx, ry, rw, rh);
|
||||
return target;
|
||||
}
|
||||
|
||||
@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
|
||||
{
|
||||
@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
|
||||
public Point getLocation () {
|
||||
return new Point(getX(), getY());
|
||||
return getLocation(new Point());
|
||||
}
|
||||
|
||||
@Override // from interface IRectangle
|
||||
public IDimension size () {
|
||||
return new AbstractDimension() {
|
||||
@Override public float getWidth () {
|
||||
return AbstractRectangle.this.getWidth();
|
||||
}
|
||||
@Override public float getHeight () {
|
||||
return AbstractRectangle.this.getHeight();
|
||||
}
|
||||
};
|
||||
public Point getLocation (Point target) {
|
||||
target.setLocation(getX(), getY());
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override // from interface IRectangle
|
||||
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
|
||||
@@ -147,16 +135,6 @@ public abstract class AbstractRectangle extends RectangularShape implements IRec
|
||||
return new Iterator(this, t);
|
||||
}
|
||||
|
||||
@Override // from RectangularShape
|
||||
public IRectangle frame () {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override // from RectangularShape
|
||||
public IRectangle bounds () {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override // from Object
|
||||
public boolean equals (Object obj) {
|
||||
if (obj == this) {
|
||||
|
||||
@@ -218,17 +218,15 @@ class Crossing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CubicCurve class provides basic functionality to find curve crossing and calculating bounds
|
||||
*/
|
||||
public static class CubicCurve
|
||||
/** CubicCurve helper for finding curve crossing and calculating bounds. */
|
||||
public static class CubicCurveH
|
||||
{
|
||||
float ax, ay, bx, by, cx, cy;
|
||||
float Ax, Ay, Bx, By, Cx, Cy;
|
||||
float Ax3, Bx2;
|
||||
|
||||
public CubicCurve (float x1, float y1, float cx1, float cy1, float cx2, float cy2,
|
||||
float x2, float y2) {
|
||||
public CubicCurveH (float x1, float y1, float cx1, float cy1, float cx2, float cy2,
|
||||
float x2, float y2) {
|
||||
ax = x2 - x1;
|
||||
ay = y2 - y1;
|
||||
bx = cx1 - x1;
|
||||
@@ -410,7 +408,7 @@ class Crossing
|
||||
}
|
||||
|
||||
// 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[] res = new float[3];
|
||||
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.
|
||||
*/
|
||||
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 crossPath(s.getPathIterator(null), x, y);
|
||||
@@ -642,7 +640,7 @@ class Crossing
|
||||
}
|
||||
|
||||
// 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 py1 = ry1 - y1;
|
||||
float px2 = rx2 - x1;
|
||||
@@ -758,7 +756,7 @@ class Crossing
|
||||
* 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) {
|
||||
if (!s.bounds().intersects(x, y, w, h)) {
|
||||
if (!s.getBounds().intersects(x, y, w, h)) {
|
||||
return 0;
|
||||
}
|
||||
return intersectPath(s.getPathIterator(null), x, y, w, h);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
* Line segment is flat by itself. Flatness of quad and cubic curves
|
||||
* evaluated by getFlatnessSq() method. Curves subdivided until current
|
||||
* flatness is bigger than user defined and subdivision limit isn't
|
||||
* exhausted. Single source segment translated to series of buffer points.
|
||||
* The less flatness the bigger serries. Every currentSegment() call extract
|
||||
* one point from the buffer. When series completed evaluate() takes next
|
||||
* 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()
|
||||
* method. Curves are subdivided until current flatness is bigger than user defined value and
|
||||
* subdivision limit isn't exhausted. Single source segments are translated to a series of
|
||||
* buffer points. The smaller the flatness the bigger the series. Every currentSegment() call
|
||||
* extracts one point from the buffer. When a series is completed, evaluate() takes the next
|
||||
* source shape segment.
|
||||
*/
|
||||
void evaluate () {
|
||||
protected void evaluate () {
|
||||
if (bufEmpty) {
|
||||
bufType = p.currentSegment(coords);
|
||||
}
|
||||
@@ -149,6 +147,7 @@ public class FlatteningPathIterator implements PathIterator
|
||||
px = coords[0];
|
||||
py = coords[1];
|
||||
break;
|
||||
|
||||
case SEG_QUADTO:
|
||||
if (bufEmpty) {
|
||||
bufIndex -= 6;
|
||||
@@ -159,7 +158,7 @@ public class FlatteningPathIterator implements PathIterator
|
||||
}
|
||||
|
||||
while (bufSubdiv < bufLimit) {
|
||||
if (QuadCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) {
|
||||
if (QuadCurves.getFlatnessSq(buf, bufIndex) < flatness2) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -173,7 +172,7 @@ public class FlatteningPathIterator implements PathIterator
|
||||
bufIndex += BUFFER_CAPACITY;
|
||||
}
|
||||
|
||||
QuadCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 4, buf, bufIndex);
|
||||
QuadCurves.subdivide(buf, bufIndex, buf, bufIndex - 4, buf, bufIndex);
|
||||
|
||||
bufIndex -= 4;
|
||||
bufSubdiv++;
|
||||
@@ -189,6 +188,7 @@ public class FlatteningPathIterator implements PathIterator
|
||||
bufType = SEG_LINETO;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEG_CUBICTO:
|
||||
if (bufEmpty) {
|
||||
bufIndex -= 8;
|
||||
@@ -199,7 +199,7 @@ public class FlatteningPathIterator implements PathIterator
|
||||
}
|
||||
|
||||
while (bufSubdiv < bufLimit) {
|
||||
if (CubicCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) {
|
||||
if (CubicCurves.getFlatnessSq(buf, bufIndex) < flatness2) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ public class FlatteningPathIterator implements PathIterator
|
||||
bufIndex += BUFFER_CAPACITY;
|
||||
}
|
||||
|
||||
CubicCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 6, buf, bufIndex);
|
||||
CubicCurves.subdivide(buf, bufIndex, buf, bufIndex - 6, buf, bufIndex);
|
||||
|
||||
bufIndex -= 6;
|
||||
bufSubdiv++;
|
||||
@@ -230,7 +230,6 @@ public class FlatteningPathIterator implements PathIterator
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 ();
|
||||
}
|
||||
@@ -8,94 +8,58 @@ package pythagoras.f;
|
||||
*/
|
||||
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 ();
|
||||
|
||||
/**
|
||||
* Returns the y-coordinate of the start of this line.
|
||||
*/
|
||||
/** Returns the y-coordinate of the start of this line. */
|
||||
float getY1 ();
|
||||
|
||||
/**
|
||||
* Returns the x-coordinate of the end of this line.
|
||||
*/
|
||||
/** Returns the x-coordinate of the end of this line. */
|
||||
float getX2 ();
|
||||
|
||||
/**
|
||||
* Returns the y-coordinate of the end of this line.
|
||||
*/
|
||||
/** Returns the y-coordinate of the end of this line. */
|
||||
float getY2 ();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/** Returns a copy of the starting point of this line. */
|
||||
Point getP1 ();
|
||||
|
||||
/**
|
||||
* Returns a view of the ending point of this line. Subsequent changes to the ending point will
|
||||
* be visible in the returned point.
|
||||
*/
|
||||
IPoint p2 ();
|
||||
/** Initializes the supplied point with this line's starting point.
|
||||
* @return the supplied point. */
|
||||
Point getP1 (Point target);
|
||||
|
||||
/**
|
||||
* Returns a copy of the ending point of this line. Subsequent changes to the ending point will
|
||||
* not be visible in the returned point.
|
||||
*/
|
||||
/** Returns a copy of the ending point of this line. */
|
||||
Point getP2 ();
|
||||
|
||||
/**
|
||||
* Returns the square of the distance from the specified point to the line defined by this line
|
||||
* segment.
|
||||
*/
|
||||
/** Initializes the supplied point with this line's ending point.
|
||||
* @return the supplied point. */
|
||||
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);
|
||||
|
||||
/**
|
||||
* Returns the square of the distance from the supplied point to the line defined by this line
|
||||
* segment.
|
||||
*/
|
||||
/** Returns the square of the distance from the supplied point to the line defined by this line
|
||||
* segment. */
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Returns the distance from the supplied point this line segment.
|
||||
*/
|
||||
/** Returns the distance from the supplied point this line segment. */
|
||||
float pointSegDist (IPoint p);
|
||||
|
||||
/**
|
||||
* Returns a mutable copy of this line.
|
||||
*/
|
||||
/** Returns a mutable copy of this line. */
|
||||
Line clone ();
|
||||
}
|
||||
|
||||
@@ -9,38 +9,24 @@ package pythagoras.f;
|
||||
*/
|
||||
public interface IPoint extends Cloneable
|
||||
{
|
||||
/**
|
||||
* Returns this point's x-coordinate.
|
||||
*/
|
||||
/** Returns this point's x-coordinate. */
|
||||
float getX ();
|
||||
|
||||
/**
|
||||
* Returns this point's y-coordinate.
|
||||
*/
|
||||
/** Returns this point's y-coordinate. */
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Returns a mutable copy of this point.
|
||||
*/
|
||||
/** Returns a mutable copy of this point. */
|
||||
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 ();
|
||||
}
|
||||
@@ -9,86 +9,60 @@ package pythagoras.f;
|
||||
*/
|
||||
public interface IRectangle extends IRectangularShape, Cloneable
|
||||
{
|
||||
/** The bitmask that indicates that a point lies to the left of this rectangle.
|
||||
* See {@link #outcode}. */
|
||||
/** The bitmask that indicates that a point lies to the left of this rectangle. See
|
||||
* {@link #outcode}. */
|
||||
int OUT_LEFT = 1;
|
||||
|
||||
/** The bitmask that indicates that a point lies above this rectangle. See {@link #outcode}. */
|
||||
int OUT_TOP = 2;
|
||||
|
||||
/** The bitmask that indicates that a point lies to the right of this rectangle.
|
||||
* See {@link #outcode}. */
|
||||
/** The bitmask that indicates that a point lies to the right of this rectangle. See
|
||||
* {@link #outcode}. */
|
||||
int OUT_RIGHT = 4;
|
||||
|
||||
/** The bitmask that indicates that a point lies below this rectangle. See {@link #outcode}. */
|
||||
int OUT_BOTTOM = 8;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/** Returns a copy of this rectangle's upper-left corner. */
|
||||
Point getLocation ();
|
||||
|
||||
/**
|
||||
* Returns a view of this rectangle's size. Subsequent changes to this rectangle's size will be
|
||||
* reflected in the returned dimension.
|
||||
*/
|
||||
IDimension size ();
|
||||
/** Initializes the supplied point with this rectangle's upper-left corner.
|
||||
* @return the supplied point. */
|
||||
Point getLocation (Point target);
|
||||
|
||||
/**
|
||||
* Returns a copy of this rectangle's size. Subsequent changes to this rectangle's size will
|
||||
* not be reflected in the returned dimension.
|
||||
*/
|
||||
/** Returns a copy of this rectangle's size. */
|
||||
Dimension getSize ();
|
||||
|
||||
/**
|
||||
* Returns the intersection of the specified rectangle and this rectangle (i.e. the largest
|
||||
* rectangle contained in both this and the specified rectangle).
|
||||
*/
|
||||
/** Initializes the supplied dimension with this rectangle's size.
|
||||
* @return the supplied dimension. */
|
||||
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);
|
||||
|
||||
/**
|
||||
* Returns the intersection of the supplied rectangle and this rectangle (i.e. the largest
|
||||
* rectangle contained in both this and the supplied rectangle).
|
||||
*/
|
||||
/** Returns the intersection of the supplied rectangle and this rectangle (i.e. the largest
|
||||
* rectangle contained in both this and the supplied rectangle). */
|
||||
Rectangle intersection (IRectangle r);
|
||||
|
||||
/**
|
||||
* Returns the union of the supplied rectangle and this rectangle (i.e. the smallest rectangle
|
||||
* that contains both this and the supplied rectangle).
|
||||
*/
|
||||
/** Returns the union of the supplied rectangle and this rectangle (i.e. the smallest rectangle
|
||||
* that contains both this and the supplied rectangle). */
|
||||
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);
|
||||
|
||||
/**
|
||||
* Returns true if the supplied line segment intersects this rectangle.
|
||||
*/
|
||||
/** Returns true if the supplied line segment intersects this rectangle. */
|
||||
boolean intersectsLine (ILine l);
|
||||
|
||||
/**
|
||||
* Returns a set of flags indicating where the specified point lies in relation to the bounds
|
||||
* of this rectangle. See {@link #OUT_LEFT}, etc.
|
||||
*/
|
||||
/** Returns a set of flags indicating where the specified point lies in relation to the bounds
|
||||
* of this rectangle. See {@link #OUT_LEFT}, etc. */
|
||||
int outcode (float px, float py);
|
||||
|
||||
/**
|
||||
* Returns a set of flags indicating where the supplied point lies in relation to the bounds of
|
||||
* this rectangle. See {@link #OUT_LEFT}, etc.
|
||||
*/
|
||||
/** Returns a set of flags indicating where the supplied point lies in relation to the bounds of
|
||||
* this rectangle. See {@link #OUT_LEFT}, etc. */
|
||||
int outcode (IPoint point);
|
||||
|
||||
/**
|
||||
* Returns a mutable copy of this rectangle.
|
||||
*/
|
||||
/** Returns a mutable copy of this rectangle. */
|
||||
Rectangle clone ();
|
||||
}
|
||||
|
||||
@@ -11,65 +11,40 @@ package pythagoras.f;
|
||||
*/
|
||||
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 ();
|
||||
|
||||
/**
|
||||
* 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 ();
|
||||
|
||||
/**
|
||||
* Returns the width of the framing rectangle.
|
||||
*/
|
||||
/** Returns the width of the framing rectangle. */
|
||||
float getWidth ();
|
||||
|
||||
/**
|
||||
* Returns the height of the framing rectangle.
|
||||
*/
|
||||
/** Returns the height of the framing rectangle. */
|
||||
float getHeight ();
|
||||
|
||||
/**
|
||||
* Returns the minimum x-coordinate of the framing rectangle.
|
||||
*/
|
||||
/** Returns the minimum x-coordinate of the framing rectangle. */
|
||||
float getMinX ();
|
||||
|
||||
/**
|
||||
* Returns the minimum y-coordinate of the framing rectangle.
|
||||
*/
|
||||
/** Returns the minimum y-coordinate of the framing rectangle. */
|
||||
float getMinY ();
|
||||
|
||||
/**
|
||||
* Returns the maximum x-coordinate of the framing rectangle.
|
||||
*/
|
||||
/** Returns the maximum x-coordinate of the framing rectangle. */
|
||||
float getMaxX ();
|
||||
|
||||
/**
|
||||
* Returns the maximum y-coordinate of the framing rectangle.
|
||||
*/
|
||||
/** Returns the maximum y-coordinate of the framing rectangle. */
|
||||
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 ();
|
||||
|
||||
/**
|
||||
* Returns the y-coordinate of the center of the framing rectangle.
|
||||
*/
|
||||
/** Returns the y-coordinate of the center of the framing rectangle. */
|
||||
float getCenterY ();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/** Returns a copy of this shape's framing rectangle. */
|
||||
Rectangle getFrame ();
|
||||
|
||||
/** Initializes the supplied rectangle with this shape's framing rectangle.
|
||||
* @return the supplied rectangle. */
|
||||
Rectangle getFrame (Rectangle target);
|
||||
}
|
||||
|
||||
@@ -9,67 +9,48 @@ package pythagoras.f;
|
||||
*/
|
||||
public interface IShape
|
||||
{
|
||||
/**
|
||||
* Returns true if this shape encloses no area.
|
||||
*/
|
||||
/** Returns true if this shape encloses no area. */
|
||||
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);
|
||||
|
||||
/**
|
||||
* Returns true if this shape contains the supplied point.
|
||||
*/
|
||||
/** Returns true if this shape contains the supplied 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);
|
||||
|
||||
/**
|
||||
* Returns true if this shape completely contains the supplied rectangle.
|
||||
*/
|
||||
/** Returns true if this shape completely contains the supplied rectangle. */
|
||||
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);
|
||||
|
||||
/**
|
||||
* Returns true if this shape intersects the supplied rectangle.
|
||||
*/
|
||||
/** Returns true if this shape intersects the supplied rectangle. */
|
||||
boolean intersects (IRectangle r);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/** Returns a copy of the bounding rectangle for this shape. */
|
||||
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.
|
||||
*
|
||||
*
|
||||
* @param at if supplied, the points in the path are transformed using this.
|
||||
*/
|
||||
PathIterator getPathIterator (AffineTransform at);
|
||||
|
||||
/**
|
||||
* Returns an iterator over the path described by this shape.
|
||||
*
|
||||
*
|
||||
* @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
|
||||
* distance the lines are allowed to deviate from the approximated curve, thus a higher
|
||||
* flatness value generally allows for a path with fewer segments.
|
||||
* distance the lines are allowed to deviate from the approximated curve, thus a higher
|
||||
* flatness value generally allows for a path with fewer segments.
|
||||
*/
|
||||
PathIterator getPathIterator (AffineTransform at, float flatness);
|
||||
}
|
||||
|
||||
@@ -167,18 +167,13 @@ public final class Path implements IShape, Cloneable
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <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
|
||||
public Rectangle getBounds () {
|
||||
return getBounds(new Rectangle());
|
||||
}
|
||||
|
||||
@Override // from interface IShape
|
||||
public Rectangle getBounds () {
|
||||
public Rectangle getBounds (Rectangle target) {
|
||||
float rx1, ry1, rx2, ry2;
|
||||
if (pointSize == 0) {
|
||||
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
|
||||
|
||||
@@ -21,7 +21,6 @@ public class Point extends AbstractPoint implements Serializable
|
||||
* Constructs a point at (0, 0).
|
||||
*/
|
||||
public Point () {
|
||||
setLocation(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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).
|
||||
*/
|
||||
public Rectangle () {
|
||||
setBounds(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -111,13 +111,13 @@ public abstract class RectangularShape implements IRectangularShape
|
||||
}
|
||||
|
||||
@Override // from IRectangularShape
|
||||
public IRectangle frame () {
|
||||
return bounds();
|
||||
public Rectangle getFrame () {
|
||||
return getBounds();
|
||||
}
|
||||
|
||||
@Override // from IRectangularShape
|
||||
public Rectangle getFrame () {
|
||||
return getBounds();
|
||||
public Rectangle getFrame (Rectangle target) {
|
||||
return getBounds(target);
|
||||
}
|
||||
|
||||
@Override // from interface IShape
|
||||
@@ -141,32 +141,17 @@ public abstract class RectangularShape implements IRectangularShape
|
||||
}
|
||||
|
||||
@Override // from interface IShape
|
||||
public IRectangle bounds () {
|
||||
return new AbstractRectangle() {
|
||||
@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();
|
||||
}
|
||||
};
|
||||
public Rectangle getBounds () {
|
||||
return getBounds(new Rectangle());
|
||||
}
|
||||
|
||||
@Override // from interface IShape
|
||||
public Rectangle getBounds () {
|
||||
return new Rectangle(getX(), getY(), getWidth(), getHeight());
|
||||
public Rectangle getBounds (Rectangle target) {
|
||||
target.setBounds(getX(), getY(), getWidth(), getHeight());
|
||||
return target;
|
||||
}
|
||||
|
||||
// @Override // from interface IShape
|
||||
// public PathIterator getPathIterator (AffineTransform t, float flatness) {
|
||||
// return new FlatteningPathIterator(getPathIterator(t), flatness);
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user