From 8c109a741b7c8b401d0d5cedf104936e6ececbf7 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 10 Oct 2023 17:25:56 -0400 Subject: [PATCH] Add Vector struct --- src/fart/vector.d | 190 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 src/fart/vector.d diff --git a/src/fart/vector.d b/src/fart/vector.d new file mode 100644 index 0000000..9713c93 --- /dev/null +++ b/src/fart/vector.d @@ -0,0 +1,190 @@ +module fart.vector; + +import std.math; + +/** + * Structure to represent a 3-dimensional vector. + */ +struct Vector +{ + /** Vector X coordinate. */ + double x; + + /** Vector Y coordinate. */ + double y; + + /** Vector Z coordinate. */ + double z; + + /** + * Compute the cross product of two vectors. + */ + public Vector cross()(auto ref const Vector other) const + { + return Vector(y * other.z - z * other.y, + z * other.x - x * other.z, + x * other.y - y * other.x); + } + + /** + * Compute the dot product of two vectors. + */ + public double dot()(auto ref const Vector other) const + { + return x * other.x + y * other.y + z * other.z; + } + + /** + * Get the magnitude of the vector. + */ + public double mag() const + { + return sqrt(mag2()); + } + + /** + * Get the squared magnitude of the vector. + */ + public double mag2() const + { + return x * x + y * y + z * z; + } + + /** + * Normalize the vector to have unit length. + */ + public ref Vector normalize() + { + double mag = mag(); + x /= mag; + y /= mag; + z /= mag; + return this; + } + + /** + * Get a normalized vector in the same direction as this. + */ + public Vector normalized() const + { + double mag = mag(); + return Vector(x / mag, y / mag, z / mag); + } + + /** + * Project the vector onto a target vector. + */ + public Vector proj()(auto ref const Vector other) const + { + Vector on = other.normalized(); + return on * dot(on); + } + + /** + * Add two vectors. + */ + public Vector opBinary(string op : "+")(auto ref const Vector other) const + { + return Vector(x + other.x, y + other.y, z + other.z); + } + + /** + * Add two vectors and assign to self. + */ + public Vector opOpAssign(string op : "+")(auto ref const Vector other) + { + x += other.x; + y += other.y; + z += other.z; + return this; + } + + /** + * Negate a vector. + */ + public Vector opUnary(string op : "-")() const + { + return Vector(-x, -y, -z); + } + + /** + * Subtract two vectors. + */ + public Vector opBinary(string op : "-")(auto ref const Vector other) const + { + return Vector(x - other.x, y - other.y, z - other.z); + } + + /** + * Subtract two vectors and assign to self. + */ + public Vector opOpAssign(string op : "-")(auto ref const Vector other) + { + x -= other.x; + y -= other.y; + z -= other.z; + return this; + } + + /** + * Scale a vector. + */ + public Vector opBinary(string op : "*")(double m) const + { + return Vector(x * m, y * m, z * m); + } + + /** + * Scale a vector. + */ + public Vector opBinaryRight(string op : "*")(double m) const + { + return Vector(x * m, y * m, z * m); + } + + /** + * Compute the cross product of two vectors. + */ + public Vector opBinary(string op : "*")(auto ref const Vector other) const + { + return cross(other); + } + + public static immutable Vector X = Vector(1.0, 0.0, 0.0); + public static immutable Vector Y = Vector(0.0, 1.0, 0.0); + public static immutable Vector Z = Vector(0.0, 0.0, 1.0); +} + +unittest +{ + Vector v = Vector(1, 2, 3); + const Vector w = Vector(0, 4, 5); + + Vector v_times_2 = v * 2; + assert(v_times_2.x == 2); + assert(v_times_2.y == 4); + assert(v_times_2.z == 6); + + Vector v_plus_w = v + w; + assert(v_plus_w == Vector(1, 6, 8)); + + Vector v_minus_w = v - w; + assert(v_minus_w == Vector(1, -2, -2)); + + assert(v_minus_w.mag2() == 9.0); + assert(v_minus_w.mag() == 3.0); + + v += v_minus_w; + assert(v == 2 * Vector.X + 0 * Vector.Y + Vector.Z); + + assert(Vector.X * Vector.Y == Vector.Z); + assert(Vector.Y * Vector.Z == Vector.X); + assert(Vector.Z * Vector.X == Vector.Y); + assert(Vector.Y * Vector.X == -Vector.Z); + assert(Vector.Z * Vector.Y == -Vector.X); + assert(Vector.X * Vector.Z == -Vector.Y); + + assert(w.proj(Vector.X) == Vector(0, 0, 0)); + assert(w.proj(Vector.Y) == Vector(0, 4, 0)); + assert(w.proj(Vector.Z) == Vector(0, 0, 5)); +}