Ellipses (by which I don't mean multiple ...s).
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Provides most of the implementation of {@link IEllipse}, obtaining the framing rectangle from
|
||||
* the derived class.
|
||||
*/
|
||||
public abstract class AbstractEllipse extends RectangularShape implements IEllipse
|
||||
{
|
||||
@Override // from IEllipse
|
||||
public Ellipse clone () {
|
||||
return new Ellipse(getX(), getY(), getWidth(), getHeight());
|
||||
}
|
||||
|
||||
@Override // from interface IShape
|
||||
public boolean contains (float px, float py) {
|
||||
if (isEmpty()) return false;
|
||||
float a = (px - getX()) / getWidth() - 0.5f;
|
||||
float b = (py - getY()) / getHeight() - 0.5f;
|
||||
return a * a + b * b < 0.25f;
|
||||
}
|
||||
|
||||
@Override // from interface IShape
|
||||
public boolean contains (float rx, float ry, float rw, float rh) {
|
||||
if (isEmpty() || rw <= 0f || rh <= 0f) return false;
|
||||
float rx1 = rx, ry1 = ry, rx2 = rx + rw, ry2 = ry + rh;
|
||||
return contains(rx1, ry1) && contains(rx2, ry1) && contains(rx2, ry2) && contains(rx1, ry2);
|
||||
}
|
||||
|
||||
@Override // from interface IShape
|
||||
public boolean intersects (float rx, float ry, float rw, float rh) {
|
||||
if (isEmpty() || rw <= 0f || rh <= 0f) return false;
|
||||
float cx = getX() + getWidth() / 2f;
|
||||
float cy = getY() + getHeight() / 2f;
|
||||
float rx1 = rx, ry1 = ry, rx2 = rx + rw, ry2 = ry + rh;
|
||||
float nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx);
|
||||
float ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy);
|
||||
return contains(nx, ny);
|
||||
}
|
||||
|
||||
@Override // from interface IShape
|
||||
public PathIterator getPathIterator (AffineTransform at) {
|
||||
return new Iterator(this, at);
|
||||
}
|
||||
|
||||
/** An iterator over an {@link IEllipse}. */
|
||||
protected static class Iterator implements PathIterator
|
||||
{
|
||||
private final float x, y, width, height;
|
||||
private final AffineTransform t;
|
||||
private int index;
|
||||
|
||||
Iterator (IEllipse e, AffineTransform t) {
|
||||
this.x = e.getX();
|
||||
this.y = e.getY();
|
||||
this.width = e.getWidth();
|
||||
this.height = e.getHeight();
|
||||
this.t = t;
|
||||
if (width < 0f || height < 0f) {
|
||||
index = 6;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int getWindingRule () {
|
||||
return WIND_NON_ZERO;
|
||||
}
|
||||
|
||||
@Override public boolean isDone () {
|
||||
return index > 5;
|
||||
}
|
||||
|
||||
@Override public void next () {
|
||||
index++;
|
||||
}
|
||||
|
||||
@Override public int currentSegment (float[] coords) {
|
||||
if (isDone()) {
|
||||
throw new NoSuchElementException("Iterator out of bounds");
|
||||
}
|
||||
if (index == 5) {
|
||||
return SEG_CLOSE;
|
||||
}
|
||||
int type;
|
||||
int count;
|
||||
if (index == 0) {
|
||||
type = SEG_MOVETO;
|
||||
count = 1;
|
||||
float p[] = POINTS[3];
|
||||
coords[0] = x + p[4] * width;
|
||||
coords[1] = y + p[5] * height;
|
||||
} else {
|
||||
type = SEG_CUBICTO;
|
||||
count = 3;
|
||||
float p[] = POINTS[index - 1];
|
||||
int j = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
coords[j] = x + p[j++] * width;
|
||||
coords[j] = y + p[j++] * height;
|
||||
}
|
||||
}
|
||||
if (t != null) {
|
||||
t.transform(coords, 0, coords, 0, count);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
// An ellipse is subdivided into four quarters by x and y axis. Each part is approximated by a
|
||||
// cubic Bezier curve. The arc in the first quarter starts in (a, 0) and finishes in (0, b)
|
||||
// points. Control points for the cubic curve are (a, 0), (a, m), (n, b) and (0, b) where n and
|
||||
// m are calculated based on the requirement that the Bezier curve in point 0.5 should lay on
|
||||
// the arc.
|
||||
|
||||
/** The coefficient to calculate control points of Bezier curves. */
|
||||
private static final float U = 2f / 3f * ((float)Math.sqrt(2) - 1f);
|
||||
|
||||
/** The points coordinates calculation table. */
|
||||
private static final float[][] POINTS = {
|
||||
{ 1f, 0.5f + U, 0.5f + U, 1f, 0.5f, 1f },
|
||||
{ 0.5f - U, 1f, 0f, 0.5f + U, 0f, 0.5f },
|
||||
{ 0f, 0.5f - U, 0.5f - U, 0f, 0.5f, 0f },
|
||||
{ 0.5f + U, 0f, 1f, 0.5f - U, 1f, 0.5f } };
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represents an ellipse that is described by a framing rectangle.
|
||||
*/
|
||||
public class Ellipse extends AbstractEllipse implements Serializable
|
||||
{
|
||||
/** The x-coordinate of the framing rectangle. */
|
||||
public float x;
|
||||
|
||||
/** The y-coordinate of the framing rectangle. */
|
||||
public float y;
|
||||
|
||||
/** The width of the framing rectangle. */
|
||||
public float width;
|
||||
|
||||
/** The height of the framing rectangle. */
|
||||
public float height;
|
||||
|
||||
/**
|
||||
* Creates an ellipse with framing rectangle (0x0+0+0).
|
||||
*/
|
||||
public Ellipse () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ellipse with the specified framing rectangle.
|
||||
*/
|
||||
public Ellipse (float x, float y, float width, float height) {
|
||||
setFrame(x, y, width, height);
|
||||
}
|
||||
|
||||
@Override // from interface IRectangularShape
|
||||
public float getX () {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override // from interface IRectangularShape
|
||||
public float getY () {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override // from interface IRectangularShape
|
||||
public float getWidth () {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override // from interface IRectangularShape
|
||||
public float getHeight () {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override // from RectangularShape
|
||||
public void setFrame (float x, float y, float w, float h) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package pythagoras.f;
|
||||
|
||||
/**
|
||||
* Provides read-only access to an {@link Ellipse}.
|
||||
*/
|
||||
public interface IEllipse extends IRectangularShape, Cloneable
|
||||
{
|
||||
/** Returns a mutable copy of this ellipse. */
|
||||
Ellipse clone ();
|
||||
}
|
||||
Reference in New Issue
Block a user