Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef bqtPrender2_MathHH
- #define bqtPrender2_MathHH
- #include <type_traits> // std::decay_t
- #include <functional>
- #include <cmath>
- //#include <cstring> // memcmp
- //#include <numeric> // std::inner_product
- #include <algorithm> // std::transform
- /* Contents of this include header:
- vec<T,N>
- xy<T> = alias to vec<T,2>
- xyz<T> = alias to vec<T,3>
- mat<T,N>
- quat<T>
- Plane
- overlap(a0,a1, b0,b1)
- IntersectBox(amin,amax, bmin,bmax)
- */
- template<typename T, unsigned N> struct vec;
- template<typename T, typename U> struct arith_result { typedef decltype(T() + U()) type; };
- template<typename T> struct arith_result<T,T> { typedef T type; };
- template<typename T, unsigned M,typename F> struct arith_result<T, vec<F,M>> : public arith_result<T,F> {};
- template<typename T, unsigned M,typename F> struct arith_result<vec<F,M>,T> : public arith_result<T,F> {};
- template<typename T, typename U> struct multiply_result : public arith_result<T,U> {};
- template<> struct multiply_result<int,int> { typedef long long type; };
- template<typename T, typename U> using multiply_result_t = typename multiply_result<std::decay_t<T>,std::decay_t<U>>::type;
- template<typename T, typename U> using arith_result_t = typename arith_result<std::decay_t<T>,std::decay_t<U>>::type;
- template<typename T, unsigned N, typename U>
- auto CrossProduct(const vec<T,N>& a, const vec<U,N>& b);
- template<typename U,typename> struct disallow_vec { typedef U type; };
- template<typename U,unsigned M,typename F> struct disallow_vec<U,vec<F,M>> { };
- template<typename U,typename T> using disallow_vec_t = typename disallow_vec<std::decay_t<U>,std::decay_t<T>>::type;
- #define VEC_GENERIC_METHODS(name) \
- typedef T value_type; \
- static constexpr unsigned size() { return N; } \
- \
- template<typename... Rest> \
- name(Rest&&... rest) : d{} \
- { \
- Assign<0u>(std::forward<Rest>(rest)...); \
- } \
- void Reset() \
- { \
- *this = vec<T,N>(); \
- } \
- void Normalize() \
- { \
- auto len = Length(); \
- if(len <= T(1e-30)) { Reset(); return; } \
- *this *= ( T(T(1) / len) ); \
- } \
- template<typename U> \
- auto DotProduct(const vec<U,N>& b) const { return (*this * b).HorizontalSum(); } \
- auto DotProduct(vec<T,N> b) const { return (*this * b).HorizontalSum(); } \
- \
- auto Normalized() const { vec<T,N> r{*this}; r.Normalize(); return r; } \
- auto DotSelf() const { return this->DotProduct(*this); } \
- auto Length() const { return std::sqrt(DotSelf()); } \
- \
- template<typename U> bool operator==(const vec<U,N>& b) const \
- { \
- for(unsigned n=0; n<N; ++n) if( (*this)[n] != b[n]) return false; \
- return true; \
- } \
- template<typename U> bool operator!=(const vec<U,N>& b) const \
- { \
- for(unsigned n=0; n<N; ++n) if( (*this)[n] != b[n]) return true; \
- return false; \
- } \
- template<typename U> bool operator<(const vec<U,N>& b) const \
- { \
- for(unsigned n=0; n<N; ++n) if((*this)[n] != b[n]) return (*this)[n] < b[n]; \
- return false; \
- } \
- \
- template<unsigned First, typename... Rest> \
- inline void PartialAssign(Rest&&... rest) \
- { \
- Assign<First>(std::forward<Rest>(rest)..., nullptr); \
- } \
- template<unsigned M, unsigned First=0> vec<T,M> Limit() const \
- { \
- static_assert(First+M <= N, "Limit: Out of range"); \
- vec<T,M> result; \
- for(unsigned n=0; n<M; ++n) result.set(n, (*this)[First+n]); \
- return result; \
- } \
- private: \
- template<unsigned index, typename U, unsigned N2, typename... Rest> \
- inline void Assign(const vec<U,N2>& b, Rest&&... rest) \
- { \
- static_assert(index+N2 <= N, "Assign: Too many parameters"); \
- for(unsigned n=0; n<N2; ++n) this->set(index+n, b[n]); \
- /*std::copy(b.d, b.d+N2, (*this)+index);*/ \
- Assign<index+N2>(std::forward<Rest>(rest)...); \
- } \
- template<unsigned index, typename V, typename... Rest> \
- inline disallow_vec_t<void, std::decay_t<V>> Assign(V&& v, Rest&&... rest) \
- { \
- static_assert(index<N, "Assign: Too many parameters"); \
- this->set(index, std::forward<V>(v)); \
- Assign<index+1>(std::forward<Rest>(rest)...); \
- } \
- template<unsigned index> \
- inline void Assign() \
- { \
- static_assert(index == 0 || index >= N, "Assign: Too few parameters"); \
- } \
- template<unsigned index> \
- inline void Assign(std::nullptr_t) \
- { \
- } \
- public: \
- /* Promote both operands to a vector of the result type if possible */ \
- template<typename U> std::enable_if_t<!std::is_same<T,U>::value, vec<arith_result_t<T,U>,N>> operator+(const vec<U,N>& b) const \
- { \
- typedef vec<arith_result_t<T,U>,N> R; \
- return R((const vec<T,N>&)*this) + R(b); \
- } \
- template<typename U> std::enable_if_t<!std::is_same<T,U>::value, vec<arith_result_t<T,U>,N>> operator-(const vec<U,N>& b) const \
- { \
- typedef vec<arith_result_t<T,U>,N> R; \
- return R((const vec<T,N>&)*this) - R(b); \
- } \
- template<typename U> std::enable_if_t<!std::is_same<T,U>::value, vec<multiply_result_t<T,U>,N>> operator*(const vec<U,N>& b) const \
- { \
- typedef vec<multiply_result_t<T,U>,N> R; \
- return R((const vec<T,N>&)*this) * R(b); \
- } \
- template<typename U> std::enable_if_t<!std::is_same<T,U>::value, vec<arith_result_t<T,U>,N>> operator/(const vec<U,N>& b) const \
- { \
- typedef vec<arith_result_t<T,U>,N> R; \
- return R((const vec<T,N>&)*this) / R(b); \
- } \
- /* Arithmetic operators with basic operands */ \
- template<typename U> disallow_vec_t<vec<arith_result_t<T,U>,N>,U> operator+(U&& b) const \
- { \
- vec<arith_result_t<T,U>,N> result; \
- for(unsigned n=0; n<N; ++n) result.set(n, (*this)[n] + std::forward<U>(b)); \
- return result; \
- } \
- template<typename U> disallow_vec_t<vec<arith_result_t<T,U>,N>,U> operator-(U&& b) const \
- { \
- vec<arith_result_t<T,U>,N> result; \
- for(unsigned n=0; n<N; ++n) result.set(n, (*this)[n] - std::forward<U>(b)); \
- return result; \
- } \
- template<typename U> disallow_vec_t<vec<multiply_result_t<T,U>,N>,U> operator*(U&& b) const \
- { \
- vec<multiply_result_t<T,U>,N> result; \
- for(unsigned n=0; n<N; ++n) result.set(n, (*this)[n] * std::forward<U>(b)); \
- return result; \
- } \
- template<typename U> disallow_vec_t<vec<arith_result_t<T,U>,N>,U> operator/(U&& b) const \
- { \
- vec<arith_result_t<T,U>,N> result; \
- for(unsigned n=0; n<N; ++n) result.set(n, (*this)[n] / std::forward<U>(b)); \
- return result; \
- } \
- /* Promote the second operand to the target type if possible */ \
- template<typename U> std::enable_if_t<!std::is_same<T,U>::value, vec<T,N>&> operator+=(const vec<U,N>& b) const \
- { \
- return *this += vec<T,N>(b); \
- } \
- template<typename U> std::enable_if_t<!std::is_same<T,U>::value, vec<T,N>&> operator-=(const vec<U,N>& b) const \
- { \
- return *this -= vec<T,N>(b); \
- } \
- template<typename U> std::enable_if_t<!std::is_same<T,U>::value, vec<T,N>&> operator*=(const vec<U,N>& b) const \
- { \
- return *this *= vec<T,N>(b); \
- } \
- template<typename U> std::enable_if_t<!std::is_same<T,U>::value, vec<T,N>&> operator/=(const vec<U,N>& b) const \
- { \
- return *this /= vec<T,N>(b); \
- } \
- /* Generic RMW operators */ \
- template<typename U> auto& operator+=(U&& b) { return *this = *this + std::forward<U>(b); } \
- template<typename U> auto& operator-=(U&& b) { return *this = *this - std::forward<U>(b); } \
- template<typename U> auto& operator*=(U&& b) { return *this = *this * std::forward<U>(b); } \
- template<typename U> auto& operator/=(U&& b) { return *this = *this / std::forward<U>(b); }
- template<typename T, unsigned N>
- struct vec
- {
- private:
- T d[N];
- public:
- VEC_GENERIC_METHODS(vec)
- public:
- vec() : d{} {}
- inline const T& operator[](unsigned n) const { return d[n]; }
- template<typename U>
- inline void set(unsigned n, U&& v) { d[n] = std::forward<U>(v); }
- #pragma omp declare simd
- T HorizontalSum() const
- {
- T result{};
- #pragma omp simd
- for(unsigned n=0; n<N; ++n) result += d[n];
- return result;
- }
- #pragma omp declare simd
- void clamp(T min, T max)
- {
- #pragma omp simd
- for(unsigned n=0; n<N; ++n)
- set(n, std::min(std::max((*this)[n], min), max));
- }
- template<typename U>
- inline auto CrossProduct(const vec<U,N>& b) const;
- /* Arithmetic operators with vector operands */
- vec<T,N> operator+ (const vec<T,N>& b) const
- {
- vec<T,N> result = *this;
- for(unsigned n=0; n<N; ++n) result.set(n, result[n] + b[n]);
- return result;
- }
- vec<T,N> operator- (const vec<T,N>& b) const
- {
- vec<T,N> result = *this;
- for(unsigned n=0; n<N; ++n) result.set(n, result[n] - b[n]);
- return result;
- }
- vec<T,N> operator* (const vec<T,N>& b) const
- {
- vec<T,N> result = *this;
- for(unsigned n=0; n<N; ++n) result.set(n, result[n] * b[n]);
- return result;
- }
- vec<T,N> operator/ (const vec<T,N>& b) const
- {
- vec<T,N> result = *this;
- for(unsigned n=0; n<N; ++n) result.set(n, result[n] / b[n]);
- return result;
- }
- vec<T,N> operator-() const
- {
- vec<T, N> result = *this;
- #pragma omp simd
- for(unsigned n=0; n<N; ++n) result.set(n, -result[n]);
- return result;
- }
- };
- template<typename T, typename U>
- auto CrossProduct(const vec<T,2>& a, const vec<U,2>& b)
- {
- auto mult = vec<U,2>(b[1],b[0]) * a;
- return mult[0] - mult[1];
- }
- template<typename T, typename U>
- auto CrossProduct(const vec<T,3>& a, const vec<U,3>& b)
- {
- auto mult = vec<T,8>{0, a[1],a[2],a[0], 0, a[2],a[0],a[1]}
- * vec<U,8>{0, b[2],b[0],b[1], 0, b[1],b[2],b[0]};
- return (mult.template Limit<4,0>() - mult.template Limit<4,4>()).template Limit<3,1>();
- }
- #if defined(__has_include)
- #if __has_include("math_simd.hh")
- #include "math_simd.hh"
- #endif
- #endif
- template<typename T> struct vec<T,0>
- {
- public:
- vec() {}
- vec(const vec<T,0>& ) {}
- T operator[](unsigned) const { return {}; }
- template<typename U> inline void set(unsigned, U&& ) {}
- T HorizontalSum() const { return {}; }
- T DotProduct(const vec<T,0>& ) const { return {}; }
- template<typename U> vec<T,0> operator+ (U&& ) const { return *this; }
- template<typename U> vec<T,0> operator- (U&& ) const { return *this; }
- template<typename U> vec<T,0> operator* (U&& ) const { return *this; }
- template<typename U> vec<T,0> operator/ (U&& ) const { return *this; }
- template<typename U> vec<T,0>& operator+= (U&& ) { return *this; }
- template<typename U> vec<T,0>& operator-= (U&& ) { return *this; }
- template<typename U> vec<T,0>& operator*= (U&& ) { return *this; }
- template<typename U> vec<T,0>& operator/= (U&& ) { return *this; }
- vec<T,0> operator- () const { return *this; }
- void clamp(T,T) {}
- };
- template<typename T> using xy = vec<T,2>;
- template<typename T> using xyz = vec<T,3>;
- template<typename T,unsigned N> template<typename U>
- inline auto vec<T,N>::CrossProduct(const vec<U,N>& b) const
- {
- return ::CrossProduct(*this, b);
- }
- template<typename T, unsigned N>
- struct mat
- {
- vec<T,N> d[N];
- template<typename U>
- auto Transform(const vec<U,N>& v) const
- {
- return transform(v, std::make_index_sequence<N>());
- }
- template<typename U>
- auto operator* (const mat<U,N>& m) const
- {
- return multiply(m, std::make_index_sequence<N>());
- }
- template<typename U>
- mat<T,N>& operator*= (const mat<U,N>& b) { return *this = (*this) * b; }
- private:
- template<typename U, std::size_t... Indexes>
- auto transform(const vec<U,N>& v, std::index_sequence<Indexes...>) const
- {
- return vec<multiply_result_t<T,U>,N> { v.DotProduct(d[Indexes]) ... };
- }
- template<typename U, std::size_t... Indexes>
- auto multiply(const mat<U,N>& m, std::index_sequence<Indexes...>) const
- {
- mat<multiply_result_t<T,U>,N> r;
- //#pragma omp simd collapse(2)
- for(unsigned i=0; i<N; ++i)
- for(unsigned j=0; j<N; ++j)
- r.d[i].set(j, (d[i] * vec<T,N> { m.d[Indexes][j]... }).HorizontalSum());
- return r;
- }
- };
- template<typename T>
- struct quat : private vec<T,4> /* quaternion. a, x,y,z */
- {
- quat() : vec<T,4>{1, 0,0,0} {}
- template<typename U>
- quat(U a,U b,U c,U d) : vec<T,4>{a,b,c,d} {}
- template<typename U, typename H>
- quat(xyz<U>&& refvec, H theta) { FromAngle(theta, refvec); }
- quat(vec<T,4> refvec) : vec<T,4>(refvec) {}
- quat(const mat<T,3>& rot) { FromMatrix(rot); }
- using vec<T,4>::operator[];
- void Reset() { *this = {1, 0,0,0}; }
- template<typename H, typename U>
- void FromAngle(H theta, const xyz<U>& vector)
- {
- auto c = std::cos(theta * H(H(1)/H(2)));
- auto s = std::sin(theta * H(H(1)/H(2)));
- vec<T,4>::operator=( vec<T,4>(1,vector) * vec<T,4>(c,s,s,s) );
- //a = c;
- //v3 = vector * s;
- }
- mat<T,3> MakeMatrix() const
- {
- auto a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3];
- return {{{a*a + b*b - c*c - d*d, 2*(b*c - a*d), 2*(b*d + a*c)},
- {2*(b*c + a*d), a*a - b*b + c*c - d*d, 2*(c*d - a*b)},
- {2*(b*d - a*c), 2*(c*d + a*b), a*a - b*b - c*c + d*d}}};
- };
- // Optimization when we know this is a unit quaternion
- mat<T,3> MakeMatrix_unit() const
- {
- auto a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3];
- return {{{T(1) - 2*(c*c + d*d), 2*(b*c - a*d), 2*(b*d + a*c)},
- {2*(b*c + a*d), T(1) - 2*(b*b + d*d), 2*(c*d - a*b)},
- {2*(b*d - a*c), 2*(c*d + a*b), T(1) - 2*(b*b + c*c)}}};
- };
- void FromMatrix(const mat<T,3>& rot)
- {
- /* From
- * http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
- */
- const T m00 = rot.d[0][0], m01 = rot.d[0][1], m02 = rot.d[0][2];
- const T m10 = rot.d[1][0], m11 = rot.d[1][1], m12 = rot.d[1][2];
- const T m20 = rot.d[2][0], m21 = rot.d[2][1], m22 = rot.d[2][2];
- T tr = m00 + m11 + m22, S;
- vec<T,4>& vek = *this;
- if (tr > 0) vek = { S = 1.0f + tr, m21-m12, m02-m20, m10-m01 };
- else if (m00 > m11 && m00 > m22) vek = { m21-m12, S = 1.0f + m00 - m11 - m22, m01+m10, m02+m20 };
- else if (m11 > m22) vek = { m02-m20, m01+m10, S = 1.0f + m11 - m00 - m22, m12+m21 };
- else vek = { m10-m01, m02+m20, m12+m21, S = 1.0f + m22 - m00 - m11 };
- vek *= (0.5f / std::sqrt(S));
- }
- template<typename U>
- quat<multiply_result_t<T,U>> operator* (const quat<U>& o) const
- {
- return { (vec<U,4>{ o[0],-o[1],-o[2],-o[3] } * (const vec<T,4>&)(*this)).HorizontalSum(),
- (vec<U,4>{ o[1], o[0], o[3],-o[2] } * (const vec<T,4>&)(*this)).HorizontalSum(),
- (vec<U,4>{ o[2],-o[3], o[0], o[1] } * (const vec<T,4>&)(*this)).HorizontalSum(),
- (vec<U,4>{ o[3], o[2],-o[1], o[0] } * (const vec<T,4>&)(*this)).HorizontalSum() };
- }
- template<typename U>
- quat<T>& operator*= (const quat<U>& o) { return *this = *this * o; }
- void Invert()
- {
- for(unsigned n=1; n<4; ++n) this->set(n, -(*this)[n]);
- // Note: [0] must not be negated
- }
- void Normalize()
- {
- auto len = this->Length();
- if(std::abs(len - T(1)) < T(T(1) / T(1 << 6))) return; // Don't normalize if there's no need.
- if(len <= T(1e-30)) { Reset(); return; }
- *this /= len;
- }
- quat<T> Inverted() const { return {(*this)[0], -(*this)[1], -(*this)[2], -(*this)[3]}; }
- quat<T> Normalized() const { quat<T> r { *this }; r.Normalize(); return r; }
- };
- struct Plane: private vec<double,4>
- {
- Plane() : vec() {}
- Plane(const vec<double,4>& b) : vec(b) {}
- template<typename T>
- Plane(const xyz<T>& a, const xyz<T>& b, const xyz<T>& c)
- {
- xyz<T> normal{(b-a).CrossProduct(c-a).Normalized()};
- *this = vec(normal, normal.DotProduct(a));
- }
- inline xyz<double> Normal() const { return Limit<3>(); }
- inline double Distance() const { return (*this)[3]; }
- void Invert() { *this = -*this; }
- Plane Inverted() const { return -*this; }
- double DistanceTo(const xyz<double>& point) const
- {
- return Normal().DotProduct(point) - Distance();
- }
- bool IsCoplanar(const Plane& b) const
- {
- return (Normal() - b.Normal()).DotSelf() < 1e-8
- && std::abs(Distance() - b.Distance()) < 1e-8;
- }
- bool IsOpposite(const Plane& b) const
- {
- return Inverted().IsCoplanar(b);
- }
- bool IsCoplanarOrOpposite(const Plane& b) const
- {
- return IsCoplanar(b) || IsOpposite(b);
- }
- };
- /*namespace std
- {
- template<> struct hash<Plane>
- { std::size_t operator() (const Plane& b) const {
- return std::hash<std::string>() ( std::string( (const char*)&b, (const char*)&b + sizeof(b) ) );
- }
- };
- template<typename T,unsigned N> struct hash<vec<T,N>>
- { std::size_t operator() (const vec<T,N>& b) const {
- return std::hash<std::string>() ( std::string( (const char*)&b, (const char*)&b + sizeof(b) ) );
- }
- };
- template<typename T,unsigned N, typename U>
- vec<T,N> pow(const vec<T,N>& a, const U& power)
- {
- vec<T,N> result;
- #pragma omp simd
- for(unsigned n=0; n<N; ++n) result.set(n, std::pow(a[n], power));
- return result;
- }
- }*/
- template<typename T, typename U>
- inline bool overlap(const T& a0, const T& a1, const U& b0, const U& b1)
- { return std::min(a0,a1) <= std::max(b0,b1) && std::min(b0,b1) <= std::max(a0,a1); }
- template<typename T,typename U,unsigned N>
- inline bool IntersectBox(const vec<T,N>& amin, const vec<T,N>& amax,
- const vec<U,N>& bmin, const vec<U,N>& bmax)
- {
- for(unsigned n=0; n<N; ++n)
- if(!overlap(amin[n],amax[n], bmin[n],bmax[n]))
- return false;
- return true;
- }
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement