Added methods to concatenate a translation, rotation or scale directly onto an

existing transform.
This commit is contained in:
Michael Bayne
2011-07-06 14:13:21 -07:00
parent 6eda0bb25e
commit 1d7ef7cdf7
9 changed files with 299 additions and 30 deletions
@@ -53,6 +53,50 @@ public abstract class AbstractTransform implements Transform
return this;
}
@Override // from Transform
public Transform uniformScale (float scale) {
throw new UnsupportedOperationException();
}
@Override // from Transform
public Transform scale (float scaleX, float scaleY) {
scaleX(scaleX);
scaleY(scaleY);
return this;
}
@Override // from Transform
public Transform scaleX (float scaleX) {
throw new UnsupportedOperationException();
}
@Override // from Transform
public Transform scaleY (float scaleY) {
throw new UnsupportedOperationException();
}
@Override // from Transform
public Transform rotate (float angle) {
throw new UnsupportedOperationException();
}
@Override // from Transform
public Transform translate (float tx, float ty) {
translateX(tx);
translateY(ty);
return this;
}
@Override // from Transform
public Transform translateX (float tx) {
throw new UnsupportedOperationException();
}
@Override // from Transform
public Transform translateY (float ty) {
throw new UnsupportedOperationException();
}
@Override // from Transform
public Transform setTx (float tx) {
throw new UnsupportedOperationException();
+84 -25
View File
@@ -141,16 +141,9 @@ public class AffineTransform extends AbstractTransform
public Transform setRotation (float angle) {
// extract the scale, then reapply rotation and scale together
float sx = getScaleX(), sy = getScaleY();
float sin = FloatMath.sin(angle), cos = FloatMath.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 = cos * sx; m01 = -sin * sx;
m10 = sin * sy; m11 = cos * sy;
float sina = FloatMath.sin(angle), cosa = FloatMath.cos(angle);
m00 = cosa * sx; m01 = -sina * sx;
m10 = sina * sy; m11 = cosa * sy;
return this;
}
@@ -184,6 +177,45 @@ public class AffineTransform extends AbstractTransform
return this;
}
@Override // from Transform
public Transform uniformScale (float scale) {
return scale(scale, scale);
}
@Override // from Transform
public Transform scaleX (float scaleX) {
m00 *= scaleX;
m01 *= scaleX;
tx *= scaleX;
return this;
}
@Override // from Transform
public Transform scaleY (float scaleY) {
m10 *= scaleY;
m11 *= scaleY;
ty *= scaleY;
return this;
}
@Override // from Transform
public Transform rotate (float angle) {
float sina = FloatMath.sin(angle), cosa = FloatMath.cos(angle);
return multiply(cosa, -sina, sina, cosa, 0, 0, this, this);
}
@Override // from Transform
public Transform translateX (float tx) {
this.tx += tx;
return this;
}
@Override // from Transform
public Transform translateY (float ty) {
this.ty += ty;
return this;
}
@Override // from Transform
public Transform invert () {
// compute the determinant, storing the subdeterminants for later use
@@ -204,8 +236,12 @@ public class AffineTransform extends AbstractTransform
if (generality() < other.generality()) {
return other.preConcatenate(this);
}
return multiply((other instanceof AffineTransform) ?
(AffineTransform)other : new AffineTransform(other));
if (other instanceof AffineTransform) {
return multiply(this, (AffineTransform)other, new AffineTransform());
} else {
AffineTransform oaff = new AffineTransform(other);
return multiply(this, oaff, oaff);
}
}
@Override // from Transform
@@ -213,8 +249,12 @@ public class AffineTransform extends AbstractTransform
if (generality() < other.generality()) {
return other.concatenate(this);
}
return ((other instanceof AffineTransform) ?
(AffineTransform)other : new AffineTransform(other)).multiply(this);
if (other instanceof AffineTransform) {
return multiply((AffineTransform)other, this, new AffineTransform());
} else {
AffineTransform oaff = new AffineTransform(other);
return multiply(oaff, this, oaff);
}
}
@Override // from Transform
@@ -281,7 +321,8 @@ public class AffineTransform extends AbstractTransform
@Override
public String toString () {
return "affine [" + m00 + " " + m01 + " " + m10 + " " + m11 + " " + getTranslation() + "]";
return "affine [" + FloatMath.toString(m00) + " " + FloatMath.toString(m01) + " " +
FloatMath.toString(m10) + " " + FloatMath.toString(m11) + " " + getTranslation() + "]";
}
// we don't publicize this because it might encourage someone to do something stupid like
@@ -291,18 +332,36 @@ public class AffineTransform extends AbstractTransform
other.getTx(), other.getTy());
}
protected AffineTransform multiply (AffineTransform other) {
return multiply(other.m00, other.m01, other.m10, other.m11, other.tx, other.ty);
protected 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);
}
protected AffineTransform multiply (float m00, float m01, float m10, float m11,
float tx, float ty) {
return new AffineTransform(
this.m00 * m00 + this.m01 * m10, this.m00 * m01 + this.m01 * m11,
this.m10 * m00 + this.m11 * m10, this.m10 * m01 + this.m11 * m11,
this.m00 * tx + this.m01 * ty + this.tx, this.m10 * tx + this.m11 * ty + this.ty);
protected static AffineTransform multiply (
AffineTransform a, float m00, float m01, float m10, float m11, float tx, float ty,
AffineTransform into) {
return multiply(a.m00, a.m01, a.m10, a.m11, a.tx, a.ty,
m00, m01, m10, m11, tx, ty, into);
}
/** The min value equivalent to zero. An absolute value < ZERO is considered to be zero. */
private static final float ZERO = 1E-7f;
protected static AffineTransform multiply (
float m00, float m01, float m10, float m11, float tx, float 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);
}
protected static AffineTransform multiply (
float am00, float am01, float am10, float am11, float atx, float aty,
float bm00, float bm01, float bm10, float bm11, float btx, float bty,
AffineTransform into) {
into.m00 = am00 * bm00 + am01 * bm10;
into.m01 = am00 * bm01 + am01 * bm11;
into.m10 = am10 * bm00 + am11 * bm10;
into.m11 = am10 * bm01 + am11 * bm11;
into.tx = am00 * btx + am01 * bty + atx;
into.ty = am10 * btx + am11 * bty + aty;
return into;
}
}
+11
View File
@@ -381,4 +381,15 @@ public class FloatMath
{
return (a > 0f ? PI : -PI) - a;
}
/**
* Returns ~0 if the value is very close to zero, the string value of the float otherwise.
*/
public static String toString (float value)
{
return Math.abs(value) < ZERO ? "~0" : String.valueOf(value);
}
/** The min value equivalent to zero. An absolute value < ZERO is rendered as ~0. */
private static final float ZERO = 1E-7f;
}
@@ -102,6 +102,51 @@ public class NonUniformTransform extends AbstractTransform
return this;
}
@Override // from Transform
public Transform uniformScale (float scale) {
return scale(scale, scale);
}
@Override // from Transform
public Transform scaleX (float 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 (float 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 (float angle) {
float otx = this.tx, oty = this.ty;
if (otx != 0 || oty != 0) {
float sina = FloatMath.sin(angle), cosa = FloatMath.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 (float tx) {
this.tx += tx;
return this;
}
@Override // from Transform
public Transform translateY (float ty) {
this.ty += ty;
return this;
}
@Override // from Transform
public Transform invert () {
Vector iscale = new Vector(1f / scaleX, 1f / scaleY);
+2 -2
View File
@@ -58,9 +58,9 @@ public class Points
public static String pointToString (float x, float y) {
StringBuilder buf = new StringBuilder();
if (x >= 0) buf.append("+");
buf.append(x);
buf.append(FloatMath.toString(x));
if (y >= 0) buf.append("+");
buf.append(y);
buf.append(FloatMath.toString(y));
return buf.toString();
}
}
@@ -76,6 +76,30 @@ public class RigidTransform extends AbstractTransform
return this;
}
@Override // from Transform
public Transform rotate (float angle) {
float otx = this.tx, oty = this.ty;
if (otx != 0 || oty != 0) {
float sina = FloatMath.sin(angle), cosa = FloatMath.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 (float tx) {
this.tx += tx;
return this;
}
@Override // from Transform
public Transform translateY (float ty) {
this.ty += ty;
return this;
}
@Override // from Transform
public Transform invert () {
Vector t = getTranslation().negateLocal().rotateLocal(-rotation);
+47 -3
View File
@@ -48,19 +48,19 @@ public interface Transform
/** 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 affine or greater. */
* @throws UnsupportedOperationException if the transform is not non-uniform or greater. */
Transform setScale (float scaleX, float 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 affine or greater. */
* @throws UnsupportedOperationException if the transform is not non-uniform or greater. */
Transform setScaleX (float 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 affine or greater. */
* @throws UnsupportedOperationException if the transform is not non-uniform or greater. */
Transform setScaleY (float scaleY);
/** Sets the rotation component of this transform.
@@ -89,6 +89,50 @@ public interface Transform
Transform setTransform (float m00, float m01, float m10, float m11,
float tx, float 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 (float 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 (float scaleX, float 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 (float 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 (float scaleY);
/** Rotates this transform.
* @return this instance, for chaining.
* @throws UnsupportedOperationException if the transform is not rigid body or greater. */
Transform rotate (float angle);
/** Translates this transform.
* @return this instance, for chaining.
* @throws UnsupportedOperationException if the transform is not rigid body or greater. */
Transform translate (float tx, float 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 (float 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 (float ty);
/** Returns a new transform that represents the inverse of this transform.
* @throws NoninvertibleTransformException if the transform is not invertible. */
Transform invert ();
@@ -88,6 +88,39 @@ public class UniformTransform extends AbstractTransform
return this;
}
@Override // from Transform
public Transform uniformScale (float 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 (float angle) {
float otx = this.tx, oty = this.ty;
if (otx != 0 || oty != 0) {
float sina = FloatMath.sin(angle), cosa = FloatMath.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 (float tx) {
this.tx += tx;
return this;
}
@Override // from Transform
public Transform translateY (float ty) {
this.ty += ty;
return this;
}
@Override // from Transform
public Transform invert () {
float nscale = 1f / scale, nrotation = -rotation;
@@ -67,15 +67,18 @@ public class TransformTest
Transform t2 = proto.clone();
t2.setRotation(angle);
Transform t = t1.clone().rotate(angle);
Transform tpost = t2.concatenate(t1);
Transform tpre = t1.preConcatenate(t2);
for (Point point : POINTS) {
Point expect = point.add(trans.x, trans.y).rotateLocal(angle);
test(t, point, expect);
test(tpost, point, expect);
test(tpre, point, expect);
}
for (Vector vector : VECTORS) {
Vector expect = vector.rotate(angle);
test(t, vector, expect);
test(tpost, vector, expect);
test(tpre, vector, expect);
}
@@ -129,15 +132,18 @@ public class TransformTest
Transform t2 = proto.clone();
t2.setUniformScale(scale);
Transform t = t1.clone().uniformScale(scale);
Transform tpost = t2.concatenate(t1);
Transform tpre = t1.preConcatenate(t2);
for (Point point : POINTS) {
Point expect = point.add(trans.x, trans.y).multLocal(scale);
test(t, point, expect);
test(tpost, point, expect);
test(tpre, point, expect);
}
for (Vector vector : VECTORS) {
Vector expect = vector.mult(scale);
test(t, vector, expect);
test(tpost, vector, expect);
test(tpre, vector, expect);
}
@@ -191,15 +197,18 @@ public class TransformTest
Transform t2 = proto.clone();
t2.setUniformScale(scale);
Transform t = t1.clone().uniformScale(scale);
Transform tpost = t2.concatenate(t1);
Transform tpre = t1.preConcatenate(t2);
for (Point point : POINTS) {
Point expect = point.rotate(angle).multLocal(scale);
test(t, point, expect);
test(tpost, point, expect);
test(tpre, point, expect);
}
for (Vector vector : VECTORS) {
Vector expect = vector.rotate(angle).multLocal(scale);
test(t, vector, expect);
test(tpost, vector, expect);
test(tpre, vector, expect);
}