| /**************************************************************************** |
| ** |
| ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
| ** All rights reserved. |
| ** Contact: Nokia Corporation (qt-info@nokia.com) |
| ** |
| ** This file is part of the demonstration applications of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial Usage |
| ** Licensees holding valid Qt Commercial licenses may use this file in |
| ** accordance with the Qt Commercial License Agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and Nokia. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 2.1 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 2.1 requirements |
| ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| ** |
| ** In addition, as a special exception, Nokia gives you certain additional |
| ** rights. These rights are described in the Nokia Qt LGPL Exception |
| ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3.0 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU General Public License version 3.0 requirements will be |
| ** met: http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** If you have questions regarding the use of this file, please contact |
| ** Nokia at qt-info@nokia.com. |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #ifndef VECTOR_H |
| #define VECTOR_H |
| |
| #include <cassert> |
| #include <cmath> |
| #include <iostream> |
| |
| namespace gfx |
| { |
| |
| template<class T, int n> |
| struct Vector |
| { |
| // Keep the Vector struct a plain old data (POD) struct by avoiding constructors |
| |
| static Vector vector(T x) |
| { |
| Vector result; |
| for (int i = 0; i < n; ++i) |
| result.v[i] = x; |
| return result; |
| } |
| |
| // Use only for 2D vectors |
| static Vector vector(T x, T y) |
| { |
| assert(n == 2); |
| Vector result; |
| result.v[0] = x; |
| result.v[1] = y; |
| return result; |
| } |
| |
| // Use only for 3D vectors |
| static Vector vector(T x, T y, T z) |
| { |
| assert(n == 3); |
| Vector result; |
| result.v[0] = x; |
| result.v[1] = y; |
| result.v[2] = z; |
| return result; |
| } |
| |
| // Use only for 4D vectors |
| static Vector vector(T x, T y, T z, T w) |
| { |
| assert(n == 4); |
| Vector result; |
| result.v[0] = x; |
| result.v[1] = y; |
| result.v[2] = z; |
| result.v[3] = w; |
| return result; |
| } |
| |
| // Pass 'n' arguments to this function. |
| static Vector vector(T *v) |
| { |
| Vector result; |
| for (int i = 0; i < n; ++i) |
| result.v[i] = v[i]; |
| return result; |
| } |
| |
| T &operator [] (int i) {return v[i];} |
| T operator [] (int i) const {return v[i];} |
| |
| #define VECTOR_BINARY_OP(op, arg, rhs) \ |
| Vector operator op (arg) const \ |
| { \ |
| Vector result; \ |
| for (int i = 0; i < n; ++i) \ |
| result.v[i] = v[i] op rhs; \ |
| return result; \ |
| } |
| |
| VECTOR_BINARY_OP(+, const Vector &u, u.v[i]) |
| VECTOR_BINARY_OP(-, const Vector &u, u.v[i]) |
| VECTOR_BINARY_OP(*, const Vector &u, u.v[i]) |
| VECTOR_BINARY_OP(/, const Vector &u, u.v[i]) |
| VECTOR_BINARY_OP(+, T s, s) |
| VECTOR_BINARY_OP(-, T s, s) |
| VECTOR_BINARY_OP(*, T s, s) |
| VECTOR_BINARY_OP(/, T s, s) |
| #undef VECTOR_BINARY_OP |
| |
| Vector operator - () const |
| { |
| Vector result; |
| for (int i = 0; i < n; ++i) |
| result.v[i] = -v[i]; |
| return result; |
| } |
| |
| #define VECTOR_ASSIGN_OP(op, arg, rhs) \ |
| Vector &operator op (arg) \ |
| { \ |
| for (int i = 0; i < n; ++i) \ |
| v[i] op rhs; \ |
| return *this; \ |
| } |
| |
| VECTOR_ASSIGN_OP(+=, const Vector &u, u.v[i]) |
| VECTOR_ASSIGN_OP(-=, const Vector &u, u.v[i]) |
| VECTOR_ASSIGN_OP(=, T s, s) |
| VECTOR_ASSIGN_OP(*=, T s, s) |
| VECTOR_ASSIGN_OP(/=, T s, s) |
| #undef VECTOR_ASSIGN_OP |
| |
| static T dot(const Vector &u, const Vector &v) |
| { |
| T sum(0); |
| for (int i = 0; i < n; ++i) |
| sum += u.v[i] * v.v[i]; |
| return sum; |
| } |
| |
| static Vector cross(const Vector &u, const Vector &v) |
| { |
| assert(n == 3); |
| return vector(u.v[1] * v.v[2] - u.v[2] * v.v[1], |
| u.v[2] * v.v[0] - u.v[0] * v.v[2], |
| u.v[0] * v.v[1] - u.v[1] * v.v[0]); |
| } |
| |
| T sqrNorm() const |
| { |
| return dot(*this, *this); |
| } |
| |
| // requires floating point type T |
| void normalize() |
| { |
| T s = sqrNorm(); |
| if (s != 0) |
| *this /= sqrt(s); |
| } |
| |
| // requires floating point type T |
| Vector normalized() const |
| { |
| T s = sqrNorm(); |
| if (s == 0) |
| return *this; |
| return *this / sqrt(s); |
| } |
| |
| T *bits() {return v;} |
| const T *bits() const {return v;} |
| |
| T v[n]; |
| }; |
| |
| #define SCALAR_VECTOR_BINARY_OP(op) \ |
| template<class T, int n> \ |
| Vector<T, n> operator op (T s, const Vector<T, n>& u) \ |
| { \ |
| Vector<T, n> result; \ |
| for (int i = 0; i < n; ++i) \ |
| result[i] = s op u[i]; \ |
| return result; \ |
| } |
| |
| SCALAR_VECTOR_BINARY_OP(+) |
| SCALAR_VECTOR_BINARY_OP(-) |
| SCALAR_VECTOR_BINARY_OP(*) |
| SCALAR_VECTOR_BINARY_OP(/) |
| #undef SCALAR_VECTOR_BINARY_OP |
| |
| template<class T, int n> |
| std::ostream &operator << (std::ostream &os, const Vector<T, n> &v) |
| { |
| assert(n > 0); |
| os << "[" << v[0]; |
| for (int i = 1; i < n; ++i) |
| os << ", " << v[i]; |
| os << "]"; |
| return os; |
| } |
| |
| typedef Vector<float, 2> Vector2f; |
| typedef Vector<float, 3> Vector3f; |
| typedef Vector<float, 4> Vector4f; |
| |
| template<class T, int rows, int cols> |
| struct Matrix |
| { |
| // Keep the Matrix struct a plain old data (POD) struct by avoiding constructors |
| |
| static Matrix matrix(T x) |
| { |
| Matrix result; |
| for (int i = 0; i < rows; ++i) { |
| for (int j = 0; j < cols; ++j) |
| result.v[i][j] = x; |
| } |
| return result; |
| } |
| |
| static Matrix matrix(T *m) |
| { |
| Matrix result; |
| for (int i = 0; i < rows; ++i) { |
| for (int j = 0; j < cols; ++j) { |
| result.v[i][j] = *m; |
| ++m; |
| } |
| } |
| return result; |
| } |
| |
| T &operator () (int i, int j) {return v[i][j];} |
| T operator () (int i, int j) const {return v[i][j];} |
| Vector<T, cols> &operator [] (int i) {return v[i];} |
| const Vector<T, cols> &operator [] (int i) const {return v[i];} |
| |
| // TODO: operators, methods |
| |
| Vector<T, rows> operator * (const Vector<T, cols> &u) const |
| { |
| Vector<T, rows> result; |
| for (int i = 0; i < rows; ++i) |
| result[i] = Vector<T, cols>::dot(v[i], u); |
| return result; |
| } |
| |
| template<int k> |
| Matrix<T, rows, k> operator * (const Matrix<T, cols, k> &m) |
| { |
| Matrix<T, rows, k> result; |
| for (int i = 0; i < rows; ++i) |
| result[i] = v[i] * m; |
| return result; |
| } |
| |
| T* bits() {return reinterpret_cast<T *>(this);} |
| const T* bits() const {return reinterpret_cast<const T *>(this);} |
| |
| // Simple Gauss elimination. |
| // TODO: Optimize and improve stability. |
| Matrix inverse(bool *ok = 0) const |
| { |
| assert(rows == cols); |
| Matrix rhs = identity(); |
| Matrix lhs(*this); |
| T temp; |
| // Down |
| for (int i = 0; i < rows; ++i) { |
| // Pivoting |
| int pivot = i; |
| for (int j = i; j < rows; ++j) { |
| if (qAbs(lhs(j, i)) > lhs(pivot, i)) |
| pivot = j; |
| } |
| // TODO: fuzzy compare. |
| if (lhs(pivot, i) == T(0)) { |
| if (ok) |
| *ok = false; |
| return rhs; |
| } |
| if (pivot != i) { |
| for (int j = i; j < cols; ++j) { |
| temp = lhs(pivot, j); |
| lhs(pivot, j) = lhs(i, j); |
| lhs(i, j) = temp; |
| } |
| for (int j = 0; j < cols; ++j) { |
| temp = rhs(pivot, j); |
| rhs(pivot, j) = rhs(i, j); |
| rhs(i, j) = temp; |
| } |
| } |
| |
| // Normalize i-th row |
| rhs[i] /= lhs(i, i); |
| for (int j = cols - 1; j > i; --j) |
| lhs(i, j) /= lhs(i, i); |
| |
| // Eliminate non-zeros in i-th column below the i-th row. |
| for (int j = i + 1; j < rows; ++j) { |
| rhs[j] -= lhs(j, i) * rhs[i]; |
| for (int k = i + 1; k < cols; ++k) |
| lhs(j, k) -= lhs(j, i) * lhs(i, k); |
| } |
| } |
| // Up |
| for (int i = rows - 1; i > 0; --i) { |
| for (int j = i - 1; j >= 0; --j) |
| rhs[j] -= lhs(j, i) * rhs[i]; |
| } |
| if (ok) |
| *ok = true; |
| return rhs; |
| } |
| |
| Matrix<T, cols, rows> transpose() const |
| { |
| Matrix<T, cols, rows> result; |
| for (int i = 0; i < rows; ++i) { |
| for (int j = 0; j < cols; ++j) |
| result.v[j][i] = v[i][j]; |
| } |
| return result; |
| } |
| |
| static Matrix identity() |
| { |
| Matrix result = matrix(T(0)); |
| for (int i = 0; i < rows && i < cols; ++i) |
| result.v[i][i] = T(1); |
| return result; |
| } |
| |
| Vector<T, cols> v[rows]; |
| }; |
| |
| template<class T, int rows, int cols> |
| Vector<T, cols> operator * (const Vector<T, rows> &u, const Matrix<T, rows, cols> &m) |
| { |
| Vector<T, cols> result = Vector<T, cols>::vector(T(0)); |
| for (int i = 0; i < rows; ++i) |
| result += m[i] * u[i]; |
| return result; |
| } |
| |
| template<class T, int rows, int cols> |
| std::ostream &operator << (std::ostream &os, const Matrix<T, rows, cols> &m) |
| { |
| assert(rows > 0); |
| os << "[" << m[0]; |
| for (int i = 1; i < rows; ++i) |
| os << ", " << m[i]; |
| os << "]"; |
| return os; |
| } |
| |
| |
| typedef Matrix<float, 2, 2> Matrix2x2f; |
| typedef Matrix<float, 3, 3> Matrix3x3f; |
| typedef Matrix<float, 4, 4> Matrix4x4f; |
| |
| template<class T> |
| struct Quaternion |
| { |
| // Keep the Quaternion struct a plain old data (POD) struct by avoiding constructors |
| |
| static Quaternion quaternion(T s, T x, T y, T z) |
| { |
| Quaternion result; |
| result.scalar = s; |
| result.vector[0] = x; |
| result.vector[1] = y; |
| result.vector[2] = z; |
| return result; |
| } |
| |
| static Quaternion quaternion(T s, const Vector<T, 3> &v) |
| { |
| Quaternion result; |
| result.scalar = s; |
| result.vector = v; |
| return result; |
| } |
| |
| static Quaternion identity() |
| { |
| return quaternion(T(1), T(0), T(0), T(0)); |
| } |
| |
| // assumes that all the elements are packed tightly |
| T& operator [] (int i) {return reinterpret_cast<T *>(this)[i];} |
| T operator [] (int i) const {return reinterpret_cast<const T *>(this)[i];} |
| |
| #define QUATERNION_BINARY_OP(op, arg, rhs) \ |
| Quaternion operator op (arg) const \ |
| { \ |
| Quaternion result; \ |
| for (int i = 0; i < 4; ++i) \ |
| result[i] = (*this)[i] op rhs; \ |
| return result; \ |
| } |
| |
| QUATERNION_BINARY_OP(+, const Quaternion &q, q[i]) |
| QUATERNION_BINARY_OP(-, const Quaternion &q, q[i]) |
| QUATERNION_BINARY_OP(*, T s, s) |
| QUATERNION_BINARY_OP(/, T s, s) |
| #undef QUATERNION_BINARY_OP |
| |
| Quaternion operator - () const |
| { |
| return Quaternion(-scalar, -vector); |
| } |
| |
| Quaternion operator * (const Quaternion &q) const |
| { |
| Quaternion result; |
| result.scalar = scalar * q.scalar - Vector<T, 3>::dot(vector, q.vector); |
| result.vector = scalar * q.vector + vector * q.scalar + Vector<T, 3>::cross(vector, q.vector); |
| return result; |
| } |
| |
| Quaternion operator * (const Vector<T, 3> &v) const |
| { |
| Quaternion result; |
| result.scalar = -Vector<T, 3>::dot(vector, v); |
| result.vector = scalar * v + Vector<T, 3>::cross(vector, v); |
| return result; |
| } |
| |
| friend Quaternion operator * (const Vector<T, 3> &v, const Quaternion &q) |
| { |
| Quaternion result; |
| result.scalar = -Vector<T, 3>::dot(v, q.vector); |
| result.vector = v * q.scalar + Vector<T, 3>::cross(v, q.vector); |
| return result; |
| } |
| |
| #define QUATERNION_ASSIGN_OP(op, arg, rhs) \ |
| Quaternion &operator op (arg) \ |
| { \ |
| for (int i = 0; i < 4; ++i) \ |
| (*this)[i] op rhs; \ |
| return *this; \ |
| } |
| |
| QUATERNION_ASSIGN_OP(+=, const Quaternion &q, q[i]) |
| QUATERNION_ASSIGN_OP(-=, const Quaternion &q, q[i]) |
| QUATERNION_ASSIGN_OP(=, T s, s) |
| QUATERNION_ASSIGN_OP(*=, T s, s) |
| QUATERNION_ASSIGN_OP(/=, T s, s) |
| #undef QUATERNION_ASSIGN_OP |
| |
| Quaternion& operator *= (const Quaternion &q) |
| { |
| Quaternion result; |
| result.scalar = scalar * q.scalar - Vector<T, 3>::dot(vector, q.vector); |
| result.vector = scalar * q.vector + vector * q.scalar + Vector<T, 3>::cross(vector, q.vector); |
| return (*this = result); |
| } |
| |
| Quaternion& operator *= (const Vector<T, 3> &v) |
| { |
| Quaternion result; |
| result.scalar = -Vector<T, 3>::dot(vector, v); |
| result.vector = scalar * v + Vector<T, 3>::cross(vector, v); |
| return (*this = result); |
| } |
| |
| Quaternion conjugate() const |
| { |
| return quaternion(scalar, -vector); |
| } |
| |
| T sqrNorm() const |
| { |
| return scalar * scalar + vector.sqrNorm(); |
| } |
| |
| Quaternion inverse() const |
| { |
| return conjugate() / sqrNorm(); |
| } |
| |
| // requires floating point type T |
| Quaternion normalized() const |
| { |
| T s = sqrNorm(); |
| if (s == 0) |
| return *this; |
| return *this / sqrt(s); |
| } |
| |
| void matrix(Matrix<T, 3, 3>& m) const |
| { |
| T bb = vector[0] * vector[0]; |
| T cc = vector[1] * vector[1]; |
| T dd = vector[2] * vector[2]; |
| T diag = scalar * scalar - bb - cc - dd; |
| T ab = scalar * vector[0]; |
| T ac = scalar * vector[1]; |
| T ad = scalar * vector[2]; |
| T bc = vector[0] * vector[1]; |
| T cd = vector[1] * vector[2]; |
| T bd = vector[2] * vector[0]; |
| m(0, 0) = diag + 2 * bb; |
| m(0, 1) = 2 * (bc - ad); |
| m(0, 2) = 2 * (ac + bd); |
| m(1, 0) = 2 * (ad + bc); |
| m(1, 1) = diag + 2 * cc; |
| m(1, 2) = 2 * (cd - ab); |
| m(2, 0) = 2 * (bd - ac); |
| m(2, 1) = 2 * (ab + cd); |
| m(2, 2) = diag + 2 * dd; |
| } |
| |
| void matrix(Matrix<T, 4, 4>& m) const |
| { |
| T bb = vector[0] * vector[0]; |
| T cc = vector[1] * vector[1]; |
| T dd = vector[2] * vector[2]; |
| T diag = scalar * scalar - bb - cc - dd; |
| T ab = scalar * vector[0]; |
| T ac = scalar * vector[1]; |
| T ad = scalar * vector[2]; |
| T bc = vector[0] * vector[1]; |
| T cd = vector[1] * vector[2]; |
| T bd = vector[2] * vector[0]; |
| m(0, 0) = diag + 2 * bb; |
| m(0, 1) = 2 * (bc - ad); |
| m(0, 2) = 2 * (ac + bd); |
| m(0, 3) = 0; |
| m(1, 0) = 2 * (ad + bc); |
| m(1, 1) = diag + 2 * cc; |
| m(1, 2) = 2 * (cd - ab); |
| m(1, 3) = 0; |
| m(2, 0) = 2 * (bd - ac); |
| m(2, 1) = 2 * (ab + cd); |
| m(2, 2) = diag + 2 * dd; |
| m(2, 3) = 0; |
| m(3, 0) = 0; |
| m(3, 1) = 0; |
| m(3, 2) = 0; |
| m(3, 3) = 1; |
| } |
| |
| // assumes that 'this' is normalized |
| Vector<T, 3> transform(const Vector<T, 3> &v) const |
| { |
| Matrix<T, 3, 3> m; |
| matrix(m); |
| return v * m; |
| } |
| |
| // assumes that all the elements are packed tightly |
| T* bits() {return reinterpret_cast<T *>(this);} |
| const T* bits() const {return reinterpret_cast<const T *>(this);} |
| |
| // requires floating point type T |
| static Quaternion rotation(T angle, const Vector<T, 3> &unitAxis) |
| { |
| T s = sin(angle / 2); |
| T c = cos(angle / 2); |
| return quaternion(c, unitAxis * s); |
| } |
| |
| T scalar; |
| Vector<T, 3> vector; |
| }; |
| |
| template<class T> |
| Quaternion<T> operator * (T s, const Quaternion<T>& q) |
| { |
| return Quaternion<T>::quaternion(s * q.scalar, s * q.vector); |
| } |
| |
| typedef Quaternion<float> Quaternionf; |
| |
| } // end namespace gfx |
| |
| #endif |