Various Vector enhancements.

- Moved Vector.direction to Point.direction as that makes more sense. If you
  want to know the angle of the vector between two points, you should do that
  on points, not vectors.

- Added Vector.angle() which returns the angle of the vector (in polar
  coordinates), which matches Vector.length() which returns the magnitude of
  the vector (in polar coordinates).

- Added Vectors.fromPolar to create a vector from polar coordinates, and added
  Vector.setLength and Vector.setAngle to set the one whilst preserving the
  other.
This commit is contained in:
Michael Bayne
2011-09-02 15:55:05 -07:00
parent 49eafa5653
commit 42d4353788
13 changed files with 156 additions and 36 deletions
@@ -32,6 +32,11 @@ public abstract class AbstractPoint implements IPoint
return Points.distance(x(), y(), p.x(), p.y());
}
@Override // from interface IPoint
public double direction (IPoint other) {
return Math.atan2(other.y() - y(), other.x() - x());
}
@Override // from IPoint
public Point mult (double s) {
return mult(s, new Point());
+11 -11
View File
@@ -37,17 +37,6 @@ public abstract class AbstractVector implements IVector
return scale(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());
@@ -70,6 +59,17 @@ public abstract class AbstractVector implements IVector
return dx*dx + dy*dy;
}
@Override // from interface IVector
public double angle () {
return Math.atan2(y(), x());
}
@Override // from interface IVector
public double angleBetween (IVector other) {
double cos = dot(other) / (length() * other.length());
return cos >= 1f ? 0f : Math.acos(cos);
}
@Override // from interface IVector
public Vector scale (double v) {
return scale(v, new Vector());
+4
View File
@@ -27,6 +27,10 @@ public interface IPoint extends Cloneable
/** Returns the Euclidian distance between this point and the supplied point. */
double distance (IPoint p);
/** Returns the angle (in radians) of the vector starting at this point and ending at the
* supplied other point. */
double direction (IPoint other);
/** Multiplies this point by a scale factor.
* @return a new point containing the result. */
Point mult (double s);
+7 -7
View File
@@ -34,13 +34,7 @@ public interface IVector
* @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. */
/** Returns the length (magnitude) of this vector. */
double length ();
/** Returns the squared length of this vector. */
@@ -52,6 +46,12 @@ public interface IVector
/** Returns the squared distance from this vector to the specified other. */
double distanceSq (IVector other);
/** Returns the angle of this vector. */
double angle ();
/** Returns the angle between this vector and the specified other vector. */
double angleBetween (IVector other);
/** Scales this vector uniformly by the specified magnitude.
* @return a new vector containing the result. */
Vector scale (double v);
+16
View File
@@ -110,6 +110,22 @@ public class Vector extends AbstractVector
return this;
}
/**
* Sets this vector's angle, preserving its magnitude.
* @return a reference to this vector, for chaining.
*/
public Vector setAngle (double angle) {
double l = length();
return set(l * Math.cos(angle), l * Math.sin(angle));
}
/**
* Sets this vector's magnitude, preserving its angle.
*/
public Vector setLength (double length) {
return normalizeLocal().scaleLocal(length);
}
@Override // from AbstractVector
public double x () {
return x;
+7
View File
@@ -25,6 +25,13 @@ public class Vectors
/** 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);
/**
* Creates a new vector from polar coordinates.
*/
public static final Vector fromPolar (double magnitude, double angle) {
return new Vector(magnitude * Math.cos(angle), magnitude * Math.sin(angle));
}
/**
* Returns the magnitude of the specified vector.
*/
@@ -32,6 +32,11 @@ public abstract class AbstractPoint implements IPoint
return Points.distance(x(), y(), p.x(), p.y());
}
@Override // from interface IPoint
public float direction (IPoint other) {
return FloatMath.atan2(other.y() - y(), other.x() - x());
}
@Override // from IPoint
public Point mult (float s) {
return mult(s, new Point());
+11 -11
View File
@@ -37,17 +37,6 @@ public abstract class AbstractVector implements IVector
return scale(1f / length(), result);
}
@Override // from interface IVector
public float angleBetween (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.y() - y(), other.x() - x());
}
@Override // from interface IVector
public float length () {
return FloatMath.sqrt(lengthSq());
@@ -70,6 +59,17 @@ public abstract class AbstractVector implements IVector
return dx*dx + dy*dy;
}
@Override // from interface IVector
public float angle () {
return FloatMath.atan2(y(), x());
}
@Override // from interface IVector
public float angleBetween (IVector other) {
float cos = dot(other) / (length() * other.length());
return cos >= 1f ? 0f : FloatMath.acos(cos);
}
@Override // from interface IVector
public Vector scale (float v) {
return scale(v, new Vector());
+4
View File
@@ -27,6 +27,10 @@ public interface IPoint extends Cloneable
/** Returns the Euclidian distance between this point and the supplied point. */
float distance (IPoint p);
/** Returns the angle (in radians) of the vector starting at this point and ending at the
* supplied other point. */
float direction (IPoint other);
/** Multiplies this point by a scale factor.
* @return a new point containing the result. */
Point mult (float s);
+7 -7
View File
@@ -34,13 +34,7 @@ public interface IVector
* @return a reference to the result, for chaining. */
Vector normalize (Vector result);
/** Returns the angle between this vector and the specified other vector. */
float angleBetween (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. */
/** Returns the length (magnitude) of this vector. */
float length ();
/** Returns the squared length of this vector. */
@@ -52,6 +46,12 @@ public interface IVector
/** Returns the squared distance from this vector to the specified other. */
float distanceSq (IVector other);
/** Returns the angle of this vector. */
float angle ();
/** Returns the angle between this vector and the specified other vector. */
float angleBetween (IVector other);
/** Scales this vector uniformly by the specified magnitude.
* @return a new vector containing the result. */
Vector scale (float v);
+16
View File
@@ -110,6 +110,22 @@ public class Vector extends AbstractVector
return this;
}
/**
* Sets this vector's angle, preserving its magnitude.
* @return a reference to this vector, for chaining.
*/
public Vector setAngle (float angle) {
float l = length();
return set(l * FloatMath.cos(angle), l * FloatMath.sin(angle));
}
/**
* Sets this vector's magnitude, preserving its angle.
*/
public Vector setLength (float length) {
return normalizeLocal().scaleLocal(length);
}
@Override // from AbstractVector
public float x () {
return x;
+7
View File
@@ -25,6 +25,13 @@ public class Vectors
/** 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);
/**
* Creates a new vector from polar coordinates.
*/
public static final Vector fromPolar (float magnitude, float angle) {
return new Vector(magnitude * FloatMath.cos(angle), magnitude * FloatMath.sin(angle));
}
/**
* Returns the magnitude of the specified vector.
*/
@@ -0,0 +1,56 @@
//
// Pythagoras - a collection of geometry classes
// http://github.com/samskivert/pythagoras
package pythagoras.f;
import org.junit.*;
import static org.junit.Assert.*;
/**
* Tests aspects of the {@link Vector} class.
*/
public class VectorTest
{
@Test
public void testFromPolar () {
for (float length = 0.05f; length < 5; length += 0.05f) {
// stay away from -PI and PI because the signs might be flipped
for (float theta = -FloatMath.PI + 0.05f; theta < FloatMath.PI; theta += 0.05f) {
Vector v = Vectors.fromPolar(length, theta);
assertEquals(length, v.length(), MathUtil.EPSILON);
assertEquals(theta, v.angle(), MathUtil.EPSILON);
}
}
}
@Test
public void testSetLength () {
for (float length = 0.05f; length < 5; length += 0.05f) {
// stay away from -PI and PI because the signs might be flipped
for (float theta = -FloatMath.PI + 0.05f; theta < FloatMath.PI; theta += 0.05f) {
Vector v = Vectors.fromPolar(length, theta);
v.setLength(10);
// make sure setting length actually sets the length
assertEquals(10, v.length(), MathUtil.EPSILON);
// make sure setting length doesn't bork angle
assertEquals(theta, v.angle(), MathUtil.EPSILON);
}
}
}
@Test
public void testSetAngle () {
for (float length = 0.05f; length < 5; length += 0.05f) {
// stay away from -PI and PI because the signs might be flipped
for (float theta = 0.05f; theta < FloatMath.PI; theta += 0.05f) {
Vector v = Vectors.fromPolar(length, theta);
v.setAngle(FloatMath.PI - theta);
// make sure setting angle actually sets the angle
assertEquals(FloatMath.PI - theta, v.angle(), MathUtil.EPSILON);
// make sure setting length doesn't bork length
assertEquals(length, v.length(), MathUtil.EPSILON);
}
}
}
}