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();
+ }
+}