/* Copyright (C) 2017 Eric Wasylishen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See file, 'COPYING', for details. */ #ifndef __COMMON_QVEC_HH__ #define __COMMON_QVEC_HH__ #include #include #include #include #ifndef qmax // FIXME: Remove this ifdef #define qmax(a,b) (((a)>(b)) ? (a) : (b)) #define qmin(a,b) (((a)>(b)) ? (b) : (a)) #define qclamp(val, min, max) (qmax(qmin((val), (max)), (min))) #endif template class qvec { protected: T v[N]; public: qvec() { for (int i=0; i qvec(const qvec &other) { for (int i=0; i(other[i]); } template qvec(const qvec &other) { const int minSize = qmin(N,N2); // truncates if `other` is longer than `this` for (int i=0; i &other, T value) { for (int i = 0; i < N - 1; ++i) { v[i] = other[i]; } v[N-1] = value; } bool operator==(const qvec &other) const { for (int i=0; i &other) const { return !(*this == other); } T operator[](const int idx) const { assert(idx >= 0 && idx < N); return v[idx]; } T &operator[](const int idx) { assert(idx >= 0 && idx < N); return v[idx]; } void operator+=(const qvec &other) { for (int i=0; i &other) { for (int i=0; i operator+(const qvec &other) const { qvec res(*this); res += other; return res; } qvec operator-(const qvec &other) const { qvec res(*this); res -= other; return res; } qvec operator*(const T &scale) const { qvec res(*this); res *= scale; return res; } qvec operator/(const T &scale) const { qvec res(*this); res /= scale; return res; } qvec operator-() const { qvec res(*this); res *= -1; return res; } qvec<3, T> xyz() const { static_assert(N >= 3); return qvec<3, T>(*this); } }; namespace qv { template qvec<3,T> cross(const qvec<3,T> &v1, const qvec<3,T> &v2) { return qvec<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]); } template T dot(const qvec &v1, const qvec &v2) { T result = 0; for (int i=0; i qvec floor(const qvec &v1) { qvec res; for (int i=0; i qvec pow(const qvec &v1, const qvec &v2) { qvec res; for (int i=0; i qvec min(const qvec &v1, const qvec &v2) { qvec res; for (int i=0; i qvec max(const qvec &v1, const qvec &v2) { qvec res; for (int i=0; i T length2(const qvec &v1) { T len2 = 0; for (int i=0; i T length(const qvec &v1) { return std::sqrt(length2(v1)); } template qvec normalize(const qvec &v1) { return v1 / length(v1); } template T distance(const qvec &v1, const qvec &v2) { return length(v2 - v1); } std::string to_string(const qvec<3,float> &v1); template bool epsilonEqual(const qvec &v1, const qvec &v2, T epsilon) { for (int i=0; i epsilon) return false; } return true; } template int indexOfLargestMagnitudeComponent(const qvec &v) { int largestIndex = 0; T largestMag = 0; for (int i=0; i largestMag) { largestMag = currentMag; largestIndex = i; } } return largestIndex; } }; using qvec2f = qvec<2, float>; using qvec3f = qvec<3, float>; using qvec4f = qvec<4, float>; using qvec2d = qvec<2, double>; using qvec3d = qvec<3, double>; using qvec4d = qvec<4, double>; using qvec2i = qvec<2, int>; template class qplane3 { private: qvec<3, T> m_normal; T m_dist; public: qplane3(const qvec<3, T> &normal, const T &dist) : m_normal(normal), m_dist(dist) {} T distAbove(const qvec<3, T> &pt) const { return qv::dot(pt, m_normal) - m_dist; } const qvec<3, T> &normal() const { return m_normal; } const T dist() const { return m_dist; } const qvec<4, T> vec4() const { return qvec<4, T>(m_normal[0], m_normal[1], m_normal[2], m_dist); } }; using qplane3f = qplane3; using qplane3d = qplane3; /** * M row, N column matrix. */ template class qmat { public: /** * Column-major order. [ (row0,col0), (row1,col0), .. ] */ T m_values[M*N]; public: /** * Identity matrix if square, otherwise fill with 0 */ qmat() { for (int i=0; iat(i,i) = 1; } } } /** * Fill with a value */ qmat(T val) { for (int i=0; i &other) { for (int i=0; im_values[i] = other.m_values[i]; } /** * Casting from another matrix type of the same size */ template qmat(const qmat &other) { for (int i=0; im_values[i] = static_cast(other.m_values[i]); } // initializer list, column-major order qmat(std::initializer_list list) { assert(list.size() == M*N); const T *listPtr = list.begin(); for (int i=0; im_values[i] = listPtr[i]; } } bool operator==(const qmat &other) const { for (int i=0; im_values[i] != other.m_values[i]) return false; return true; } // access to elements T& at(int row, int col) { assert(row >= 0 && row < M); assert(col >= 0 && col < N); return m_values[col * M + row]; } T at(int row, int col) const { assert(row >= 0 && row < M); assert(col >= 0 && col < N); return m_values[col * M + row]; } // hacky accessor for mat[col][row] access const T* operator[](int col) const { assert(col >= 0 && col < N); return &m_values[col * M]; } T* operator[](int col) { assert(col >= 0 && col < N); return &m_values[col * M]; } // multiplication by a vector qvec operator*(const qvec &vec) const { qvec res(0); for (int i=0; iat(i, j) * vec[j]; } } return res; } // multiplication by a matrix template qmat operator*(const qmat &other) const { qmat res; for (int i=0; iat(i,k) * other.at(k,j); } res.at(i,j) = val; } } return res; } // multiplication by a scalar qmat operator*(const T scalar) const { qmat res(*this); for (int i=0; i; using qmat2x3f = qmat<2, 3, float>; using qmat2x4f = qmat<2, 4, float>; using qmat3x2f = qmat<3, 2, float>; using qmat3x3f = qmat<3, 3, float>; using qmat3x4f = qmat<3, 4, float>; using qmat4x2f = qmat<4, 2, float>; using qmat4x3f = qmat<4, 3, float>; using qmat4x4f = qmat<4, 4, float>; using qmat2x2d = qmat<2, 2, double>; using qmat2x3d = qmat<2, 3, double>; using qmat2x4d = qmat<2, 4, double>; using qmat3x2d = qmat<3, 2, double>; using qmat3x3d = qmat<3, 3, double>; using qmat3x4d = qmat<3, 4, double>; using qmat4x2d = qmat<4, 2, double>; using qmat4x3d = qmat<4, 3, double>; using qmat4x4d = qmat<4, 4, double>; namespace qv { /** * These return a matrix filled with NaN if there is no inverse. */ qmat4x4f inverse(const qmat4x4f &input); qmat4x4d inverse(const qmat4x4d &input); qmat2x2f inverse(const qmat2x2f &input); }; #endif /* __COMMON_QVEC_HH__ */