#include "vector.h"
-#include <math.h> // For sqrt()
+#include <math.h> // For sqrt()
#include "mathconstants.h"
// Vector implementation
-Vector::Vector(double xx/*= 0*/, double yy/*= 0*/, double zz/*= 0*/): x(xx), y(yy), z(zz)
+Vector::Vector(double xx/*= 0*/, double yy/*= 0*/, double zz/*= 0*/): x(xx), y(yy), z(zz), b(0)
{
}
+Vector::Vector(Vector tail, Vector head): x(head.x - tail.x), y(head.y - tail.y), z(head.z - tail.z), b(0)
+{
+}
-Vector::Vector(Vector tail, Vector head): x(head.x - tail.x), y(head.y - tail.y), z(head.z - tail.z)
+Vector::Vector(const Vector &v): x(v.x), y(v.y), z(v.z), b(v.b)
{
}
+// Create vector from angle + length (2D; z is set to zero)
+void Vector::SetAngleAndLength(double angle, double length)
+{
+ x = cos(angle) * length;
+ y = sin(angle) * length;
+ z = 0;
+}
Vector Vector::operator=(Vector const v)
{
- x = v.x, y = v.y, z = v.z;
+ x = v.x, y = v.y, z = v.z, b = v.b;
return *this;
}
-
Vector Vector::operator+(Vector const v)
{
return Vector(x + v.x, y + v.y, z + v.z);
}
-
Vector Vector::operator-(Vector const v)
{
return Vector(x - v.x, y - v.y, z - v.z);
}
-
// Unary negation
Vector Vector::operator-(void)
return Vector(-x, -y, -z);
}
-
// Vector x constant
Vector Vector::operator*(double const v)
return Vector(x * v, y * v, z * v);
}
-
// Vector x constant
Vector Vector::operator*(float const v)
return Vector(x * v, y * v, z * v);
}
-
// Vector / constant
Vector Vector::operator/(double const v)
return Vector(x / v, y / v, z / v);
}
-
// Vector / constant
Vector Vector::operator/(float const v)
return Vector(x / v, y / v, z / v);
}
-
// Vector (cross) product
Vector Vector::operator*(Vector const v)
return Vector((y * v.z) - (z * v.y), (z * v.x) - (x * v.z), (x * v.y) - (y * v.x));
}
-
// Dot product
double Vector::Dot(Vector const v)
return (x * v.x) + (y * v.y) + (z * v.z);
}
-
// Vector x constant, self assigned
Vector& Vector::operator*=(double const v)
return *this;
}
-
// Vector / constant, self assigned
Vector& Vector::operator/=(double const v)
return *this;
}
-
// Vector + constant, self assigned
Vector& Vector::operator+=(double const v)
return *this;
}
-
// Vector - vector, self assigned
Vector& Vector::operator-=(Vector const v)
return *this;
}
-
// Vector - constant, self assigned
Vector& Vector::operator-=(double const v)
return *this;
}
-
// Check for equality
bool Vector::operator==(Vector const v)
{
return (x == v.x && y == v.y && z == v.z ? true : false);
}
-
// Check for inequality
bool Vector::operator!=(Vector const v)
{
return (x != v.x || y != v.y || z != v.z ? true : false);
}
-
Vector Vector::Unit(void)
{
double mag = Magnitude();
- // If the magnitude of the vector is zero, then the Unit vector is undefined...
+ // If the magnitude of the vector is zero, then the Unit vector is
+ // undefined...
if (mag == 0)
return Vector(0, 0, 0);
return Vector(x / mag, y / mag, z / mag);
}
-
double Vector::Magnitude(void)
{
- return sqrt(x * x + y * y + z * z);
+ return sqrt((x * x) + (y * y) + (z * z));
}
-
double Vector::Angle(void)
{
- // acos returns a value between zero and PI, which means we don't know which
- // quadrant the angle is in... Though, if the y-coordinate of the vector is
- // negative, that means that the angle is in quadrants III - IV.
+ // acos returns a value between zero and TAU/2, which means we don't know
+ // which quadrant the angle is in... However, if the y-coordinate of the
+ // vector is negative, that means that the angle is in quadrants III - IV.
double rawAngle = acos(Unit().x);
- double correctedAngle = (y < 0 ? (2.0 * PI) - rawAngle : rawAngle);
+ double correctedAngle = (y < 0 ? TAU - rawAngle : rawAngle);
return correctedAngle;
}
-
bool Vector::isZero(double epsilon/*= 1e-6*/)
{
return (fabs(x) < epsilon && fabs(y) < epsilon && fabs(z) < epsilon ? true : false);
}
-
// Class methods
-double Vector::Dot(Vector v1, Vector v2)
+/*static*/ double Vector::Dot(Vector v1, Vector v2)
{
return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
}
-
-double Vector::Magnitude(Vector v1, Vector v2)
+/*static*/ double Vector::Magnitude(Vector v1, Vector v2)
{
double xx = v1.x - v2.x;
double yy = v1.y - v2.y;
double zz = v1.z - v2.z;
+
return sqrt((xx * xx) + (yy * yy) + (zz * zz));
}
+//
+// Convenience function
+//
+/*static*/ Vector Vector::Unit(Point p1, Point p2)
+{
+ return Vector(p1, p2).Unit();
+}
+
+//
+// Convenience function
+//
+/*static*/ double Vector::Angle(Point p1, Point p2)
+{
+ return Vector(p1, p2).Angle();
+}
// Returns the parameter of a point in space to this vector. If the parameter
// is between 0 and 1, the normal of the vector to the point is on the vector.
// Note: v1 is the tail, v2 is the head of the line (vector).
-double Vector::Parameter(Vector tail, Vector head, Vector p)
+/*static*/ double Vector::Parameter(Vector tail, Vector head, Vector p)
{
// Geometric interpretation:
// The parameterized point on the vector lineSegment is where the normal of
double magnitude = lineSegment.Magnitude();
Vector pointSegment = p - tail;
double t = lineSegment.Dot(pointSegment) / (magnitude * magnitude);
+
return t;
}
-
-// Return the normal to the linesegment formed by the passed in points.
-// (Not sure which is head or tail, or which hand the normal lies)
-// [v1 should be the tail, v2 should be the head, in which case the normal should
-// rotate anti-clockwise.]
-///*static*/ Vector Vector::Normal(Vector v1, Vector v2)
+// Return the 2D normal to the linesegment formed by the passed in points.
+// The normal thus calculated should rotate anti-clockwise.
/*static*/ Vector Vector::Normal(Vector tail, Vector head)
{
-// Vector v = (v1 - v2).Unit();
Vector v = (head - tail).Unit();
+
return Vector(-v.y, v.x);
}
+/*static*/ double Vector::AngleBetween(Vector a1, Vector a2)
+{
+ // This is done using the following formula:
+ // (a . b) = ||a|| ||b|| cos(theta)
+ // However, have to check for two degenerate cases, where a = cb:
+ // 1) if c > 0, theta = 0; 2) if c < 0, theta = 180°.
+ // Also, the vectors a & b have to be non-zero.
+ // Also, have to check using an epsilon because acos will not return an
+ // exact value if the vectors are orthogonal.
+ if (a1.isZero() || a2.isZero())
+ return 0;
+
+ return acos(a1.Dot(a2) / (a1.Magnitude() * a2.Magnitude()));
+}
+
+/*static*/ Point Vector::Midpoint(Point p1, Point p2)
+{
+ return Point((p1.x + p2.x) / 2.0, (p1.y + p2.y) / 2.0);
+}