--- /dev/null
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef _VECTOR_HH_
+#define _VECTOR_HH_
+
+/**
+ * @file vector.hh
+ * Vector classes.
+ */
+
+#include <iostream>
+#include <cassert>
+
+#include "math.hh"
+#include "random.hh"
+
+
+// TODO: project, reflect, random, normal (of plane), orthonormal
+
+namespace dc {
+
+/**
+ * 2-dimensional vector.
+ */
+
+struct vector2
+{
+ vector2() {}
+ vector2(scalar X, scalar Y) : x(X), y(Y) {}
+ vector2(scalar v[2]) : x(v[0]), y(v[1]) {}
+
+ const scalar& operator[](int i) const
+ {
+ assert(i >= 0 && i <= 1 && "Index into vector2 out of bounds.");
+ return array[i];
+ }
+ scalar& operator[](int i)
+ {
+ assert(i >= 0 && i <= 1 && "Index into vector2 out of bounds.");
+ return array[i];
+ }
+
+ vector2 operator+(const vector2& v) const
+ {
+ return vector2(x + v.x, y + v.y);
+ }
+ vector2 operator-(const vector2& v) const
+ {
+ return vector2(x - v.x, y - v.y);
+ }
+ vector2 operator*(scalar s) const
+ {
+ return vector2(x * s, y * s);
+ }
+ vector2 operator/(scalar s) const
+ {
+ return vector2(x / s, y / s);
+ }
+
+ vector2& operator+=(const vector2& v)
+ {
+ x += v.x; y += v.y;
+ return *this;
+ }
+ vector2& operator-=(const vector2& v)
+ {
+ x -= v.x; y -= v.y;
+ return *this;
+ }
+ vector2& operator*=(scalar s)
+ {
+ x *= s; y *= s;
+ return *this;
+ }
+ vector2& operator/=(scalar s)
+ {
+ x /= s; y /= s;
+ return *this;
+ }
+
+ vector2 operator-() const
+ {
+ return vector2(-x, -y);
+ }
+
+ scalar dot(const vector2& v) const /// dot product
+ {
+ return x * v.x + y * v.y;
+ }
+ scalar angleBetween(const vector2& v) const
+ {
+ scalar lens = length() * v.length();
+ if (lens == 0.0) { return HUGE_VAL; }
+ return std::acos(dot(v) / lens);
+ }
+
+ void normalize() /// scale such that length is one
+ {
+ scalar len = length();
+ if (len != 0.0) { *this /= len; }
+ }
+ vector2 normalized() const
+ {
+ scalar len = length();
+ if (len != 0.0) { return *this / len; }
+ return vector2(0.0, 0.0);
+ }
+
+ scalar length2() const /// magnitude squared
+ {
+ return dot(*this);
+ }
+ scalar length() const /// magnitude
+ {
+ return std::sqrt(length2());
+ }
+
+ bool operator==(const vector2& v) const
+ {
+ return equals(x, v.x) && equals(y, v.y);
+ }
+ bool operator!=(const vector2& v) const
+ {
+ return !(*this == v);
+ }
+
+
+ static vector2 random()
+ {
+ vector2 v = random(-1.0, 1.0);
+ v.normalize();
+ return v;
+ }
+
+ static vector2 random(scalar lower, scalar upper)
+ {
+ return vector2(rng::get<scalar>(lower, upper),
+ rng::get<scalar>(lower, upper));
+ }
+
+
+ union
+ {
+ struct
+ {
+ scalar x, y; ///< euler coordinates
+ };
+ scalar array[2]; ///< array
+ };
+
+ static vector2 zero; ///< zero vector
+};
+
+inline vector2 operator*(scalar s, const vector2& v)
+{
+ return v * s;
+}
+inline vector2 operator/(scalar s, const vector2& v)
+{
+ return vector2(s / v.x, s / v.y);
+}
+
+inline std::ostream& operator<<(std::ostream& output, const vector2& v)
+{
+ output << "(" << v.x << "," << v.y << ")";
+ return output;
+}
+
+
+typedef vector2 point;
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+/**
+ * 3-dimensional vector.
+ */
+
+struct vector3
+{
+ vector3() {}
+ vector3(scalar X, scalar Y, scalar Z) : x(X), y(Y), z(Z) {}
+ vector3(scalar v[3]) : x(v[0]), y(v[1]), z(v[2]) {}
+
+ const scalar& operator[](int i) const
+ {
+ assert(i >= 0 && i <= 2 && "Index into vector3 out of bounds.");
+ return array[i];
+ }
+ scalar& operator[](int i)
+ {
+ assert(i >= 0 && i <= 2 && "Index into vector3 out of bounds.");
+ return array[i];
+ }
+
+ vector3 operator+(const vector3& v) const
+ {
+ return vector3(x + v.x, y + v.y, z + v.z);
+ }
+ vector3 operator-(const vector3& v) const
+ {
+ return vector3(x - v.x, y - v.y, z - v.z);
+ }
+ vector3 operator*(scalar s) const
+ {
+ return vector3(x * s, y * s, z * s);
+ }
+ vector3 operator/(scalar s) const
+ {
+ return vector3(x / s, y / s, z / s);
+ }
+
+ vector3& operator+=(const vector3& v)
+ {
+ x += v.x; y += v.y; z += v.z;
+ return *this;
+ }
+ vector3& operator-=(const vector3& v)
+ {
+ x -= v.x; y -= v.y; z -= v.z;
+ return *this;
+ }
+ vector3& operator*=(scalar s)
+ {
+ x *= s; y *= s; z *= s;
+ return *this;
+ }
+ vector3& operator/=(scalar s)
+ {
+ x /= s; y /= s; z /= s;
+ return *this;
+ }
+
+ vector3 operator-() const
+ {
+ return vector3(-x, -y, -z);
+ }
+
+ scalar dot(const vector3& v) const /// dot product
+ {
+ return x * v.x + y * v.y + z * v.z;
+ }
+ vector3 cross(const vector3& v) const /// cross product
+ {
+ return vector3(y * v.z - z * v.y,
+ z * v.x - x * v.z,
+ x * v.y - y * v.x);
+ }
+
+ scalar angleBetween(const vector3& v) const
+ {
+ scalar lens = length() * v.length();
+ if (lens == 0.0) { return HUGE_VAL; }
+ return std::acos(dot(v) / lens);
+ }
+
+ void normalize() /// scale such that length is one
+ {
+ scalar len = length();
+ if (len != 0.0) { *this /= len; }
+ }
+ vector3 normalized() const
+ {
+ scalar len = length();
+ if (len != 0.0) { return *this / len; }
+ return vector3(0.0, 0.0, 0.0);
+ }
+
+ scalar length2() const /// magnitude squared
+ {
+ return dot(*this);
+ }
+ scalar length() const /// magnitude
+ {
+ return std::sqrt(length2());
+ }
+
+ bool operator==(const vector3& v) const
+ {
+ return equals(x, v.x) && equals(y, v.y) && equals(z, v.z);
+ }
+ bool operator!=(const vector3& v) const
+ {
+ return !(*this == v);
+ }
+
+
+ static vector3 random()
+ {
+ vector3 v = random(-1.0, 1.0);
+ v.normalize();
+ return v;
+ }
+
+ static vector3 random(scalar lower, scalar upper)
+ {
+ return vector3(rng::get<scalar>(lower, upper),
+ rng::get<scalar>(lower, upper),
+ rng::get<scalar>(lower, upper));
+ }
+
+
+ union
+ {
+ struct
+ {
+ scalar x, y, z; ///< euler coordinates
+ };
+ struct
+ {
+ scalar u, v, w; ///< texture coordinates
+ };
+ struct
+ {
+ scalar r, g, b; ///< color intensities
+ };
+ scalar array[3]; ///< array
+ };
+
+ static vector3 zero; ///< zero vector
+};
+
+inline vector3 operator*(scalar s, const vector3& v)
+{
+ return v * s;
+}
+inline vector3 operator/(scalar s, const vector3& v)
+{
+ return vector3(s / v.x, s / v.y, s / v.z);
+}
+
+inline std::ostream& operator<<(std::ostream& output, const vector3& v)
+{
+ output << "(" << v.x << "," << v.y << "," << v.z << ")";
+ return output;
+}
+
+
+typedef vector3 color;
+
+
+} // namespace dc
+
+
+#endif // _VECTOR_HH_
+