/******************************************************************************* 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 #include #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(lower, upper), rng::get(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(lower, upper), rng::get(lower, upper), rng::get(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_