From c8d591c8a2b924db1b056188dee5902a062fb8ea Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Fri, 12 Aug 2011 11:00:36 -0700 Subject: [PATCH] Converted the float bits to double since they've substantially evolved. --- src/main/java/pythagoras/d/AbstractArc.java | 128 ++- .../java/pythagoras/d/AbstractCubicCurve.java | 78 +- .../java/pythagoras/d/AbstractDimension.java | 8 +- .../java/pythagoras/d/AbstractEllipse.java | 26 +- src/main/java/pythagoras/d/AbstractLine.java | 68 +- src/main/java/pythagoras/d/AbstractPoint.java | 56 +- .../java/pythagoras/d/AbstractQuadCurve.java | 62 +- .../java/pythagoras/d/AbstractRectangle.java | 83 +- .../pythagoras/d/AbstractRoundRectangle.java | 32 +- .../java/pythagoras/d/AbstractTransform.java | 117 +++ .../java/pythagoras/d/AbstractVector.java | 198 ++++ .../java/pythagoras/d/AffineTransform.java | 885 ++++++------------ src/main/java/pythagoras/d/Arc.java | 55 +- src/main/java/pythagoras/d/Area.java | 218 ++--- src/main/java/pythagoras/d/Crossing.java | 8 +- .../java/pythagoras/d/CrossingHelper.java | 10 +- src/main/java/pythagoras/d/CubicCurve.java | 32 +- src/main/java/pythagoras/d/CubicCurves.java | 22 +- .../pythagoras/d/CurveCrossingHelper.java | 22 +- src/main/java/pythagoras/d/Dimension.java | 8 +- src/main/java/pythagoras/d/Ellipse.java | 8 +- .../pythagoras/d/FlatteningPathIterator.java | 14 +- src/main/java/pythagoras/d/GeometryUtil.java | 20 +- src/main/java/pythagoras/d/IArc.java | 14 +- src/main/java/pythagoras/d/ICubicCurve.java | 28 +- src/main/java/pythagoras/d/IDimension.java | 4 +- src/main/java/pythagoras/d/ILine.java | 16 +- src/main/java/pythagoras/d/IPoint.java | 29 +- src/main/java/pythagoras/d/IQuadCurve.java | 22 +- src/main/java/pythagoras/d/IRectangle.java | 8 +- .../java/pythagoras/d/IRectangularShape.java | 30 +- .../java/pythagoras/d/IRoundRectangle.java | 4 +- src/main/java/pythagoras/d/IShape.java | 8 +- src/main/java/pythagoras/d/IVector.java | 132 +++ .../java/pythagoras/d/IdentityTransform.java | 113 +++ .../java/pythagoras/d/IntersectPoint.java | 14 +- src/main/java/pythagoras/d/Line.java | 10 +- src/main/java/pythagoras/d/Lines.java | 9 +- src/main/java/pythagoras/d/MathUtil.java | 230 +++++ .../pythagoras/d/NonUniformTransform.java | 259 +++++ src/main/java/pythagoras/d/Path.java | 42 +- src/main/java/pythagoras/d/PathIterator.java | 2 +- src/main/java/pythagoras/d/Point.java | 50 +- src/main/java/pythagoras/d/Points.java | 36 +- src/main/java/pythagoras/d/QuadCurve.java | 24 +- src/main/java/pythagoras/d/QuadCurves.java | 20 +- src/main/java/pythagoras/d/Rectangle.java | 32 +- src/main/java/pythagoras/d/Rectangles.java | 16 +- .../java/pythagoras/d/RectangularShape.java | 72 +- .../java/pythagoras/d/RigidTransform.java | 196 ++++ .../java/pythagoras/d/RoundRectangle.java | 16 +- src/main/java/pythagoras/d/Transform.java | 196 ++++ src/main/java/pythagoras/d/Transforms.java | 80 ++ .../java/pythagoras/d/UniformTransform.java | 225 +++++ src/main/java/pythagoras/d/Vector.java | 121 +++ src/main/java/pythagoras/d/Vectors.java | 79 ++ 56 files changed, 3006 insertions(+), 1289 deletions(-) create mode 100644 src/main/java/pythagoras/d/AbstractTransform.java create mode 100644 src/main/java/pythagoras/d/AbstractVector.java create mode 100644 src/main/java/pythagoras/d/IVector.java create mode 100644 src/main/java/pythagoras/d/IdentityTransform.java create mode 100644 src/main/java/pythagoras/d/MathUtil.java create mode 100644 src/main/java/pythagoras/d/NonUniformTransform.java create mode 100644 src/main/java/pythagoras/d/RigidTransform.java create mode 100644 src/main/java/pythagoras/d/Transform.java create mode 100644 src/main/java/pythagoras/d/Transforms.java create mode 100644 src/main/java/pythagoras/d/UniformTransform.java create mode 100644 src/main/java/pythagoras/d/Vector.java create mode 100644 src/main/java/pythagoras/d/Vectors.java diff --git a/src/main/java/pythagoras/d/AbstractArc.java b/src/main/java/pythagoras/d/AbstractArc.java index e1b1583..509414e 100644 --- a/src/main/java/pythagoras/d/AbstractArc.java +++ b/src/main/java/pythagoras/d/AbstractArc.java @@ -13,39 +13,37 @@ import java.util.NoSuchElementException; public abstract class AbstractArc extends RectangularShape implements IArc { @Override // from interface IArc - public Point getStartPoint () { - return getStartPoint(new Point()); + public Point startPoint () { + return startPoint(new Point()); } @Override // from interface IArc - public Point getStartPoint (Point target) { - double a = Math.toRadians(getAngleStart()); - target.setLocation(getX() + (1f + Math.cos(a)) * getWidth() / 2f, - getY() + (1f - Math.sin(a)) * getHeight() / 2f); - return target; + public Point startPoint (Point target) { + double a = Math.toRadians(angleStart()); + return target.set(x() + (1f + Math.cos(a)) * width() / 2f, + y() + (1f - Math.sin(a)) * height() / 2f); } @Override // from interface IArc - public Point getEndPoint () { - return getEndPoint(new Point()); + public Point endPoint () { + return endPoint(new Point()); } @Override // from interface IArc - public Point getEndPoint (Point target) { - double a = Math.toRadians(getAngleStart() + getAngleExtent()); - target.setLocation(getX() + (1f + Math.cos(a)) * getWidth() / 2f, - getY() + (1f - Math.sin(a)) * getHeight() / 2f); - return target; + public Point endPoint (Point target) { + double a = Math.toRadians(angleStart() + angleExtent()); + return target.set(x() + (1f + Math.cos(a)) * width() / 2f, + y() + (1f - Math.sin(a)) * height() / 2f); } @Override // from interface IArc public boolean containsAngle (double angle) { - double extent = getAngleExtent(); + double extent = angleExtent(); if (extent >= 360f) { return true; } - angle = getNormAngle(angle); - double a1 = getNormAngle(getAngleStart()); + angle = normAngle(angle); + double a1 = normAngle(angleStart()); double a2 = a1 + extent; if (a2 > 360f) { return angle >= a1 || angle <= a2 - 360f; @@ -58,41 +56,41 @@ public abstract class AbstractArc extends RectangularShape implements IArc @Override // from interface IArc public Arc clone () { - return new Arc(getX(), getY(), getWidth(), getHeight(), getAngleStart(), getAngleExtent(), - getArcType()); + return new Arc(x(), y(), width(), height(), angleStart(), angleExtent(), + arcType()); } @Override // from RectangularShape public boolean isEmpty () { - return getArcType() == OPEN || super.isEmpty(); + return arcType() == OPEN || super.isEmpty(); } @Override // from RectangularShape public boolean contains (double px, double py) { // normalize point - double nx = (px - getX()) / getWidth() - 0.5f; - double ny = (py - getY()) / getHeight() - 0.5f; + double nx = (px - x()) / width() - 0.5f; + double ny = (py - y()) / height() - 0.5f; if ((nx * nx + ny * ny) > 0.25) { return false; } - double extent = getAngleExtent(); + double extent = angleExtent(); double absExtent = Math.abs(extent); if (absExtent >= 360f) { return true; } boolean containsAngle = containsAngle(Math.toDegrees(-Math.atan2(ny, nx))); - if (getArcType() == PIE) { + if (arcType() == PIE) { return containsAngle; } if (absExtent <= 180f && !containsAngle) { return false; } - Line l = new Line(getStartPoint(), getEndPoint()); + Line l = new Line(startPoint(), endPoint()); int ccw1 = l.relativeCCW(px, py); - int ccw2 = l.relativeCCW(getCenterX(), getCenterY()); + int ccw2 = l.relativeCCW(centerX(), centerY()); return ccw1 == 0 || ccw2 == 0 || ((ccw1 + ccw2) == 0 ^ absExtent > 180f); } @@ -103,20 +101,20 @@ public abstract class AbstractArc extends RectangularShape implements IArc return false; } - double absExtent = Math.abs(getAngleExtent()); - if (getArcType() != PIE || absExtent <= 180f || absExtent >= 360f) { + double absExtent = Math.abs(angleExtent()); + if (arcType() != PIE || absExtent <= 180f || absExtent >= 360f) { return true; } Rectangle r = new Rectangle(rx, ry, rw, rh); - double cx = getCenterX(), cy = getCenterY(); + double cx = centerX(), cy = centerY(); if (r.contains(cx, cy)) { return false; } - Point p1 = getStartPoint(), p2 = getEndPoint(); - return !r.intersectsLine(cx, cy, p1.getX(), p1.getY()) && - !r.intersectsLine(cx, cy, p2.getX(), p2.getY()); + Point p1 = startPoint(), p2 = endPoint(); + return !r.intersectsLine(cx, cy, p1.x(), p1.y()) && + !r.intersectsLine(cx, cy, p2.x(), p2.y()); } @Override // from RectangularShape @@ -131,22 +129,22 @@ public abstract class AbstractArc extends RectangularShape implements IArc return true; } - double cx = getCenterX(), cy = getCenterY(); - Point p1 = getStartPoint(), p2 = getEndPoint(); + double cx = centerX(), cy = centerY(); + Point p1 = startPoint(), p2 = endPoint(); // check: does rectangle contain arc's points Rectangle r = new Rectangle(rx, ry, rw, rh); - if (r.contains(p1) || r.contains(p2) || (getArcType() == PIE && r.contains(cx, cy))) { + if (r.contains(p1) || r.contains(p2) || (arcType() == PIE && r.contains(cx, cy))) { return true; } - if (getArcType() == PIE) { - if (r.intersectsLine(p1.getX(), p1.getY(), cx, cy) || - r.intersectsLine(p2.getX(), p2.getY(), cx, cy)) { + if (arcType() == PIE) { + if (r.intersectsLine(p1.x(), p1.y(), cx, cy) || + r.intersectsLine(p2.x(), p2.y(), cx, cy)) { return true; } } else { - if (r.intersectsLine(p1.getX(), p1.getY(), p2.getX(), p2.getY())) { + if (r.intersectsLine(p1.x(), p1.y(), p2.x(), p2.y())) { return true; } } @@ -158,27 +156,27 @@ public abstract class AbstractArc extends RectangularShape implements IArc } @Override // from RectangularShape - public Rectangle getBounds (Rectangle target) { + public Rectangle bounds (Rectangle target) { if (isEmpty()) { - target.setBounds(getX(), getY(), getWidth(), getHeight()); + target.setBounds(x(), y(), width(), height()); return target; } - double rx1 = getX(); - double ry1 = getY(); - double rx2 = rx1 + getWidth(); - double ry2 = ry1 + getHeight(); + double rx1 = x(); + double ry1 = y(); + double rx2 = rx1 + width(); + double ry2 = ry1 + height(); - Point p1 = getStartPoint(), p2 = getEndPoint(); + Point p1 = startPoint(), p2 = endPoint(); - double bx1 = containsAngle(180f) ? rx1 : Math.min(p1.getX(), p2.getX()); - double by1 = containsAngle(90f) ? ry1 : Math.min(p1.getY(), p2.getY()); - double bx2 = containsAngle(0f) ? rx2 : Math.max(p1.getX(), p2.getX()); - double by2 = containsAngle(270f) ? ry2 : Math.max(p1.getY(), p2.getY()); + double bx1 = containsAngle(180f) ? rx1 : Math.min(p1.x(), p2.x()); + double by1 = containsAngle(90f) ? ry1 : Math.min(p1.y(), p2.y()); + double bx2 = containsAngle(0f) ? rx2 : Math.max(p1.x(), p2.x()); + double by2 = containsAngle(270f) ? ry2 : Math.max(p1.y(), p2.y()); - if (getArcType() == PIE) { - double cx = getCenterX(); - double cy = getCenterY(); + if (arcType() == PIE) { + double cx = centerX(); + double cy = centerY(); bx1 = Math.min(bx1, cx); by1 = Math.min(by1, cy); bx2 = Math.max(bx2, cx); @@ -189,12 +187,12 @@ public abstract class AbstractArc extends RectangularShape implements IArc } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform at) { + public PathIterator pathIterator (Transform at) { return new Iterator(this, at); } /** Returns a normalized angle (bound between 0 and 360 degrees). */ - protected double getNormAngle (double angle) { + protected double normAngle (double angle) { return angle - Math.floor(angle / 360f) * 360f; } @@ -223,7 +221,7 @@ public abstract class AbstractArc extends RectangularShape implements IArc private int type; /** The path iterator transformation */ - private AffineTransform t; + private Transform t; /** The current segment index */ private int index; @@ -259,14 +257,14 @@ public abstract class AbstractArc extends RectangularShape implements IArc /** The y coordinate of the first path point (MOVE_TO) */ private double my; - Iterator (IArc a, AffineTransform t) { - this.width = a.getWidth() / 2f; - this.height = a.getHeight() / 2f; - this.x = a.getX() + width; - this.y = a.getY() + height; - this.angle = -Math.toRadians(a.getAngleStart()); - this.extent = -a.getAngleExtent(); - this.type = a.getArcType(); + Iterator (IArc a, Transform t) { + this.width = a.width() / 2f; + this.height = a.height() / 2f; + this.x = a.x() + width; + this.y = a.y() + height; + this.angle = -Math.toRadians(a.angleStart()); + this.extent = -a.angleExtent(); + this.type = a.arcType(); this.t = t; if (width < 0 || height < 0) { @@ -298,7 +296,7 @@ public abstract class AbstractArc extends RectangularShape implements IArc } } - @Override public int getWindingRule () { + @Override public int windingRule () { return WIND_NON_ZERO; } diff --git a/src/main/java/pythagoras/d/AbstractCubicCurve.java b/src/main/java/pythagoras/d/AbstractCubicCurve.java index ab9ff64..34fe234 100644 --- a/src/main/java/pythagoras/d/AbstractCubicCurve.java +++ b/src/main/java/pythagoras/d/AbstractCubicCurve.java @@ -13,35 +13,35 @@ import java.util.NoSuchElementException; public abstract class AbstractCubicCurve implements ICubicCurve { @Override // from interface ICubicCurve - public Point getP1 () { - return new Point(getX1(), getY1()); + public Point p1 () { + return new Point(x1(), y1()); } @Override // from interface ICubicCurve - public Point getCtrlP1 () { - return new Point(getCtrlX1(), getCtrlY1()); + public Point ctrlP1 () { + return new Point(ctrlX1(), ctrlY1()); } @Override // from interface ICubicCurve - public Point getCtrlP2 () { - return new Point(getCtrlX2(), getCtrlY2()); + public Point ctrlP2 () { + return new Point(ctrlX2(), ctrlY2()); } @Override // from interface ICubicCurve - public Point getP2 () { - return new Point(getX2(), getY2()); + public Point p2 () { + return new Point(x2(), y2()); } @Override // from interface ICubicCurve - public double getFlatnessSq () { - return CubicCurves.getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(), - getCtrlX2(), getCtrlY2(), getX2(), getY2()); + public double flatnessSq () { + return CubicCurves.flatnessSq(x1(), y1(), ctrlX1(), ctrlY1(), + ctrlX2(), ctrlY2(), x2(), y2()); } @Override // from interface ICubicCurve - public double getFlatness () { - return CubicCurves.getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(), - getCtrlX2(), getCtrlY2(), getX2(), getY2()); + public double flatness () { + return CubicCurves.flatness(x1(), y1(), ctrlX1(), ctrlY1(), + ctrlX2(), ctrlY2(), x2(), y2()); } @Override // from interface ICubicCurve @@ -51,8 +51,8 @@ public abstract class AbstractCubicCurve implements ICubicCurve @Override // from interface ICubicCurve public CubicCurve clone () { - return new CubicCurve(getX1(), getY1(), getCtrlX1(), getCtrlY1(), - getCtrlX2(), getCtrlY2(), getX2(), getY2()); + return new CubicCurve(x1(), y1(), ctrlX1(), ctrlY1(), + ctrlX2(), ctrlY2(), x2(), y2()); } @Override // from interface IShape @@ -73,12 +73,12 @@ public abstract class AbstractCubicCurve implements ICubicCurve @Override // from interface IShape public boolean contains (IPoint p) { - return contains(p.getX(), p.getY()); + return contains(p.x(), p.y()); } @Override // from interface IShape public boolean contains (IRectangle r) { - return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + return contains(r.x(), r.y(), r.width(), r.height()); } @Override // from interface IShape @@ -89,19 +89,19 @@ public abstract class AbstractCubicCurve implements ICubicCurve @Override // from interface IShape public boolean intersects (IRectangle r) { - return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + return intersects(r.x(), r.y(), r.width(), r.height()); } @Override // from interface IShape - public Rectangle getBounds () { - return getBounds(new Rectangle()); + public Rectangle bounds () { + return bounds(new Rectangle()); } @Override // from interface IShape - public Rectangle getBounds (Rectangle target) { - double x1 = getX1(), y1 = getY1(), x2 = getX2(), y2 = getY2(); - double ctrlx1 = getCtrlX1(), ctrly1 = getCtrlY1(); - double ctrlx2 = getCtrlX2(), ctrly2 = getCtrlY2(); + public Rectangle bounds (Rectangle target) { + double x1 = x1(), y1 = y1(), x2 = x2(), y2 = y2(); + double ctrlx1 = ctrlX1(), ctrly1 = ctrlY1(); + double ctrlx2 = ctrlX2(), ctrly2 = ctrlY2(); double rx1 = Math.min(Math.min(x1, x2), Math.min(ctrlx1, ctrlx2)); double ry1 = Math.min(Math.min(y1, y2), Math.min(ctrly1, ctrly2)); double rx2 = Math.max(Math.max(x1, x2), Math.max(ctrlx1, ctrlx2)); @@ -111,28 +111,28 @@ public abstract class AbstractCubicCurve implements ICubicCurve } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform t) { + public PathIterator pathIterator (Transform t) { return new Iterator(this, t); } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform at, double flatness) { - return new FlatteningPathIterator(getPathIterator(at), flatness); + public PathIterator pathIterator (Transform at, double flatness) { + return new FlatteningPathIterator(pathIterator(at), flatness); } /** An iterator over an {@link ICubicCurve}. */ protected static class Iterator implements PathIterator { private ICubicCurve c; - private AffineTransform t; + private Transform t; private int index; - Iterator (ICubicCurve c, AffineTransform t) { + Iterator (ICubicCurve c, Transform t) { this.c = c; this.t = t; } - @Override public int getWindingRule () { + @Override public int windingRule () { return WIND_NON_ZERO; } @@ -152,17 +152,17 @@ public abstract class AbstractCubicCurve implements ICubicCurve int count; if (index == 0) { type = SEG_MOVETO; - coords[0] = c.getX1(); - coords[1] = c.getY1(); + coords[0] = c.x1(); + coords[1] = c.y1(); 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(); + coords[0] = c.ctrlX1(); + coords[1] = c.ctrlY1(); + coords[2] = c.ctrlX2(); + coords[3] = c.ctrlY2(); + coords[4] = c.x2(); + coords[5] = c.y2(); count = 3; } if (t != null) { diff --git a/src/main/java/pythagoras/d/AbstractDimension.java b/src/main/java/pythagoras/d/AbstractDimension.java index 3c12e43..d025361 100644 --- a/src/main/java/pythagoras/d/AbstractDimension.java +++ b/src/main/java/pythagoras/d/AbstractDimension.java @@ -19,9 +19,7 @@ public abstract class AbstractDimension implements IDimension @Override public int hashCode () { - long bits = Platform.hashCode(getWidth()); - bits += Platform.hashCode(getHeight()) * 37; - return (((int) bits) ^ ((int) (bits >> 32))); + return Platform.hashCode(width()) ^ Platform.hashCode(height()); } @Override @@ -31,13 +29,13 @@ public abstract class AbstractDimension implements IDimension } if (obj instanceof AbstractDimension) { AbstractDimension d = (AbstractDimension)obj; - return (d.getWidth() == getWidth() && d.getHeight() == getHeight()); + return (d.width() == width() && d.height() == height()); } return false; } @Override public String toString () { - return Dimensions.dimenToString(getWidth(), getHeight()); + return Dimensions.dimenToString(width(), height()); } } diff --git a/src/main/java/pythagoras/d/AbstractEllipse.java b/src/main/java/pythagoras/d/AbstractEllipse.java index bb3cb93..f0fa587 100644 --- a/src/main/java/pythagoras/d/AbstractEllipse.java +++ b/src/main/java/pythagoras/d/AbstractEllipse.java @@ -14,14 +14,14 @@ public abstract class AbstractEllipse extends RectangularShape implements IEllip { @Override // from IEllipse public Ellipse clone () { - return new Ellipse(getX(), getY(), getWidth(), getHeight()); + return new Ellipse(x(), y(), width(), height()); } @Override // from interface IShape public boolean contains (double px, double py) { if (isEmpty()) return false; - double a = (px - getX()) / getWidth() - 0.5f; - double b = (py - getY()) / getHeight() - 0.5f; + double a = (px - x()) / width() - 0.5f; + double b = (py - y()) / height() - 0.5f; return a * a + b * b < 0.25f; } @@ -35,8 +35,8 @@ public abstract class AbstractEllipse extends RectangularShape implements IEllip @Override // from interface IShape public boolean intersects (double rx, double ry, double rw, double rh) { if (isEmpty() || rw <= 0f || rh <= 0f) return false; - double cx = getX() + getWidth() / 2f; - double cy = getY() + getHeight() / 2f; + double cx = x() + width() / 2f; + double cy = y() + height() / 2f; double rx1 = rx, ry1 = ry, rx2 = rx + rw, ry2 = ry + rh; double nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx); double ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy); @@ -44,7 +44,7 @@ public abstract class AbstractEllipse extends RectangularShape implements IEllip } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform at) { + public PathIterator pathIterator (Transform at) { return new Iterator(this, at); } @@ -52,21 +52,21 @@ public abstract class AbstractEllipse extends RectangularShape implements IEllip protected static class Iterator implements PathIterator { private final double x, y, width, height; - private final AffineTransform t; + private final Transform 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(); + Iterator (IEllipse e, Transform t) { + this.x = e.x(); + this.y = e.y(); + this.width = e.width(); + this.height = e.height(); this.t = t; if (width < 0f || height < 0f) { index = 6; } } - @Override public int getWindingRule () { + @Override public int windingRule () { return WIND_NON_ZERO; } diff --git a/src/main/java/pythagoras/d/AbstractLine.java b/src/main/java/pythagoras/d/AbstractLine.java index 1bb50db..038ef05 100644 --- a/src/main/java/pythagoras/d/AbstractLine.java +++ b/src/main/java/pythagoras/d/AbstractLine.java @@ -13,80 +13,78 @@ import java.util.NoSuchElementException; public abstract class AbstractLine implements ILine { @Override // from interface ILine - public Point getP1 () { - return getP1(new Point()); + public Point p1 () { + return p1(new Point()); } @Override // from interface ILine - public Point getP1 (Point target) { - target.setLocation(getX1(), getY1()); - return target; + public Point p1 (Point target) { + return target.set(x1(), y1()); } @Override // from interface ILine - public Point getP2 () { - return getP2(new Point()); + public Point p2 () { + return p2(new Point()); } @Override // from interface ILine - public Point getP2 (Point target) { - target.setLocation(getX2(), getY2()); - return target; + public Point p2 (Point target) { + return target.set(x2(), y2()); } @Override // from interface ILine public double pointLineDistSq (double px, double py) { - return Lines.pointLineDistSq(px, py, getX1(), getY1(), getX2(), getY2()); + return Lines.pointLineDistSq(px, py, x1(), y1(), x2(), y2()); } @Override // from interface ILine public double pointLineDistSq (IPoint p) { - return Lines.pointLineDistSq(p.getX(), p.getY(), getX1(), getY1(), getX2(), getY2()); + return Lines.pointLineDistSq(p.x(), p.y(), x1(), y1(), x2(), y2()); } @Override // from interface ILine public double pointLineDist (double px, double py) { - return Lines.pointLineDist(px, py, getX1(), getY1(), getX2(), getY2()); + return Lines.pointLineDist(px, py, x1(), y1(), x2(), y2()); } @Override // from interface ILine public double pointLineDist (IPoint p) { - return Lines.pointLineDist(p.getX(), p.getY(), getX1(), getY1(), getX2(), getY2()); + return Lines.pointLineDist(p.x(), p.y(), x1(), y1(), x2(), y2()); } @Override // from interface ILine public double pointSegDistSq (double px, double py) { - return Lines.pointSegDistSq(px, py, getX1(), getY1(), getX2(), getY2()); + return Lines.pointSegDistSq(px, py, x1(), y1(), x2(), y2()); } @Override // from interface ILine public double pointSegDistSq (IPoint p) { - return Lines.pointSegDistSq(p.getX(), p.getY(), getX1(), getY1(), getX2(), getY2()); + return Lines.pointSegDistSq(p.x(), p.y(), x1(), y1(), x2(), y2()); } @Override // from interface ILine public double pointSegDist (double px, double py) { - return Lines.pointSegDist(px, py, getX1(), getY1(), getX2(), getY2()); + return Lines.pointSegDist(px, py, x1(), y1(), x2(), y2()); } @Override // from interface ILine public double pointSegDist (IPoint p) { - return Lines.pointSegDist(p.getX(), p.getY(), getX1(), getY1(), getX2(), getY2()); + return Lines.pointSegDist(p.x(), p.y(), x1(), y1(), x2(), y2()); } @Override // from interface ILine public int relativeCCW (double px, double py) { - return Lines.relativeCCW(px, py, getX1(), getY1(), getX2(), getY2()); + return Lines.relativeCCW(px, py, x1(), y1(), x2(), y2()); } @Override // from interface ILine public int relativeCCW (IPoint p) { - return Lines.relativeCCW(p.getX(), p.getY(), getX1(), getY1(), getX2(), getY2()); + return Lines.relativeCCW(p.x(), p.y(), x1(), y1(), x2(), y2()); } @Override // from interface ILine public Line clone () { - return new Line(getX1(), getY1(), getX2(), getY2()); + return new Line(x1(), y1(), x2(), y2()); } @Override // from interface IShape @@ -116,7 +114,7 @@ public abstract class AbstractLine implements ILine @Override // from interface IShape public boolean intersects (double rx, double ry, double rw, double rh) { - return Lines.lineIntersectsRect(getX1(), getY1(), getX2(), getY2(), rx, ry, rw, rh); + return Lines.lineIntersectsRect(x1(), y1(), x2(), y2(), rx, ry, rw, rh); } @Override // from interface IShape @@ -125,13 +123,13 @@ public abstract class AbstractLine implements ILine } @Override // from interface IShape - public Rectangle getBounds () { - return getBounds(new Rectangle()); + public Rectangle bounds () { + return bounds(new Rectangle()); } @Override // from interface IShape - public Rectangle getBounds (Rectangle target) { - double x1 = getX1(), x2 = getX2(), y1 = getY1(), y2 = getY2(); + public Rectangle bounds (Rectangle target) { + double x1 = x1(), x2 = x2(), y1 = y1(), y2 = y2(); double rx, ry, rw, rh; if (x1 < x2) { rx = x1; @@ -152,12 +150,12 @@ public abstract class AbstractLine implements ILine } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform at) { + public PathIterator pathIterator (Transform at) { return new Iterator(this, at); } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform at, double flatness) { + public PathIterator pathIterator (Transform at, double flatness) { return new Iterator(this, at); } @@ -165,18 +163,18 @@ public abstract class AbstractLine implements ILine protected static class Iterator implements PathIterator { private double x1, y1, x2, y2; - private AffineTransform t; + private Transform t; private int index; - Iterator (ILine l, AffineTransform at) { - this.x1 = l.getX1(); - this.y1 = l.getY1(); - this.x2 = l.getX2(); - this.y2 = l.getY2(); + Iterator (ILine l, Transform at) { + this.x1 = l.x1(); + this.y1 = l.y1(); + this.x2 = l.x2(); + this.y2 = l.y2(); this.t = at; } - @Override public int getWindingRule () { + @Override public int windingRule () { return WIND_NON_ZERO; } diff --git a/src/main/java/pythagoras/d/AbstractPoint.java b/src/main/java/pythagoras/d/AbstractPoint.java index 116be02..0a96f42 100644 --- a/src/main/java/pythagoras/d/AbstractPoint.java +++ b/src/main/java/pythagoras/d/AbstractPoint.java @@ -12,27 +12,59 @@ import pythagoras.util.Platform; */ public abstract class AbstractPoint implements IPoint { - @Override // from interface IPoint + @Override // from IPoint public double distanceSq (double px, double py) { - return Points.distanceSq(getX(), getY(), px, py); + return Points.distanceSq(x(), y(), px, py); } - @Override // from interface IPoint + @Override // from IPoint public double distanceSq (IPoint p) { - return Points.distanceSq(getX(), getY(), p.getX(), p.getY()); + return Points.distanceSq(x(), y(), p.x(), p.y()); } - @Override // from interface IPoint + @Override // from IPoint public double distance (double px, double py) { - return Points.distance(getX(), getY(), px, py); + return Points.distance(x(), y(), px, py); } - @Override // from interface IPoint + @Override // from IPoint public double distance (IPoint p) { - return Points.distance(getX(), getY(), p.getX(), p.getY()); + return Points.distance(x(), y(), p.x(), p.y()); } - @Override // from interface IPoint + @Override // from IPoint + public Point mult (double s) { + return mult(s, new Point()); + } + + @Override // from IPoint + public Point mult (double s, Point result) { + return result.set(x() * s, y() * s); + } + + @Override // from IPoint + public Point add (double x, double y) { + return new Point(x() + x, y() + y); + } + + @Override // from IPoint + public Point add (double x, double y, Point result) { + return result.set(x() + x, y() + y); + } + + @Override // from IPoint + public Point rotate (double angle) { + return rotate(angle, new Point()); + } + + @Override // from IPoint + public Point rotate (double angle, Point result) { + double x = x(), y = y(); + double sina = Math.sin(angle), cosa = Math.cos(angle); + return result.set(x*cosa - y*sina, x*sina + y*cosa); + } + + @Override // from IPoint public Point clone () { return new Point(this); } @@ -44,18 +76,18 @@ public abstract class AbstractPoint implements IPoint } if (obj instanceof AbstractPoint) { AbstractPoint p = (AbstractPoint)obj; - return getX() == p.getX() && getY() == p.getY(); + return x() == p.x() && y() == p.y(); } return false; } @Override public int hashCode () { - return Platform.hashCode(getX()) ^ Platform.hashCode(getY()); + return Platform.hashCode(x()) ^ Platform.hashCode(y()); } @Override public String toString () { - return Points.pointToString(getX(), getY()); + return Points.pointToString(x(), y()); } } diff --git a/src/main/java/pythagoras/d/AbstractQuadCurve.java b/src/main/java/pythagoras/d/AbstractQuadCurve.java index 0769d84..816220c 100644 --- a/src/main/java/pythagoras/d/AbstractQuadCurve.java +++ b/src/main/java/pythagoras/d/AbstractQuadCurve.java @@ -13,28 +13,28 @@ import java.util.NoSuchElementException; public abstract class AbstractQuadCurve implements IQuadCurve { @Override // from interface IQuadCurve - public Point getP1 () { - return new Point(getX1(), getY1()); + public Point p1 () { + return new Point(x1(), y1()); } @Override // from interface IQuadCurve - public Point getCtrlP () { - return new Point(getCtrlX(), getCtrlY()); + public Point ctrlP () { + return new Point(ctrlX(), ctrlY()); } @Override // from interface IQuadCurve - public Point getP2 () { - return new Point(getX2(), getY2()); + public Point p2 () { + return new Point(x2(), y2()); } @Override // from interface IQuadCurve - public double getFlatnessSq () { - return Lines.pointSegDistSq(getCtrlX(), getCtrlY(), getX1(), getY1(), getX2(), getY2()); + public double flatnessSq () { + return Lines.pointSegDistSq(ctrlX(), ctrlY(), x1(), y1(), x2(), y2()); } @Override // from interface IQuadCurve - public double getFlatness () { - return Lines.pointSegDist(getCtrlX(), getCtrlY(), getX1(), getY1(), getX2(), getY2()); + public double flatness () { + return Lines.pointSegDist(ctrlX(), ctrlY(), x1(), y1(), x2(), y2()); } @Override // from interface IQuadCurve @@ -44,7 +44,7 @@ public abstract class AbstractQuadCurve implements IQuadCurve @Override // from interface IQuadCurve public QuadCurve clone () { - return new QuadCurve(getX1(), getY1(), getCtrlX(), getCtrlY(), getX2(), getY2()); + return new QuadCurve(x1(), y1(), ctrlX(), ctrlY(), x2(), y2()); } @Override // from interface IShape @@ -65,12 +65,12 @@ public abstract class AbstractQuadCurve implements IQuadCurve @Override // from interface IShape public boolean contains (IPoint p) { - return contains(p.getX(), p.getY()); + return contains(p.x(), p.y()); } @Override // from interface IShape public boolean contains (IRectangle r) { - return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + return contains(r.x(), r.y(), r.width(), r.height()); } @Override // from interface IShape @@ -81,18 +81,18 @@ public abstract class AbstractQuadCurve implements IQuadCurve @Override // from interface IShape public boolean intersects (IRectangle r) { - return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + return intersects(r.x(), r.y(), r.width(), r.height()); } @Override // from interface IShape - public Rectangle getBounds () { - return getBounds(new Rectangle()); + public Rectangle bounds () { + return bounds(new Rectangle()); } @Override // from interface IShape - public Rectangle getBounds (Rectangle target) { - double x1 = getX1(), y1 = getY1(), x2 = getX2(), y2 = getY2(); - double ctrlx = getCtrlX(), ctrly = getCtrlY(); + public Rectangle bounds (Rectangle target) { + double x1 = x1(), y1 = y1(), x2 = x2(), y2 = y2(); + double ctrlx = ctrlX(), ctrly = ctrlY(); double rx0 = Math.min(Math.min(x1, x2), ctrlx); double ry0 = Math.min(Math.min(y1, y2), ctrly); double rx1 = Math.max(Math.max(x1, x2), ctrlx); @@ -102,28 +102,28 @@ public abstract class AbstractQuadCurve implements IQuadCurve } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform t) { + public PathIterator pathIterator (Transform t) { return new Iterator(this, t); } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform t, double flatness) { - return new FlatteningPathIterator(getPathIterator(t), flatness); + public PathIterator pathIterator (Transform t, double flatness) { + return new FlatteningPathIterator(pathIterator(t), flatness); } /** An iterator over an {@link IQuadCurve}. */ protected static class Iterator implements PathIterator { private IQuadCurve c; - private AffineTransform t; + private Transform t; private int index; - Iterator (IQuadCurve q, AffineTransform t) { + Iterator (IQuadCurve q, Transform t) { this.c = q; this.t = t; } - @Override public int getWindingRule () { + @Override public int windingRule () { return WIND_NON_ZERO; } @@ -143,15 +143,15 @@ public abstract class AbstractQuadCurve implements IQuadCurve int count; if (index == 0) { type = SEG_MOVETO; - coords[0] = c.getX1(); - coords[1] = c.getY1(); + coords[0] = c.x1(); + coords[1] = c.y1(); count = 1; } else { type = SEG_QUADTO; - coords[0] = c.getCtrlX(); - coords[1] = c.getCtrlY(); - coords[2] = c.getX2(); - coords[3] = c.getY2(); + coords[0] = c.ctrlX(); + coords[1] = c.ctrlY(); + coords[2] = c.x2(); + coords[3] = c.y2(); count = 2; } if (t != null) { diff --git a/src/main/java/pythagoras/d/AbstractRectangle.java b/src/main/java/pythagoras/d/AbstractRectangle.java index de38ec9..1467650 100644 --- a/src/main/java/pythagoras/d/AbstractRectangle.java +++ b/src/main/java/pythagoras/d/AbstractRectangle.java @@ -15,39 +15,38 @@ import pythagoras.util.Platform; public abstract class AbstractRectangle extends RectangularShape implements IRectangle { @Override // from interface IRectangle - public Point getLocation () { - return getLocation(new Point()); + public Point location () { + return location(new Point()); } @Override // from interface IRectangle - public Point getLocation (Point target) { - target.setLocation(getX(), getY()); - return target; + public Point location (Point target) { + return target.set(x(), y()); } @Override // from interface IRectangle - public Dimension getSize () { - return getSize(new Dimension()); + public Dimension size () { + return size(new Dimension()); } @Override // from interface IRectangle - public Dimension getSize (Dimension target) { - target.setSize(getWidth(), getHeight()); + public Dimension size (Dimension target) { + target.setSize(width(), height()); return target; } @Override // from interface IRectangle public Rectangle intersection (double rx, double ry, double rw, double rh) { - double x1 = Math.max(getX(), rx); - double y1 = Math.max(getY(), ry); - double x2 = Math.min(getMaxX(), rx + rw); - double y2 = Math.min(getMaxY(), ry + rh); + double x1 = Math.max(x(), rx); + double y1 = Math.max(y(), ry); + double x2 = Math.min(maxX(), rx + rw); + double y2 = Math.min(maxY(), ry + rh); return new Rectangle(x1, y1, x2 - x1, y2 - y1); } @Override // from interface IRectangle public Rectangle intersection (IRectangle r) { - return intersection(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + return intersection(r.x(), r.y(), r.width(), r.height()); } @Override // from interface IRectangle @@ -59,31 +58,31 @@ public abstract class AbstractRectangle extends RectangularShape implements IRec @Override // from interface IRectangle public boolean intersectsLine (double x1, double y1, double x2, double y2) { - return Lines.lineIntersectsRect(x1, y1, x2, y2, getX(), getY(), getWidth(), getHeight()); + return Lines.lineIntersectsRect(x1, y1, x2, y2, x(), y(), width(), height()); } @Override // from interface IRectangle public boolean intersectsLine (ILine l) { - return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2()); + return intersectsLine(l.x1(), l.y1(), l.x2(), l.y2()); } @Override // from interface IRectangle public int outcode (double px, double py) { int code = 0; - if (getWidth() <= 0) { + if (width() <= 0) { code |= OUT_LEFT | OUT_RIGHT; - } else if (px < getX()) { + } else if (px < x()) { code |= OUT_LEFT; - } else if (px > getMaxX()) { + } else if (px > maxX()) { code |= OUT_RIGHT; } - if (getHeight() <= 0) { + if (height() <= 0) { code |= OUT_TOP | OUT_BOTTOM; - } else if (py < getY()) { + } else if (py < y()) { code |= OUT_TOP; - } else if (py > getMaxY()) { + } else if (py > maxY()) { code |= OUT_BOTTOM; } @@ -92,7 +91,7 @@ public abstract class AbstractRectangle extends RectangularShape implements IRec @Override // from interface IRectangle public int outcode (IPoint p) { - return outcode(p.getX(), p.getY()); + return outcode(p.x(), p.y()); } @Override // from interface IRectangle @@ -104,19 +103,19 @@ public abstract class AbstractRectangle extends RectangularShape implements IRec public boolean contains (double px, double py) { if (isEmpty()) return false; - double x = getX(), y = getY(); + double x = x(), y = y(); if (px < x || py < y) return false; px -= x; py -= y; - return px < getWidth() && py < getHeight(); + return px < width() && py < height(); } @Override // from interface IShape public boolean contains (double rx, double ry, double rw, double rh) { if (isEmpty()) return false; - double x1 = getX(), y1 = getY(), x2 = x1 + getWidth(), y2 = y1 + getHeight(); + double x1 = x(), y1 = y(), x2 = x1 + width(), y2 = y1 + height(); return (x1 <= rx) && (rx + rw <= x2) && (y1 <= ry) && (ry + rh <= y2); } @@ -124,17 +123,17 @@ public abstract class AbstractRectangle extends RectangularShape implements IRec public boolean intersects (double rx, double ry, double rw, double rh) { if (isEmpty()) return false; - double x1 = getX(), y1 = getY(), x2 = x1 + getWidth(), y2 = y1 + getHeight(); + double x1 = x(), y1 = y(), x2 = x1 + width(), y2 = y1 + height(); return (rx + rw > x1) && (rx < x2) && (ry + rh > y1) && (ry < y2); } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform t) { + public PathIterator pathIterator (Transform t) { return new Iterator(this, t); } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform t, double flatness) { + public PathIterator pathIterator (Transform t, double flatness) { return new Iterator(this, t); } @@ -145,45 +144,45 @@ public abstract class AbstractRectangle extends RectangularShape implements IRec } if (obj instanceof AbstractRectangle) { AbstractRectangle r = (AbstractRectangle)obj; - return r.getX() == getX() && r.getY() == getY() && - r.getWidth() == getWidth() && r.getHeight() == getHeight(); + return r.x() == x() && r.y() == y() && + r.width() == width() && r.height() == height(); } return false; } @Override // from Object public int hashCode () { - return Platform.hashCode(getX()) ^ Platform.hashCode(getY()) ^ - Platform.hashCode(getWidth()) ^ Platform.hashCode(getHeight()); + return Platform.hashCode(x()) ^ Platform.hashCode(y()) ^ + Platform.hashCode(width()) ^ Platform.hashCode(height()); } @Override // from Object public String toString () { - return Dimensions.dimenToString(getWidth(), getHeight()) + - Points.pointToString(getX(), getY()); + return Dimensions.dimenToString(width(), height()) + + Points.pointToString(x(), y()); } /** An iterator over an {@link IRectangle}. */ protected static class Iterator implements PathIterator { private double x, y, width, height; - private AffineTransform t; + private Transform t; /** The current segment index. */ private int index; - Iterator (IRectangle r, AffineTransform at) { - this.x = r.getX(); - this.y = r.getY(); - this.width = r.getWidth(); - this.height = r.getHeight(); + Iterator (IRectangle r, Transform at) { + this.x = r.x(); + this.y = r.y(); + this.width = r.width(); + this.height = r.height(); this.t = at; if (width < 0f || height < 0f) { index = 6; } } - @Override public int getWindingRule () { + @Override public int windingRule () { return WIND_NON_ZERO; } diff --git a/src/main/java/pythagoras/d/AbstractRoundRectangle.java b/src/main/java/pythagoras/d/AbstractRoundRectangle.java index 9bcb48c..05f7ba9 100644 --- a/src/main/java/pythagoras/d/AbstractRoundRectangle.java +++ b/src/main/java/pythagoras/d/AbstractRoundRectangle.java @@ -14,21 +14,21 @@ public abstract class AbstractRoundRectangle extends RectangularShape implements { @Override // from interface IRoundRectangle public RoundRectangle clone () { - return new RoundRectangle(getX(), getY(), getWidth(), getHeight(), - getArcWidth(), getArcHeight()); + return new RoundRectangle(x(), y(), width(), height(), + arcWidth(), arcHeight()); } @Override // from interface IShape public boolean contains (double px, double py) { if (isEmpty()) return false; - double rx1 = getX(), ry1 = getY(); - double rx2 = rx1 + getWidth(), ry2 = ry1 + getHeight(); + double rx1 = x(), ry1 = y(); + double rx2 = rx1 + width(), ry2 = ry1 + height(); if (px < rx1 || px >= rx2 || py < ry1 || py >= ry2) { return false; } - double aw = getArcWidth() / 2f, ah = getArcHeight() / 2f; + double aw = arcWidth() / 2f, ah = arcHeight() / 2f; double cx, cy; if (px < rx1 + aw) { cx = rx1 + aw; @@ -62,7 +62,7 @@ public abstract class AbstractRoundRectangle extends RectangularShape implements public boolean intersects (double rx, double ry, double rw, double rh) { if (isEmpty() || rw <= 0f || rh <= 0f) return false; - double x1 = getX(), y1 = getY(), x2 = x1 + getWidth(), y2 = y1 + getHeight(); + double x1 = x(), y1 = y(), x2 = x1 + width(), y2 = y1 + height(); double rx1 = rx, ry1 = ry, rx2 = rx + rw, ry2 = ry + rh; if (rx2 < x1 || x2 < rx1 || ry2 < y1 || y2 < ry1) { return false; @@ -75,7 +75,7 @@ public abstract class AbstractRoundRectangle extends RectangularShape implements } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform at) { + public PathIterator pathIterator (Transform at) { return new Iterator(this, at); } @@ -83,23 +83,23 @@ public abstract class AbstractRoundRectangle extends RectangularShape implements protected static class Iterator implements PathIterator { private final double x, y, width, height, aw, ah; - private final AffineTransform t; + private final Transform t; private int index; - Iterator (IRoundRectangle rr, AffineTransform at) { - this.x = rr.getX(); - this.y = rr.getY(); - this.width = rr.getWidth(); - this.height = rr.getHeight(); - this.aw = Math.min(width, rr.getArcWidth()); - this.ah = Math.min(height, rr.getArcHeight()); + Iterator (IRoundRectangle rr, Transform at) { + this.x = rr.x(); + this.y = rr.y(); + this.width = rr.width(); + this.height = rr.height(); + this.aw = Math.min(width, rr.arcWidth()); + this.ah = Math.min(height, rr.arcHeight()); this.t = at; if (width < 0f || height < 0f || aw < 0f || ah < 0f) { index = POINTS.length; } } - @Override public int getWindingRule () { + @Override public int windingRule () { return WIND_NON_ZERO; } diff --git a/src/main/java/pythagoras/d/AbstractTransform.java b/src/main/java/pythagoras/d/AbstractTransform.java new file mode 100644 index 0000000..fdb09e1 --- /dev/null +++ b/src/main/java/pythagoras/d/AbstractTransform.java @@ -0,0 +1,117 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * Implements some code shared by the various {@link Transform} implementations. + */ +public abstract class AbstractTransform implements Transform +{ + @Override // from Transform + public Vector scale () { + return new Vector(scaleX(), scaleY()); + } + + @Override // from Transform + public Vector translation () { + return new Vector(tx(), ty()); + } + + @Override // from Transform + public Transform setUniformScale (double scale) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform setScale (double scaleX, double scaleY) { + setScaleX(scaleX); + setScaleY(scaleY); + return this; + } + + @Override // from Transform + public Transform setScaleX (double scaleX) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform setScaleY (double scaleY) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform setRotation (double angle) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform setTranslation (double tx, double ty) { + setTx(tx); + setTy(ty); + return this; + } + + @Override // from Transform + public Transform uniformScale (double scale) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform scale (double scaleX, double scaleY) { + scaleX(scaleX); + scaleY(scaleY); + return this; + } + + @Override // from Transform + public Transform scaleX (double scaleX) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform scaleY (double scaleY) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform rotate (double angle) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform translate (double tx, double ty) { + translateX(tx); + translateY(ty); + return this; + } + + @Override // from Transform + public Transform translateX (double tx) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform translateY (double ty) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform setTx (double tx) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform setTy (double ty) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public Transform setTransform (double m00, double m01, double m10, double m11, double tx, double ty) { + throw new UnsupportedOperationException(); + } + + @Override // from Transform + public abstract Transform clone (); +} diff --git a/src/main/java/pythagoras/d/AbstractVector.java b/src/main/java/pythagoras/d/AbstractVector.java new file mode 100644 index 0000000..2671081 --- /dev/null +++ b/src/main/java/pythagoras/d/AbstractVector.java @@ -0,0 +1,198 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +import pythagoras.util.Platform; + +/** + * Provides most of the implementation of {@link IVector}, obtaining only x and y from the derived + * class. + */ +public abstract class AbstractVector implements IVector +{ + @Override // from interface IVector + public double dot (IVector other) { + return x()*other.x() + y()*other.y(); + } + + @Override // from interface IVector + public Vector negate () { + return negate(new Vector()); + } + + @Override // from interface IVector + public Vector negate (Vector result) { + return result.set(-x(), -y()); + } + + @Override // from interface IVector + public Vector normalize () { + return normalize(new Vector()); + } + + @Override // from interface IVector + public Vector normalize (Vector result) { + return mult(1f / length(), result); + } + + @Override // from interface IVector + public double angle (IVector other) { + double cos = dot(other) / (length() * other.length()); + return cos >= 1f ? 0f : Math.acos(cos); + } + + @Override // from interface IVector + public double direction (IVector other) { + return Math.atan2(other.y() - y(), other.x() - x()); + } + + @Override // from interface IVector + public double length () { + return Math.sqrt(lengthSq()); + } + + @Override // from interface IVector + public double lengthSq () { + double x = x(), y = y(); + return (x*x + y*y); + } + + @Override // from interface IVector + public double distance (IVector other) { + return Math.sqrt(distanceSq(other)); + } + + @Override // from interface IVector + public double distanceSq (IVector other) { + double dx = x() - other.x(), dy = y() - other.y(); + return dx*dx + dy*dy; + } + + @Override // from interface IVector + public Vector mult (double v) { + return mult(v, new Vector()); + } + + @Override // from interface IVector + public Vector mult (double v, Vector result) { + return result.set(x()*v, y()*v); + } + + @Override // from interface IVector + public Vector mult (IVector other) { + return mult(other, new Vector()); + } + + @Override // from interface IVector + public Vector mult (IVector other, Vector result) { + return result.set(x()*other.x(), y()*other.y()); + } + + @Override // from interface IVector + public Vector add (IVector other) { + return add(other, new Vector()); + } + + @Override // from interface IVector + public Vector add (IVector other, Vector result) { + return add(other.x(), other.y(), result); + } + + @Override // from interface IVector + public Vector subtract (IVector other) { + return subtract(other, new Vector()); + } + + @Override // from interface IVector + public Vector subtract (IVector other, Vector result) { + return add(-other.x(), -other.y(), result); + } + + @Override // from interface IVector + public Vector add (double x, double y) { + return add(x, y, new Vector()); + } + + @Override // from interface IVector + public Vector add (double x, double y, Vector result) { + return result.set(x() + x, y() + y); + } + + @Override // from interface IVector + public Vector addScaled (IVector other, double v) { + return addScaled(other, v, new Vector()); + } + + @Override // from interface IVector + public Vector addScaled (IVector other, double v, Vector result) { + return result.set(x() + other.x()*v, y() + other.y()*v); + } + + @Override // from interface IVector + public Vector rotate (double angle) { + return rotate(angle, new Vector()); + } + + @Override // from interface IVector + public Vector rotate (double angle, Vector result) { + double x = x(), y = y(); + double sina = Math.sin(angle), cosa = Math.cos(angle); + return result.set(x*cosa - y*sina, x*sina + y*cosa); + } + + @Override // from interface IVector + public Vector rotateAndAdd (double angle, IVector add, Vector result) { + double x = x(), y = y(); + double sina = Math.sin(angle), cosa = Math.cos(angle); + return result.set(x*cosa - y*sina + add.x(), x*sina + y*cosa + add.y()); + } + + @Override // from interface IVector + public Vector rotateScaleAndAdd (double angle, double scale, IVector add, Vector result) { + double x = x(), y = y(); + double sina = Math.sin(angle), cosa = Math.cos(angle); + return result.set((x*cosa - y*sina)*scale + add.x(), + (x*sina + y*cosa)*scale + add.y()); + } + + @Override // from interface IVector + public Vector lerp (IVector other, double t) { + return lerp(other, t, new Vector()); + } + + @Override // from interface IVector + public Vector lerp (IVector other, double t, Vector result) { + double x = x(), y = y(); + double dx = other.x() - x, dy = other.y() - y; + return result.set(x + t*dx, y + t*dy); + } + + @Override // from interface IVector + public Vector clone () { + return new Vector(this); + } + + @Override + public boolean equals (Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof AbstractVector) { + AbstractVector p = (AbstractVector)obj; + return x() == p.x() && y() == p.y(); + } + return false; + } + + @Override + public int hashCode () { + return Platform.hashCode(x()) ^ Platform.hashCode(y()); + } + + @Override + public String toString () { + return Vectors.vectorToString(x(), y()); + } +} diff --git a/src/main/java/pythagoras/d/AffineTransform.java b/src/main/java/pythagoras/d/AffineTransform.java index 4b2a25d..04d966f 100644 --- a/src/main/java/pythagoras/d/AffineTransform.java +++ b/src/main/java/pythagoras/d/AffineTransform.java @@ -4,649 +4,350 @@ package pythagoras.d; -import java.io.Serializable; - import pythagoras.util.NoninvertibleTransformException; -import pythagoras.util.Platform; /** - * Represents a 2D affine transform, which performs a linear mapping that preserves the - * straightness and parallelness of lines. - * - * See http://download.oracle.com/javase/6/docs/api/java/awt/geom/AffineTransform.html + * Implements an affine (3x2 matrix) transform. The transformation matrix has the form: + *
{@code
+ * [ m00, m10, tx ]
+ * [ m01, m11, ty ]
+ * [   0,   0,  1 ]
+ * }
*/ -public class AffineTransform implements Cloneable, Serializable +public class AffineTransform extends AbstractTransform { - public static final int TYPE_IDENTITY = 0; - public static final int TYPE_TRANSLATION = 1; - public static final int TYPE_UNIFORM_SCALE = 2; - public static final int TYPE_GENERAL_SCALE = 4; - public static final int TYPE_QUADRANT_ROTATION = 8; - public static final int TYPE_GENERAL_ROTATION = 16; - public static final int TYPE_GENERAL_TRANSFORM = 32; - public static final int TYPE_FLIP = 64; - public static final int TYPE_MASK_SCALE = TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE; - public static final int TYPE_MASK_ROTATION = TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION; + /** Identifies the affine transform in {@link #generality}. */ + public static final int GENERALITY = 4; - /** - * Returns a transform that performs the specified translation. - */ - public static AffineTransform getTranslateInstance (double tx, double ty) { - AffineTransform t = new AffineTransform(); - t.setToTranslation(tx, ty); - return t; - } + /** The scale, rotation and shear components of this transform. */ + public double m00, m01, m10, m11; - /** - * Returns a transform that performs the specified scale. - */ - public static AffineTransform getScaleInstance (double scx, double scY) { - AffineTransform t = new AffineTransform(); - t.setToScale(scx, scY); - return t; - } + /** The translation components of this transform. */ + public double tx, ty; - /** - * Returns a transform that performs the specified shear. - */ - public static AffineTransform getShearInstance (double shx, double shy) { - AffineTransform m = new AffineTransform(); - m.setToShear(shx, shy); - return m; - } - - /** - * Returns a transform that performs the specified rotation. - */ - public static AffineTransform getRotateInstance (double angle) { - AffineTransform t = new AffineTransform(); - t.setToRotation(angle); - return t; - } - - /** - * Returns a transform that performs the specified rotation. - */ - public static AffineTransform getRotateInstance (double angle, double x, double y) { - AffineTransform t = new AffineTransform(); - t.setToRotation(angle, x, y); - return t; - } - - /** - * Constructs an identity transform. - */ + /** Creates an affine transform configured with the identity transform. */ public AffineTransform () { - setToIdentity(); + this(1, 0, 0, 1, 0, 0); } - /** - * Constructs a transform that is a copy of the supplied transform. - */ - public AffineTransform (AffineTransform t) { - setTransform(t); + /** Creates an affine transform from the supplied scale, rotation and translation. */ + public AffineTransform (double scale, double angle, double tx, double ty) { + this(scale, scale, angle, tx, ty); } - /** - * Constructs a transform with the specified transformation matrix. - */ - public AffineTransform (double m00, double m10, double m01, double m11, - double m02, double m12) { - setTransform(m00, m10, m01, m11, m02, m12); + /** Creates an affine transform from the supplied scale, rotation and translation. */ + public AffineTransform (double scaleX, double scaleY, double angle, double tx, double ty) { + double sina = Math.sin(angle), cosa = Math.cos(angle); + this.m00 = cosa * scaleX; this.m01 = sina * scaleY; + this.m10 = -sina * scaleX; this.m11 = cosa * scaleY; + this.tx = tx; this.ty = ty; } - /** - * Constructs a transform with the specified transformation matrix. - * - * @param matrix either {@code [m00, m10, m01, m11]} or {@code [m00, m10, m01, m11, m02, m12]}. - */ - public AffineTransform (double[] matrix) { - this.type = TYPE_UNKNOWN; - m00 = matrix[0]; - m10 = matrix[1]; - m01 = matrix[2]; - m11 = matrix[3]; - if (matrix.length > 4) { - m02 = matrix[4]; - m12 = matrix[5]; - } + /** Creates an affine transform with the specified transform matrix. */ + public AffineTransform (double m00, double m01, double m10, double m11, double tx, double ty) { + this.m00 = m00; this.m01 = m01; + this.m10 = m10; this.m11 = m11; + this.tx = tx; this.ty = ty; } - /** - * Returns the type of this affine transform, which is a bitwise-or of the type flags - * ({@link #TYPE_TRANSLATION}, etc.). - */ - public int getType () { - if (type != TYPE_UNKNOWN) { - return type; - } - - int type = 0; - - if (m00 * m01 + m10 * m11 != 0) { - type |= TYPE_GENERAL_TRANSFORM; - return type; - } - - if (m02 != 0 || m12 != 0) { - type |= TYPE_TRANSLATION; - } else if (m00 == 1f && m11 == 1f && m01 == 0 && m10 == 0) { - type = TYPE_IDENTITY; - return type; - } - - if (m00 * m11 - m01 * m10 < 0) { - type |= TYPE_FLIP; - } - - double dx = m00 * m00 + m10 * m10; - double dy = m01 * m01 + m11 * m11; - if (dx != dy) { - type |= TYPE_GENERAL_SCALE; - } else if (dx != 1f) { - type |= TYPE_UNIFORM_SCALE; - } - - if ((m00 == 0 && m11 == 0) || (m10 == 0 && m01 == 0 && (m00 < 0 || m11 < 0))) { - type |= TYPE_QUADRANT_ROTATION; - } else if (m01 != 0 || m10 != 0) { - type |= TYPE_GENERAL_ROTATION; - } - - return type; + @Override // from Transform + public double uniformScale () { + // the square root of the signed area of the parallelogram spanned by the axis vectors + double cp = m00*m11 - m01*m10; + return (cp < 0f) ? -Math.sqrt(-cp) : Math.sqrt(cp); } - /** - * Returns the x-component of the scale vector. - */ - public double getScaleX () { - return m00; + @Override // from Transform + public double scaleX () { + return Math.sqrt(m00*m00 + m01*m01); } - /** - * Returns the y-component of the scale vector. - */ - public double getScaleY () { - return m11; + @Override // from Transform + public double scaleY () { + return Math.sqrt(m10*m10 + m11*m11); } - /** - * Returns the x-component of the shear vector. - */ - public double getShearX () { - return m01; - } + @Override // from Transform + public double rotation () { + // use the iterative polar decomposition algorithm described by Ken Shoemake: + // http://www.cs.wisc.edu/graphics/Courses/838-s2002/Papers/polar-decomp.pdf - /** - * Returns the y-component of the shear vector. - */ - public double getShearY () { - return m10; - } + // start with the contents of the upper 2x2 portion of the matrix + double n00 = m00, n10 = m10; + double n01 = m01, n11 = m11; + for (int ii = 0; ii < 10; ii++) { + // store the results of the previous iteration + double o00 = n00, o10 = n10; + double o01 = n01, o11 = n11; - /** - * Returns the x-component of the translation vector. - */ - public double getTranslateX () { - return m02; - } - - /** - * Returns the y-component of the translation vector. - */ - public double getTranslateY () { - return m12; - } - - /** - * Returns true if this transform is the identity. - */ - public boolean isIdentity () { - return getType() == TYPE_IDENTITY; - } - - /** - * Fills in the supplied matrix with this transform's values. - * - * @param matrix either a length-4 or length-6 array. - */ - public void getMatrix (double[] matrix) { - matrix[0] = m00; - matrix[1] = m10; - matrix[2] = m01; - matrix[3] = m11; - if (matrix.length > 4) { - matrix[4] = m02; - matrix[5] = m12; - } - } - - /** - * Returns the determinant of this - * matrix. - */ - public double getDeterminant () { - return m00 * m11 - m01 * m10; - } - - /** - * Sets this transform's values. - */ - public void setTransform (double m00, double m10, double m01, double m11, - double m02, double m12) { - this.type = TYPE_UNKNOWN; - this.m00 = m00; - this.m10 = m10; - this.m01 = m01; - this.m11 = m11; - this.m02 = m02; - this.m12 = m12; - } - - /** - * Sets this transform's values to be equal to those of the supplied transform. - */ - public void setTransform (AffineTransform t) { - setTransform(t.m00, t.m10, t.m01, t.m11, t.m02, t.m12); - type = t.type; - } - - /** - * Sets this transform to the identity transform. Any existing transform values are - * overwritten. - */ - public void setToIdentity () { - type = TYPE_IDENTITY; - m00 = m11 = 1f; - m10 = m01 = m02 = m12 = 0; - } - - /** - * Sets this transform to a simple translation using the supplied values. Any existing - * transform values are overwritten. - */ - public void setToTranslation (double tx, double ty) { - m00 = m11 = 1f; - m01 = m10 = 0; - m02 = tx; - m12 = ty; - if (tx == 0 && ty == 0) { - type = TYPE_IDENTITY; - } else { - type = TYPE_TRANSLATION; - } - } - - /** - * Sets this transform to a simple scale using the supplied values. Any existing transform - * values are overwritten. - */ - public void setToScale (double scx, double scy) { - m00 = scx; - m11 = scy; - m10 = m01 = m02 = m12 = 0; - if (scx != 1f || scy != 1f) { - type = TYPE_UNKNOWN; - } else { - type = TYPE_IDENTITY; - } - } - - /** - * Sets this transform to a simple shear using the supplied values. Any existing transform - * values are overwritten. - */ - public void setToShear (double shx, double shy) { - m00 = m11 = 1f; - m02 = m12 = 0; - m01 = shx; - m10 = shy; - if (shx != 0 || shy != 0) { - type = TYPE_UNKNOWN; - } else { - type = TYPE_IDENTITY; - } - } - - /** - * Sets this transform to a simple rotation using the supplied values. Any existing transform - * values are overwritten. - * - * @param angle the angle of rotation (in radians). - */ - public void setToRotation (double angle) { - double sin = Math.sin(angle); - double cos = Math.cos(angle); - if (Math.abs(cos) < ZERO) { - cos = 0; - sin = sin > 0 ? 1f : -1f; - } else if (Math.abs(sin) < ZERO) { - sin = 0; - cos = cos > 0 ? 1f : -1f; - } - m00 = m11 = cos; - m01 = -sin; - m10 = sin; - m02 = m12 = 0; - type = TYPE_UNKNOWN; - } - - /** - * Sets this transform to a simple rotation using the supplied values. Any existing transform - * values are overwritten. - * - * @param angle the angle of rotation (in radians). - * @param px the x-coordinate of the point around which to rotate. - * @param py the y-coordinate of the point around which to rotate. - */ - public void setToRotation (double angle, double px, double py) { - setToRotation(angle); - m02 = px * (1f - m00) + py * m10; - m12 = py * (1f - m00) - px * m10; - type = TYPE_UNKNOWN; - } - - /** - * Concatenates the specified translation to this transform. - */ - public void translate (double tx, double ty) { - concatenate(getTranslateInstance(tx, ty)); - } - - /** - * Concatenates the specified scale to this transform. - */ - public void scale (double scx, double scy) { - concatenate(getScaleInstance(scx, scy)); - } - - /** - * Concatenates the specified shear to this transform. - */ - public void shear (double shx, double shy) { - concatenate(getShearInstance(shx, shy)); - } - - /** - * Concatenates the specified rotation to this transform. - */ - public void rotate (double angle) { - concatenate(getRotateInstance(angle)); - } - - /** - * Concatenates the specified rotation to this transform. - */ - public void rotate (double angle, double px, double py) { - concatenate(getRotateInstance(angle, px, py)); - } - - /** - * Concatenates the specified transform to this transform. - */ - public void concatenate (AffineTransform t) { - multiply(t, this, this); - } - - /** - * Pre-concatenates the specified transform to this transform. - */ - public void preConcatenate (AffineTransform t) { - multiply(this, t, this); - } - - /** - * Computes the inverse of this transform and stores it in the supplied target. - * - * @return the supplied target. - * @throws NoninvertibleTransformException if this transform cannot be inverted. - */ - public AffineTransform createInverse (AffineTransform target) - throws NoninvertibleTransformException { - double det = getDeterminant(); - if (Math.abs(det) < ZERO) { - throw new NoninvertibleTransformException("Determinant is zero"); - } - target.setTransform(m11 / det, // m00 - -m10 / det, // m10 - -m01 / det, // m01 - m00 / det, // m11 - (m01 * m12 - m11 * m02) / det, // m02 - (m10 * m02 - m00 * m12) / det); // m12 - return target; - } - - /** - * Computes and returns the inverse of this transform. - * - * @return the supplied target. - * @throws NoninvertibleTransformException if this transform cannot be inverted. - */ - public AffineTransform createInverse () throws NoninvertibleTransformException { - return createInverse(new AffineTransform()); - } - - /** - * Transforms the supplied point using this transform's matrix. - * - * @param src the point to be transformed. - * @param dst the point in which to store the transformed values, if null a new instance will - * be created. May be {@code src}. - * @return the supplied (or created) destination point. - */ - public Point transform (IPoint src, Point dst) { - if (dst == null) { - dst = new Point(); - } - - double x = src.getX(), y = src.getY(); - dst.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12); - return dst; - } - - /** - * Transforms the supplied points using this transform's matrix. - * - * @param src the points to be transformed. - * @param srcOff the offset into the {@code src} array at which to start. - * @param dst the points into which to store the transformed points. May be {@code src}. - * @param dstOff the offset into the {@code dst} array at which to start. - * @param length the number of points to transform. - */ - public void transform (IPoint[] src, int srcOff, Point[] dst, int dstOff, int length) { - while (--length >= 0) { - IPoint srcPoint = src[srcOff++]; - double x = srcPoint.getX(); - double y = srcPoint.getY(); - Point dstPoint = dst[dstOff]; - if (dstPoint == null) { - dstPoint = new Point(); + // compute average of the matrix with its inverse transpose + double det = o00*o11 - o10*o01; + if (Math.abs(det) == 0f) { + // determinant is zero; matrix is not invertible + throw new NoninvertibleTransformException(this.toString()); } - dstPoint.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12); - dst[dstOff++] = dstPoint; + double hrdet = 0.5f / det; + n00 = +o11 * hrdet + o00*0.5f; + n10 = -o01 * hrdet + o10*0.5f; + + n01 = -o10 * hrdet + o01*0.5f; + n11 = +o00 * hrdet + o11*0.5f; + + // compute the difference; if it's small enough, we're done + double d00 = n00 - o00, d10 = n10 - o10; + double d01 = n01 - o01, d11 = n11 - o11; + if (d00*d00 + d10*d10 + d01*d01 + d11*d11 < MathUtil.EPSILON) { + break; + } + } + // now that we have a nice orthogonal matrix, we can extract the rotation + return Math.atan2(n01, n00); + } + + @Override // from Transform + public double tx () { + return this.tx; + } + + @Override // from Transform + public double ty () { + return this.ty; + } + + @Override // from Transform + public Transform setUniformScale (double scale) { + return setScale(scale, scale); + } + + @Override // from Transform + public Transform setScaleX (double scaleX) { + // normalize the scale to 1, then re-apply + double osx = scaleX(); + m00 /= osx; m01 /= osx; + m00 *= scaleX; m01 *= scaleX; + return this; + } + + @Override // from Transform + public Transform setScaleY (double scaleY) { + // normalize the scale to 1, then re-apply + double osy = scaleY(); + m10 /= osy; m11 /= osy; + m10 *= scaleY; m11 *= scaleY; + return this; + } + + @Override // from Transform + public Transform setRotation (double angle) { + // extract the scale, then reapply rotation and scale together + double sx = scaleX(), sy = scaleY(); + double sina = Math.sin(angle), cosa = Math.cos(angle); + m00 = cosa * sx; m01 = sina * sx; + m10 = -sina * sy; m11 = cosa * sy; + return this; + } + + @Override // from Transform + public Transform setTranslation (double tx, double ty) { + this.tx = tx; + this.ty = ty; + return this; + } + + @Override // from Transform + public Transform setTx (double tx) { + this.tx = tx; + return this; + } + + @Override // from Transform + public Transform setTy (double ty) { + this.ty = ty; + return this; + } + + @Override // from Transform + public Transform setTransform (double m00, double m01, double m10, double m11, double tx, double ty) { + this.m00 = m00; + this.m01 = m01; + this.m10 = m10; + this.m11 = m11; + this.tx = tx; + this.ty = ty; + return this; + } + + @Override // from Transform + public Transform uniformScale (double scale) { + return scale(scale, scale); + } + + @Override // from Transform + public Transform scaleX (double scaleX) { + m00 *= scaleX; + m01 *= scaleX; + tx *= scaleX; + return this; + } + + @Override // from Transform + public Transform scaleY (double scaleY) { + m10 *= scaleY; + m11 *= scaleY; + ty *= scaleY; + return this; + } + + @Override // from Transform + public Transform rotate (double angle) { + double sina = Math.sin(angle), cosa = Math.cos(angle); + return Transforms.multiply(cosa, sina, -sina, cosa, 0, 0, this, this); + } + + @Override // from Transform + public Transform translate (double tx, double ty) { + return Transforms.multiply(this, 1, 0, 0, 1, tx, ty, this); + } + + @Override // from Transform + public Transform translateX (double tx) { + return Transforms.multiply(this, 1, 0, 0, 1, tx, 0, this); + } + + @Override // from Transform + public Transform translateY (double ty) { + return Transforms.multiply(this, 1, 0, 0, 1, 0, ty, this); + } + + @Override // from Transform + public Transform invert () { + // compute the determinant, storing the subdeterminants for later use + double det = m00*m11 - m10*m01; + if (Math.abs(det) == 0f) { + // determinant is zero; matrix is not invertible + throw new NoninvertibleTransformException(this.toString()); + } + double rdet = 1f / det; + return new AffineTransform( + +m11 * rdet, -m10 * rdet, + -m01 * rdet, +m00 * rdet, + (m10*ty - m11*tx) * rdet, (m01*tx - m00*ty) * rdet); + } + + @Override // from Transform + public Transform concatenate (Transform other) { + if (generality() < other.generality()) { + return other.preConcatenate(this); + } + if (other instanceof AffineTransform) { + return Transforms.multiply(this, (AffineTransform)other, new AffineTransform()); + } else { + AffineTransform oaff = new AffineTransform(other); + return Transforms.multiply(this, oaff, oaff); } } - /** - * Transforms the supplied points using this transform's matrix. - * - * @param src the points to be transformed (as {@code [x, y, x, y, ...]}). - * @param srcOff the offset into the {@code src} array at which to start. - * @param dst the points into which to store the transformed points. May be {@code src}. - * @param dstOff the offset into the {@code dst} array at which to start. - * @param length the number of points to transform. - */ - public void transform (double[] src, int srcOff, double[] dst, int dstOff, int length) { - int step = 2; - if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) { - srcOff = srcOff + length * 2 - 2; - dstOff = dstOff + length * 2 - 2; - step = -2; + @Override // from Transform + public Transform preConcatenate (Transform other) { + if (generality() < other.generality()) { + return other.concatenate(this); } - while (--length >= 0) { - double x = src[srcOff + 0]; - double y = src[srcOff + 1]; - dst[dstOff + 0] = (x * m00 + y * m01 + m02); - dst[dstOff + 1] = (x * m10 + y * m11 + m12); - srcOff += step; - dstOff += step; + if (other instanceof AffineTransform) { + return Transforms.multiply((AffineTransform)other, this, new AffineTransform()); + } else { + AffineTransform oaff = new AffineTransform(other); + return Transforms.multiply(oaff, this, oaff); } } - /** - * Transforms the supplied relative distance vector (ignores the translation component). - * - * @param src the point to be transformed. - * @param dst the point in which to store the transformed values, if null a new instance will - * be created. May be {@code src}. - * @return the supplied (or created) destination point. - */ - public Point deltaTransform (IPoint src, Point dst) { - if (dst == null) { - dst = new Point(); + @Override // from Transform + public Transform lerp (Transform other, double t) { + if (generality() < other.generality()) { + return other.lerp(this, -t); // TODO: is this correct? } - double x = src.getX(), y = src.getY(); - dst.setLocation(x * m00 + y * m01, x * m10 + y * m11); - return dst; + + AffineTransform ot = (other instanceof AffineTransform) ? + (AffineTransform)other : new AffineTransform(other); + return new AffineTransform( + m00 + t*(ot.m00 - m00), m01 + t*(ot.m01 - m01), + m10 + t*(ot.m10 - m10), m11 + t*(ot.m11 - m11), + tx + t*(ot.tx - tx ), ty + t*(ot.ty - ty )); } - /** - * Transforms the supplied relative distance vectors using this transform's matrix (ignores the - * translation component). - * - * @param src the points to be transformed (as {@code [x, y, x, y, ...]}). - * @param srcOff the offset into the {@code src} array at which to start. - * @param dst the points into which to store the transformed points. May be {@code src}. - * @param dstOff the offset into the {@code dst} array at which to start. - * @param length the number of points to transform. - */ - public void deltaTransform (double[] src, int srcOff, double[] dst, int dstOff, int length) { - while (--length >= 0) { + @Override // from Transform + public Point transform (IPoint p, Point into) { + double x = p.x(), y = p.y(); + return into.set(m00*x + m10*y + tx, m01*x + m11*y + ty); + } + + @Override // from Transform + public void transform (IPoint[] src, int srcOff, Point[] dst, int dstOff, int count) { + for (int ii = 0; ii < count; ii++) { + transform(src[srcOff++], dst[dstOff++]); + } + } + + @Override // from Transform + public void transform (double[] src, int srcOff, double[] dst, int dstOff, int count) { + for (int ii = 0; ii < count; ii++) { double x = src[srcOff++], y = src[srcOff++]; - dst[dstOff++] = x * m00 + y * m01; - dst[dstOff++] = x * m10 + y * m11; + dst[dstOff++] = m00*x + m10*y + tx; + dst[dstOff++] = m01*x + m11*y + ty; } } - /** - * Transforms the supplied point using the inverse of this transform's matrix. - * - * @param src the point to be transformed. - * @param dst the point in which to store the transformed values, if null a new instance will - * be created. May be {@code src}. - * @return the supplied (or created) destination point. - */ - public Point inverseTransform (IPoint src, Point dst) throws NoninvertibleTransformException { - double det = getDeterminant(); - if (Math.abs(det) < ZERO) { - throw new NoninvertibleTransformException("Determinant is zero"); + @Override // from Transform + public Point inverseTransform (IPoint p, Point into) { + double x = p.x() - tx, y = p.y() - ty; + double det = m00 * m11 - m01 * m10; + if (Math.abs(det) == 0f) { + // determinant is zero; matrix is not invertible + throw new NoninvertibleTransformException(this.toString()); } - if (dst == null) { - dst = new Point(); - } - double x = src.getX() - m02, y = src.getY() - m12; - dst.setLocation((x * m11 - y * m01) / det, (y * m00 - x * m10) / det); - return dst; + double rdet = 1 / det; + return into.set((x * m11 - y * m10) * rdet, + (y * m00 - x * m01) * rdet); } - /** - * Transforms the supplied points using the inverse of this transform's matrix. - * - * @param src the points to be transformed (as {@code [x, y, x, y, ...]}). - * @param srcOff the offset into the {@code src} array at which to start. - * @param dst the points into which to store the transformed points. May be {@code src}. - * @param dstOff the offset into the {@code dst} array at which to start. - * @param length the number of points to transform. - */ - public void inverseTransform (double[] src, int srcOff, double[] dst, int dstOff, int length) - throws NoninvertibleTransformException { - double det = getDeterminant(); - if (Math.abs(det) < ZERO) { - throw new NoninvertibleTransformException("Determinant is zero"); - } - while (--length >= 0) { - double x = src[srcOff++] - m02, y = src[srcOff++] - m12; - dst[dstOff++] = (x * m11 - y * m01) / det; - dst[dstOff++] = (y * m00 - x * m10) / det; - } + @Override // from Transform + public Vector transform (IVector v, Vector into) { + double x = v.x(), y = v.y(); + return into.set(m00*x + m10*y, m01*x + m11*y); } - /** - * Creates and returns a new shape that is the supplied shape transformed by this transform's - * matrix. - */ - public IShape createTransformedShape (IShape src) { - if (src == null) { - return null; + @Override // from Transform + public Vector inverseTransform (IVector v, Vector into) { + double x = v.x(), y = v.y(); + double det = m00 * m11 - m01 * m10; + if (Math.abs(det) == 0f) { + // determinant is zero; matrix is not invertible + throw new NoninvertibleTransformException(this.toString()); } - if (src instanceof Path) { - return ((Path)src).createTransformedShape(this); - } - PathIterator path = src.getPathIterator(this); - Path dst = new Path(path.getWindingRule()); - dst.append(path, false); - return dst; + double rdet = 1 / det; + return into.set((x * m11 - y * m10) * rdet, + (y * m00 - x * m01) * rdet); + } + + @Override // from Transform + public Transform clone () { + return new AffineTransform(m00, m01, m10, m11, tx, ty); + } + + @Override // from Transform + public int generality () { + return GENERALITY; } @Override public String toString () { - return getClass().getName() + - "[[" + m00 + ", " + m01 + ", " + m02 + "], [" + m10 + ", " + m11 + ", " + m12 + "]]"; + return "affine [" + MathUtil.toString(m00) + " " + MathUtil.toString(m01) + " " + + MathUtil.toString(m10) + " " + MathUtil.toString(m11) + " " + translation() + "]"; } - // @Override // can't declare @Override due to GWT - public AffineTransform clone () { - return new AffineTransform(this); + // we don't publicize this because it might encourage someone to do something stupid like + // create a new AffineTransform from another AffineTransform using this instead of clone() + protected AffineTransform (Transform other) { + this(other.scaleX(), other.scaleY(), other.rotation(), + other.tx(), other.ty()); } - - @Override - public int hashCode () { - return Platform.hashCode(m00) ^ Platform.hashCode(m01) ^ Platform.hashCode(m02) ^ - Platform.hashCode(m10) ^ Platform.hashCode(m11) ^ Platform.hashCode(m12); - } - - @Override - public boolean equals (Object obj) { - if (obj == this) { - return true; - } - if (obj instanceof AffineTransform) { - AffineTransform t = (AffineTransform)obj; - return m00 == t.m00 && m01 == t.m01 && m02 == t.m02 && - m10 == t.m10 && m11 == t.m11 && m12 == t.m12; - } - return false; - } - - /** - * Multiplies two transforms, storing the result in the target transform. - * @return the supplied target transform. - */ - protected static AffineTransform multiply (AffineTransform t1, AffineTransform t2, - AffineTransform into) { - into.setTransform(t1.m00 * t2.m00 + t1.m10 * t2.m01, // m00 - t1.m00 * t2.m10 + t1.m10 * t2.m11, // m01 - t1.m01 * t2.m00 + t1.m11 * t2.m01, // m10 - t1.m01 * t2.m10 + t1.m11 * t2.m11, // m11 - t1.m02 * t2.m00 + t1.m12 * t2.m01 + t2.m02, // m02 - t1.m02 * t2.m10 + t1.m12 * t2.m11 + t2.m12); // m12 - return into; - } - - // the values of transformation matrix - private double m00; - private double m10; - private double m01; - private double m11; - private double m02; - private double m12; - - /** The transformation {@code type}. */ - private transient int type; - - /** An initial type value. */ - private static final int TYPE_UNKNOWN = -1; - - /** The min value equivalent to zero. An absolute value < ZERO is considered to be zero. */ - private static final double ZERO = 1E-10f; } diff --git a/src/main/java/pythagoras/d/Arc.java b/src/main/java/pythagoras/d/Arc.java index 1c55adf..115bbda 100644 --- a/src/main/java/pythagoras/d/Arc.java +++ b/src/main/java/pythagoras/d/Arc.java @@ -47,8 +47,7 @@ public class Arc extends AbstractArc implements Serializable * Creates an arc of the specified type with the specified framing rectangle, starting angle * and angular extent. */ - public Arc (double x, double y, double width, double height, - double start, double extent, int type) { + public Arc (double x, double y, double width, double height, double start, double extent, int type) { setArc(x, y, width, height, start, extent, type); } @@ -57,42 +56,42 @@ public class Arc extends AbstractArc implements Serializable * angular extent. */ public Arc (IRectangle bounds, double start, double extent, int type) { - setArc(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), + setArc(bounds.x(), bounds.y(), bounds.width(), bounds.height(), start, extent, type); } @Override // from interface IArc - public int getArcType () { + public int arcType () { return type; } @Override // from interface IArc - public double getX () { + public double x () { return x; } @Override // from interface IArc - public double getY () { + public double y () { return y; } @Override // from interface IArc - public double getWidth () { + public double width () { return width; } @Override // from interface IArc - public double getHeight () { + public double height () { return height; } @Override // from interface IArc - public double getAngleStart () { + public double angleStart () { return start; } @Override // from interface IArc - public double getAngleExtent () { + public double angleExtent () { return extent; } @@ -140,7 +139,7 @@ public class Arc extends AbstractArc implements Serializable * values. */ public void setArc (IPoint point, IDimension size, double start, double extent, int type) { - setArc(point.getX(), point.getY(), size.getWidth(), size.getHeight(), start, extent, type); + setArc(point.x(), point.y(), size.width(), size.height(), start, extent, type); } /** @@ -148,7 +147,7 @@ public class Arc extends AbstractArc implements Serializable * values. */ public void setArc (IRectangle rect, double start, double extent, int type) { - setArc(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), start, extent, type); + setArc(rect.x(), rect.y(), rect.width(), rect.height(), start, extent, type); } /** @@ -156,8 +155,8 @@ public class Arc extends AbstractArc implements Serializable * the supplied arc. */ public void setArc (IArc arc) { - setArc(arc.getX(), arc.getY(), arc.getWidth(), arc.getHeight(), arc.getAngleStart(), - arc.getAngleExtent(), arc.getArcType()); + setArc(arc.x(), arc.y(), arc.width(), arc.height(), arc.angleStart(), + arc.angleExtent(), arc.arcType()); } /** @@ -175,16 +174,16 @@ public class Arc extends AbstractArc implements Serializable */ public void setArcByTangent (IPoint p1, IPoint p2, IPoint p3, double radius) { // use simple geometric calculations of arc center, radius and angles by tangents - double a1 = -Math.atan2(p1.getY() - p2.getY(), p1.getX() - p2.getX()); - double a2 = -Math.atan2(p3.getY() - p2.getY(), p3.getX() - p2.getX()); + double a1 = -Math.atan2(p1.y() - p2.y(), p1.x() - p2.x()); + double a2 = -Math.atan2(p3.y() - p2.y(), p3.x() - p2.x()); double am = (a1 + a2) / 2f; double ah = a1 - am; double d = radius / Math.abs(Math.sin(ah)); - double x = p2.getX() + d * Math.cos(am); - double y = p2.getY() - d * Math.sin(am); + double x = p2.x() + d * Math.cos(am); + double y = p2.y() - d * Math.sin(am); ah = ah >= 0f ? Math.PI * 1.5f - ah : Math.PI * 0.5f - ah; - a1 = getNormAngle(Math.toDegrees(am - ah)); - a2 = getNormAngle(Math.toDegrees(am + ah)); + a1 = normAngle(Math.toDegrees(am - ah)); + a2 = normAngle(Math.toDegrees(am + ah)); double delta = a2 - a1; if (delta <= 0f) { delta += 360f; @@ -197,8 +196,8 @@ public class Arc extends AbstractArc implements Serializable * the center of this arc. */ public void setAngleStart (IPoint point) { - double angle = Math.atan2(point.getY() - getCenterY(), point.getX() - getCenterX()); - setAngleStart(getNormAngle(-Math.toDegrees(angle))); + double angle = Math.atan2(point.y() - centerY(), point.x() - centerX()); + setAngleStart(normAngle(-Math.toDegrees(angle))); } /** @@ -209,10 +208,10 @@ public class Arc extends AbstractArc implements Serializable * counterclockwise from the first point around to the second point. */ public void setAngles (double x1, double y1, double x2, double y2) { - double cx = getCenterX(); - double cy = getCenterY(); - double a1 = getNormAngle(-Math.toDegrees(Math.atan2(y1 - cy, x1 - cx))); - double a2 = getNormAngle(-Math.toDegrees(Math.atan2(y2 - cy, x2 - cx))); + double cx = centerX(); + double cy = centerY(); + double a1 = normAngle(-Math.toDegrees(Math.atan2(y1 - cy, x1 - cx))); + double a2 = normAngle(-Math.toDegrees(Math.atan2(y2 - cy, x2 - cx))); a2 -= a1; if (a2 <= 0f) { a2 += 360f; @@ -229,12 +228,12 @@ public class Arc extends AbstractArc implements Serializable * counterclockwise from the first point around to the second point. */ public void setAngles (IPoint p1, IPoint p2) { - setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + setAngles(p1.x(), p1.y(), p2.x(), p2.y()); } @Override // from RectangularShape public void setFrame (double x, double y, double width, double height) { - setArc(x, y, width, height, getAngleStart(), getAngleExtent(), type); + setArc(x, y, width, height, angleStart(), angleExtent(), type); } private int type; diff --git a/src/main/java/pythagoras/d/Area.java b/src/main/java/pythagoras/d/Area.java index 3ad915a..b1983d1 100644 --- a/src/main/java/pythagoras/d/Area.java +++ b/src/main/java/pythagoras/d/Area.java @@ -30,7 +30,7 @@ public class Area implements IShape, Cloneable int rulesIndex = 0; int coordsIndex = 0; - for (PathIterator pi = s.getPathIterator(null); !pi.isDone(); pi.next()) { + for (PathIterator pi = s.pathIterator(null); !pi.isDone(); pi.next()) { coords = adjustSize(coords, coordsIndex + 6); rules = adjustSize(rules, rulesIndex + 1); offsets = adjustSize(offsets, rulesIndex + 1); @@ -112,15 +112,15 @@ public class Area implements IShape, Cloneable /** * Transforms this area with the supplied transform. */ - public void transform (AffineTransform t) { - copy(new Area(t.createTransformedShape(this)), this); + public void transform (Transform t) { + copy(new Area(Transforms.createTransformedShape(t, this)), this); } /** * Creates a new area equal to this area transformed by the supplied transform. */ - public Area createTransformedArea (AffineTransform t) { - return new Area(t.createTransformedShape(this)); + public Area createTransformedArea (Transform t) { + return new Area(Transforms.createTransformedShape(t, this)); } /** @@ -140,7 +140,7 @@ public class Area implements IShape, Cloneable addCurvePolygon(area); } - if (getAreaBoundsSquare() < GeometryUtil.EPSILON) { + if (areaBoundsSquare() < GeometryUtil.EPSILON) { reset(); } } @@ -162,7 +162,7 @@ public class Area implements IShape, Cloneable intersectCurvePolygon(area); } - if (getAreaBoundsSquare() < GeometryUtil.EPSILON) { + if (areaBoundsSquare() < GeometryUtil.EPSILON) { reset(); } } @@ -181,7 +181,7 @@ public class Area implements IShape, Cloneable subtractCurvePolygon(area); } - if (getAreaBoundsSquare() < GeometryUtil.EPSILON) { + if (areaBoundsSquare() < GeometryUtil.EPSILON) { reset(); } } @@ -209,25 +209,25 @@ public class Area implements IShape, Cloneable @Override // from interface IShape public boolean contains (double x, double y, double width, double height) { - int crossCount = Crossing.intersectPath(getPathIterator(null), x, y, width, height); + int crossCount = Crossing.intersectPath(pathIterator(null), x, y, width, height); return crossCount != Crossing.CROSSING && Crossing.isInsideEvenOdd(crossCount); } @Override // from interface IShape public boolean contains (IPoint p) { - return contains(p.getX(), p.getY()); + return contains(p.x(), p.y()); } @Override // from interface IShape public boolean contains (IRectangle r) { - return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + return contains(r.x(), r.y(), r.width(), r.height()); } @Override // from interface IShape public boolean intersects (double x, double y, double width, double height) { if ((width <= 0f) || (height <= 0f)) { return false; - } else if (!getBounds().intersects(x, y, width, height)) { + } else if (!bounds().intersects(x, y, width, height)) { return false; } int crossCount = Crossing.intersectShape(this, x, y, width, height); @@ -236,16 +236,16 @@ public class Area implements IShape, Cloneable @Override // from interface IShape public boolean intersects (IRectangle r) { - return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + return intersects(r.x(), r.y(), r.width(), r.height()); } @Override // from interface IShape - public Rectangle getBounds () { - return getBounds(new Rectangle()); + public Rectangle bounds () { + return bounds(new Rectangle()); } @Override // from interface IShape - public Rectangle getBounds (Rectangle target) { + public Rectangle bounds (Rectangle target) { double maxX = coords[0], maxY = coords[1]; double minX = coords[0], minY = coords[1]; for (int i = 0; i < coordsSize;) { @@ -258,13 +258,13 @@ public class Area implements IShape, Cloneable } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform t) { + public PathIterator pathIterator (Transform t) { return new AreaPathIterator(t); } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform t, double flatness) { - return new FlatteningPathIterator(getPathIterator(t), flatness); + public PathIterator pathIterator (Transform t, double flatness) { + return new FlatteningPathIterator(pathIterator(t), flatness); } @Override // from Object @@ -296,9 +296,9 @@ public class Area implements IShape, Cloneable IntersectPoint[] intersectPoints = crossHelper.findCrossing(); if (intersectPoints.length == 0) { - if (area.contains(getBounds())) { + if (area.contains(bounds())) { copy(area, this); - } else if (!contains(area.getBounds())) { + } else if (!contains(area.bounds())) { coords = adjustSize(coords, coordsSize + area.coordsSize); System.arraycopy(area.coords, 0, coords, coordsSize, area.coordsSize); coordsSize += area.coordsSize; @@ -324,9 +324,9 @@ public class Area implements IShape, Cloneable resultOffsets[resultRulesPos++] = resultCoordPos; do { - resultCoords[resultCoordPos++] = point.getX(); - resultCoords[resultCoordPos++] = point.getY(); - int curIndex = point.getEndIndex(true); + resultCoords[resultCoordPos++] = point.x(); + resultCoords[resultCoordPos++] = point.y(); + int curIndex = point.endIndex(true); if (curIndex < 0) { isCurrentArea = !isCurrentArea; } else if (area.containsExact(coords[2 * curIndex], coords[2 * curIndex + 1]) > 0) { @@ -335,13 +335,13 @@ public class Area implements IShape, Cloneable isCurrentArea = true; } - IntersectPoint nextPoint = getNextIntersectPoint(intersectPoints, point, isCurrentArea); + IntersectPoint nextPoint = nextIntersectPoint(intersectPoints, point, isCurrentArea); double[] coords = (isCurrentArea) ? this.coords : area.coords; int[] offsets = (isCurrentArea) ? this.offsets : area.offsets; int[] rules = (isCurrentArea) ? this.rules : area.rules; - int offset = point.getRuleIndex(isCurrentArea); + int offset = point.ruleIndex(isCurrentArea); boolean isCopyUntilZero = false; - if ((point.getRuleIndex(isCurrentArea) > nextPoint.getRuleIndex(isCurrentArea))) { + if ((point.ruleIndex(isCurrentArea) > nextPoint.ruleIndex(isCurrentArea))) { int rulesSize = (isCurrentArea) ? this.rulesSize : area.rulesSize; resultCoordPos = includeCoordsAndRules(offset + 1, rulesSize, rules, offsets, resultRules, resultOffsets, resultCoords, coords, resultRulesPos, @@ -351,7 +351,7 @@ public class Area implements IShape, Cloneable isCopyUntilZero = true; } - int length = nextPoint.getRuleIndex(isCurrentArea) - offset + 1; + int length = nextPoint.ruleIndex(isCurrentArea) - offset + 1; if (isCopyUntilZero) { offset = 0; } @@ -379,9 +379,9 @@ public class Area implements IShape, Cloneable IntersectPoint[] intersectPoints = crossHelper.findCrossing(); if (intersectPoints.length == 0) { - if (area.contains(getBounds())) { + if (area.contains(bounds())) { copy(area, this); - } else if (!contains(area.getBounds())) { + } else if (!contains(area.bounds())) { coords = adjustSize(coords, coordsSize + area.coordsSize); System.arraycopy(area.coords, 0, coords, coordsSize, area.coordsSize); coordsSize += area.coordsSize; @@ -406,11 +406,11 @@ public class Area implements IShape, Cloneable resultOffsets[resultRulesPos++] = resultCoordPos; do { - resultCoords[resultCoordPos++] = point.getX(); - resultCoords[resultCoordPos++] = point.getY(); + resultCoords[resultCoordPos++] = point.x(); + resultCoords[resultCoordPos++] = point.y(); resultRules[resultRulesPos] = PathIterator.SEG_LINETO; resultOffsets[resultRulesPos++] = resultCoordPos - 2; - int curIndex = point.getEndIndex(true); + int curIndex = point.endIndex(true); if (curIndex < 0) { isCurrentArea = !isCurrentArea; } else if (area.containsExact(coords[2 * curIndex], coords[2 * curIndex + 1]) > 0) { @@ -419,11 +419,11 @@ public class Area implements IShape, Cloneable isCurrentArea = true; } - IntersectPoint nextPoint = getNextIntersectPoint(intersectPoints, point, isCurrentArea); + IntersectPoint nextPoint = nextIntersectPoint(intersectPoints, point, isCurrentArea); double[] coords = (isCurrentArea) ? this.coords : area.coords; - int offset = 2 * point.getEndIndex(isCurrentArea); + int offset = 2 * point.endIndex(isCurrentArea); if ((offset >= 0) && - (nextPoint.getBegIndex(isCurrentArea) < point.getEndIndex(isCurrentArea))) { + (nextPoint.begIndex(isCurrentArea) < point.endIndex(isCurrentArea))) { int coordSize = (isCurrentArea) ? this.coordsSize : area.coordsSize; int length = coordSize - offset; System.arraycopy(coords, offset, resultCoords, resultCoordPos, length); @@ -438,7 +438,7 @@ public class Area implements IShape, Cloneable } if (offset >= 0) { - int length = 2 * nextPoint.getBegIndex(isCurrentArea) - offset + 2; + int length = 2 * nextPoint.begIndex(isCurrentArea) - offset + 2; System.arraycopy(coords, offset, resultCoords, resultCoordPos, length); for (int i = 0; i < length / 2; i++) { @@ -469,9 +469,9 @@ public class Area implements IShape, Cloneable new int[][] { offsets, area.offsets }); IntersectPoint[] intersectPoints = crossHelper.findCrossing(); if (intersectPoints.length == 0) { - if (contains(area.getBounds())) { + if (contains(area.bounds())) { copy(area, this); - } else if (!area.contains(getBounds())) { + } else if (!area.contains(bounds())) { reset(); } return; @@ -490,10 +490,10 @@ public class Area implements IShape, Cloneable resultOffsets[resultRulesPos++] = resultCoordPos; do { - resultCoords[resultCoordPos++] = point.getX(); - resultCoords[resultCoordPos++] = point.getY(); + resultCoords[resultCoordPos++] = point.x(); + resultCoords[resultCoordPos++] = point.y(); - int curIndex = point.getEndIndex(true); + int curIndex = point.endIndex(true); if ((curIndex < 0) || (area.containsExact(coords[2 * curIndex], coords[2 * curIndex + 1]) == 0)) { isCurrentArea = !isCurrentArea; @@ -503,14 +503,14 @@ public class Area implements IShape, Cloneable isCurrentArea = false; } - nextPoint = getNextIntersectPoint(intersectPoints, point, isCurrentArea); + nextPoint = nextIntersectPoint(intersectPoints, point, isCurrentArea); double[] coords = (isCurrentArea) ? this.coords : area.coords; int[] offsets = (isCurrentArea) ? this.offsets : area.offsets; int[] rules = (isCurrentArea) ? this.rules : area.rules; - int offset = point.getRuleIndex(isCurrentArea); + int offset = point.ruleIndex(isCurrentArea); boolean isCopyUntilZero = false; - if (point.getRuleIndex(isCurrentArea) > nextPoint.getRuleIndex(isCurrentArea)) { + if (point.ruleIndex(isCurrentArea) > nextPoint.ruleIndex(isCurrentArea)) { int rulesSize = (isCurrentArea) ? this.rulesSize : area.rulesSize; resultCoordPos = includeCoordsAndRules( offset + 1, rulesSize, rules, offsets, resultRules, resultOffsets, @@ -521,17 +521,17 @@ public class Area implements IShape, Cloneable isCopyUntilZero = true; } - int length = nextPoint.getRuleIndex(isCurrentArea) - offset + 1; + int length = nextPoint.ruleIndex(isCurrentArea) - offset + 1; if (isCopyUntilZero) { offset = 0; isCopyUntilZero = false; } if ((length == offset) && - (nextPoint.getRule(isCurrentArea) != PathIterator.SEG_LINETO) && - (nextPoint.getRule(isCurrentArea) != PathIterator.SEG_CLOSE) && - (point.getRule(isCurrentArea) != PathIterator.SEG_LINETO) && - (point.getRule(isCurrentArea) != PathIterator.SEG_CLOSE)) { + (nextPoint.rule(isCurrentArea) != PathIterator.SEG_LINETO) && + (nextPoint.rule(isCurrentArea) != PathIterator.SEG_CLOSE) && + (point.rule(isCurrentArea) != PathIterator.SEG_LINETO) && + (point.rule(isCurrentArea) != PathIterator.SEG_CLOSE)) { isCopyUntilZero = true; length++; } @@ -548,8 +548,8 @@ public class Area implements IShape, Cloneable if (resultRules[resultRulesPos - 1] == PathIterator.SEG_LINETO) { resultRules[resultRulesPos - 1] = PathIterator.SEG_CLOSE; } else { - resultCoords[resultCoordPos++] = nextPoint.getX(); - resultCoords[resultCoordPos++] = nextPoint.getY(); + resultCoords[resultCoordPos++] = nextPoint.x(); + resultCoords[resultCoordPos++] = nextPoint.y(); resultRules[resultRulesPos++] = PathIterator.SEG_CLOSE; } @@ -567,9 +567,9 @@ public class Area implements IShape, Cloneable new int[] { coordsSize, area.coordsSize }); IntersectPoint[] intersectPoints = crossHelper.findCrossing(); if (intersectPoints.length == 0) { - if (contains(area.getBounds())) { + if (contains(area.bounds())) { copy(area, this); - } else if (!area.contains(getBounds())) { + } else if (!area.contains(bounds())) { reset(); } return; @@ -587,11 +587,11 @@ public class Area implements IShape, Cloneable resultOffsets[resultRulesPos++] = resultCoordPos; do { - resultCoords[resultCoordPos++] = point.getX(); - resultCoords[resultCoordPos++] = point.getY(); + resultCoords[resultCoordPos++] = point.x(); + resultCoords[resultCoordPos++] = point.y(); resultRules[resultRulesPos] = PathIterator.SEG_LINETO; resultOffsets[resultRulesPos++] = resultCoordPos - 2; - int curIndex = point.getEndIndex(true); + int curIndex = point.endIndex(true); if ((curIndex < 0) || (area.containsExact(coords[2 * curIndex], coords[2 * curIndex + 1]) == 0)) { @@ -602,11 +602,11 @@ public class Area implements IShape, Cloneable isCurrentArea = false; } - IntersectPoint nextPoint = getNextIntersectPoint(intersectPoints, point, isCurrentArea); + IntersectPoint nextPoint = nextIntersectPoint(intersectPoints, point, isCurrentArea); double[] coords = (isCurrentArea) ? this.coords : area.coords; - int offset = 2 * point.getEndIndex(isCurrentArea); + int offset = 2 * point.endIndex(isCurrentArea); if ((offset >= 0) && - (nextPoint.getBegIndex(isCurrentArea) < point.getEndIndex(isCurrentArea))) { + (nextPoint.begIndex(isCurrentArea) < point.endIndex(isCurrentArea))) { int coordSize = (isCurrentArea) ? this.coordsSize : area.coordsSize; int length = coordSize - offset; System.arraycopy(coords, offset, resultCoords, resultCoordPos, length); @@ -621,7 +621,7 @@ public class Area implements IShape, Cloneable } if (offset >= 0) { - int length = 2 * nextPoint.getBegIndex(isCurrentArea) - offset + 2; + int length = 2 * nextPoint.begIndex(isCurrentArea) - offset + 2; System.arraycopy(coords, offset, resultCoords, resultCoordPos, length); for (int i = 0; i < length / 2; i++) { @@ -651,7 +651,7 @@ public class Area implements IShape, Cloneable new int[] { rulesSize, area.rulesSize }, new int[][] { offsets, area.offsets }); IntersectPoint[] intersectPoints = crossHelper.findCrossing(); - if (intersectPoints.length == 0 && contains(area.getBounds())) { + if (intersectPoints.length == 0 && contains(area.bounds())) { copy(area, this); return; } @@ -668,9 +668,9 @@ public class Area implements IShape, Cloneable resultOffsets[resultRulesPos++] = resultCoordPos; do { - resultCoords[resultCoordPos++] = point.getX(); - resultCoords[resultCoordPos++] = point.getY(); - int curIndex = offsets[point.getRuleIndex(true)] % coordsSize; + resultCoords[resultCoordPos++] = point.x(); + resultCoords[resultCoordPos++] = point.y(); + int curIndex = offsets[point.ruleIndex(true)] % coordsSize; if (area.containsExact(coords[curIndex], coords[curIndex + 1]) == 0) { isCurrentArea = !isCurrentArea; } else if (area.containsExact(coords[curIndex], coords[curIndex + 1]) > 0) { @@ -680,19 +680,19 @@ public class Area implements IShape, Cloneable } IntersectPoint nextPoint = (isCurrentArea) ? - getNextIntersectPoint(intersectPoints, point, isCurrentArea) : - getPrevIntersectPoint(intersectPoints, point, isCurrentArea); + nextIntersectPoint(intersectPoints, point, isCurrentArea) : + prevIntersectPoint(intersectPoints, point, isCurrentArea); double[] coords = (isCurrentArea) ? this.coords : area.coords; int[] offsets = (isCurrentArea) ? this.offsets : area.offsets; int[] rules = (isCurrentArea) ? this.rules : area.rules; - int offset = (isCurrentArea) ? point.getRuleIndex(isCurrentArea) : - nextPoint.getRuleIndex(isCurrentArea); + int offset = (isCurrentArea) ? point.ruleIndex(isCurrentArea) : + nextPoint.ruleIndex(isCurrentArea); boolean isCopyUntilZero = false; if (((isCurrentArea) && - (point.getRuleIndex(isCurrentArea) > nextPoint.getRuleIndex(isCurrentArea))) || + (point.ruleIndex(isCurrentArea) > nextPoint.ruleIndex(isCurrentArea))) || ((!isCurrentArea) && - (nextPoint.getRuleIndex(isCurrentArea) > nextPoint.getRuleIndex(isCurrentArea)))) { + (nextPoint.ruleIndex(isCurrentArea) > nextPoint.ruleIndex(isCurrentArea)))) { int rulesSize = (isCurrentArea) ? this.rulesSize : area.rulesSize; resultCoordPos = includeCoordsAndRules( offset + 1, rulesSize, rules, offsets, resultRules, resultOffsets, resultCoords, @@ -702,7 +702,7 @@ public class Area implements IShape, Cloneable isCopyUntilZero = true; } - int length = nextPoint.getRuleIndex(isCurrentArea) - offset + 1; + int length = nextPoint.ruleIndex(isCurrentArea) - offset + 1; if (isCopyUntilZero) { offset = 0; @@ -740,7 +740,7 @@ public class Area implements IShape, Cloneable new int[] { coordsSize, area.coordsSize }); IntersectPoint[] intersectPoints = crossHelper.findCrossing(); if (intersectPoints.length == 0) { - if (contains(area.getBounds())) { + if (contains(area.bounds())) { copy(area, this); return; } @@ -763,18 +763,18 @@ public class Area implements IShape, Cloneable resultOffsets[resultRulesPos++] = resultCoordPos; do { - resultCoords[resultCoordPos++] = point.getX(); - resultCoords[resultCoordPos++] = point.getY(); + resultCoords[resultCoordPos++] = point.x(); + resultCoords[resultCoordPos++] = point.y(); resultRules[resultRulesPos] = PathIterator.SEG_LINETO; resultOffsets[resultRulesPos++] = resultCoordPos - 2; - int curIndex = point.getEndIndex(true); + int curIndex = point.endIndex(true); if ((curIndex < 0) || (area.isVertex(coords[2 * curIndex], coords[2 * curIndex + 1]) && crossHelper.containsPoint(new double[] { coords[2 * curIndex], coords[2 * curIndex + 1] }) && - (coords[2 * curIndex] != point.getX() || - coords[2 * curIndex + 1] != point.getY()))) { + (coords[2 * curIndex] != point.x() || + coords[2 * curIndex + 1] != point.y()))) { isCurrentArea = !isCurrentArea; } else if (area.containsExact(coords[2 * curIndex], coords[2 * curIndex + 1]) > 0) { isCurrentArea = false; @@ -793,18 +793,18 @@ public class Area implements IShape, Cloneable } IntersectPoint nextPoint = (isCurrentArea) ? - getNextIntersectPoint(intersectPoints, point, isCurrentArea) : - getPrevIntersectPoint(intersectPoints, point, isCurrentArea); + nextIntersectPoint(intersectPoints, point, isCurrentArea) : + prevIntersectPoint(intersectPoints, point, isCurrentArea); double[] coords = (isCurrentArea) ? this.coords : area.coords; - int offset = (isCurrentArea) ? 2 * point.getEndIndex(isCurrentArea) : - 2 * nextPoint.getEndIndex(isCurrentArea); + int offset = (isCurrentArea) ? 2 * point.endIndex(isCurrentArea) : + 2 * nextPoint.endIndex(isCurrentArea); if ((offset > 0) && (((isCurrentArea) && - (nextPoint.getBegIndex(isCurrentArea) < point.getEndIndex(isCurrentArea))) || + (nextPoint.begIndex(isCurrentArea) < point.endIndex(isCurrentArea))) || ((!isCurrentArea) && - (nextPoint.getEndIndex(isCurrentArea) < nextPoint.getBegIndex(isCurrentArea))))) { + (nextPoint.endIndex(isCurrentArea) < nextPoint.begIndex(isCurrentArea))))) { int coordSize = (isCurrentArea) ? this.coordsSize : area.coordsSize; int length = coordSize - offset; @@ -829,8 +829,8 @@ public class Area implements IShape, Cloneable if (offset >= 0) { int length = (isCurrentArea) ? - 2 * nextPoint.getBegIndex(isCurrentArea) - offset + 2 : - 2 * point.getBegIndex(isCurrentArea) - offset + 2; + 2 * nextPoint.begIndex(isCurrentArea) - offset + 2 : + 2 * point.begIndex(isCurrentArea) - offset + 2; if (isCurrentArea) { System.arraycopy(coords, offset, resultCoords, resultCoordPos, length); @@ -861,10 +861,10 @@ public class Area implements IShape, Cloneable rulesSize = resultRulesPos; } - private IntersectPoint getNextIntersectPoint (IntersectPoint[] iPoints, + private IntersectPoint nextIntersectPoint (IntersectPoint[] iPoints, IntersectPoint isectPoint, boolean isCurrentArea) { - int endIndex = isectPoint.getEndIndex(isCurrentArea); + int endIndex = isectPoint.endIndex(isCurrentArea); if (endIndex < 0) { return iPoints[Math.abs(endIndex) - 1]; } @@ -872,11 +872,11 @@ public class Area implements IShape, Cloneable IntersectPoint firstIsectPoint = null; IntersectPoint nextIsectPoint = null; for (IntersectPoint point : iPoints) { - int begIndex = point.getBegIndex(isCurrentArea); + int begIndex = point.begIndex(isCurrentArea); if (begIndex >= 0) { if (firstIsectPoint == null) { firstIsectPoint = point; - } else if (begIndex < firstIsectPoint.getBegIndex(isCurrentArea)) { + } else if (begIndex < firstIsectPoint.begIndex(isCurrentArea)) { firstIsectPoint = point; } } @@ -884,7 +884,7 @@ public class Area implements IShape, Cloneable if (endIndex <= begIndex) { if (nextIsectPoint == null) { nextIsectPoint = point; - } else if (begIndex < nextIsectPoint.getBegIndex(isCurrentArea)) { + } else if (begIndex < nextIsectPoint.begIndex(isCurrentArea)) { nextIsectPoint = point; } } @@ -893,10 +893,10 @@ public class Area implements IShape, Cloneable return (nextIsectPoint != null) ? nextIsectPoint : firstIsectPoint; } - private IntersectPoint getPrevIntersectPoint (IntersectPoint[] iPoints, + private IntersectPoint prevIntersectPoint (IntersectPoint[] iPoints, IntersectPoint isectPoint, boolean isCurrentArea) { - int begIndex = isectPoint.getBegIndex(isCurrentArea); + int begIndex = isectPoint.begIndex(isCurrentArea); if (begIndex < 0) { return iPoints[Math.abs(begIndex) - 1]; } @@ -904,11 +904,11 @@ public class Area implements IShape, Cloneable IntersectPoint firstIsectPoint = null; IntersectPoint predIsectPoint = null; for (IntersectPoint point : iPoints) { - int endIndex = point.getEndIndex(isCurrentArea); + int endIndex = point.endIndex(isCurrentArea); if (endIndex >= 0) { if (firstIsectPoint == null) { firstIsectPoint = point; - } else if (endIndex < firstIsectPoint.getEndIndex(isCurrentArea)) { + } else if (endIndex < firstIsectPoint.endIndex(isCurrentArea)) { firstIsectPoint = point; } } @@ -916,7 +916,7 @@ public class Area implements IShape, Cloneable if (endIndex <= begIndex) { if (predIsectPoint == null) { predIsectPoint = point; - } else if (endIndex > predIsectPoint.getEndIndex(isCurrentArea)) { + } else if (endIndex > predIsectPoint.endIndex(isCurrentArea)) { predIsectPoint = point; } } @@ -976,7 +976,7 @@ public class Area implements IShape, Cloneable resultRules[resultRulesPos] = PathIterator.SEG_LINETO; resultOffsets[resultRulesPos++] = resultCoordPos + 2; boolean isLeft = CrossingHelper.compare( - coords[index], coords[index + 1], point.getX(), point.getY()) > 0; + coords[index], coords[index + 1], point.x(), point.y()) > 0; if (way || !isLeft) { temp[coordsCount++] = coords[index]; temp[coordsCount++] = coords[index + 1]; @@ -990,13 +990,13 @@ public class Area implements IShape, Cloneable coords[index - 2], coords[index - 1], coords[index], coords[index + 1], coords[index + 2], coords[index + 3] }; isLeft = CrossingHelper.compare( - coords[index - 2], coords[index - 1], point.getX(), point.getY()) > 0; + coords[index - 2], coords[index - 1], point.x(), point.y()) > 0; if ((!additional) && (operation == 0 || operation == 2)) { isLeft = !isLeft; way = false; } - GeometryUtil.subQuad(coefs, point.getParam(isCurrentArea), isLeft); + GeometryUtil.subQuad(coefs, point.param(isCurrentArea), isLeft); if (way || isLeft) { temp[coordsCount++] = coefs[2]; @@ -1014,8 +1014,8 @@ public class Area implements IShape, Cloneable coords[index + 1], coords[index + 2], coords[index + 3], coords[index + 4], coords[index + 5] }; isLeft = CrossingHelper.compare( - coords[index - 2], coords[index - 1], point.getX(), point.getY()) > 0; - GeometryUtil.subCubic(coefs, point.getParam(isCurrentArea), !isLeft); + coords[index - 2], coords[index - 1], point.x(), point.y()) > 0; + GeometryUtil.subCubic(coefs, point.param(isCurrentArea), !isLeft); if (isLeft) { System.arraycopy(coefs, 2, temp, coordsCount, 6); @@ -1048,7 +1048,7 @@ public class Area implements IShape, Cloneable } private int containsExact (double x, double y) { - PathIterator pi = getPathIterator(null); + PathIterator pi = pathIterator(null); int crossCount = Crossing.crossPath(pi, x, y); if (Crossing.isInsideEvenOdd(crossCount)) { return 1; @@ -1062,7 +1062,7 @@ public class Area implements IShape, Cloneable double moveX = -1; double moveY = -1; - for (pi = getPathIterator(null); !pi.isDone(); pi.next()) { + for (pi = pathIterator(null); !pi.isDone(); pi.next()) { rule = pi.currentSegment(segmentCoords); switch (rule) { case PathIterator.SEG_MOVETO: @@ -1123,9 +1123,9 @@ public class Area implements IShape, Cloneable } } - private double getAreaBoundsSquare () { - Rectangle bounds = getBounds(); - return bounds.getHeight() * bounds.getWidth(); + private double areaBoundsSquare () { + Rectangle bounds = bounds(); + return bounds.height() * bounds.width(); } private boolean isVertex (double x, double y) { @@ -1159,15 +1159,15 @@ public class Area implements IShape, Cloneable // the internal class implements PathIterator private class AreaPathIterator implements PathIterator { - private final AffineTransform transform; + private final Transform transform; private int curRuleIndex = 0; private int curCoordIndex = 0; - AreaPathIterator (AffineTransform t) { + AreaPathIterator (Transform t) { this.transform = t; } - @Override public int getWindingRule () { + @Override public int windingRule () { return WIND_EVEN_ODD; } diff --git a/src/main/java/pythagoras/d/Crossing.java b/src/main/java/pythagoras/d/Crossing.java index f0d401a..08cf4d8 100644 --- a/src/main/java/pythagoras/d/Crossing.java +++ b/src/main/java/pythagoras/d/Crossing.java @@ -472,10 +472,10 @@ class Crossing * Returns how many times a ray from point (x,y) crosses a shape. */ public static int crossShape (IShape s, double x, double y) { - if (!s.getBounds().contains(x, y)) { + if (!s.bounds().contains(x, y)) { return 0; } - return crossPath(s.getPathIterator(null), x, y); + return crossPath(s.pathIterator(null), x, y); } /** @@ -759,10 +759,10 @@ class Crossing * Returns how many times rectangle stripe cross shape or the are intersect */ public static int intersectShape (IShape s, double x, double y, double w, double h) { - if (!s.getBounds().intersects(x, y, w, h)) { + if (!s.bounds().intersects(x, y, w, h)) { return 0; } - return intersectPath(s.getPathIterator(null), x, y, w, h); + return intersectPath(s.pathIterator(null), x, y, w, h); } /** diff --git a/src/main/java/pythagoras/d/CrossingHelper.java b/src/main/java/pythagoras/d/CrossingHelper.java index 25f9298..0c07c83 100644 --- a/src/main/java/pythagoras/d/CrossingHelper.java +++ b/src/main/java/pythagoras/d/CrossingHelper.java @@ -177,8 +177,8 @@ class CrossingHelper IntersectPoint ip; for (Iterator i = isectPoints.iterator(); i.hasNext();) { ip = i.next(); - if ((initBegin == ip.getBegIndex(true)) && (initEnd == ip.getEndIndex(true))) { - if (compare(ip.getX(), ip.getY(), point[0], point[1]) > 0) { + if ((initBegin == ip.begIndex(true)) && (initEnd == ip.endIndex(true))) { + if (compare(ip.x(), ip.y(), point[0], point[1]) > 0) { initEnd = -(isectPoints.indexOf(ip) + 1); ip.setBegIndex1(-(isectPoints.size() + 1)); } else { @@ -187,8 +187,8 @@ class CrossingHelper } } - if ((addBegin == ip.getBegIndex(false)) && (addEnd == ip.getEndIndex(false))) { - if (compare(ip.getX(), ip.getY(), point[0], point[1]) > 0) { + if ((addBegin == ip.begIndex(false)) && (addEnd == ip.endIndex(false))) { + if (compare(ip.x(), ip.y(), point[0], point[1]) > 0) { addEnd = -(isectPoints.indexOf(ip) + 1); ip.setBegIndex2(-(isectPoints.size() + 1)); } else { @@ -256,7 +256,7 @@ class CrossingHelper IntersectPoint ipoint; for (Iterator i = isectPoints.iterator(); i.hasNext();) { ipoint = i.next(); - if (ipoint.getX() == point[0] && ipoint.getY() == point[1]) { + if (ipoint.x() == point[0] && ipoint.y() == point[1]) { return true; } } diff --git a/src/main/java/pythagoras/d/CubicCurve.java b/src/main/java/pythagoras/d/CubicCurve.java index dd89cba..1195f34 100644 --- a/src/main/java/pythagoras/d/CubicCurve.java +++ b/src/main/java/pythagoras/d/CubicCurve.java @@ -68,8 +68,8 @@ public class CubicCurve extends AbstractCubicCurve implements Serializable * 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()); + setCurve(p1.x(), p1.y(), cp1.x(), cp1.y(), + cp2.x(), cp2.y(), p2.x(), p2.y()); } /** @@ -86,10 +86,10 @@ public class CubicCurve extends AbstractCubicCurve implements Serializable * specified offset in the {@code 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()); + setCurve(points[offset + 0].x(), points[offset + 0].y(), + points[offset + 1].x(), points[offset + 1].y(), + points[offset + 2].x(), points[offset + 2].y(), + points[offset + 3].x(), points[offset + 3].y()); } /** @@ -97,47 +97,47 @@ public class CubicCurve extends AbstractCubicCurve implements Serializable * curve. */ public void setCurve (ICubicCurve curve) { - setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX1(), curve.getCtrlY1(), - curve.getCtrlX2(), curve.getCtrlY2(), curve.getX2(), curve.getY2()); + setCurve(curve.x1(), curve.y1(), curve.ctrlX1(), curve.ctrlY1(), + curve.ctrlX2(), curve.ctrlY2(), curve.x2(), curve.y2()); } @Override // from interface ICubicCurve - public double getX1 () { + public double x1 () { return x1; } @Override // from interface ICubicCurve - public double getY1 () { + public double y1 () { return y1; } @Override // from interface ICubicCurve - public double getCtrlX1 () { + public double ctrlX1 () { return ctrlx1; } @Override // from interface ICubicCurve - public double getCtrlY1 () { + public double ctrlY1 () { return ctrly1; } @Override // from interface ICubicCurve - public double getCtrlX2 () { + public double ctrlX2 () { return ctrlx2; } @Override // from interface ICubicCurve - public double getCtrlY2 () { + public double ctrlY2 () { return ctrly2; } @Override // from interface ICubicCurve - public double getX2 () { + public double x2 () { return x2; } @Override // from interface ICubicCurve - public double getY2 () { + public double y2 () { return y2; } } diff --git a/src/main/java/pythagoras/d/CubicCurves.java b/src/main/java/pythagoras/d/CubicCurves.java index f8e15e0..8895254 100644 --- a/src/main/java/pythagoras/d/CubicCurves.java +++ b/src/main/java/pythagoras/d/CubicCurves.java @@ -9,34 +9,34 @@ package pythagoras.d; */ public class CubicCurves { - public static double getFlatnessSq (double x1, double y1, double ctrlx1, double ctrly1, + public static double flatnessSq (double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, double ctrly2, double x2, double y2) { return Math.max(Lines.pointSegDistSq(ctrlx1, ctrly1, x1, y1, x2, y2), Lines.pointSegDistSq(ctrlx2, ctrly2, x1, y1, x2, y2)); } - public static double getFlatnessSq (double[] coords, int offset) { - return getFlatnessSq(coords[offset + 0], coords[offset + 1], coords[offset + 2], + public static double flatnessSq (double[] coords, int offset) { + return flatnessSq(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 double getFlatness (double x1, double y1, double ctrlx1, double ctrly1, + public static double flatness (double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, double ctrly2, double x2, double y2) { - return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2)); + return Math.sqrt(flatnessSq(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2)); } - public static double getFlatness (double[] coords, int offset) { - return getFlatness(coords[offset + 0], coords[offset + 1], coords[offset + 2], + public static double flatness (double[] coords, int offset) { + return flatness(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) { - double x1 = src.getX1(), y1 = src.getY1(); - double cx1 = src.getCtrlX1(), cy1 = src.getCtrlY1(); - double cx2 = src.getCtrlX2(), cy2 = src.getCtrlY2(); - double x2 = src.getX2(), y2 = src.getY2(); + double x1 = src.x1(), y1 = src.y1(); + double cx1 = src.ctrlX1(), cy1 = src.ctrlY1(); + double cx2 = src.ctrlX2(), cy2 = src.ctrlY2(); + double x2 = src.x2(), y2 = src.y2(); double cx = (cx1 + cx2) / 2f, cy = (cy1 + cy2) / 2f; cx1 = (x1 + cx1) / 2f; cy1 = (y1 + cy1) / 2f; diff --git a/src/main/java/pythagoras/d/CurveCrossingHelper.java b/src/main/java/pythagoras/d/CurveCrossingHelper.java index da011b7..05a044b 100644 --- a/src/main/java/pythagoras/d/CurveCrossingHelper.java +++ b/src/main/java/pythagoras/d/CurveCrossingHelper.java @@ -43,11 +43,11 @@ class CurveCrossingHelper for (int i = 0; i < rulesSizes[0]; i++) { rule1 = rules[0][i]; - endIndex1 = getCurrentEdge(0, i, edge1, mp1, cp1); + endIndex1 = currentEdge(0, i, edge1, mp1, cp1); for (int j = 0; j < rulesSizes[1]; j++) { ipCount = 0; rule2 = rules[1][j]; - endIndex2 = getCurrentEdge(1, j, edge2, mp2, cp2); + endIndex2 = currentEdge(1, j, edge2, mp2, cp2); if (((rule1 == PathIterator.SEG_LINETO) || (rule1 == PathIterator.SEG_CLOSE)) && ((rule2 == PathIterator.SEG_LINETO) || (rule2 == PathIterator.SEG_CLOSE))) { ipCount = GeometryUtil.intersectLinesWithParams( @@ -167,9 +167,9 @@ class CurveCrossingHelper for (Iterator iter = isectPoints.iterator(); iter.hasNext();) { ip = iter.next(); - if ((begIndex1 == ip.getBegIndex(true)) && - (endIndex1 == ip.getEndIndex(true))) { - if (ip.getParam(true) > params[2 * k]) { + if ((begIndex1 == ip.begIndex(true)) && + (endIndex1 == ip.endIndex(true))) { + if (ip.param(true) > params[2 * k]) { endIndex1 = -(isectPoints.indexOf(ip) + 1); ip.setBegIndex1(-(isectPoints.size() + 1)); } else { @@ -178,9 +178,9 @@ class CurveCrossingHelper } } - if ((begIndex2 == ip.getBegIndex(false)) && - (endIndex2 == ip.getEndIndex(false))) { - if (ip.getParam(false) > params[2 * k + 1]) { + if ((begIndex2 == ip.begIndex(false)) && + (endIndex2 == ip.endIndex(false))) { + if (ip.param(false) > params[2 * k + 1]) { endIndex2 = -(isectPoints.indexOf(ip) + 1); ip.setBegIndex2(-(isectPoints.size() + 1)); } else { @@ -209,7 +209,7 @@ class CurveCrossingHelper return isectPoints.toArray(new IntersectPoint[isectPoints.size()]); } - private int getCurrentEdge (int areaIndex, int index, double[] c, double[] mp, double[] cp) { + private int currentEdge (int areaIndex, int index, double[] c, double[] mp, double[] cp) { int endIndex = 0; switch (rules[areaIndex][index]) { @@ -263,8 +263,8 @@ class CurveCrossingHelper IntersectPoint ipoint; for (Iterator i = isectPoints.iterator(); i.hasNext();) { ipoint = i.next(); - if ((Math.abs(ipoint.getX() - x) < Math.pow(10, -6)) && - (Math.abs(ipoint.getY() - y) < Math.pow(10, -6))) { + if ((Math.abs(ipoint.x() - x) < Math.pow(10, -6)) && + (Math.abs(ipoint.y() - y) < Math.pow(10, -6))) { return true; } } diff --git a/src/main/java/pythagoras/d/Dimension.java b/src/main/java/pythagoras/d/Dimension.java index f8d39e0..dec6d6a 100644 --- a/src/main/java/pythagoras/d/Dimension.java +++ b/src/main/java/pythagoras/d/Dimension.java @@ -35,7 +35,7 @@ public class Dimension extends AbstractDimension implements Serializable * Creates a dimension with width and height equal to the supplied dimension. */ public Dimension (IDimension d) { - this(d.getWidth(), d.getHeight()); + this(d.width(), d.height()); } /** @@ -50,16 +50,16 @@ public class Dimension extends AbstractDimension implements Serializable * Sets the magnitudes of this dimension to be equal to the supplied dimension. */ public void setSize (IDimension d) { - setSize(d.getWidth(), d.getHeight()); + setSize(d.width(), d.height()); } @Override // from interface IDimension - public double getWidth () { + public double width () { return width; } @Override // from interface IDimension - public double getHeight () { + public double height () { return height; } } diff --git a/src/main/java/pythagoras/d/Ellipse.java b/src/main/java/pythagoras/d/Ellipse.java index b42937f..f9e9efe 100644 --- a/src/main/java/pythagoras/d/Ellipse.java +++ b/src/main/java/pythagoras/d/Ellipse.java @@ -37,22 +37,22 @@ public class Ellipse extends AbstractEllipse implements Serializable } @Override // from interface IRectangularShape - public double getX () { + public double x () { return x; } @Override // from interface IRectangularShape - public double getY () { + public double y () { return y; } @Override // from interface IRectangularShape - public double getWidth () { + public double width () { return width; } @Override // from interface IRectangularShape - public double getHeight () { + public double height () { return height; } diff --git a/src/main/java/pythagoras/d/FlatteningPathIterator.java b/src/main/java/pythagoras/d/FlatteningPathIterator.java index 041c787..686f34f 100644 --- a/src/main/java/pythagoras/d/FlatteningPathIterator.java +++ b/src/main/java/pythagoras/d/FlatteningPathIterator.java @@ -34,18 +34,18 @@ class FlatteningPathIterator implements PathIterator this.bufIndex = bufSize; } - public double getFlatness () { + public double flatness () { return flatness; } - public int getRecursionLimit () { + public int recursionLimit () { return bufLimit; } @Override // from interface PathIterator - public int getWindingRule () { - return p.getWindingRule(); + public int windingRule () { + return p.windingRule(); } @Override @@ -81,7 +81,7 @@ class FlatteningPathIterator implements PathIterator } /** 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() + * flat by itself. Flatness of quad and cubic curves are evaluated by the flatnessSq() * 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 @@ -109,7 +109,7 @@ class FlatteningPathIterator implements PathIterator } while (bufSubdiv < bufLimit) { - if (QuadCurves.getFlatnessSq(buf, bufIndex) < flatness2) { + if (QuadCurves.flatnessSq(buf, bufIndex) < flatness2) { break; } @@ -150,7 +150,7 @@ class FlatteningPathIterator implements PathIterator } while (bufSubdiv < bufLimit) { - if (CubicCurves.getFlatnessSq(buf, bufIndex) < flatness2) { + if (CubicCurves.flatnessSq(buf, bufIndex) < flatness2) { break; } diff --git a/src/main/java/pythagoras/d/GeometryUtil.java b/src/main/java/pythagoras/d/GeometryUtil.java index d5b1489..67189c3 100644 --- a/src/main/java/pythagoras/d/GeometryUtil.java +++ b/src/main/java/pythagoras/d/GeometryUtil.java @@ -46,8 +46,8 @@ public class GeometryUtil * * @return 1 if two lines intersect in the defined interval, otherwise 0. */ - public static int intersectLines (double x1, double y1, double x2, double y2, - double x3, double y3, double x4, double y4, double[] point) { + public static int intersectLines (double x1, double y1, double x2, double y2, double x3, double y3, + double x4, double y4, double[] point) { double A1 = -(y2 - y1); double B1 = (x2 - x1); double C1 = x1 * y2 - x2 * y1; @@ -172,10 +172,9 @@ public class GeometryUtil * * @return the number of roots that lie in the interval. */ - public static int intersectQuads (double x1, double y1, double x2, double y2, - double x3, double y3, - double qx1, double qy1, double qx2, double qy2, - double qx3, double qy3, double[] params) { + public static int intersectQuads (double x1, double y1, double x2, double y2, double x3, double y3, + double qx1, double qy1, double qx2, double qy2, double qx3, + double qy3, double[] params) { double[] initParams = new double[2]; double[] xCoefs1 = new double[3]; double[] yCoefs1 = new double[3]; @@ -288,11 +287,10 @@ public class GeometryUtil * * @return the number of intersection points that lie in the interval. */ - public static int intersectCubics (double x1, double y1, double x2, double y2, - double x3, double y3, double x4, double y4, - double cx1, double cy1, double cx2, double cy2, - double cx3, double cy3, double cx4, double cy4, - double[] params) { + public static int intersectCubics (double x1, double y1, double x2, double y2, double x3, double y3, + double x4, double y4, double cx1, double cy1, + double cx2, double cy2, double cx3, double cy3, + double cx4, double cy4, double[] params) { int quantity = 0; double[] initParams = new double[3]; double[] xCoefs1 = new double[4]; diff --git a/src/main/java/pythagoras/d/IArc.java b/src/main/java/pythagoras/d/IArc.java index bccb37b..84b9409 100644 --- a/src/main/java/pythagoras/d/IArc.java +++ b/src/main/java/pythagoras/d/IArc.java @@ -22,31 +22,31 @@ public interface IArc extends IRectangularShape, Cloneable int PIE = 2; /** Returns the type of this arc: {@link #OPEN}, etc. */ - int getArcType (); + int arcType (); /** Returns the starting angle of this arc. */ - double getAngleStart (); + double angleStart (); /** Returns the angular extent of this arc. */ - double getAngleExtent (); + double angleExtent (); /** Returns the intersection of the ray from the center (defined by the starting angle) and the * elliptical boundary of the arc. */ - Point getStartPoint (); + Point startPoint (); /** Writes the intersection of the ray from the center (defined by the starting angle) and the * elliptical boundary of the arc into {@code target}. * @return the supplied point. */ - Point getStartPoint (Point target); + Point startPoint (Point target); /** Returns the intersection of the ray from the center (defined by the starting angle plus the * angular extent of the arc) and the elliptical boundary of the arc. */ - Point getEndPoint (); + Point endPoint (); /** Writes the intersection of the ray from the center (defined by the starting angle plus the * angular extent of the arc) and the elliptical boundary of the arc into {@code target}. * @return the supplied point. */ - Point getEndPoint (Point target); + Point endPoint (Point target); /** Returns whether the specified angle is within the angular extents of this arc. */ boolean containsAngle (double angle); diff --git a/src/main/java/pythagoras/d/ICubicCurve.java b/src/main/java/pythagoras/d/ICubicCurve.java index 9b34209..d85c503 100644 --- a/src/main/java/pythagoras/d/ICubicCurve.java +++ b/src/main/java/pythagoras/d/ICubicCurve.java @@ -10,48 +10,48 @@ package pythagoras.d; public interface ICubicCurve extends IShape, Cloneable { /** Returns the x-coordinate of the start of this curve. */ - double getX1 (); + double x1 (); /** Returns the y-coordinate of the start of this curve. */ - double getY1 (); + double y1 (); /** Returns the x-coordinate of the first control point. */ - double getCtrlX1 (); + double ctrlX1 (); /** Returns the y-coordinate of the first control point. */ - double getCtrlY1 (); + double ctrlY1 (); /** Returns the x-coordinate of the second control point. */ - double getCtrlX2 (); + double ctrlX2 (); /** Returns the y-coordinate of the second control point. */ - double getCtrlY2 (); + double ctrlY2 (); /** Returns the x-coordinate of the end of this curve. */ - double getX2 (); + double x2 (); /** Returns the y-coordinate of the end of this curve. */ - double getY2 (); + double y2 (); /** Returns a copy of the starting point of this curve. */ - Point getP1 (); + Point p1 (); /** Returns a copy of the first control point of this curve. */ - Point getCtrlP1 (); + Point ctrlP1 (); /** Returns a copy of the second control point of this curve. */ - Point getCtrlP2 (); + Point ctrlP2 (); /** Returns a copy of the ending point of this curve. */ - Point getP2 (); + Point p2 (); /** Returns the square of the flatness (maximum distance of a control point from the line * connecting the end points) of this curve. */ - double getFlatnessSq (); + double flatnessSq (); /** Returns the flatness (maximum distance of a control point from the line connecting the end * points) of this curve. */ - double getFlatness (); + double flatness (); /** Subdivides this curve and stores the results into {@code left} and {@code right}. */ void subdivide (CubicCurve left, CubicCurve right); diff --git a/src/main/java/pythagoras/d/IDimension.java b/src/main/java/pythagoras/d/IDimension.java index f173148..80c2c21 100644 --- a/src/main/java/pythagoras/d/IDimension.java +++ b/src/main/java/pythagoras/d/IDimension.java @@ -12,12 +12,12 @@ public interface IDimension extends Cloneable /** * Returns the magnitude in the x-dimension. */ - double getWidth (); + double width (); /** * Returns the magnitude in the y-dimension. */ - double getHeight (); + double height (); /** * Returns a mutable copy of this dimension. diff --git a/src/main/java/pythagoras/d/ILine.java b/src/main/java/pythagoras/d/ILine.java index 1ef8f99..c9e6354 100644 --- a/src/main/java/pythagoras/d/ILine.java +++ b/src/main/java/pythagoras/d/ILine.java @@ -10,30 +10,30 @@ package pythagoras.d; public interface ILine extends IShape, Cloneable { /** Returns the x-coordinate of the start of this line. */ - double getX1 (); + double x1 (); /** Returns the y-coordinate of the start of this line. */ - double getY1 (); + double y1 (); /** Returns the x-coordinate of the end of this line. */ - double getX2 (); + double x2 (); /** Returns the y-coordinate of the end of this line. */ - double getY2 (); + double y2 (); /** Returns a copy of the starting point of this line. */ - Point getP1 (); + Point p1 (); /** Initializes the supplied point with this line's starting point. * @return the supplied point. */ - Point getP1 (Point target); + Point p1 (Point target); /** Returns a copy of the ending point of this line. */ - Point getP2 (); + Point p2 (); /** Initializes the supplied point with this line's ending point. * @return the supplied point. */ - Point getP2 (Point target); + Point p2 (Point target); /** Returns the square of the distance from the specified point to the line defined by this * line segment. */ diff --git a/src/main/java/pythagoras/d/IPoint.java b/src/main/java/pythagoras/d/IPoint.java index 5dbe070..7ab2cd6 100644 --- a/src/main/java/pythagoras/d/IPoint.java +++ b/src/main/java/pythagoras/d/IPoint.java @@ -10,10 +10,10 @@ package pythagoras.d; public interface IPoint extends Cloneable { /** Returns this point's x-coordinate. */ - double getX (); + double x (); /** Returns this point's y-coordinate. */ - double getY (); + double y (); /** Returns the squared Euclidian distance between this point and the specified point. */ double distanceSq (double px, double py); @@ -27,6 +27,31 @@ public interface IPoint extends Cloneable /** Returns the Euclidian distance between this point and the supplied point. */ double distance (IPoint p); + /** Multiplies this point by a scale factor. + * @return a new point containing the result. */ + Point mult (double s); + + /** Multiplies this point by a scale factor and places the result in the supplied object. + * @return a reference to the result, for chaining. */ + Point mult (double s, Point result); + + /** Translates this point by the specified offset. + * @return a new point containing the result. */ + Point add (double x, double y); + + /** Translates this point by the specified offset and stores the result in the object provided. + * @return a reference to the result, for chaining. */ + Point add (double x, double y, Point result); + + /** Rotates this point around the origin by the specified angle. + * @return a new point containing the result. */ + Point rotate (double angle); + + /** Rotates this point around the origin by the specified angle, storing the result in the + * point provided. + * @return a reference to the result point, for chaining. */ + Point rotate (double angle, Point result); + /** Returns a mutable copy of this point. */ Point clone (); } diff --git a/src/main/java/pythagoras/d/IQuadCurve.java b/src/main/java/pythagoras/d/IQuadCurve.java index 200ad90..bbf511a 100644 --- a/src/main/java/pythagoras/d/IQuadCurve.java +++ b/src/main/java/pythagoras/d/IQuadCurve.java @@ -10,39 +10,39 @@ package pythagoras.d; public interface IQuadCurve extends IShape, Cloneable { /** Returns the x-coordinate of the start of this curve. */ - double getX1 (); + double x1 (); /** Returns the y-coordinate of the start of this curve. */ - double getY1 (); + double y1 (); /** Returns the x-coordinate of the control point. */ - double getCtrlX (); + double ctrlX (); /** Returns the y-coordinate of the control point. */ - double getCtrlY (); + double ctrlY (); /** Returns the x-coordinate of the end of this curve. */ - double getX2 (); + double x2 (); /** Returns the y-coordinate of the end of this curve. */ - double getY2 (); + double y2 (); /** Returns a copy of the starting point of this curve. */ - Point getP1 (); + Point p1 (); /** Returns a copy of the control point of this curve. */ - Point getCtrlP (); + Point ctrlP (); /** Returns a copy of the ending point of this curve. */ - Point getP2 (); + Point p2 (); /** Returns the square of the flatness (maximum distance of a control point from the line * connecting the end points) of this curve. */ - double getFlatnessSq (); + double flatnessSq (); /** Returns the flatness (maximum distance of a control point from the line connecting the end * points) of this curve. */ - double getFlatness (); + double flatness (); /** Subdivides this curve and stores the results into {@code left} and {@code right}. */ void subdivide (QuadCurve left, QuadCurve right); diff --git a/src/main/java/pythagoras/d/IRectangle.java b/src/main/java/pythagoras/d/IRectangle.java index ba5eabb..db908cd 100644 --- a/src/main/java/pythagoras/d/IRectangle.java +++ b/src/main/java/pythagoras/d/IRectangle.java @@ -24,18 +24,18 @@ public interface IRectangle extends IRectangularShape, Cloneable int OUT_BOTTOM = 8; /** Returns a copy of this rectangle's upper-left corner. */ - Point getLocation (); + Point location (); /** Initializes the supplied point with this rectangle's upper-left corner. * @return the supplied point. */ - Point getLocation (Point target); + Point location (Point target); /** Returns a copy of this rectangle's size. */ - Dimension getSize (); + Dimension size (); /** Initializes the supplied dimension with this rectangle's size. * @return the supplied dimension. */ - Dimension getSize (Dimension target); + Dimension size (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). */ diff --git a/src/main/java/pythagoras/d/IRectangularShape.java b/src/main/java/pythagoras/d/IRectangularShape.java index be4a6c2..c31546e 100644 --- a/src/main/java/pythagoras/d/IRectangularShape.java +++ b/src/main/java/pythagoras/d/IRectangularShape.java @@ -12,48 +12,48 @@ package pythagoras.d; public interface IRectangularShape extends IShape { /** Returns the x-coordinate of the upper-left corner of the framing rectangle. */ - double getX (); + double x (); /** Returns the y-coordinate of the upper-left corner of the framing rectangle. */ - double getY (); + double y (); /** Returns the width of the framing rectangle. */ - double getWidth (); + double width (); /** Returns the height of the framing rectangle. */ - double getHeight (); + double height (); /** Returns the minimum x,y-coordinate of the framing rectangle. */ - Point getMin (); + Point min (); /** Returns the minimum x-coordinate of the framing rectangle. */ - double getMinX (); + double minX (); /** Returns the minimum y-coordinate of the framing rectangle. */ - double getMinY (); + double minY (); /** Returns the maximum x,y-coordinate of the framing rectangle. */ - Point getMax (); + Point max (); /** Returns the maximum x-coordinate of the framing rectangle. */ - double getMaxX (); + double maxX (); /** Returns the maximum y-coordinate of the framing rectangle. */ - double getMaxY (); + double maxY (); /** Returns the center of the framing rectangle. */ - Point getCenter (); + Point center (); /** Returns the x-coordinate of the center of the framing rectangle. */ - double getCenterX (); + double centerX (); /** Returns the y-coordinate of the center of the framing rectangle. */ - double getCenterY (); + double centerY (); /** Returns a copy of this shape's framing rectangle. */ - Rectangle getFrame (); + Rectangle frame (); /** Initializes the supplied rectangle with this shape's framing rectangle. * @return the supplied rectangle. */ - Rectangle getFrame (Rectangle target); + Rectangle frame (Rectangle target); } diff --git a/src/main/java/pythagoras/d/IRoundRectangle.java b/src/main/java/pythagoras/d/IRoundRectangle.java index 75257c1..711370f 100644 --- a/src/main/java/pythagoras/d/IRoundRectangle.java +++ b/src/main/java/pythagoras/d/IRoundRectangle.java @@ -10,10 +10,10 @@ package pythagoras.d; public interface IRoundRectangle extends IRectangularShape, Cloneable { /** Returns the width of the corner arc. */ - double getArcWidth (); + double arcWidth (); /** Returns the height of the corner arc. */ - double getArcHeight (); + double arcHeight (); /** Returns a mutable copy of this round rectangle. */ RoundRectangle clone (); diff --git a/src/main/java/pythagoras/d/IShape.java b/src/main/java/pythagoras/d/IShape.java index fc25f37..a9ae074 100644 --- a/src/main/java/pythagoras/d/IShape.java +++ b/src/main/java/pythagoras/d/IShape.java @@ -31,18 +31,18 @@ public interface IShape boolean intersects (IRectangle r); /** Returns a copy of the bounding rectangle for this shape. */ - Rectangle getBounds (); + Rectangle bounds (); /** Initializes the supplied rectangle with this shape's bounding rectangle. * @return the supplied rectangle. */ - Rectangle getBounds (Rectangle target); + Rectangle bounds (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); + PathIterator pathIterator (Transform at); /** * Returns an iterator over the path described by this shape. @@ -52,5 +52,5 @@ public interface IShape * 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, double flatness); + PathIterator pathIterator (Transform at, double flatness); } diff --git a/src/main/java/pythagoras/d/IVector.java b/src/main/java/pythagoras/d/IVector.java new file mode 100644 index 0000000..41d05fe --- /dev/null +++ b/src/main/java/pythagoras/d/IVector.java @@ -0,0 +1,132 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * Provides read-only access to a {@link Vector}. + */ +public interface IVector +{ + /** Returns the x-component of this vector. */ + double x (); + + /** Returns the y-component of this vector. */ + double y (); + + /** Computes and returns the dot product of this and the specified other vector. */ + double dot (IVector other); + + /** Negates this vector. + * @return a new vector containing the result. */ + Vector negate (); + + /** Negates this vector, storing the result in the supplied object. + * @return a reference to the result, for chaining. */ + Vector negate (Vector result); + + /** Normalizes this vector. + * @return a new vector containing the result. */ + Vector normalize (); + + /** Normalizes this vector, storing the result in the object supplied. + * @return a reference to the result, for chaining. */ + Vector normalize (Vector result); + + /** Returns the angle between this vector and the specified other vector. */ + double angle (IVector other); + + /** Returns the direction of a vector pointing from this point to the specified other point. */ + double direction (IVector other); + + /** Returns the length of this vector. */ + double length (); + + /** Returns the squared length of this vector. */ + double lengthSq (); + + /** Returns the distance from this vector to the specified other vector. */ + double distance (IVector other); + + /** Returns the squared distance from this vector to the specified other. */ + double distanceSq (IVector other); + + /** Multiplies this vector by a scalar. + * @return a new vector containing the result. */ + Vector mult (double v); + + /** Multiplies this vector by a scalar and places the result in the supplied object. + * @return a reference to the result, for chaining. */ + Vector mult (double v, Vector result); + + /** Multiplies this vector by another. + * @return a new vector containing the result. */ + Vector mult (IVector other); + + /** Multiplies this vector by another, storing the result in the object provided. + * @return a reference to the result vector, for chaining. */ + Vector mult (IVector other, Vector result); + + /** Adds a vector to this one. + * @return a new vector containing the result. */ + Vector add (IVector other); + + /** Adds a vector to this one, storing the result in the object provided. + * @return a reference to the result, for chaining. */ + Vector add (IVector other, Vector result); + + /** Adds a vector to this one. + * @return a new vector containing the result. */ + Vector add (double x, double y); + + /** Adds a vector to this one and stores the result in the object provided. + * @return a reference to the result, for chaining. */ + Vector add (double x, double y, Vector result); + + /** Adds a scaled vector to this one. + * @return a new vector containing the result. */ + Vector addScaled (IVector other, double v); + + /** Adds a scaled vector to this one and stores the result in the supplied vector. + * @return a reference to the result, for chaining. */ + Vector addScaled (IVector other, double v, Vector result); + + /** Subtracts a vector from this one. + * @return a new vector containing the result. */ + Vector subtract (IVector other); + + /** Subtracts a vector from this one and places the result in the supplied object. + * @return a reference to the result, for chaining. */ + Vector subtract (IVector other, Vector result); + + /** Rotates this vector by the specified angle. + * @return a new vector containing the result. */ + Vector rotate (double angle); + + /** Rotates this vector by the specified angle, storing the result in the vector provided. + * @return a reference to the result vector, for chaining. */ + Vector rotate (double angle, Vector result); + + /** Rotates this vector by the specified angle and adds another vector to it, placing the + * result in the object provided. + * @return a reference to the result, for chaining. */ + Vector rotateAndAdd (double angle, IVector add, Vector result); + + /** Rotates this vector by the specified angle, applies a uniform scale, and adds another + * vector to it, placing the result in the object provided. + * @return a reference to the result, for chaining. */ + Vector rotateScaleAndAdd (double angle, double scale, IVector add, Vector result); + + /** Linearly interpolates between this and the specified other vector by the supplied amount. + * @return a new vector containing the result. */ + Vector lerp (IVector other, double t); + + /** Linearly interpolates between this and the supplied other vector by the supplied amount, + * storing the result in the supplied object. + * @return a reference to the result, for chaining. */ + Vector lerp (IVector other, double t, Vector result); + + /** Returns a mutable copy of this vector. */ + Vector clone (); +} diff --git a/src/main/java/pythagoras/d/IdentityTransform.java b/src/main/java/pythagoras/d/IdentityTransform.java new file mode 100644 index 0000000..267e388 --- /dev/null +++ b/src/main/java/pythagoras/d/IdentityTransform.java @@ -0,0 +1,113 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * Implements the identity transform. + */ +public class IdentityTransform extends AbstractTransform +{ + /** Identifies the identity transform in {@link #generality}. */ + public static final int GENERALITY = 0; + + @Override // from Transform + public double uniformScale () { + return 1; + } + + @Override // from Transform + public double scaleX () { + return 1; + } + + @Override // from Transform + public double scaleY () { + return 1; + } + + @Override // from Transform + public double rotation () { + return 0; + } + + @Override // from Transform + public double tx () { + return 0; + } + + @Override // from Transform + public double ty () { + return 0; + } + + @Override // from Transform + public Transform invert () { + return this; + } + + @Override // from Transform + public Transform concatenate (Transform other) { + return other; + } + + @Override // from Transform + public Transform preConcatenate (Transform other) { + return other; + } + + @Override // from Transform + public Transform lerp (Transform other, double t) { + throw new UnsupportedOperationException(); // TODO + } + + @Override // from Transform + public Point transform (IPoint p, Point into) { + return into.set(p); + } + + @Override // from Transform + public void transform (IPoint[] src, int srcOff, Point[] dst, int dstOff, int count) { + for (int ii = 0; ii < count; ii++) { + transform(src[srcOff++], dst[dstOff++]); + } + } + + @Override // from Transform + public void transform (double[] src, int srcOff, double[] dst, int dstOff, int count) { + for (int ii = 0; ii < count; ii++) { + dst[dstOff++] = src[srcOff++]; + } + } + + @Override // from Transform + public Point inverseTransform (IPoint p, Point into) { + return into.set(p); + } + + @Override // from Transform + public Vector transform (IVector v, Vector into) { + return into.set(v); + } + + @Override // from Transform + public Vector inverseTransform (IVector v, Vector into) { + return into.set(v); + } + + @Override // from Transform + public Transform clone () { + return this; + } + + @Override // from Transform + public int generality () { + return GENERALITY; + } + + @Override + public String toString () { + return "ident"; + } +} diff --git a/src/main/java/pythagoras/d/IntersectPoint.java b/src/main/java/pythagoras/d/IntersectPoint.java index 8503b17..7460249 100644 --- a/src/main/java/pythagoras/d/IntersectPoint.java +++ b/src/main/java/pythagoras/d/IntersectPoint.java @@ -36,31 +36,31 @@ class IntersectPoint this.y = y; } - public int getBegIndex (boolean isCurrentArea) { + public int begIndex (boolean isCurrentArea) { return isCurrentArea ? begIndex1 : begIndex2; } - public int getEndIndex (boolean isCurrentArea) { + public int endIndex (boolean isCurrentArea) { return isCurrentArea ? endIndex1 : endIndex2; } - public int getRuleIndex (boolean isCurrentArea) { + public int ruleIndex (boolean isCurrentArea) { return isCurrentArea ? ruleIndex1 : ruleIndex2; } - public double getParam (boolean isCurrentArea) { + public double param (boolean isCurrentArea) { return isCurrentArea ? param1 : param2; } - public int getRule (boolean isCurrentArea) { + public int rule (boolean isCurrentArea) { return isCurrentArea ? rule1 : rule2; } - public double getX () { + public double x () { return x; } - public double getY () { + public double y () { return y; } diff --git a/src/main/java/pythagoras/d/Line.java b/src/main/java/pythagoras/d/Line.java index e778903..db03993 100644 --- a/src/main/java/pythagoras/d/Line.java +++ b/src/main/java/pythagoras/d/Line.java @@ -57,26 +57,26 @@ public class Line extends AbstractLine implements Serializable * Sets the start and end of this line to the specified points. */ public void setLine (IPoint p1, IPoint p2) { - setLine(p1.getX(), p1.getY(), p2.getY(), p2.getY()); + setLine(p1.x(), p1.y(), p2.y(), p2.y()); } @Override // from interface ILine - public double getX1 () { + public double x1 () { return x1; } @Override // from interface ILine - public double getY1 () { + public double y1 () { return y1; } @Override // from interface ILine - public double getX2 () { + public double x2 () { return x2; } @Override // from interface ILine - public double getY2 () { + public double y2 () { return y2; } } diff --git a/src/main/java/pythagoras/d/Lines.java b/src/main/java/pythagoras/d/Lines.java index 69bdb33..ccfcc86 100644 --- a/src/main/java/pythagoras/d/Lines.java +++ b/src/main/java/pythagoras/d/Lines.java @@ -80,8 +80,7 @@ public class Lines /** * Returns the distance from the specified point to the specified line. */ - public static double pointLineDist (double px, double py, - double x1, double y1, double x2, double y2) { + public static double pointLineDist (double px, double py, double x1, double y1, double x2, double y2) { return Math.sqrt(pointLineDistSq(px, py, x1, y1, x2, y2)); } @@ -119,8 +118,7 @@ public class Lines /** * Returns the distance between the specified point and the specified line segment. */ - public static double pointSegDist (double px, double py, - double x1, double y1, double x2, double y2) { + public static double pointSegDist (double px, double py, double x1, double y1, double x2, double y2) { return Math.sqrt(pointSegDistSq(px, py, x1, y1, x2, y2)); } @@ -130,8 +128,7 @@ public class Lines * * See http://download.oracle.com/javase/6/docs/api/java/awt/geom/Line2D.html */ - public static int relativeCCW (double px, double py, - double x1, double y1, double x2, double y2) { + public static int relativeCCW (double px, double py, double x1, double y1, double x2, double y2) { // A = (x2-x1, y2-y1) // P = (px-x1, py-y1) x2 -= x1; diff --git a/src/main/java/pythagoras/d/MathUtil.java b/src/main/java/pythagoras/d/MathUtil.java new file mode 100644 index 0000000..aded971 --- /dev/null +++ b/src/main/java/pythagoras/d/MathUtil.java @@ -0,0 +1,230 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * Math utility methods. + */ +public class MathUtil +{ + /** A small number. */ + public static final double EPSILON = 0.00001f; + + /** The circle constant, Tau (τ) http://tauday.com/ */ + public static final double TAU = (Math.PI * 2); + + /** Twice Pi. */ + public static final double TWO_PI = TAU; + + /** Pi times one half. */ + public static final double HALF_PI = (Math.PI * 0.5); + + /** + * A cheaper version of {@link Math#round} that doesn't handle the special cases. + */ + public static int round (double v) + { + return (v < 0f) ? (int)(v - 0.5f) : (int)(v + 0.5f); + } + + /** + * Returns the floor of v as an integer without calling the relatively expensive + * {@link Math#floor}. + */ + public static int ifloor (double v) + { + int iv = (int)v; + return (v < 0f) ? ((iv == v || iv == Integer.MIN_VALUE) ? iv : (iv - 1)) : iv; + } + + /** + * Returns the ceiling of v as an integer without calling the relatively expensive + * {@link Math#ceil}. + */ + public static int iceil (double v) + { + int iv = (int)v; + return (v > 0f) ? ((iv == v || iv == Integer.MAX_VALUE) ? iv : (iv + 1)) : iv; + } + + /** + * Clamps a value to the range [lower, upper]. + */ + public static double clamp (double v, double lower, double upper) + { + return Math.min(Math.max(v, lower), upper); + } + + /** + * Rounds a value to the nearest multiple of a target. + */ + public static double roundNearest (double v, double target) + { + target = Math.abs(target); + if (v >= 0) { + return target * Math.floor((v + 0.5f * target) / target); + } else { + return target * Math.ceil((v - 0.5f * target) / target); + } + } + + /** + * Checks whether the value supplied is in [lower, upper]. + */ + public static boolean isWithin (double v, double lower, double upper) + { + return v >= lower && v <= upper; + } + + /** + * Returns a random value according to the normal distribution with the provided mean and + * standard deviation. + * + * @param normal a normally distributed random value. + * @param mean the desired mean. + * @param stddev the desired standard deviation. + */ + public static double normal (double normal, double mean, double stddev) + { + return stddev*normal + mean; + } + + /** + * Returns a random value according to the exponential distribution with the provided mean. + * + * @param random a uniformly distributed random value. + * @param mean the desired mean. + */ + public static double exponential (double random, double mean) + { + return -Math.log(1f - random) * mean; + } + + /** + * Linearly interpolates between two angles, taking the shortest path around the circle. + * This assumes that both angles are in [-pi, +pi]. + */ + public static double lerpa (double a1, double a2, double t) + { + double ma1 = mirrorAngle(a1), ma2 = mirrorAngle(a2); + double d = Math.abs(a2 - a1), md = Math.abs(ma1 - ma2); + return (d < md) ? lerp(a1, a2, t) : mirrorAngle(lerp(ma1, ma2, t)); + } + + /** + * Linearly interpolates between v1 and v2 by the parameter t. + */ + public static double lerp (double v1, double v2, double t) + { + return v1 + t*(v2 - v1); + } + + /** + * Determines whether two values are "close enough" to equal. + */ + public static boolean epsilonEquals (double v1, double v2) + { + return Math.abs(v1 - v2) < EPSILON; + } + + /** + * Returns the (shortest) distance between two angles, assuming that both angles are in + * [-pi, +pi]. + */ + public static double angularDistance (double a1, double a2) + { + double ma1 = mirrorAngle(a1), ma2 = mirrorAngle(a2); + return Math.min(Math.abs(a1 - a2), Math.abs(ma1 - ma2)); + } + + /** + * Returns the (shortest) difference between two angles, assuming that both angles are in + * [-pi, +pi]. + */ + public static double angularDifference (double a1, double a2) + { + double ma1 = mirrorAngle(a1), ma2 = mirrorAngle(a2); + double diff = a1 - a2, mdiff = ma2 - ma1; + return (Math.abs(diff) < Math.abs(mdiff)) ? diff : mdiff; + } + + /** + * Returns an angle in the range [-pi, pi]. + */ + public static double normalizeAngle (double a) + { + while (a < -Math.PI) { + a += TWO_PI; + } + while (a > Math.PI) { + a -= TWO_PI; + } + return a; + } + + /** + * Returns an angle in the range [0, 2pi]. + */ + public static double normalizeAnglePositive (double a) + { + while (a < 0f) { + a += TWO_PI; + } + while (a > TWO_PI) { + a -= TWO_PI; + } + return a; + } + + /** + * Returns the mirror angle of the specified angle (assumed to be in [-pi, +pi]). + */ + public static double mirrorAngle (double a) + { + return (a > 0f ? Math.PI : -Math.PI) - a; + } + + /** + * Sets the number of decimal places to show when formatting values. By default, they are + * formatted to three decimal places. + */ + public static void setToStringDecimalPlaces (int places) { + if (places < 0) throw new IllegalArgumentException("Decimal places must be >= 0."); + TO_STRING_DECIMAL_PLACES = places; + } + + /** + * Formats the supplied doubleing point value, truncated to the currently configured number of + * decimal places. The value is also always preceded by a sign (e.g. +1.0 or -0.5). + */ + public static String toString (double value) + { + StringBuilder buf = new StringBuilder(); + if (value >= 0) buf.append("+"); + else { + buf.append("-"); + value = -value; + } + int ivalue = (int)value; + buf.append(ivalue); + if (TO_STRING_DECIMAL_PLACES > 0) { + buf.append("."); + for (int ii = 0; ii < TO_STRING_DECIMAL_PLACES; ii++) { + value = (value - ivalue) * 10; + ivalue = (int)value; + buf.append(ivalue); + } + // trim trailing zeros + for (int ii = 0; ii < TO_STRING_DECIMAL_PLACES-1; ii++) { + if (buf.charAt(buf.length()-1) == '0') { + buf.setLength(buf.length()-1); + } + } + } + return buf.toString(); + } + + protected static int TO_STRING_DECIMAL_PLACES = 3; +} diff --git a/src/main/java/pythagoras/d/NonUniformTransform.java b/src/main/java/pythagoras/d/NonUniformTransform.java new file mode 100644 index 0000000..ad4c1e8 --- /dev/null +++ b/src/main/java/pythagoras/d/NonUniformTransform.java @@ -0,0 +1,259 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * Implements a uniform (translation, rotation, scaleX, scaleY) transform. + */ +public class NonUniformTransform extends AbstractTransform +{ + /** Identifies the uniform transform in {@link #generality}. */ + public static final int GENERALITY = 3; + + /** The scale components of this transform. */ + public double scaleX, scaleY; + + /** The rotation component of this transform (in radians). */ + public double rotation; + + /** The translation components of this transform. */ + public double tx, ty; + + /** Creates a uniform transform with zero translation and rotation, and unit scale. */ + public NonUniformTransform () { + this.scaleX = this.scaleY = 1; + } + + /** Creates a uniform transform with the specified translation, rotation and scale. */ + public NonUniformTransform (double scaleX, double scaleY, double rotation, double tx, double ty) { + setScale(scaleX, scaleY); + setRotation(rotation); + setTranslation(tx, ty); + } + + @Override // from Transform + public double uniformScale () { + return (scaleX + scaleY) / 2; // TODO: is this sane + } + + @Override // from Transform + public double scaleX () { + return scaleX; + } + + @Override // from Transform + public double scaleY () { + return scaleY; + } + + @Override // from Transform + public double rotation () { + return rotation; + } + + @Override // from Transform + public double tx () { + return tx; + } + + @Override // from Transform + public double ty () { + return ty; + } + + @Override // from Transform + public Transform setUniformScale (double scale) { + setScaleX(scale); + setScaleY(scale); + return this; + } + + @Override // from Transform + public Transform setScaleX (double scaleX) { + if (scaleX == 0) throw new IllegalArgumentException("Scale (x) must not be zero."); + this.scaleX = scaleX; + return this; + } + + @Override // from Transform + public Transform setScaleY (double scaleY) { + if (scaleY == 0) throw new IllegalArgumentException("Scale (y) must not be zero."); + this.scaleY = scaleY; + return this; + } + + @Override // from Transform + public Transform setRotation (double angle) { + this.rotation = angle; + return this; + } + + @Override // from Transform + public Transform setTx (double tx) { + this.tx = tx; + return this; + } + + @Override // from Transform + public Transform setTy (double ty) { + this.ty = ty; + return this; + } + + @Override // from Transform + public Transform uniformScale (double scale) { + return scale(scale, scale); + } + + @Override // from Transform + public Transform scaleX (double scaleX) { + if (scaleX == 0) throw new IllegalArgumentException("Scale (x) must not be zero."); + this.tx *= scaleX; + this.scaleX *= scaleX; + return this; + } + + @Override // from Transform + public Transform scaleY (double scaleY) { + if (scaleY == 0) throw new IllegalArgumentException("Scale (y) must not be zero."); + this.ty *= scaleX; + this.scaleY *= scaleY; + return this; + } + + @Override // from Transform + public Transform rotate (double angle) { + double otx = this.tx, oty = this.ty; + if (otx != 0 || oty != 0) { + double sina = Math.sin(angle), cosa = Math.cos(angle); + this.tx = otx*cosa - oty*sina; + this.ty = otx*sina + oty*cosa; + } + this.rotation += angle; + return this; + } + + @Override // from Transform + public Transform translateX (double tx) { + this.tx += tx; + return this; + } + + @Override // from Transform + public Transform translateY (double ty) { + this.ty += ty; + return this; + } + + @Override // from Transform + public Transform invert () { + Vector iscale = new Vector(1f / scaleX, 1f / scaleY); + Vector t = new Vector(tx, ty).negateLocal().rotateLocal(-rotation).multLocal(iscale); + return new NonUniformTransform(iscale.x, iscale.y, -rotation, t.x, t.y); + } + + @Override // from Transform + public Transform concatenate (Transform other) { + if (generality() < other.generality()) { + return other.preConcatenate(this); + } + + double otx = other.tx(), oty = other.ty(); + double sina = Math.sin(rotation), cosa = Math.cos(rotation); + double ntx = (otx*cosa - oty*sina) * scaleX + tx(); + double nty = (otx*sina + oty*cosa) * scaleY + ty(); + + double nrotation = MathUtil.normalizeAngle(rotation + other.rotation()); + double nscaleX = scaleX * other.scaleX(); + double nscaleY = scaleY * other.scaleY(); + return new NonUniformTransform(nscaleX, nscaleY, nrotation, ntx, nty); + } + + @Override // from Transform + public Transform preConcatenate (Transform other) { + if (generality() < other.generality()) { + return other.concatenate(this); + } + + double tx = tx(), ty = ty(); + double sina = Math.sin(other.rotation()), cosa = Math.cos(other.rotation()); + double ntx = (tx*cosa - ty*sina) * other.scaleX() + other.tx(); + double nty = (tx*sina + ty*cosa) * other.scaleY() + other.ty(); + double nrotation = MathUtil.normalizeAngle(other.rotation() + rotation); + double nscaleX = other.scaleX() * scaleX; + double nscaleY = other.scaleY() * scaleY; + return new NonUniformTransform(nscaleX, nscaleY, nrotation, ntx, nty); + } + + @Override // from Transform + public Transform lerp (Transform other, double t) { + if (generality() < other.generality()) { + return other.lerp(this, -t); // TODO: is this correct? + } + + double ntx = MathUtil.lerpa(tx, other.tx(), t); + double nty = MathUtil.lerpa(ty, other.ty(), t); + double nrotation = MathUtil.lerpa(rotation, other.rotation(), t); + double nscaleX = MathUtil.lerp(scaleX, other.scaleX(), t); + double nscaleY = MathUtil.lerp(scaleY, other.scaleY(), t); + return new NonUniformTransform(nscaleX, nscaleY, nrotation, ntx, nty); + } + + @Override // from Transform + public Point transform (IPoint p, Point into) { + return Points.transform(p.x(), p.y(), scaleX, scaleY, rotation, tx, ty, into); + } + + @Override // from Transform + public void transform (IPoint[] src, int srcOff, Point[] dst, int dstOff, int count) { + double sina = Math.sin(rotation), cosa = Math.cos(rotation); + for (int ii = 0; ii < count; ii++) { + IPoint s = src[srcOff++]; + Points.transform(s.x(), s.y(), scaleX, scaleY, sina, cosa, tx, ty, dst[dstOff++]); + } + } + + @Override // from Transform + public void transform (double[] src, int srcOff, double[] dst, int dstOff, int count) { + Point p = new Point(); + double sina = Math.sin(rotation), cosa = Math.cos(rotation); + for (int ii = 0; ii < count; ii++) { + Points.transform(src[srcOff++], src[srcOff++], scaleX, scaleY, sina, cosa, tx, ty, p); + dst[dstOff++] = p.x; + dst[dstOff++] = p.y; + } + } + + @Override // from Transform + public Point inverseTransform (IPoint p, Point into) { + return Points.inverseTransform(p.x(), p.y(), scaleX, scaleY, rotation, tx, ty, into); + } + + @Override // from Transform + public Vector transform (IVector v, Vector into) { + return Vectors.transform(v.x(), v.y(), scaleX, scaleY, rotation, into); + } + + @Override // from Transform + public Vector inverseTransform (IVector v, Vector into) { + return Vectors.inverseTransform(v.x(), v.y(), scaleX, scaleY, rotation, into); + } + + @Override // from Transform + public Transform clone () { + return new NonUniformTransform(scaleX, scaleY, rotation, tx, ty); + } + + @Override // from Transform + public int generality () { + return GENERALITY; + } + + @Override + public String toString () { + return "nonunif [scale=" + scale() + ", rot=" + rotation + + ", trans=" + translation() + "]"; + } +} diff --git a/src/main/java/pythagoras/d/Path.java b/src/main/java/pythagoras/d/Path.java index c9ab395..df98ed2 100644 --- a/src/main/java/pythagoras/d/Path.java +++ b/src/main/java/pythagoras/d/Path.java @@ -35,8 +35,8 @@ public final class Path implements IShape, Cloneable public Path (IShape shape) { this(WIND_NON_ZERO, BUFFER_SIZE); - PathIterator p = shape.getPathIterator(null); - setWindingRule(p.getWindingRule()); + PathIterator p = shape.pathIterator(null); + setWindingRule(p.windingRule()); append(p, false); } @@ -47,7 +47,7 @@ public final class Path implements IShape, Cloneable this.rule = rule; } - public int getWindingRule () { + public int windingRule () { return rule; } @@ -98,7 +98,7 @@ public final class Path implements IShape, Cloneable } public void append (IShape shape, boolean connect) { - PathIterator p = shape.getPathIterator(null); + PathIterator p = shape.pathIterator(null); append(p, connect); } @@ -135,7 +135,7 @@ public final class Path implements IShape, Cloneable } } - public Point getCurrentPoint () { + public Point currentPoint () { if (typeSize == 0) { return null; } @@ -157,11 +157,11 @@ public final class Path implements IShape, Cloneable pointSize = 0; } - public void transform (AffineTransform t) { + public void transform (Transform t) { t.transform(points, 0, points, 0, pointSize / 2); } - public IShape createTransformedShape (AffineTransform t) { + public IShape createTransformedShape (Transform t) { Path p = clone(); if (t != null) { p.transform(t); @@ -170,12 +170,12 @@ public final class Path implements IShape, Cloneable } @Override // from interface IShape - public Rectangle getBounds () { - return getBounds(new Rectangle()); + public Rectangle bounds () { + return bounds(new Rectangle()); } @Override // from interface IShape - public Rectangle getBounds (Rectangle target) { + public Rectangle bounds (Rectangle target) { double rx1, ry1, rx2, ry2; if (pointSize == 0) { rx1 = ry1 = rx2 = ry2 = 0f; @@ -205,7 +205,7 @@ public final class Path implements IShape, Cloneable @Override // from interface IShape public boolean isEmpty () { // TODO: will this be insanely difficult to do correctly? - return getBounds().isEmpty(); + return bounds().isEmpty(); } @Override // from interface IShape @@ -227,27 +227,27 @@ public final class Path implements IShape, Cloneable @Override // from interface IShape public boolean contains (IPoint p) { - return contains(p.getX(), p.getY()); + return contains(p.x(), p.y()); } @Override // from interface IShape public boolean contains (IRectangle r) { - return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + return contains(r.x(), r.y(), r.width(), r.height()); } @Override // from interface IShape public boolean intersects (IRectangle r) { - return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + return intersects(r.x(), r.y(), r.width(), r.height()); } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform t) { + public PathIterator pathIterator (Transform t) { return new Iterator(this, t); } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform t, double flatness) { - return new FlatteningPathIterator(getPathIterator(t), flatness); + public PathIterator pathIterator (Transform t, double flatness) { + return new FlatteningPathIterator(pathIterator(t), flatness); } // @Override // can't declare @Override due to GWT @@ -309,19 +309,19 @@ public final class Path implements IShape, Cloneable private Path p; /** The path iterator transformation. */ - private AffineTransform t; + private Transform t; Iterator (Path path) { this(path, null); } - Iterator (Path path, AffineTransform at) { + Iterator (Path path, Transform at) { this.p = path; this.t = at; } - @Override public int getWindingRule () { - return p.getWindingRule(); + @Override public int windingRule () { + return p.windingRule(); } @Override public boolean isDone () { diff --git a/src/main/java/pythagoras/d/PathIterator.java b/src/main/java/pythagoras/d/PathIterator.java index b0c2f65..349bc62 100644 --- a/src/main/java/pythagoras/d/PathIterator.java +++ b/src/main/java/pythagoras/d/PathIterator.java @@ -36,7 +36,7 @@ public interface PathIterator /** * Returns the winding rule used to determine the interior of this path. */ - int getWindingRule (); + int windingRule (); /** * Returns true if this path has no additional segments. diff --git a/src/main/java/pythagoras/d/Point.java b/src/main/java/pythagoras/d/Point.java index 0ef753e..040fb78 100644 --- a/src/main/java/pythagoras/d/Point.java +++ b/src/main/java/pythagoras/d/Point.java @@ -27,53 +27,55 @@ public class Point extends AbstractPoint implements Serializable * Constructs a point at the specified coordinates. */ public Point (double x, double y) { - setLocation(x, y); + set(x, y); } /** * Constructs a point with coordinates equal to the supplied point. */ public Point (IPoint p) { - setLocation(p.getX(), p.getY()); + set(p.x(), p.y()); } - /** - * Sets the coordinates of this point to be equal to those of the supplied point. - */ - public void setLocation (IPoint p) { - setLocation(p.getX(), p.getY()); + /** Sets the coordinates of this point to be equal to those of the supplied point. + * @return a reference to this this, for chaining. */ + public Point set (IPoint p) { + return set(p.x(), p.y()); } - /** - * Sets the coordinates of this point to the supplied values. - */ - public void setLocation (double x, double y) { + /** Sets the coordinates of this point to the supplied values. + * @return a reference to this this, for chaining. */ + public Point set (double x, double y) { this.x = x; this.y = y; + return this; } - /** - * A synonym for {@link #setLocation}. - */ - public void move (double x, double y) { - setLocation(x, y); + /** Multiplies this point by a scale factor. + * @return a a reference to this point, for chaining. */ + public Point multLocal (double s) { + return mult(s, this); } - /** - * Translates this point by the specified offset. - */ - public void translate (double dx, double dy) { - x += dx; - y += dy; + /** Translates this point by the specified offset. + * @return a reference to this point, for chaining. */ + public Point addLocal (double dx, double dy) { + return add(dx, dy, this); + } + + /** Rotates this point in-place by the specified angle. + * @return a reference to this point, for chaining. */ + public Point rotateLocal (double angle) { + return rotate(angle, this); } @Override // from interface IPoint - public double getX () { + public double x () { return x; } @Override // from interface IPoint - public double getY () { + public double y () { return y; } } diff --git a/src/main/java/pythagoras/d/Points.java b/src/main/java/pythagoras/d/Points.java index b813d11..1604f07 100644 --- a/src/main/java/pythagoras/d/Points.java +++ b/src/main/java/pythagoras/d/Points.java @@ -9,6 +9,9 @@ package pythagoras.d; */ public class Points { + /** The point at the origin. */ + public static final IPoint ZERO = new Point(0f, 0f); + /** * Returns the squared Euclidean distance between the specified two points. */ @@ -25,16 +28,37 @@ public class Points return Math.sqrt(distanceSq(x1, y1, x2, y2)); } + /** Transforms a point as specified, storing the result in the point provided. + * @return a reference to the result point, for chaining. */ + public static Point transform (double x, double y, double sx, double sy, double rotation, + double tx, double ty, Point result) { + return transform(x, y, sx, sy, Math.sin(rotation), Math.cos(rotation), tx, ty, + result); + } + + /** Transforms a point as specified, storing the result in the point provided. + * @return a reference to the result point, for chaining. */ + public static Point transform (double x, double y, double sx, double sy, double sina, double cosa, + double tx, double ty, Point result) { + return result.set((x*cosa - y*sina) * sx + tx, (x*sina + y*cosa) * sy + ty); + } + + /** Inverse transforms a point as specified, storing the result in the point provided. + * @return a reference to the result point, for chaining. */ + public static Point inverseTransform (double x, double y, double sx, double sy, double rotation, + double tx, double ty, Point result) { + x -= tx; y -= ty; // untranslate + double sinnega = Math.sin(-rotation), cosnega = Math.cos(-rotation); + double nx = (x * cosnega - y * sinnega); // unrotate + double ny = (x * sinnega + y * cosnega); + return result.set(nx / sx, ny / sy); // unscale + } + /** * Returns a string describing the supplied point, of the form +x+y, * +x-y, -x-y, etc. */ public static String pointToString (double x, double y) { - StringBuilder buf = new StringBuilder(); - if (x >= 0) buf.append("+"); - buf.append(x); - if (y >= 0) buf.append("+"); - buf.append(y); - return buf.toString(); + return MathUtil.toString(x) + MathUtil.toString(y); } } diff --git a/src/main/java/pythagoras/d/QuadCurve.java b/src/main/java/pythagoras/d/QuadCurve.java index f6e456d..bad9ed9 100644 --- a/src/main/java/pythagoras/d/QuadCurve.java +++ b/src/main/java/pythagoras/d/QuadCurve.java @@ -58,7 +58,7 @@ public class QuadCurve extends AbstractQuadCurve implements Serializable * 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()); + setCurve(p1.x(), p1.y(), cp.x(), cp.y(), p2.x(), p2.y()); } /** @@ -76,9 +76,9 @@ public class QuadCurve extends AbstractQuadCurve implements Serializable * specified offset in the {@code 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()); + setCurve(points[offset + 0].x(), points[offset + 0].y(), + points[offset + 1].x(), points[offset + 1].y(), + points[offset + 2].x(), points[offset + 2].y()); } /** @@ -86,37 +86,37 @@ public class QuadCurve extends AbstractQuadCurve implements Serializable * curve. */ public void setCurve (IQuadCurve curve) { - setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX(), curve.getCtrlY(), - curve.getX2(), curve.getY2()); + setCurve(curve.x1(), curve.y1(), curve.ctrlX(), curve.ctrlY(), + curve.x2(), curve.y2()); } @Override // from interface IQuadCurve - public double getX1 () { + public double x1 () { return x1; } @Override // from interface IQuadCurve - public double getY1 () { + public double y1 () { return y1; } @Override // from interface IQuadCurve - public double getCtrlX () { + public double ctrlX () { return ctrlx; } @Override // from interface IQuadCurve - public double getCtrlY () { + public double ctrlY () { return ctrly; } @Override // from interface IQuadCurve - public double getX2 () { + public double x2 () { return x2; } @Override // from interface IQuadCurve - public double getY2 () { + public double y2 () { return y2; } } diff --git a/src/main/java/pythagoras/d/QuadCurves.java b/src/main/java/pythagoras/d/QuadCurves.java index 57b0a53..90c4d31 100644 --- a/src/main/java/pythagoras/d/QuadCurves.java +++ b/src/main/java/pythagoras/d/QuadCurves.java @@ -9,35 +9,35 @@ package pythagoras.d; */ public class QuadCurves { - public static double getFlatnessSq (double x1, double y1, double ctrlx, double ctrly, + public static double flatnessSq (double x1, double y1, double ctrlx, double ctrly, double x2, double y2) { return Lines.pointSegDistSq(ctrlx, ctrly, x1, y1, x2, y2); } - public static double getFlatnessSq (double[] coords, int offset) { + public static double flatnessSq (double[] 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 double getFlatness (double x1, double y1, double ctrlx, double ctrly, + public static double flatness (double x1, double y1, double ctrlx, double ctrly, double x2, double y2) { return Lines.pointSegDist(ctrlx, ctrly, x1, y1, x2, y2); } - public static double getFlatness (double[] coords, int offset) { + public static double flatness (double[] 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) { - double x1 = src.getX1(); - double y1 = src.getY1(); - double cx = src.getCtrlX(); - double cy = src.getCtrlY(); - double x2 = src.getX2(); - double y2 = src.getY2(); + double x1 = src.x1(); + double y1 = src.y1(); + double cx = src.ctrlX(); + double cy = src.ctrlY(); + double x2 = src.x2(); + double y2 = src.y2(); double cx1 = (x1 + cx) / 2f; double cy1 = (y1 + cy) / 2f; double cx2 = (x2 + cx) / 2f; diff --git a/src/main/java/pythagoras/d/Rectangle.java b/src/main/java/pythagoras/d/Rectangle.java index 873ed19..fca1adf 100644 --- a/src/main/java/pythagoras/d/Rectangle.java +++ b/src/main/java/pythagoras/d/Rectangle.java @@ -33,14 +33,14 @@ public class Rectangle extends AbstractRectangle implements Serializable * Constructs a rectangle with the supplied upper-left corner and dimensions (0,0). */ public Rectangle (IPoint p) { - setBounds(p.getX(), p.getY(), 0, 0); + setBounds(p.x(), p.y(), 0, 0); } /** * Constructs a rectangle with upper-left corner at (0,) and the supplied dimensions. */ public Rectangle (IDimension d) { - setBounds(0, 0, d.getWidth(), d.getHeight()); + setBounds(0, 0, d.width(), d.height()); } /** @@ -48,7 +48,7 @@ public class Rectangle extends AbstractRectangle implements Serializable * dimensions. */ public Rectangle (IPoint p, IDimension d) { - setBounds(p.getX(), p.getY(), d.getWidth(), d.getHeight()); + setBounds(p.x(), p.y(), d.width(), d.height()); } /** @@ -62,7 +62,7 @@ public class Rectangle extends AbstractRectangle implements Serializable * Constructs a rectangle with bounds equal to the supplied rectangle. */ public Rectangle (IRectangle r) { - setBounds(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + setBounds(r.x(), r.y(), r.width(), r.height()); } /** @@ -77,7 +77,7 @@ public class Rectangle extends AbstractRectangle implements Serializable * Sets the upper-left corner of this rectangle to the supplied point. */ public void setLocation (IPoint p) { - setLocation(p.getX(), p.getY()); + setLocation(p.x(), p.y()); } /** @@ -92,7 +92,7 @@ public class Rectangle extends AbstractRectangle implements Serializable * Sets the size of this rectangle to the supplied dimensions. */ public void setSize (IDimension d) { - setSize(d.getWidth(), d.getHeight()); + setSize(d.width(), d.height()); } /** @@ -109,7 +109,7 @@ public class Rectangle extends AbstractRectangle implements Serializable * Sets the bounds of this rectangle to those of the supplied rectangle. */ public void setBounds (IRectangle r) { - setBounds(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + setBounds(r.x(), r.y(), r.width(), r.height()); } /** @@ -147,37 +147,37 @@ public class Rectangle extends AbstractRectangle implements Serializable * Expands the bounds of this rectangle to contain the supplied point. */ public void add (IPoint p) { - add(p.getX(), p.getY()); + add(p.x(), p.y()); } /** * Expands the bounds of this rectangle to contain the supplied rectangle. */ public void add (IRectangle r) { - double x1 = Math.min(x, r.getX()); - double x2 = Math.max(x + width, r.getX() + r.getWidth()); - double y1 = Math.min(y, r.getY()); - double y2 = Math.max(y + height, r.getY() + r.getHeight()); + double x1 = Math.min(x, r.x()); + double x2 = Math.max(x + width, r.x() + r.width()); + double y1 = Math.min(y, r.y()); + double y2 = Math.max(y + height, r.y() + r.height()); setBounds(x1, y1, x2 - x1, y2 - y1); } @Override // from interface IRectangularShape - public double getX () { + public double x () { return x; } @Override // from interface IRectangularShape - public double getY () { + public double y () { return y; } @Override // from interface IRectangularShape - public double getWidth () { + public double width () { return width; } @Override // from interface IRectangularShape - public double getHeight () { + public double height () { return height; } diff --git a/src/main/java/pythagoras/d/Rectangles.java b/src/main/java/pythagoras/d/Rectangles.java index cc33c64..043770e 100644 --- a/src/main/java/pythagoras/d/Rectangles.java +++ b/src/main/java/pythagoras/d/Rectangles.java @@ -13,10 +13,10 @@ public class Rectangles * Intersects the supplied two rectangles, writing the result into {@code dst}. */ public static void intersect (IRectangle src1, IRectangle src2, Rectangle dst) { - double x1 = Math.max(src1.getMinX(), src2.getMinX()); - double y1 = Math.max(src1.getMinY(), src2.getMinY()); - double x2 = Math.min(src1.getMaxX(), src2.getMaxX()); - double y2 = Math.min(src1.getMaxY(), src2.getMaxY()); + double x1 = Math.max(src1.minX(), src2.minX()); + double y1 = Math.max(src1.minY(), src2.minY()); + double x2 = Math.min(src1.maxX(), src2.maxX()); + double y2 = Math.min(src1.maxY(), src2.maxY()); dst.setBounds(x1, y1, x2 - x1, y2 - y1); } @@ -24,10 +24,10 @@ public class Rectangles * Unions the supplied two rectangles, writing the result into {@code dst}. */ public static void union (IRectangle src1, IRectangle src2, Rectangle dst) { - double x1 = Math.min(src1.getMinX(), src2.getMinX()); - double y1 = Math.min(src1.getMinY(), src2.getMinY()); - double x2 = Math.max(src1.getMaxX(), src2.getMaxX()); - double y2 = Math.max(src1.getMaxY(), src2.getMaxY()); + double x1 = Math.min(src1.minX(), src2.minX()); + double y1 = Math.min(src1.minY(), src2.minY()); + double x2 = Math.max(src1.maxX(), src2.maxX()); + double y2 = Math.max(src1.maxY(), src2.maxY()); dst.setBounds(x1, y1, x2 - x1, y2 - y1); } } diff --git a/src/main/java/pythagoras/d/RectangularShape.java b/src/main/java/pythagoras/d/RectangularShape.java index 3e2951e..91e382c 100644 --- a/src/main/java/pythagoras/d/RectangularShape.java +++ b/src/main/java/pythagoras/d/RectangularShape.java @@ -19,7 +19,7 @@ public abstract class RectangularShape implements IRectangularShape * Sets the location and size of the framing rectangle of this shape to the supplied values. */ public void setFrame (IPoint loc, IDimension size) { - setFrame(loc.getX(), loc.getY(), size.getWidth(), size.getHeight()); + setFrame(loc.x(), loc.y(), size.width(), size.height()); } /** @@ -27,7 +27,7 @@ public abstract class RectangularShape implements IRectangularShape * supplied rectangle. */ public void setFrame (IRectangle r) { - setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight()); + setFrame(r.x(), r.y(), r.width(), r.height()); } /** @@ -58,7 +58,7 @@ public abstract class RectangularShape implements IRectangularShape * diagonal line. */ public void setFrameFromDiagonal (IPoint p1, IPoint p2) { - setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + setFrameFromDiagonal(p1.x(), p1.y(), p2.x(), p2.y()); } /** @@ -77,100 +77,100 @@ public abstract class RectangularShape implements IRectangularShape * center and corner points. */ public void setFrameFromCenter (IPoint center, IPoint corner) { - setFrameFromCenter(center.getX(), center.getY(), corner.getX(), corner.getY()); + setFrameFromCenter(center.x(), center.y(), corner.x(), corner.y()); } @Override // from IRectangularShape - public Point getMin () + public Point min () { - return new Point(getMinX(), getMinY()); + return new Point(minX(), minY()); } @Override // from IRectangularShape - public double getMinX () { - return getX(); + public double minX () { + return x(); } @Override // from IRectangularShape - public double getMinY () { - return getY(); + public double minY () { + return y(); } @Override // from IRectangularShape - public Point getMax () + public Point max () { - return new Point(getMaxX(), getMaxY()); + return new Point(maxX(), maxY()); } @Override // from IRectangularShape - public double getMaxX () { - return getX() + getWidth(); + public double maxX () { + return x() + width(); } @Override // from IRectangularShape - public double getMaxY () { - return getY() + getHeight(); + public double maxY () { + return y() + height(); } @Override // from IRectangularShape - public Point getCenter () + public Point center () { - return new Point(getCenterX(), getCenterY()); + return new Point(centerX(), centerY()); } @Override // from IRectangularShape - public double getCenterX () { - return getX() + getWidth() / 2; + public double centerX () { + return x() + width() / 2; } @Override // from IRectangularShape - public double getCenterY () { - return getY() + getHeight() / 2; + public double centerY () { + return y() + height() / 2; } @Override // from IRectangularShape - public Rectangle getFrame () { - return getBounds(); + public Rectangle frame () { + return bounds(); } @Override // from IRectangularShape - public Rectangle getFrame (Rectangle target) { - return getBounds(target); + public Rectangle frame (Rectangle target) { + return bounds(target); } @Override // from interface IShape public boolean isEmpty () { - return getWidth() <= 0 || getHeight() <= 0; + return width() <= 0 || height() <= 0; } @Override // from interface IShape public boolean contains (IPoint point) { - return contains(point.getX(), point.getY()); + return contains(point.x(), point.y()); } @Override // from interface IShape public boolean contains (IRectangle rect) { - return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); + return contains(rect.x(), rect.y(), rect.width(), rect.height()); } @Override // from interface IShape public boolean intersects (IRectangle rect) { - return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); + return intersects(rect.x(), rect.y(), rect.width(), rect.height()); } @Override // from interface IShape - public Rectangle getBounds () { - return getBounds(new Rectangle()); + public Rectangle bounds () { + return bounds(new Rectangle()); } @Override // from interface IShape - public Rectangle getBounds (Rectangle target) { - target.setBounds(getX(), getY(), getWidth(), getHeight()); + public Rectangle bounds (Rectangle target) { + target.setBounds(x(), y(), width(), height()); return target; } @Override // from interface IShape - public PathIterator getPathIterator (AffineTransform t, double flatness) { - return new FlatteningPathIterator(getPathIterator(t), flatness); + public PathIterator pathIterator (Transform t, double flatness) { + return new FlatteningPathIterator(pathIterator(t), flatness); } } diff --git a/src/main/java/pythagoras/d/RigidTransform.java b/src/main/java/pythagoras/d/RigidTransform.java new file mode 100644 index 0000000..e05b6da --- /dev/null +++ b/src/main/java/pythagoras/d/RigidTransform.java @@ -0,0 +1,196 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * Implements a rigid body (translation, rotation) transform. + */ +public class RigidTransform extends AbstractTransform +{ + /** Identifies the rigid body transform in {@link #generality}. */ + public static final int GENERALITY = 1; + + /** The rotation component of this transform (in radians). */ + public double rotation; + + /** The translation components of this transform. */ + public double tx, ty; + + /** Creates a rigid body transform with zero translation and rotation. */ + public RigidTransform () { + } + + /** Creates a rigid body transform with the specified translation and rotation. */ + public RigidTransform (double rotation, double tx, double ty) { + setRotation(rotation); + setTranslation(tx, ty); + } + + @Override // from Transform + public double uniformScale () { + return 1; + } + + @Override // from Transform + public double scaleX () { + return 1; + } + + @Override // from Transform + public double scaleY () { + return 1; + } + + @Override // from Transform + public double rotation () { + return rotation; + } + + @Override // from Transform + public double tx () { + return tx; + } + + @Override // from Transform + public double ty () { + return ty; + } + + @Override // from Transform + public Transform setRotation (double angle) { + this.rotation = angle; + return this; + } + + @Override // from Transform + public Transform setTx (double tx) { + this.tx = tx; + return this; + } + + @Override // from Transform + public Transform setTy (double ty) { + this.ty = ty; + return this; + } + + @Override // from Transform + public Transform rotate (double angle) { + double otx = this.tx, oty = this.ty; + if (otx != 0 || oty != 0) { + double sina = Math.sin(angle), cosa = Math.cos(angle); + this.tx = otx*cosa - oty*sina; + this.ty = otx*sina + oty*cosa; + } + this.rotation += angle; + return this; + } + + @Override // from Transform + public Transform translateX (double tx) { + this.tx += tx; + return this; + } + + @Override // from Transform + public Transform translateY (double ty) { + this.ty += ty; + return this; + } + + @Override // from Transform + public Transform invert () { + Vector t = translation().negateLocal().rotateLocal(-rotation); + return new RigidTransform(-rotation, t.x, t.y); + } + + @Override // from Transform + public Transform concatenate (Transform other) { + if (generality() < other.generality()) { + return other.preConcatenate(this); + } + + Vector nt = other.translation(); + nt.rotateAndAdd(rotation, translation(), nt); + double nrotation = MathUtil.normalizeAngle(rotation + other.rotation()); + return new RigidTransform(nrotation, nt.x, nt.y); + } + + @Override // from Transform + public Transform preConcatenate (Transform other) { + if (generality() < other.generality()) { + return other.concatenate(this); + } + + Vector nt = translation(); + nt.rotateAndAdd(other.rotation(), other.translation(), nt); + double nrotation = MathUtil.normalizeAngle(other.rotation() + rotation); + return new RigidTransform(nrotation, nt.x, nt.y); + } + + @Override // from Transform + public Transform lerp (Transform other, double t) { + if (generality() < other.generality()) { + return other.lerp(this, -t); // TODO: is this correct? + } + Vector nt = translation().lerpLocal(other.translation(), t); + return new RigidTransform(MathUtil.lerpa(rotation, other.rotation(), t), nt.x, nt.y); + } + + @Override // from Transform + public Point transform (IPoint p, Point into) { + return Points.transform(p.x(), p.y(), 1, 1, rotation, tx, ty, into); + } + + @Override // from Transform + public void transform (IPoint[] src, int srcOff, Point[] dst, int dstOff, int count) { + double sina = Math.sin(rotation), cosa = Math.cos(rotation); + for (int ii = 0; ii < count; ii++) { + IPoint s = src[srcOff++]; + Points.transform(s.x(), s.y(), 1, 1, sina, cosa, tx, ty, dst[dstOff++]); + } + } + + @Override // from Transform + public void transform (double[] src, int srcOff, double[] dst, int dstOff, int count) { + Point p = new Point(); + double sina = Math.sin(rotation), cosa = Math.cos(rotation); + for (int ii = 0; ii < count; ii++) { + Points.transform(src[srcOff++], src[srcOff++], 1, 1, sina, cosa, tx, ty, p); + dst[dstOff++] = p.x; + dst[dstOff++] = p.y; + } + } + + @Override // from Transform + public Point inverseTransform (IPoint p, Point into) { + return Points.inverseTransform(p.x(), p.y(), 1, 1, rotation, tx, ty, into); + } + + @Override // from Transform + public Vector transform (IVector v, Vector into) { + return v.rotate(rotation, into); + } + + @Override // from Transform + public Vector inverseTransform (IVector v, Vector into) { + return v.rotate(-rotation, into); + } + + @Override // from Transform + public Transform clone () { + return new RigidTransform(rotation, tx, ty); + } + + @Override // from Transform + public int generality () { + return GENERALITY; + } + + @Override + public String toString () { + return "rigid [rot=" + rotation + ", trans=" + translation() + "]"; + } +} diff --git a/src/main/java/pythagoras/d/RoundRectangle.java b/src/main/java/pythagoras/d/RoundRectangle.java index fbdb2a5..c87db15 100644 --- a/src/main/java/pythagoras/d/RoundRectangle.java +++ b/src/main/java/pythagoras/d/RoundRectangle.java @@ -61,37 +61,37 @@ public class RoundRectangle extends AbstractRoundRectangle implements Serializab * rectangle. */ public void setRoundRect (IRoundRectangle rr) { - setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(), - rr.getArcWidth(), rr.getArcHeight()); + setRoundRect(rr.x(), rr.y(), rr.width(), rr.height(), + rr.arcWidth(), rr.arcHeight()); } @Override // from interface IRoundRectangle - public double getArcWidth () { + public double arcWidth () { return arcwidth; } @Override // from interface IRoundRectangle - public double getArcHeight () { + public double arcHeight () { return archeight; } @Override // from interface IRectangularShape - public double getX () { + public double x () { return x; } @Override // from interface IRectangularShape - public double getY () { + public double y () { return y; } @Override // from interface IRectangularShape - public double getWidth () { + public double width () { return width; } @Override // from interface IRectangularShape - public double getHeight () { + public double height () { return height; } diff --git a/src/main/java/pythagoras/d/Transform.java b/src/main/java/pythagoras/d/Transform.java new file mode 100644 index 0000000..2e642d6 --- /dev/null +++ b/src/main/java/pythagoras/d/Transform.java @@ -0,0 +1,196 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * Represents a geometric transform. Specialized implementations exist for identity, rigid body, + * uniform, non-uniform, and affine transforms. + */ +public interface Transform +{ + /** Returns the uniform scale applied by this transform. The uniform scale will be approximated + * for non-uniform transforms. */ + double uniformScale (); + + /** Returns the scale vector for this transform. */ + Vector scale (); + + /** Returns the x-component of the scale applied by this transform. Note that this will be + * extracted and therefore approximate for affine transforms. */ + double scaleX (); + + /** Returns the y-component of the scale applied by this transform. Note that this will be + * extracted and therefore approximate for affine transforms. */ + double scaleY (); + + /** Returns the rotation applied by this transform. Note that the rotation is extracted and + * therefore approximate for affine transforms. + * @throws NoninvertibleTransformException if the transform is not invertible. */ + double rotation (); + + /** Returns the translation vector for this transform. */ + Vector translation (); + + /** Returns the x-coordinate of the translation component. */ + double tx (); + + /** Returns the y-coordinate of the translation component. */ + double ty (); + + /** Sets the uniform scale of this transform. + * @return this instance, for chaining. + * @throws IllegalArgumentException if the supplied scale is zero. + * @throws UnsupportedOperationException if the transform is not uniform or greater. */ + Transform setUniformScale (double scale); + + /** Sets the x and y scale of this transform. + * @return this instance, for chaining. + * @throws IllegalArgumentException if either supplied scale is zero. + * @throws UnsupportedOperationException if the transform is not non-uniform or greater. */ + Transform setScale (double scaleX, double scaleY); + + /** Sets the x scale of this transform. + * @return this instance, for chaining. + * @throws IllegalArgumentException if the supplied scale is zero. + * @throws UnsupportedOperationException if the transform is not non-uniform or greater. */ + Transform setScaleX (double scaleX); + + /** Sets the y scale of this transform. + * @return this instance, for chaining. + * @throws IllegalArgumentException if the supplied scale is zero. + * @throws UnsupportedOperationException if the transform is not non-uniform or greater. */ + Transform setScaleY (double scaleY); + + /** Sets the rotation component of this transform. + * @return this instance, for chaining. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + Transform setRotation (double angle); + + /** Sets the translation component of this transform. + * @return this instance, for chaining. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + Transform setTranslation (double tx, double ty); + + /** Sets the x-component of this transform's translation. + * @return this instance, for chaining. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + Transform setTx (double tx); + + /** Sets the y-component of this transform's translation. + * @return this instance, for chaining. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + Transform setTy (double ty); + + /** Sets the affine transform matrix. + * @return this instance, for chaining. + * @throws UnsupportedOperationException if the transform is not affine or greater. */ + Transform setTransform (double m00, double m01, double m10, double m11, + double tx, double ty); + + /** Scales this transform in a uniform manner by the specified amount. + * @return this instance, for chaining. + * @throws IllegalArgumentException if the supplied scale is zero. + * @throws UnsupportedOperationException if the transform is not uniform or greater. */ + Transform uniformScale (double scale); + + /** Scales this transform by the specified amount in the x and y dimensions. + * @return this instance, for chaining. + * @throws IllegalArgumentException if either supplied scale is zero. + * @throws UnsupportedOperationException if the transform is not non-uniform or greater. */ + Transform scale (double scaleX, double scaleY); + + /** Scales this transform by the specified amount in the x dimension. + * @return this instance, for chaining. + * @throws IllegalArgumentException if the supplied scale is zero. + * @throws UnsupportedOperationException if the transform is not non-uniform or greater. */ + Transform scaleX (double scaleX); + + /** Scales this transform by the specified amount in the y dimension. + * @return this instance, for chaining. + * @throws IllegalArgumentException if the supplied scale is zero. + * @throws UnsupportedOperationException if the transform is not non-uniform or greater. */ + Transform scaleY (double scaleY); + + /** Rotates this transform. + * @return this instance, for chaining. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + Transform rotate (double angle); + + /** Translates this transform. + * @return this instance, for chaining. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + Transform translate (double tx, double ty); + + /** Translates this transform in the x dimension. + * @return this instance, for chaining. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + Transform translateX (double tx); + + /** Translates this transform in the y dimension. + * @return this instance, for chaining. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + Transform translateY (double ty); + + /** Returns a new transform that represents the inverse of this transform. + * @throws NoninvertibleTransformException if the transform is not invertible. */ + Transform invert (); + + /** Returns a new transform comprised of the concatenation of {@code other} to this transform + * (i.e. {@code this x other}). */ + Transform concatenate (Transform other); + + /** Returns a new transform comprised of the concatenation of this transform to {@code other} + * (i.e. {@code other x this}). */ + Transform preConcatenate (Transform other); + + /** Returns a new transform comprised of the linear interpolation between this transform and + * the specified other. */ + Transform lerp (Transform other, double t); + + /** Transforms the supplied point, writing the result into {@code into}. + * @param into a point into which to store the result, may be the same object as {@code p}. + * @return {@code into} for chaining. */ + Point transform (IPoint p, Point into); + + /** Transforms the supplied points. + * @param src the points to be transformed. + * @param srcOff the offset into the {@code src} array at which to start. + * @param dst the points into which to store the transformed points. May be {@code src}. + * @param dstOff the offset into the {@code dst} array at which to start. + * @param count the number of points to transform. */ + void transform (IPoint[] src, int srcOff, Point[] dst, int dstOff, int count); + + /** Transforms the supplied points. + * @param src the points to be transformed (as {@code [x, y, x, y, ...]}). + * @param srcOff the offset into the {@code src} array at which to start. + * @param dst the points into which to store the transformed points. May be {@code src}. + * @param dstOff the offset into the {@code dst} array at which to start. + * @param count the number of points to transform. */ + void transform (double[] src, int srcOff, double[] dst, int dstOff, int count); + + /** Inverse transforms the supplied point, writing the result into {@code into}. + * @param into a point into which to store the result, may be the same object as {@code p}. + * @return {@code into}, for chaining. + * @throws NoninvertibleTransformException if the transform is not invertible. */ + Point inverseTransform (IPoint p, Point into); + + /** Transforms the supplied vector, writing the result into {@code into}. + * @param into a vector into which to store the result, may be the same object as {@code v}. + * @return {@code into}, for chaining. */ + Vector transform (IVector v, Vector into); + + /** Inverse transforms the supplied vector, writing the result into {@code into}. + * @param into a vector into which to store the result, may be the same object as {@code v}. + * @return {@code into}, for chaining. + * @throws NoninvertibleTransformException if the transform is not invertible. */ + Vector inverseTransform (IVector v, Vector into); + + /** Returns a clone of this transform. */ + Transform clone (); + + /** Returns an integer that increases monotonically with the generality of the transform + * implementation. Used internally when combining transforms. */ + int generality (); +} diff --git a/src/main/java/pythagoras/d/Transforms.java b/src/main/java/pythagoras/d/Transforms.java new file mode 100644 index 0000000..82649a9 --- /dev/null +++ b/src/main/java/pythagoras/d/Transforms.java @@ -0,0 +1,80 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * {@link Transform} related utility methods. + */ +public class Transforms +{ + /** + * Creates and returns a new shape that is the supplied shape transformed by this transform's + * matrix. + */ + public static IShape createTransformedShape (Transform t, IShape src) { + if (src == null) { + return null; + } + if (src instanceof Path) { + return ((Path)src).createTransformedShape(t); + } + PathIterator path = src.pathIterator(t); + Path dst = new Path(path.windingRule()); + dst.append(path, false); + return dst; + } + + /** + * Multiplies the supplied two affine transforms, storing the result in {@code into}. {@code + * into} may refer to the same instance as {@code a} or {@code b}. + * @return {@code into} for chaining. + */ + public static AffineTransform multiply ( + AffineTransform a, AffineTransform b, AffineTransform into) { + return multiply(a.m00, a.m01, a.m10, a.m11, a.tx, a.ty, + b.m00, b.m01, b.m10, b.m11, b.tx, b.ty, into); + } + + /** + * Multiplies the supplied two affine transforms, storing the result in {@code into}. {@code + * into} may refer to the same instance as {@code a}. + * @return {@code into} for chaining. + */ + public static AffineTransform multiply ( + AffineTransform a, double m00, double m01, double m10, double m11, double tx, double ty, + AffineTransform into) { + return multiply(a.m00, a.m01, a.m10, a.m11, a.tx, a.ty, + m00, m01, m10, m11, tx, ty, into); + } + + /** + * Multiplies the supplied two affine transforms, storing the result in {@code into}. {@code + * into} may refer to the same instance as {@code b}. + * @return {@code into} for chaining. + */ + public static AffineTransform multiply ( + double m00, double m01, double m10, double m11, double tx, double ty, + AffineTransform b, AffineTransform into) { + return multiply(m00, m01, m10, m11, tx, ty, + b.m00, b.m01, b.m10, b.m11, b.tx, b.ty, into); + } + + /** + * Multiplies the supplied two affine transforms, storing the result in {@code into}. + * @return {@code into} for chaining. + */ + public static AffineTransform multiply ( + double am00, double am01, double am10, double am11, double atx, double aty, + double bm00, double bm01, double bm10, double bm11, double btx, double bty, + AffineTransform into) { + into.m00 = am00 * bm00 + am10 * bm01; + into.m01 = am01 * bm00 + am11 * bm01; + into.m10 = am00 * bm10 + am10 * bm11; + into.m11 = am01 * bm10 + am11 * bm11; + into.tx = am00 * btx + am10 * bty + atx; + into.ty = am01 * btx + am11 * bty + aty; + return into; + } +} diff --git a/src/main/java/pythagoras/d/UniformTransform.java b/src/main/java/pythagoras/d/UniformTransform.java new file mode 100644 index 0000000..e6e5326 --- /dev/null +++ b/src/main/java/pythagoras/d/UniformTransform.java @@ -0,0 +1,225 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * Implements a uniform (translation, rotation, scale) transform. + */ +public class UniformTransform extends AbstractTransform +{ + /** Identifies the uniform transform in {@link #generality}. */ + public static final int GENERALITY = 2; + + /** The uniform scale component of this transform. */ + public double scale; + + /** The rotation component of this transform (in radians). */ + public double rotation; + + /** The translation components of this transform. */ + public double tx, ty; + + /** Creates a uniform transform with zero translation and rotation, and unit scale. */ + public UniformTransform () { + setUniformScale(1); + } + + /** Creates a uniform transform with the specified translation, rotation and scale. */ + public UniformTransform (double scale, double rotation, double tx, double ty) { + setUniformScale(scale); + setRotation(rotation); + setTranslation(tx, ty); + } + + @Override // from Transform + public double uniformScale () { + return scale; + } + + @Override // from Transform + public double scaleX () { + return scale; + } + + @Override // from Transform + public double scaleY () { + return scale; + } + + @Override // from Transform + public double rotation () { + return rotation; + } + + @Override // from Transform + public double tx () { + return tx; + } + + @Override // from Transform + public double ty () { + return ty; + } + + @Override // from Transform + public Transform setUniformScale (double scale) { + if (scale == 0) throw new IllegalArgumentException("Scale must be non-zero."); + this.scale = scale; + return this; + } + + @Override // from Transform + public Transform setRotation (double angle) { + this.rotation = angle; + return this; + } + + @Override // from Transform + public Transform setTx (double tx) { + this.tx = tx; + return this; + } + + @Override // from Transform + public Transform setTy (double ty) { + this.ty = ty; + return this; + } + + @Override // from Transform + public Transform uniformScale (double scale) { + if (scale == 0) throw new IllegalArgumentException("Scale must be non-zero."); + this.tx *= scale; + this.ty *= scale; + this.scale *= scale; + return this; + } + + @Override // from Transform + public Transform rotate (double angle) { + double otx = this.tx, oty = this.ty; + if (otx != 0 || oty != 0) { + double sina = Math.sin(angle), cosa = Math.cos(angle); + this.tx = otx*cosa - oty*sina; + this.ty = otx*sina + oty*cosa; + } + this.rotation += angle; + return this; + } + + @Override // from Transform + public Transform translateX (double tx) { + this.tx += tx; + return this; + } + + @Override // from Transform + public Transform translateY (double ty) { + this.ty += ty; + return this; + } + + @Override // from Transform + public Transform invert () { + double nscale = 1f / scale, nrotation = -rotation; + Vector t = translation().negateLocal().rotateLocal(nrotation).multLocal(nscale); + return new UniformTransform(nscale, nrotation, t.x, t.y); + } + + @Override // from Transform + public Transform concatenate (Transform other) { + if (generality() < other.generality()) { + return other.preConcatenate(this); + } + + Vector nt = other.translation(); + nt.rotateScaleAndAdd(rotation, scale, translation(), nt); + double nrotation = MathUtil.normalizeAngle(rotation + other.rotation()); + double nscale = scale * other.uniformScale(); + return new UniformTransform(nscale, nrotation, nt.x, nt.y); + } + + @Override // from Transform + public Transform preConcatenate (Transform other) { + if (generality() < other.generality()) { + return other.concatenate(this); + } + + Vector nt = translation(); + nt.rotateScaleAndAdd(other.rotation(), other.uniformScale(), + other.translation(), nt); + double nrotation = MathUtil.normalizeAngle(other.rotation() + rotation); + double nscale = other.uniformScale() * scale; + return new UniformTransform(nscale, nrotation, nt.x, nt.y); + } + + @Override // from Transform + public Transform lerp (Transform other, double t) { + if (generality() < other.generality()) { + return other.lerp(this, -t); // TODO: is this correct? + } + + Vector nt = translation().lerpLocal(other.translation(), t); + double nrotation = MathUtil.lerpa(rotation, other.rotation(), t); + double nscale = MathUtil.lerp(scale, other.uniformScale(), t); + return new UniformTransform(nscale, nrotation, nt.x, nt.y); + } + + @Override // from Transform + public Point transform (IPoint p, Point into) { + return Points.transform(p.x(), p.y(), scale, scale, rotation, tx, ty, into); + } + + @Override // from Transform + public void transform (IPoint[] src, int srcOff, Point[] dst, int dstOff, int count) { + double sina = Math.sin(rotation), cosa = Math.cos(rotation); + for (int ii = 0; ii < count; ii++) { + IPoint p = src[srcOff++]; + Points.transform(p.x(), p.y(), scale, scale, sina, cosa, tx, ty, dst[dstOff++]); + } + } + + @Override // from Transform + public void transform (double[] src, int srcOff, double[] dst, int dstOff, int count) { + Point p = new Point(); + double sina = Math.sin(rotation), cosa = Math.cos(rotation); + for (int ii = 0; ii < count; ii++) { + Points.transform(src[srcOff++], src[srcOff++], scale, scale, sina, cosa, tx, ty, p); + dst[dstOff++] = p.x; + dst[dstOff++] = p.y; + } + } + + @Override // from Transform + public Point inverseTransform (IPoint p, Point into) { + return Points.inverseTransform(p.x(), p.y(), scale, scale, rotation, tx, ty, into); + } + + @Override // from Transform + public Vector transform (IVector v, Vector into) { + return Vectors.transform(v.x(), v.y(), scale, scale, rotation, into); + } + + @Override // from Transform + public Vector inverseTransform (IVector v, Vector into) { + return Vectors.inverseTransform(v.x(), v.y(), scale, scale, rotation, into); + } + + @Override // from Transform + public Transform clone () { + return new UniformTransform(scale, rotation, tx, ty); + } + + @Override // from Transform + public int generality () { + return GENERALITY; + } + + @Override + public String toString () { + return "uniform [scale=" + scale + ", rot=" + rotation + + ", trans=" + translation() + "]"; + } +} diff --git a/src/main/java/pythagoras/d/Vector.java b/src/main/java/pythagoras/d/Vector.java new file mode 100644 index 0000000..a7bafe9 --- /dev/null +++ b/src/main/java/pythagoras/d/Vector.java @@ -0,0 +1,121 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * Represents a vector in a plane. + */ +public class Vector extends AbstractVector +{ + /** The x-component of the vector. */ + public double x; + + /** The y-component of the vector. */ + public double y; + + /** Creates a vector with the specified x and y components. */ + public Vector (double x, double y) { + set(x, y); + } + + /** Creates a vector equal to {@code other}. */ + public Vector (IVector other) { + set(other); + } + + /** Creates a vector with zero x and y components. */ + public Vector () { + } + + /** Negates this vector in-place. + * @return a reference to this vector, for chaining. */ + public Vector negateLocal () { + return negate(this); + } + + /** Normalizes this vector in-place. + * @return a reference to this vector, for chaining. */ + public Vector normalizeLocal () { + return normalize(this); + } + + /** Multiplies this vector in-place by a scalar. + * @return a reference to this vector, for chaining. */ + public Vector multLocal (double v) { + return mult(v, this); + } + + /** Multiplies this vector in-place by another. + * @return a reference to this vector, for chaining. */ + public Vector multLocal (IVector other) { + return mult(other, this); + } + + /** Adds a vector in-place to this one. + * @return a reference to this vector, for chaining. */ + public Vector addLocal (IVector other) { + return add(other, this); + } + + /** Subtracts a vector in-place from this one. + * @return a reference to this vector, for chaining. */ + public Vector subtractLocal (IVector other) { + return subtract(other, this); + } + + /** Adds a vector in-place to this one. + * @return a reference to this vector, for chaining. */ + public Vector addLocal (double x, double y) { + return add(x, y, this); + } + + /** Adds a scaled vector in-place to this one. + * @return a reference to this vector, for chaining. */ + public Vector addScaledLocal (IVector other, double v) { + return addScaled(other, v, this); + } + + /** Rotates this vector in-place by the specified angle. + * @return a reference to this vector, for chaining. */ + public Vector rotateLocal (double angle) { + return rotate(angle, this); + } + + /** Linearly interpolates between this and {@code other} in-place by the supplied amount. + * @return a reference to this vector, for chaining. */ + public Vector lerpLocal (IVector other, double t) { + return lerp(other, t, this); + } + + /** Copies the elements of another vector. + * @return a reference to this vector, for chaining. */ + public Vector set (IVector other) { + return set(other.x(), other.y()); + } + + /** Copies the elements of an array. + * @return a reference to this vector, for chaining. */ + public Vector set (double[] values) { + return set(values[0], values[1]); + } + + /** Sets all of the elements of the vector. + * @return a reference to this vector, for chaining. */ + public Vector set (double x, double y) { + this.x = x; + this.y = y; + return this; + } + + @Override // from AbstractVector + public double x () { + return x; + } + + @Override // from AbstractVector + public double y () { + return y; + } +} diff --git a/src/main/java/pythagoras/d/Vectors.java b/src/main/java/pythagoras/d/Vectors.java new file mode 100644 index 0000000..dcc661e --- /dev/null +++ b/src/main/java/pythagoras/d/Vectors.java @@ -0,0 +1,79 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.d; + +/** + * Vector-related utility methods. + */ +public class Vectors +{ + /** A unit vector in the X+ direction. */ + public static final IVector UNIT_X = new Vector(1f, 0f); + + /** A unit vector in the Y+ direction. */ + public static final IVector UNIT_Y = new Vector(0f, 1f); + + /** The zero vector. */ + public static final IVector ZERO = new Vector(0f, 0f); + + /** A vector containing the minimum doubleing point value for all components + * (note: the components are -{@link Float#MAX_VALUE}, not {@link Float#MIN_VALUE}). */ + public static final IVector MIN_VALUE = new Vector(-Float.MAX_VALUE, -Float.MAX_VALUE); + + /** A vector containing the maximum doubleing point value for all components. */ + public static final IVector MAX_VALUE = new Vector(Float.MAX_VALUE, Float.MAX_VALUE); + + /** + * Returns the magnitude of the specified vector. + */ + public static final double length (double x, double y) { + return Math.sqrt(lengthSq(x, y)); + } + + /** + * Returns the square of the magnitude of the specified vector. + */ + public static final double lengthSq (double x, double y) { + return (x*x + y*y); + } + + /** + * Transforms a point as specified, storing the result in the point provided. + * @return a reference to the result vector, for chaining. + */ + public static Vector transform (double x, double y, double sx, double sy, double rotation, + Vector result) { + return transform(x, y, sx, sy, Math.sin(rotation), Math.cos(rotation), result); + } + + /** + * Transforms a vector as specified, storing the result in the vector provided. + * @return a reference to the result vector, for chaining. + */ + public static Vector transform (double x, double y, double sx, double sy, double sina, double cosa, + Vector result) { + return result.set((x*cosa - y*sina) * sx, (x*sina + y*cosa) * sy); + } + + /** + * Inverse transforms a point as specified, storing the result in the point provided. + * @return a reference to the result vector, for chaining. + */ + public static Vector inverseTransform (double x, double y, double sx, double sy, double rotation, + Vector result) { + double sinnega = Math.sin(-rotation), cosnega = Math.cos(-rotation); + double nx = (x * cosnega - y * sinnega); // unrotate + double ny = (x * sinnega + y * cosnega); + return result.set(nx / sx, ny / sy); // unscale + } + + /** + * Returns a string describing the supplied vector, of the form +x+y, + * +x-y, -x-y, etc. + */ + public static String vectorToString (double x, double y) { + return MathUtil.toString(x) + MathUtil.toString(y); + } +}