#ifndef VEC_H #define VEC_H #undef min #undef max #include #include #include using namespace std; // Let gcc optimize conditional branches a bit better... #ifndef likely # if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) # define likely(x) (x) # define unlikely(x) (x) # else # define likely(x) (__builtin_expect((x), 1)) # define unlikely(x) (__builtin_expect((x), 0)) # endif #endif // Boost-like compile-time assertion checking template struct VEC_STATIC_ASSERTION_FAILURE; template <> struct VEC_STATIC_ASSERTION_FAILURE { void operator () () {} }; #define VEC_STATIC_CHECK(expr) VEC_STATIC_ASSERTION_FAILURE() template class Vec { private: T v[D]; public: // Constructor for no arguments. Everything initialized to 0. Vec() { for (int i = 0; i < D; i++) v[i] = T(0); } // Constructors for 2-4 arguments Vec(T x, T y) { VEC_STATIC_CHECK(D == 2); v[0] = x; v[1] = y; } Vec(T x, T y, T z) { VEC_STATIC_CHECK(D == 3); v[0] = x; v[1] = y; v[2] = z; } Vec(T x, T y, T z, T w) { VEC_STATIC_CHECK(D == 4); v[0] = x; v[1] = y; v[2] = z; v[3] = w; } // Constructor from anything that can be accessed using [] // This one's pretty aggressive, so marked explicit template explicit Vec(const S &x) { for (int i = 0; i < D; i++) v[i] = T(x[i]); } // No destructor or assignment operator needed // Array reference and conversion to pointer - no bounds checking const T &operator [] (int i) const { return v[i]; } T &operator [] (int i) { return v[i]; } operator const T * () const { return v; } operator const T * () { return v; } operator T * () { return v; } bool operator == (const Vec& d) const { return ((v[0] == d.v[0]) && (v[1] == d.v[1]) && (v[2] == d.v[2])); } bool operator != (const Vec& d) const { return ((v[0] != d.v[0]) || (v[1] != d.v[1]) || (v[2] != d.v[2])); } // Member operators Vec &operator += (const Vec &x) { for (int i = 0; i < D; i++) v[i] += x[i]; return *this; } Vec &operator -= (const Vec &x) { for (int i = 0; i < D; i++) v[i] -= x[i]; return *this; } Vec &operator *= (const Vec &x) { for (int i = 0; i < D; i++) v[i] *= x[i]; return *this; } Vec &operator *= (const T &x) { for (int i = 0; i < D; i++) v[i] *= x; return *this; } Vec &operator /= (const Vec &x) { for (int i = 0; i < D; i++) v[i] /= x[i]; return *this; } Vec &operator /= (const T &x) { for (int i = 0; i < D; i++) v[i] /= x; return *this; } // Outside of class: + - * / % ^ << >> // Some partial compatibility with valarrays and vectors typedef T value_type; size_t size() const { return D; } T sum() const { T total = v[0]; for (int i = 1; i < D; i++) total += v[i]; return total; } T avg() const { return sum() / D; } T product() const { T total = v[0]; for (int i = 1; i < D; i++) total *= v[i]; return total; } T min() const { T m = v[0]; for (int i = 0; i < D; i++) if (v[i] < m) m = v[i]; return m; } T max() const { T m = v[0]; for (int i = 1; i < D; i++) if (v[i] > m) m = v[i]; return m; } T *begin() { return &(v[0]); } const T *begin() const { return &(v[0]); } T *end() { return begin() + D; } const T *end() const { return begin() + D; } void clear() { for (int i = 0; i < D; i++) v[i] = T(0); } bool empty() const { for (int i = 0; i < D; i++) if (v[i]) return false; return true; } }; typedef Vec<3, float> vec; typedef Vec<3, float> point; typedef Vec<2, float> vec2; typedef Vec<3, float> vec3; typedef Vec<4, float> vec4; typedef Vec<2, int> ivec2; typedef Vec<3, int> ivec3; typedef Vec<4, int> ivec4; // Nonmember operators that take two Vecs template static inline const Vec operator + (const Vec &v1, const Vec &v2) { return Vec(v1) += v2; } template static inline const Vec operator - (const Vec &v1, const Vec &v2) { return Vec(v1) -= v2; } template static inline const Vec operator * (const Vec &v1, const Vec &v2) { return Vec(v1) *= v2; } template static inline const Vec operator / (const Vec &v1, const Vec &v2) { return Vec(v1) /= v2; } template static inline const T operator ^ (const Vec &v1, const Vec &v2) { T sum = v1[0] * v2[0]; for (int i = 1; i < D; i++) sum += v1[i] * v2[i]; return sum; } #define DOT ^ template static inline const Vec<3, T> operator % (const Vec<3, T> &v1, const Vec<3, T> &v2) { return Vec<3, T>(v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]); } #define CROSS % // Component-wise equality and inequality (#include the usual caveats // about comparing floats for equality...) template static inline bool operator == (const Vec &v1, const Vec &v2) { for (int i = 0; i < D; i++) if (v1[i] != v2[i]) return false; return true; } template static inline bool operator != (const Vec &v1, const Vec &v2) { for (int i = 0; i < D; i++) if (v1[i] != v2[i]) return true; return false; } // Unary operators template static inline const Vec &operator + (const Vec &v) { return v; } template static inline const Vec operator - (const Vec &v) { Vec result(v); for (int i = 0; i < D; i++) result[i] = -result[i]; return result; } template static inline bool operator ! (const Vec &v) { return v.empty(); } // Vec/scalar operators template static inline const Vec operator * (const T &x, const Vec &v) { Vec result(v); for (int i = 0; i < D; i++) result[i] = x * result[i]; return result; } template static inline const Vec operator * (const Vec &v, const T &x) { return Vec(v) *= x; } template static inline const Vec operator / (const T &x, const Vec &v) { Vec result(v); for (int i = 0; i < D; i++) result[i] = x / result[i]; return result; } template static inline const Vec operator / (const Vec &v, const T &x) { return Vec(v) /= x; } // iostream operators template static inline std::ostream &operator << (std::ostream &os, const Vec &v) { os << "("; for (int i = 0; i < D - 1; i++) os << v[i] << ", "; return os << v[D - 1] << ")"; } template static inline std::istream &operator >> (std::istream &is, Vec &v) { char c1 = 0, c2 = 0; is >> c1; if (c1 == '(' || c1 == '[') { is >> v[0] >> std::ws >> c2; for (int i = 1; i < D; i++) { if (c2 == ',') is >> v[i] >> std::ws >> c2; else is.setstate(std::ios::failbit); } } if (c1 == '(' && c2 != ')') is.setstate(std::ios::failbit); else if (c1 == '[' && c2 != ']') is.setstate(std::ios::failbit); return is; } // Utility functions for square and cube, to go along with sqrt and cbrt template static inline T sqr(const T &x) { return x*x; } template static inline T cube(const T &x) { return x*x*x; } // Utility functions based on GLSL template static inline T fract(const T &x) { return x - floor(x); } template static inline T clamp(const T &x, const T &a, const T &b) { return x > a ? x < b ? x : b : a; // returns a on NaN } template static inline T mix(const T &x, const T &y, const S &a) { return (S(1) - a) * x + a * y; } template static inline T step(const T &x, const T &a) { return x < a ? T(0) : T(1); } template static inline T smoothstep(const T &x, const T &a, const T &b) { if (b <= a) return step(x, a); T t = (x - a) / (b - a); return t <= T(0) ? T(0) : t >= T(1) ? T(1) : t * t * (T(3) - T(2) * t); } // Area-weighted triangle face normal template static inline T trinorm(const T &v0, const T &v1, const T &v2) { return (typename T::value_type) 0.5 * ((v1 - v0) CROSS(v2 - v0)); } // Sign of a scalar template static inline T sgn(const T &x) { return (x < T(0)) ? T(-1) : T(1); } // Functions on Vecs template static inline const T len2(const Vec &v) { T l2 = v[0] * v[0]; for (int i = 1; i < D; i++) l2 += v[i] * v[i]; return l2; } template static inline const T len(const Vec &v) { return sqrt(len2(v)); } template static inline const T dist2(const Vec &v1, const Vec &v2) { T d2 = sqr(v2[0] - v1[0]); for (int i = 1; i < D; i++) d2 += sqr(v2[i] - v1[i]); return d2; } template static inline const T dist(const Vec &v1, const Vec &v2) { return sqrt(dist2(v1, v2)); } template static inline Vec normalize(Vec &v) { T l = len(v); if (unlikely(l <= T(0))) { v[0] = T(1); for (int i = 1; i < D; i++) v[i] = T(0); return v; } l = T(1) / l; for (int i = 0; i < D; i++) v[i] *= l; return v; } template static inline void swap(const Vec &v1, const Vec &v2) { for (int i = 0; i < D; i++) swap(v1[i], v2[i]); } template static inline Vec fabs(const Vec &v) { Vec result(v); for (int i = 0; i < D; i++) if (result[i] < T(0)) result[i] = -result[i]; return result; } #endif