From b6f87af8a0befd6c85fbfc51d0df92cd094c9025 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Tue, 5 Jul 2011 08:57:44 -0700 Subject: [PATCH] Added Vector and friends, and Transform interface. --- .../java/pythagoras/f/AbstractVector.java | 198 ++++++++++++++++++ src/main/java/pythagoras/f/IVector.java | 132 ++++++++++++ src/main/java/pythagoras/f/Transform.java | 103 +++++++++ src/main/java/pythagoras/f/Vector.java | 121 +++++++++++ src/main/java/pythagoras/f/Vectors.java | 40 ++++ 5 files changed, 594 insertions(+) create mode 100644 src/main/java/pythagoras/f/AbstractVector.java create mode 100644 src/main/java/pythagoras/f/IVector.java create mode 100644 src/main/java/pythagoras/f/Transform.java create mode 100644 src/main/java/pythagoras/f/Vector.java create mode 100644 src/main/java/pythagoras/f/Vectors.java diff --git a/src/main/java/pythagoras/f/AbstractVector.java b/src/main/java/pythagoras/f/AbstractVector.java new file mode 100644 index 0000000..e12f97a --- /dev/null +++ b/src/main/java/pythagoras/f/AbstractVector.java @@ -0,0 +1,198 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.f; + +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 float dot (IVector other) { + return getX()*other.getX() + getY()*other.getY(); + } + + @Override // from interface IVector + public Vector negate () { + return negate(new Vector()); + } + + @Override // from interface IVector + public Vector negate (Vector result) { + return result.set(-getX(), -getY()); + } + + @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 float angle (IVector other) { + float cos = dot(other) / (length() * other.length()); + return cos >= 1f ? 0f : FloatMath.acos(cos); + } + + @Override // from interface IVector + public float direction (IVector other) { + return FloatMath.atan2(other.getY() - getY(), other.getX() - getX()); + } + + @Override // from interface IVector + public float length () { + return FloatMath.sqrt(lengthSq()); + } + + @Override // from interface IVector + public float lengthSq () { + float x = getX(), y = getY(); + return (x*x + y*y); + } + + @Override // from interface IVector + public float distance (IVector other) { + return FloatMath.sqrt(distanceSq(other)); + } + + @Override // from interface IVector + public float distanceSq (IVector other) { + float dx = getX() - other.getX(), dy = getY() - other.getY(); + return dx*dx + dy*dy; + } + + @Override // from interface IVector + public Vector mult (float v) { + return mult(v, new Vector()); + } + + @Override // from interface IVector + public Vector mult (float v, Vector result) { + return result.set(getX()*v, getY()*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(getX()*other.getX(), getY()*other.getY()); + } + + @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.getX(), other.getY(), 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.getX(), -other.getY(), result); + } + + @Override // from interface IVector + public Vector add (float x, float y) { + return add(x, y, new Vector()); + } + + @Override // from interface IVector + public Vector add (float x, float y, Vector result) { + return result.set(getX() + x, getY() + y); + } + + @Override // from interface IVector + public Vector addScaled (IVector other, float v) { + return addScaled(other, v, new Vector()); + } + + @Override // from interface IVector + public Vector addScaled (IVector other, float v, Vector result) { + return result.set(getX() + other.getX()*v, getY() + other.getY()*v); + } + + @Override // from interface IVector + public Vector rotate (float angle) { + return rotate(angle, new Vector()); + } + + @Override // from interface IVector + public Vector rotate (float angle, Vector result) { + float x = getX(), y = getY(); + float sina = FloatMath.sin(angle), cosa = FloatMath.cos(angle); + return result.set(x*cosa - y*sina, x*sina + y*cosa); + } + + @Override // from interface IVector + public Vector rotateAndAdd (float angle, IVector add, Vector result) { + float x = getX(), y = getY(); + float sina = FloatMath.sin(angle), cosa = FloatMath.cos(angle); + return result.set(x*cosa - y*sina + add.getX(), x*sina + y*cosa + add.getY()); + } + + @Override // from interface IVector + public Vector rotateScaleAndAdd (float angle, float scale, IVector add, Vector result) { + float x = getX(), y = getY(); + float sina = FloatMath.sin(angle), cosa = FloatMath.cos(angle); + return result.set((x*cosa - y*sina)*scale + add.getX(), + (x*sina + y*cosa)*scale + add.getY()); + } + + @Override // from interface IVector + public Vector lerp (IVector other, float t) { + return lerp(other, t, new Vector()); + } + + @Override // from interface IVector + public Vector lerp (IVector other, float t, Vector result) { + float x = getX(), y = getY(); + float dx = other.getX() - x, dy = other.getY() - 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 getX() == p.getX() && getY() == p.getY(); + } + return false; + } + + @Override + public int hashCode () { + return Platform.hashCode(getX()) ^ Platform.hashCode(getY()); + } + + @Override + public String toString () { + return Vectors.vectorToString(getX(), getY()); + } +} diff --git a/src/main/java/pythagoras/f/IVector.java b/src/main/java/pythagoras/f/IVector.java new file mode 100644 index 0000000..87a4734 --- /dev/null +++ b/src/main/java/pythagoras/f/IVector.java @@ -0,0 +1,132 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.f; + +/** + * Provides read-only access to a {@link Vector}. + */ +public interface IVector +{ + /** Returns the x-component of this vector. */ + float getX (); + + /** Returns the y-component of this vector. */ + float getY (); + + /** Computes and returns the dot product of this and the specified other vector. */ + float 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. */ + float angle (IVector other); + + /** Returns the direction of a vector pointing from this point to the specified other point. */ + float direction (IVector other); + + /** Returns the length of this vector. */ + float length (); + + /** Returns the squared length of this vector. */ + float lengthSq (); + + /** Returns the distance from this vector to the specified other vector. */ + float distance (IVector other); + + /** Returns the squared distance from this vector to the specified other. */ + float distanceSq (IVector other); + + /** Multiplies this vector by a scalar. + * @return a new vector containing the result. */ + Vector mult (float 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 (float 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 (float x, float 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 (float x, float y, Vector result); + + /** Adds a scaled vector to this one. + * @return a new vector containing the result. */ + Vector addScaled (IVector other, float 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, float 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 (float 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 (float 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 (float 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 (float angle, float 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, float 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, float t, Vector result); + + /** Returns a mutable copy of this vector. */ + Vector clone (); +} diff --git a/src/main/java/pythagoras/f/Transform.java b/src/main/java/pythagoras/f/Transform.java new file mode 100644 index 0000000..b2bd6f1 --- /dev/null +++ b/src/main/java/pythagoras/f/Transform.java @@ -0,0 +1,103 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.f; + +/** + * Represents a geometric transform. Specialized implementations exist for identity, rigid body, + * uniform, affine and general transforms. + */ +public interface Transform +{ + /** Sets the translation component of this transform. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + void setTranslation (float tx, float ty); + + /** Sets the x-component of this transform's translation. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + void setTx (float tx); + + /** Sets the y-component of this transform's translation. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + void setTy (float ty); + + /** Sets the rotation component of this transform. + * @throws UnsupportedOperationException if the transform is not rigid body or greater. */ + void setRotation (float angle); + + /** Sets the uniform scale of this transform. + * @throws UnsupportedOperationException if the transform is not uniform or greater. */ + void setScale (float scale); + + /** Sets the x and y scale of this transform. + * @throws UnsupportedOperationException if the transform is not affine or greater. */ + void setScale (float scaleX, float scaleY); + + /** Sets the x scale of this transform. + * @throws UnsupportedOperationException if the transform is not affine or greater. */ + void setScaleX (float scaleX); + + /** Sets the y scale of this transform. + * @throws UnsupportedOperationException if the transform is not affine or greater. */ + void setScaleY (float scaleY); + + /** Sets the affine transform matrix. + * @throws UnsupportedOperationException if the transform is not affine or greater. */ + void setTransform (float m00, float m01, float m10, float m11, + float tx, float ty); + + /** Sets the general transform matrix. + * @throws UnsupportedOperationException if the transform is not general. */ + void setTransform (float m00, float m01, float m02, + float m10, float m11, float m12, + float m20, float m21, float m22); + + /** Returns the x-coordinate of the translation component. */ + float getTx (); + + /** Returns the y-coordinate of the translation component. */ + float getTy (); + + /** Returns the rotation applied by this transform. Note that the rotation is extracted and + * therefore approximate for affine and general transforms. */ + float getRotation (); // will be extracted from affine+ + + /** Returns the uniform scale applied by this transform. Note that the uniform scale will be + * approximated for non-uniform transforms (affine and general). */ + float getScale (); // will be extracted/approximated for affine+ + + /** Returns the x-component of the scale applied by this transform. */ + float getScaleX (); // will be extracted from affine+ + + /** Returns the y-component of the scale applied by this transform. */ + float getScaleY (); // will be extracted from affine+ + + /** Returns the inverse of this transform. + * @throws NoninvertibleTransformException if the transform is not invertible. */ + Transform invert (); + + /** Composes this transform with the supplied transform (i.e. {@code this x other}). */ + Transform compose (Transform other); + + /** Returns the linear interpolation between this transform and the specified other. */ + Transform lerp (Transform other, float t); + + /** Transforms the supplied point, writing the result into {@code into}, which may reference + * the same object as {@code p}. */ + void transform (IPoint p, Point into); + + /** Inverse transforms the supplied point, writing the result into {@code into}, which may + * reference the same object as {@code p}. + * @throws NoninvertibleTransformException if the transform is not invertible. */ + void inverseTransform (IPoint p, Point into); + + /** Transforms the supplied vector, writing the result into {@code into}, which may reference + * the same object as {@code v}. */ + void transform (IVector v, Vector into); + + /** Inverse transforms the supplied vector, writing the result into {@code into}, which may + * reference the same object as {@code v}. + * @throws NoninvertibleTransformException if the transform is not invertible. */ + void inverseTransform (IVector v, Vector into); +} diff --git a/src/main/java/pythagoras/f/Vector.java b/src/main/java/pythagoras/f/Vector.java new file mode 100644 index 0000000..43751f7 --- /dev/null +++ b/src/main/java/pythagoras/f/Vector.java @@ -0,0 +1,121 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.f; + +/** + * Represents a vector in a plane. + */ +public class Vector extends AbstractVector +{ + /** The x-component of the vector. */ + public float x; + + /** The y-component of the vector. */ + public float y; + + /** Creates a vector with the specified x and y components. */ + public Vector (float x, float 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 () { + } + + @Override // from AbstractVector + public float getX () { + return x; + } + + @Override // from AbstractVector + public float getY () { + return y; + } + + /** 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 (float 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 (float x, float 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, float 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 (float 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, float 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.getX(), other.getY()); + } + + /** Copies the elements of an array. + * @return a reference to this vector, for chaining. */ + public Vector set (float[] 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 (float x, float y) { + this.x = x; + this.y = y; + return this; + } +} diff --git a/src/main/java/pythagoras/f/Vectors.java b/src/main/java/pythagoras/f/Vectors.java new file mode 100644 index 0000000..7f1dfc8 --- /dev/null +++ b/src/main/java/pythagoras/f/Vectors.java @@ -0,0 +1,40 @@ +// +// Pythagoras - a collection of geometry classes +// http://github.com/samskivert/pythagoras + +package pythagoras.f; + +/** + * 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 floating 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 floating point value for all components. */ + public static final IVector MAX_VALUE = new Vector(Float.MAX_VALUE, Float.MAX_VALUE); + + /** + * Returns a string describing the supplied vector, of the form +x+y, + * +x-y, -x-y, etc. + */ + public static String vectorToString (float x, float y) { + StringBuilder buf = new StringBuilder(); + if (x >= 0) buf.append("+"); + buf.append(x); + if (y >= 0) buf.append("+"); + buf.append(y); + return buf.toString(); + } +}