// linalg.h - v2.0 - Single-header public domain linear algebra library // // The intent of this library is to provide the bulk of the functionality // you need to write programs that frequently use small, fixed-size vectors // and matrices, in domains such as computational geometry or computer // graphics. It strives for terse, readable source code. // // The original author of this software is Sterling Orsten, and its permanent // home is . If you find this software // useful, an acknowledgement in your source text and/or product documentation // is appreciated, but not required. // // The author acknowledges significant insights and contributions by: // Stan Melax // Dimitri Diakopoulos // This is free and unencumbered software released into the public domain. // // Anyone is free to copy, modify, publish, use, compile, sell, or // distribute this software, either in source code form or as a compiled // binary, for any purpose, commercial or non-commercial, and by any // means. // // In jurisdictions that recognize copyright laws, the author or authors // of this software dedicate any and all copyright interest in the // software to the public domain. We make this dedication for the benefit // of the public at large and to the detriment of our heirs and // successors. We intend this dedication to be an overt act of // relinquishment in perpetuity of all present and future rights to this // software under copyright law. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // For more information, please refer to #pragma once #ifndef LINALG_H #define LINALG_H #include // For various unary math functions, such as std::sqrt #include // To resolve std::abs ambiguity on clang #include // For implementing namespace linalg::aliases #include // For std::array, used in the relational operator overloads #include // For std::numeric_limits/epsilon // Visual Studio versions prior to 2015 lack constexpr support #if defined(_MSC_VER) && _MSC_VER < 1900 && !defined(constexpr) #define constexpr #endif namespace linalg { // Small, fixed-length vector type, consisting of exactly M elements of type T, and presumed to be a column-vector unless otherwise noted template struct vec; template struct vec { T x,y; constexpr vec() : x(), y() {} constexpr vec(const T & x_, const T & y_) : x(x_), y(y_) {} constexpr vec(const std::array & a) : x(a[0]), y(a[1]) {} constexpr explicit vec(const T & s) : vec(s, s) {} constexpr explicit vec(const T * p) : vec(p[0], p[1]) {} template constexpr explicit vec(const vec & v) : vec(static_cast(v.x), static_cast(v.y)) {} constexpr const T & operator[] (int i) const { return (&x)[i]; } T & operator[] (int i) { return (&x)[i]; } }; template struct vec { T x,y,z; constexpr vec() : x(), y(), z() {} constexpr vec(const T & x_, const T & y_, const T & z_) : x(x_), y(y_), z(z_) {} constexpr vec(const vec & xy, const T & z_) : vec(xy.x, xy.y, z_) {} constexpr vec(const std::array & a) : x(a[0]), y(a[1]), z(a[2]) {} constexpr explicit vec(const T & s) : vec(s, s, s) {} constexpr explicit vec(const T * p) : vec(p[0], p[1], p[2]) {} template constexpr explicit vec(const vec & v) : vec(static_cast(v.x), static_cast(v.y), static_cast(v.z)) {} constexpr const T & operator[] (int i) const { return (&x)[i]; } T & operator[] (int i) { return (&x)[i]; } constexpr const vec & xy() const { return *reinterpret_cast *>(this); } vec & xy() { return *reinterpret_cast *>(this); } }; template struct vec { T x,y,z,w; constexpr vec() : x(), y(), z(), w() {} constexpr vec(const T & x_, const T & y_, const T & z_, const T & w_) : x(x_), y(y_), z(z_), w(w_) {} constexpr vec(const vec & xy, const T & z_, const T & w_) : vec(xy.x, xy.y, z_, w_) {} constexpr vec(const vec & xyz, const T & w_) : vec(xyz.x, xyz.y, xyz.z, w_) {} constexpr vec(const std::array & a) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {} constexpr explicit vec(const T & s) : vec(s, s, s, s) {} constexpr explicit vec(const T * p) : vec(p[0], p[1], p[2], p[3]) {} template constexpr explicit vec(const vec & v) : vec(static_cast(v.x), static_cast(v.y), static_cast(v.z), static_cast(v.w)) {} constexpr const T & operator[] (int i) const { return (&x)[i]; } T & operator[] (int i) { return (&x)[i]; } constexpr const vec & xy() const { return *reinterpret_cast *>(this); } constexpr const vec & xyz() const { return *reinterpret_cast *>(this); } vec & xy() { return *reinterpret_cast *>(this); } vec & xyz() { return *reinterpret_cast *>(this); } }; // Small, fixed-size matrix type, consisting of exactly M rows and N columns of type T, stored in column-major order. template struct mat; template struct mat { typedef vec V; V x,y; constexpr mat() : x(), y() {} constexpr mat(const V & x_, const V & y_) : x(x_), y(y_) {} constexpr explicit mat(const T & s) : x(s), y(s) {} constexpr explicit mat(const T * p) : x(p+M*0), y(p+M*1) {} template constexpr explicit mat(const mat & m) : mat(V(m.x), V(m.y)) {} constexpr vec row(int i) const { return {x[i], y[i]}; } constexpr const V & operator[] (int j) const { return (&x)[j]; } V & operator[] (int j) { return (&x)[j]; } }; template struct mat { typedef vec V; V x,y,z; constexpr mat() : x(), y(), z() {} constexpr mat(const V & x_, const V & y_, const V & z_) : x(x_), y(y_), z(z_) {} constexpr explicit mat(const T & s) : x(s), y(s), z(s) {} constexpr explicit mat(const T * p) : x(p+M*0), y(p+M*1), z(p+M*2) {} template constexpr explicit mat(const mat & m) : mat(V(m.x), V(m.y), V(m.z)) {} constexpr vec row(int i) const { return {x[i], y[i], z[i]}; } constexpr const V & operator[] (int j) const { return (&x)[j]; } V & operator[] (int j) { return (&x)[j]; } }; template struct mat { typedef vec V; V x,y,z,w; constexpr mat() : x(), y(), z(), w() {} constexpr mat(const V & x_, const V & y_, const V & z_, const V & w_) : x(x_), y(y_), z(z_), w(w_) {} constexpr explicit mat(const T & s) : x(s), y(s), z(s), w(s) {} constexpr explicit mat(const T * p) : x(p+M*0), y(p+M*1), z(p+M*2), w(p+M*3) {} template constexpr explicit mat(const mat & m) : mat(V(m.x), V(m.y), V(m.z), V(m.w)) {} constexpr vec row(int i) const { return {x[i], y[i], z[i], w[i]}; } constexpr const V & operator[] (int j) const { return (&x)[j]; } V & operator[] (int j) { return (&x)[j]; } }; // Type traits for a binary operation involving linear algebra types, used for SFINAE on templated functions and operator overloads template struct traits {}; template struct traits, vec> { typedef T scalar; typedef vec result; typedef vec bool_result; typedef vec arith_result; typedef std::array compare_as; }; template struct traits, T > { typedef T scalar; typedef vec result; typedef vec bool_result; typedef vec arith_result; }; template struct traits> { typedef T scalar; typedef vec result; typedef vec bool_result; typedef vec arith_result; }; template struct traits, mat> { typedef T scalar; typedef mat result; typedef mat bool_result; typedef mat arith_result; typedef std::array compare_as; }; template struct traits, T > { typedef T scalar; typedef mat result; typedef mat bool_result; typedef mat arith_result; }; template struct traits> { typedef T scalar; typedef mat result; typedef mat bool_result; typedef mat arith_result; }; template using scalar_t = typename traits::scalar; // Underlying scalar type when performing elementwise operations template using result_t = typename traits::result; // Result of calling a function on linear algebra types template using bool_result_t = typename traits::bool_result; // Result of a comparison or unary not operation on linear algebra types template using arith_result_t = typename traits::arith_result; // Result of an arithmetic operation on linear algebra types (accounts for integer promotion) // Produce a scalar by applying f(T,T) -> T to adjacent pairs of elements from vector/matrix a in left-to-right order (matching the associativity of arithmetic and logical operators) template constexpr T fold(const vec & a, F f) { return f(a.x,a.y); } template constexpr T fold(const vec & a, F f) { return f(f(a.x,a.y),a.z); } template constexpr T fold(const vec & a, F f) { return f(f(f(a.x,a.y),a.z),a.w); } template constexpr T fold(const mat & a, F f) { return f(fold(a.x,f),fold(a.y,f)); } template constexpr T fold(const mat & a, F f) { return f(f(fold(a.x,f),fold(a.y,f)),fold(a.z,f)); } template constexpr T fold(const mat & a, F f) { return f(f(f(fold(a.x,f),fold(a.y,f)),fold(a.z,f)),fold(a.w,f)); } // Produce a vector/matrix by applying f(T,T) to corresponding pairs of elements from vectors/matrix a and b template constexpr auto zip(const vec & a, const vec & b, F f) -> vec { return {f(a.x,b.x), f(a.y,b.y)}; } template constexpr auto zip(const vec & a, const vec & b, F f) -> vec { return {f(a.x,b.x), f(a.y,b.y), f(a.z,b.z)}; } template constexpr auto zip(const vec & a, const vec & b, F f) -> vec { return {f(a.x,b.x), f(a.y,b.y), f(a.z,b.z), f(a.w,b.w)}; } template constexpr auto zip(const vec & a, T b, F f) -> vec { return zip(a, vec(b), f); } template constexpr auto zip( T a, const vec & b, F f) -> vec { return zip(vec(a), b, f); } template constexpr auto zip(const mat & a, const mat & b, F f) -> mat { return {zip(a.x,b.x,f), zip(a.y,b.y,f)}; } template constexpr auto zip(const mat & a, const mat & b, F f) -> mat { return {zip(a.x,b.x,f), zip(a.y,b.y,f), zip(a.z,b.z,f)}; } template constexpr auto zip(const mat & a, const mat & b, F f) -> mat { return {zip(a.x,b.x,f), zip(a.y,b.y,f), zip(a.z,b.z,f), zip(a.w,b.w,f)}; } template constexpr auto zip(const mat & a, T b, F f) -> mat { return zip(a, mat(b), f); } template constexpr auto zip( T a, const mat & b, F f) -> mat { return zip(mat(a), b, f); } // Produce a vector/matrix by applying f(T) to elements from vector/matrix a template constexpr auto map(const vec & a, F f) -> vec { return zip(a, a, [f](T l, T) { return f(l); }); } template constexpr auto map(const mat & a, F f) -> mat { return zip(a, a, [f](T l, T) { return f(l); }); } // Relational operators are defined to compare the elements of two vectors or matrices lexicographically, in column-major order template::compare_as> constexpr bool operator == (const A & a, const A & b) { return reinterpret_cast(a) == reinterpret_cast(b); } template::compare_as> constexpr bool operator != (const A & a, const A & b) { return reinterpret_cast(a) != reinterpret_cast(b); } template::compare_as> constexpr bool operator < (const A & a, const A & b) { return reinterpret_cast(a) < reinterpret_cast(b); } template::compare_as> constexpr bool operator > (const A & a, const A & b) { return reinterpret_cast(a) > reinterpret_cast(b); } template::compare_as> constexpr bool operator <= (const A & a, const A & b) { return reinterpret_cast(a) <= reinterpret_cast(b); } template::compare_as> constexpr bool operator >= (const A & a, const A & b) { return reinterpret_cast(a) >= reinterpret_cast(b); } // Lambdas are not permitted inside constexpr functions, so we provide explicit function objects instead namespace op { template struct pos { constexpr auto operator() (T r) const -> decltype(+r) { return +r; } }; template struct neg { constexpr auto operator() (T r) const -> decltype(-r) { return -r; } }; template struct add { constexpr auto operator() (T l, T r) const -> decltype(l + r) { return l + r; } }; template struct sub { constexpr auto operator() (T l, T r) const -> decltype(l - r) { return l - r; } }; template struct mul { constexpr auto operator() (T l, T r) const -> decltype(l * r) { return l * r; } }; template struct div { constexpr auto operator() (T l, T r) const -> decltype(l / r) { return l / r; } }; template struct mod { constexpr auto operator() (T l, T r) const -> decltype(l % r) { return l % r; } }; template struct lshift { constexpr auto operator() (T l, T r) const -> decltype(l << r) { return l << r; } }; template struct rshift { constexpr auto operator() (T l, T r) const -> decltype(l >> r) { return l >> r; } }; template struct binary_not { constexpr auto operator() (T r) const -> decltype(+r) { return ~r; } }; template struct binary_or { constexpr auto operator() (T l, T r) const -> decltype(l | r) { return l | r; } }; template struct binary_xor { constexpr auto operator() (T l, T r) const -> decltype(l ^ r) { return l ^ r; } }; template struct binary_and { constexpr auto operator() (T l, T r) const -> decltype(l & r) { return l & r; } }; template struct logical_not { constexpr bool operator() (T r) const { return !r; } }; template struct logical_or { constexpr bool operator() (T l, T r) const { return l || r; } }; template struct logical_and { constexpr bool operator() (T l, T r) const { return l && r; } }; template struct equal { constexpr bool operator() (T l, T r) const { return l == r; } }; template struct nequal { constexpr bool operator() (T l, T r) const { return l != r; } }; template struct less { constexpr bool operator() (T l, T r) const { return l < r; } }; template struct greater { constexpr bool operator() (T l, T r) const { return l > r; } }; template struct lequal { constexpr bool operator() (T l, T r) const { return l <= r; } }; template struct gequal { constexpr bool operator() (T l, T r) const { return l >= r; } }; template struct min { constexpr T operator() (T l, T r) const { return l < r ? l : r; } }; template struct max { constexpr T operator() (T l, T r) const { return l > r ? l : r; } }; } // Functions for coalescing scalar values template constexpr scalar_t any (const A & a) { return fold(a, op::logical_or>{}); } template constexpr scalar_t all (const A & a) { return fold(a, op::logical_and>{}); } template constexpr scalar_t sum (const A & a) { return fold(a, op::add>{}); } template constexpr scalar_t product(const A & a) { return fold(a, op::mul>{}); } template int argmin(const vec & a) { int j=0; for(int i=1; i int argmax(const vec & a) { int j=0; for(int i=1; i a[j]) j = i; return j; } template T minelem(const vec & a) { return a[argmin(a)]; } template T maxelem(const vec & a) { return a[argmax(a)]; } // Overloads for unary operators on vectors are implemented in terms of elementwise application of the operator template constexpr arith_result_t operator + (const A & a) { return map(a, op::pos>{}); } template constexpr arith_result_t operator - (const A & a) { return map(a, op::neg>{}); } template constexpr arith_result_t operator ~ (const A & a) { return map(a, op::binary_not>{}); } template constexpr bool_result_t operator ! (const A & a) { return map(a, op::logical_not>{}); } // Mirror the set of unary scalar math functions to apply elementwise to vectors template result_t abs (const A & a) { return map(a, [](scalar_t l) { return std::abs (l); }); } template result_t floor(const A & a) { return map(a, [](scalar_t l) { return std::floor(l); }); } template result_t ceil (const A & a) { return map(a, [](scalar_t l) { return std::ceil (l); }); } template result_t exp (const A & a) { return map(a, [](scalar_t l) { return std::exp (l); }); } template result_t log (const A & a) { return map(a, [](scalar_t l) { return std::log (l); }); } template result_t log10(const A & a) { return map(a, [](scalar_t l) { return std::log10(l); }); } template result_t sqrt (const A & a) { return map(a, [](scalar_t l) { return std::sqrt (l); }); } template result_t sin (const A & a) { return map(a, [](scalar_t l) { return std::sin (l); }); } template result_t cos (const A & a) { return map(a, [](scalar_t l) { return std::cos (l); }); } template result_t tan (const A & a) { return map(a, [](scalar_t l) { return std::tan (l); }); } template result_t asin (const A & a) { return map(a, [](scalar_t l) { return std::asin (l); }); } template result_t acos (const A & a) { return map(a, [](scalar_t l) { return std::acos (l); }); } template result_t atan (const A & a) { return map(a, [](scalar_t l) { return std::atan (l); }); } template result_t sinh (const A & a) { return map(a, [](scalar_t l) { return std::sinh (l); }); } template result_t cosh (const A & a) { return map(a, [](scalar_t l) { return std::cosh (l); }); } template result_t tanh (const A & a) { return map(a, [](scalar_t l) { return std::tanh (l); }); } template result_t round(const A & a) { return map(a, [](scalar_t l) { return std::round(l); }); } template result_t fract(const A & a) { return map(a, [](scalar_t l) { return l - std::floor(l); }); } // Overloads for vector op vector are implemented in terms of elementwise application of the operator, followed by casting back to the original type (integer promotion is suppressed) template constexpr arith_result_t operator + (const A & a, const B & b) { return zip(a, b, op::add>{}); } template constexpr arith_result_t operator - (const A & a, const B & b) { return zip(a, b, op::sub>{}); } template constexpr arith_result_t operator * (const A & a, const B & b) { return zip(a, b, op::mul>{}); } template constexpr arith_result_t operator / (const A & a, const B & b) { return zip(a, b, op::div>{}); } template constexpr arith_result_t operator % (const A & a, const B & b) { return zip(a, b, op::mod>{}); } template constexpr arith_result_t operator | (const A & a, const B & b) { return zip(a, b, op::binary_or>{}); } template constexpr arith_result_t operator ^ (const A & a, const B & b) { return zip(a, b, op::binary_xor>{}); } template constexpr arith_result_t operator & (const A & a, const B & b) { return zip(a, b, op::binary_and>{}); } template constexpr arith_result_t operator << (const A & a, const B & b) { return zip(a, b, op::lshift>{}); } template constexpr arith_result_t operator >> (const A & a, const B & b) { return zip(a, b, op::rshift>{}); } // Overloads for assignment operators are implemented trivially template result_t & operator += (A & a, const B & b) { return a = a + b; } template result_t & operator -= (A & a, const B & b) { return a = a - b; } template result_t & operator *= (A & a, const B & b) { return a = a * b; } template result_t & operator /= (A & a, const B & b) { return a = a / b; } template result_t & operator %= (A & a, const B & b) { return a = a % b; } template result_t & operator |= (A & a, const B & b) { return a = a | b; } template result_t & operator ^= (A & a, const B & b) { return a = a ^ b; } template result_t & operator &= (A & a, const B & b) { return a = a & b; } template result_t & operator <<= (A & a, const B & b) { return a = a << b; } template result_t & operator >>= (A & a, const B & b) { return a = a >> b; } // Mirror the set of binary scalar math functions to apply elementwise to vectors template constexpr result_t min (const A & a, const B & b) { return zip(a, b, op::min>{}); } template constexpr result_t max (const A & a, const B & b) { return zip(a, b, op::max>{}); } template constexpr result_t clamp(const A & a, const B & b, const B & c) { return min(max(a,b),c); } // TODO: Revisit template result_t fmod (const A & a, const B & b) { return zip(a, b, [](scalar_t l, scalar_t r) { return std::fmod (l, r); }); } template result_t pow (const A & a, const B & b) { return zip(a, b, [](scalar_t l, scalar_t r) { return std::pow (l, r); }); } template result_t atan2 (const A & a, const B & b) { return zip(a, b, [](scalar_t l, scalar_t r) { return std::atan2 (l, r); }); } template result_t copysign(const A & a, const B & b) { return zip(a, b, [](scalar_t l, scalar_t r) { return std::copysign(l, r); }); } // Functions for componentwise application of equivalence and relational operators template bool_result_t equal (const A & a, const B & b) { return zip(a, b, op::equal >{}); } template bool_result_t nequal (const A & a, const B & b) { return zip(a, b, op::nequal >{}); } template bool_result_t less (const A & a, const B & b) { return zip(a, b, op::less >{}); } template bool_result_t greater(const A & a, const B & b) { return zip(a, b, op::greater>{}); } template bool_result_t lequal (const A & a, const B & b) { return zip(a, b, op::lequal >{}); } template bool_result_t gequal (const A & a, const B & b) { return zip(a, b, op::gequal >{}); } // Support for vector algebra template constexpr T cross (const vec & a, const vec & b) { return a.x*b.y-a.y*b.x; } template constexpr vec cross (T a, const vec & b) { return {-a*b.y, a*b.x}; } template constexpr vec cross (const vec & a, T b) { return {a.y*b, -a.x*b}; } template constexpr vec cross (const vec & a, const vec & b) { return {a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x}; } template constexpr T dot (const vec & a, const vec & b) { return sum(a*b); } template constexpr T length2 (const vec & a) { return dot(a,a); } template T length (const vec & a) { return std::sqrt(length2(a)); } template vec normalize(const vec & a) { return a / length(a); } template constexpr T distance2(const vec & a, const vec & b) { return length2(b-a); } template T distance (const vec & a, const vec & b) { return length(b-a); } template T uangle (const vec & a, const vec & b) { T d=dot(a,b); return d > 1 ? 0 : std::acos(d < -1 ? -1 : d); } template T angle (const vec & a, const vec & b) { return uangle(normalize(a), normalize(b)); } template vec rot (T a, const vec & v) { const T s = std::sin(a), c = std::cos(a); return {v.x*c - v.y*s, v.x*s + v.y*c}; } template constexpr vec lerp (const vec & a, const vec & b, T t) { return a*(1-t) + b*t; } template vec nlerp (const vec & a, const vec & b, T t) { return normalize(lerp(a,b,t)); } template vec slerp (const vec & a, const vec & b, T t) { T th=uangle(a,b); return th == 0 ? a : a*(std::sin(th*(1-t))/std::sin(th)) + b*(std::sin(th*t)/std::sin(th)); } template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x, a*b.y}; } template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x, a*b.y, a*b.z}; } template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x, a*b.y, a*b.z, a*b.w}; } // Support for quaternion algebra using 4D vectors, representing xi + yj + zk + w template constexpr vec qconj(const vec & q) { return {-q.x,-q.y,-q.z,q.w}; } template vec qinv (const vec & q) { return qconj(q)/length2(q); } template vec qexp (const vec & q) { const auto v = q.xyz(); const auto vv = length(v); return std::exp(q.w) * vec{v * (vv > 0 ? std::sin(vv)/vv : 0), std::cos(vv)}; } template vec qlog (const vec & q) { const auto v = q.xyz(); const auto vv = length(v), qq = length(q); return {v * (vv > 0 ? std::acos(q.w/qq)/vv : 0), std::log(qq)}; } template vec qpow (const vec & q, const T & p) { const auto v = q.xyz(); const auto vv = length(v), qq = length(q), th = std::acos(q.w/qq); return std::pow(qq,p)*vec{v * (vv > 0 ? std::sin(p*th)/vv : 0), std::cos(p*th)}; } template constexpr vec qmul (const vec & a, const vec & b) { return {a.x*b.w+a.w*b.x+a.y*b.z-a.z*b.y, a.y*b.w+a.w*b.y+a.z*b.x-a.x*b.z, a.z*b.w+a.w*b.z+a.x*b.y-a.y*b.x, a.w*b.w-a.x*b.x-a.y*b.y-a.z*b.z}; } template constexpr vec qmul(const vec & a, R... r) { return qmul(a, qmul(r...)); } // Support for 3D spatial rotations using quaternions, via qmul(qmul(q, v), qconj(q)) template constexpr vec qxdir (const vec & q) { return {q.w*q.w+q.x*q.x-q.y*q.y-q.z*q.z, (q.x*q.y+q.z*q.w)*2, (q.z*q.x-q.y*q.w)*2}; } template constexpr vec qydir (const vec & q) { return {(q.x*q.y-q.z*q.w)*2, q.w*q.w-q.x*q.x+q.y*q.y-q.z*q.z, (q.y*q.z+q.x*q.w)*2}; } template constexpr vec qzdir (const vec & q) { return {(q.z*q.x+q.y*q.w)*2, (q.y*q.z-q.x*q.w)*2, q.w*q.w-q.x*q.x-q.y*q.y+q.z*q.z}; } template constexpr mat qmat (const vec & q) { return {qxdir(q), qydir(q), qzdir(q)}; } template constexpr vec qrot (const vec & q, const vec & v) { return qxdir(q)*v.x + qydir(q)*v.y + qzdir(q)*v.z; } template T qangle(const vec & q) { return std::atan2(length(q.xyz()), q.w)*2; } template vec qaxis (const vec & q) { return normalize(q.xyz()); } template vec qnlerp(const vec & a, const vec & b, T t) { return nlerp(a, dot(a,b) < 0 ? -b : b, t); } template vec qslerp(const vec & a, const vec & b, T t) { return slerp(a, dot(a,b) < 0 ? -b : b, t); } // Support for matrix algebra template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x + a.y*b.y; } template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x + a.y*b.y + a.z*b.z; } template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; } template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x), mul(a,b.y)}; } template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x), mul(a,b.y), mul(a,b.z)}; } template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x), mul(a,b.y), mul(a,b.z), mul(a,b.w)}; } #if _MSC_VER >= 1910 template constexpr auto mul(const mat & a, R... r) { return mul(a, mul(r...)); } #else template constexpr auto mul(const mat & a, R... r) -> decltype(mul(a, mul(r...))) { return mul(a, mul(r...)); } #endif template constexpr vec diagonal(const mat & a) { return {a.x.x, a.y.y}; } template constexpr vec diagonal(const mat & a) { return {a.x.x, a.y.y, a.z.z}; } template constexpr vec diagonal(const mat & a) { return {a.x.x, a.y.y, a.z.z, a.w.w}; } template constexpr mat transpose(const mat & m) { return {m.row(0), m.row(1)}; } template constexpr mat transpose(const mat & m) { return {m.row(0), m.row(1), m.row(2)}; } template constexpr mat transpose(const mat & m) { return {m.row(0), m.row(1), m.row(2), m.row(3)}; } template constexpr mat adjugate(const mat & a) { return {{a.y.y, -a.x.y}, {-a.y.x, a.x.x}}; } template constexpr mat adjugate(const mat & a); template constexpr mat adjugate(const mat & a); template constexpr T determinant(const mat & a) { return a.x.x*a.y.y - a.x.y*a.y.x; } template constexpr T determinant(const mat & a) { return a.x.x*(a.y.y*a.z.z - a.z.y*a.y.z) + a.x.y*(a.y.z*a.z.x - a.z.z*a.y.x) + a.x.z*(a.y.x*a.z.y - a.z.x*a.y.y); } template constexpr T determinant(const mat & a); template constexpr mat inverse(const mat & a) { return adjugate(a)/determinant(a); } // Vectors and matrices can be used as ranges template T * begin( vec & a) { return &a[0]; } template const T * begin(const vec & a) { return &a[0]; } template T * end ( vec & a) { return begin(a) + M; } template const T * end (const vec & a) { return begin(a) + M; } template vec * begin( mat & a) { return &a[0]; } template const vec * begin(const mat & a) { return &a[0]; } template vec * end ( mat & a) { return begin(a) + N; } template const vec * end (const mat & a) { return begin(a) + N; } // linalg::identity is a constant which can be assigned to any square matrix type struct identity_t { constexpr identity_t() {}; template constexpr operator mat() const { return {{1,0},{0,1}}; } template constexpr operator mat() const { return {{1,0,0},{0,1,0},{0,0,1}}; } template constexpr operator mat() const { return {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}; } }; static constexpr const identity_t identity {}; // Factory functions for 3D spatial transformations (will possibly be removed or changed in a future version) enum fwd_axis { neg_z, pos_z }; // Should projection matrices be generated assuming forward is {0,0,-1} or {0,0,1} enum z_range { neg_one_to_one, zero_to_one }; // Should projection matrices map z into the range of [-1,1] or [0,1]? template vec rotation_quat (const vec & axis, T angle) { return {axis*std::sin(angle/2), std::cos(angle/2)}; } template vec rotation_quat (const mat & m); template mat translation_matrix(const vec & translation) { return {{1,0,0,0},{0,1,0,0},{0,0,1,0},{translation,1}}; } template mat rotation_matrix (const vec & rotation) { return {{qxdir(rotation),0}, {qydir(rotation),0}, {qzdir(rotation),0}, {0,0,0,1}}; } template mat scaling_matrix (const vec & scaling) { return {{scaling.x,0,0,0}, {0,scaling.y,0,0}, {0,0,scaling.z,0}, {0,0,0,1}}; } template mat pose_matrix (const vec & q, const vec & p) { return {{qxdir(q),0}, {qydir(q),0}, {qzdir(q),0}, {p,1}}; } template mat frustum_matrix (T x0, T x1, T y0, T y1, T n, T f, fwd_axis a = neg_z, z_range z = neg_one_to_one); template mat perspective_matrix(T fovy, T aspect, T n, T f, fwd_axis a = neg_z, z_range z = neg_one_to_one) { T y = n*std::tan(fovy / 2), x = y*aspect; return frustum_matrix(-x, x, -y, y, n, f, a, z); } // Provide typedefs for common element types and vector/matrix sizes namespace aliases { typedef vec bool2; typedef vec byte2; typedef vec short2; typedef vec ushort2; typedef vec bool3; typedef vec byte3; typedef vec short3; typedef vec ushort3; typedef vec bool4; typedef vec byte4; typedef vec short4; typedef vec ushort4; typedef vec int2; typedef vec uint2; typedef vec float2; typedef vec double2; typedef vec int3; typedef vec uint3; typedef vec float3; typedef vec double3; typedef vec int4; typedef vec uint4; typedef vec float4; typedef vec double4; typedef mat bool2x2; typedef mat int2x2; typedef mat float2x2; typedef mat double2x2; typedef mat bool2x3; typedef mat int2x3; typedef mat float2x3; typedef mat double2x3; typedef mat bool2x4; typedef mat int2x4; typedef mat float2x4; typedef mat double2x4; typedef mat bool3x2; typedef mat int3x2; typedef mat float3x2; typedef mat double3x2; typedef mat bool3x3; typedef mat int3x3; typedef mat float3x3; typedef mat double3x3; typedef mat bool3x4; typedef mat int3x4; typedef mat float3x4; typedef mat double3x4; typedef mat bool4x2; typedef mat int4x2; typedef mat float4x2; typedef mat double4x2; typedef mat bool4x3; typedef mat int4x3; typedef mat float4x3; typedef mat double4x3; typedef mat bool4x4; typedef mat int4x4; typedef mat float4x4; typedef mat double4x4; } } // Provide specializations for std::hash<...> with linalg types namespace std { template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x) ^ (h(v.y) << 1); } }; template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x) ^ (h(v.y) << 1) ^ (h(v.z) << 2); } }; template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x) ^ (h(v.y) << 1) ^ (h(v.z) << 2) ^ (h(v.w) << 3); } }; template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x) ^ (h(v.y) << M); } }; template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x) ^ (h(v.y) << M) ^ (h(v.z) << (M*2)); } }; template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x) ^ (h(v.y) << M) ^ (h(v.z) << (M*2)) ^ (h(v.w) << (M*3)); } }; } // Definitions of functions too long to be defined inline template constexpr linalg::mat linalg::adjugate(const mat & a) { return {{a.y.y*a.z.z - a.z.y*a.y.z, a.z.y*a.x.z - a.x.y*a.z.z, a.x.y*a.y.z - a.y.y*a.x.z}, {a.y.z*a.z.x - a.z.z*a.y.x, a.z.z*a.x.x - a.x.z*a.z.x, a.x.z*a.y.x - a.y.z*a.x.x}, {a.y.x*a.z.y - a.z.x*a.y.y, a.z.x*a.x.y - a.x.x*a.z.y, a.x.x*a.y.y - a.y.x*a.x.y}}; } template constexpr linalg::mat linalg::adjugate(const mat & a) { return {{a.y.y*a.z.z*a.w.w + a.w.y*a.y.z*a.z.w + a.z.y*a.w.z*a.y.w - a.y.y*a.w.z*a.z.w - a.z.y*a.y.z*a.w.w - a.w.y*a.z.z*a.y.w, a.x.y*a.w.z*a.z.w + a.z.y*a.x.z*a.w.w + a.w.y*a.z.z*a.x.w - a.w.y*a.x.z*a.z.w - a.z.y*a.w.z*a.x.w - a.x.y*a.z.z*a.w.w, a.x.y*a.y.z*a.w.w + a.w.y*a.x.z*a.y.w + a.y.y*a.w.z*a.x.w - a.x.y*a.w.z*a.y.w - a.y.y*a.x.z*a.w.w - a.w.y*a.y.z*a.x.w, a.x.y*a.z.z*a.y.w + a.y.y*a.x.z*a.z.w + a.z.y*a.y.z*a.x.w - a.x.y*a.y.z*a.z.w - a.z.y*a.x.z*a.y.w - a.y.y*a.z.z*a.x.w}, {a.y.z*a.w.w*a.z.x + a.z.z*a.y.w*a.w.x + a.w.z*a.z.w*a.y.x - a.y.z*a.z.w*a.w.x - a.w.z*a.y.w*a.z.x - a.z.z*a.w.w*a.y.x, a.x.z*a.z.w*a.w.x + a.w.z*a.x.w*a.z.x + a.z.z*a.w.w*a.x.x - a.x.z*a.w.w*a.z.x - a.z.z*a.x.w*a.w.x - a.w.z*a.z.w*a.x.x, a.x.z*a.w.w*a.y.x + a.y.z*a.x.w*a.w.x + a.w.z*a.y.w*a.x.x - a.x.z*a.y.w*a.w.x - a.w.z*a.x.w*a.y.x - a.y.z*a.w.w*a.x.x, a.x.z*a.y.w*a.z.x + a.z.z*a.x.w*a.y.x + a.y.z*a.z.w*a.x.x - a.x.z*a.z.w*a.y.x - a.y.z*a.x.w*a.z.x - a.z.z*a.y.w*a.x.x}, {a.y.w*a.z.x*a.w.y + a.w.w*a.y.x*a.z.y + a.z.w*a.w.x*a.y.y - a.y.w*a.w.x*a.z.y - a.z.w*a.y.x*a.w.y - a.w.w*a.z.x*a.y.y, a.x.w*a.w.x*a.z.y + a.z.w*a.x.x*a.w.y + a.w.w*a.z.x*a.x.y - a.x.w*a.z.x*a.w.y - a.w.w*a.x.x*a.z.y - a.z.w*a.w.x*a.x.y, a.x.w*a.y.x*a.w.y + a.w.w*a.x.x*a.y.y + a.y.w*a.w.x*a.x.y - a.x.w*a.w.x*a.y.y - a.y.w*a.x.x*a.w.y - a.w.w*a.y.x*a.x.y, a.x.w*a.z.x*a.y.y + a.y.w*a.x.x*a.z.y + a.z.w*a.y.x*a.x.y - a.x.w*a.y.x*a.z.y - a.z.w*a.x.x*a.y.y - a.y.w*a.z.x*a.x.y}, {a.y.x*a.w.y*a.z.z + a.z.x*a.y.y*a.w.z + a.w.x*a.z.y*a.y.z - a.y.x*a.z.y*a.w.z - a.w.x*a.y.y*a.z.z - a.z.x*a.w.y*a.y.z, a.x.x*a.z.y*a.w.z + a.w.x*a.x.y*a.z.z + a.z.x*a.w.y*a.x.z - a.x.x*a.w.y*a.z.z - a.z.x*a.x.y*a.w.z - a.w.x*a.z.y*a.x.z, a.x.x*a.w.y*a.y.z + a.y.x*a.x.y*a.w.z + a.w.x*a.y.y*a.x.z - a.x.x*a.y.y*a.w.z - a.w.x*a.x.y*a.y.z - a.y.x*a.w.y*a.x.z, a.x.x*a.y.y*a.z.z + a.z.x*a.x.y*a.y.z + a.y.x*a.z.y*a.x.z - a.x.x*a.z.y*a.y.z - a.y.x*a.x.y*a.z.z - a.z.x*a.y.y*a.x.z}}; } template constexpr T linalg::determinant(const mat & a) { return a.x.x*(a.y.y*a.z.z*a.w.w + a.w.y*a.y.z*a.z.w + a.z.y*a.w.z*a.y.w - a.y.y*a.w.z*a.z.w - a.z.y*a.y.z*a.w.w - a.w.y*a.z.z*a.y.w) + a.x.y*(a.y.z*a.w.w*a.z.x + a.z.z*a.y.w*a.w.x + a.w.z*a.z.w*a.y.x - a.y.z*a.z.w*a.w.x - a.w.z*a.y.w*a.z.x - a.z.z*a.w.w*a.y.x) + a.x.z*(a.y.w*a.z.x*a.w.y + a.w.w*a.y.x*a.z.y + a.z.w*a.w.x*a.y.y - a.y.w*a.w.x*a.z.y - a.z.w*a.y.x*a.w.y - a.w.w*a.z.x*a.y.y) + a.x.w*(a.y.x*a.w.y*a.z.z + a.z.x*a.y.y*a.w.z + a.w.x*a.z.y*a.y.z - a.y.x*a.z.y*a.w.z - a.w.x*a.y.y*a.z.z - a.z.x*a.w.y*a.y.z); } template linalg::vec linalg::rotation_quat(const mat & m) { const vec q {m.x.x-m.y.y-m.z.z, m.y.y-m.x.x-m.z.z, m.z.z-m.x.x-m.y.y, m.x.x+m.y.y+m.z.z}, s[] { {1, m.x.y + m.y.x, m.z.x + m.x.z, m.y.z - m.z.y}, {m.x.y + m.y.x, 1, m.y.z + m.z.y, m.z.x - m.x.z}, {m.x.z + m.z.x, m.y.z + m.z.y, 1, m.x.y - m.y.x}, {m.y.z - m.z.y, m.z.x - m.x.z, m.x.y - m.y.x, 1}}; return copysign(normalize(sqrt(max(T(0), T(1)+q))), s[argmax(q)]); } template linalg::mat linalg::frustum_matrix(T x0, T x1, T y0, T y1, T n, T f, fwd_axis a, z_range z) { const T s = a == pos_z ? T(1) : T(-1), o = z == neg_one_to_one ? n : 0; return {{2*n/(x1-x0),0,0,0}, {0,2*n/(y1-y0),0,0}, {-s*(x0+x1)/(x1-x0),-s*(y0+y1)/(y1-y0),s*(f+o)/(f-n),s}, {0,0,-(n+o)*f/(f-n),0}}; } #endif