blob: 51add21baa8e2d807278d185378620b17f6ce4b2 [file] [log] [blame]
/*
* vec_mat.h - vector and matrix defination & calculation
*
* Copyright (c) 2017 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Zong Wei <wei.zong@intel.com>
*/
#ifndef XCAM_VECTOR_MATRIX_H
#define XCAM_VECTOR_MATRIX_H
#include <xcam_std.h>
#include <cmath>
namespace XCam {
#ifndef PI
#define PI 3.14159265358979323846
#endif
#ifndef FLT_EPSILON
#define FLT_EPSILON 1.19209290e-07F // float
#endif
#ifndef DBL_EPSILON
#define DBL_EPSILON 2.2204460492503131e-16 // double
#endif
#ifndef DEGREE_2_RADIANS
#define DEGREE_2_RADIANS(x) (((x) * PI) / 180.0)
#endif
#ifndef RADIANS_2_DEGREE
#define RADIANS_2_DEGREE(x) (((x) * 180.0) / PI)
#endif
#define XCAM_VECT2_OPERATOR_VECT2(op) \
Vector2<T> operator op (const Vector2<T>& b) const { \
return Vector2<T>(x op b.x, y op b.y); \
} \
Vector2<T> &operator op##= (const Vector2<T>& b) { \
x op##= b.x; y op##= b.y; return *this; \
}
#define XCAM_VECT2_OPERATOR_SCALER(op) \
Vector2<T> operator op (const T& b) const { \
return Vector2<T>(x op b, y op b); \
} \
Vector2<T> &operator op##= (const T& b) { \
x op##= b; y op##= b; return *this; \
}
template<class T>
class Vector2
{
public:
T x;
T y;
Vector2 () : x(0), y(0) {};
Vector2 (T _x, T _y) : x(_x), y(_y) {};
template <typename New>
Vector2<New> convert_to () const {
Vector2<New> ret((New)(this->x), (New)(this->y));
return ret;
}
Vector2<T>& operator = (const Vector2<T>& rhs)
{
x = rhs.x;
y = rhs.y;
return *this;
}
template <typename Other>
Vector2<T>& operator = (const Vector2<Other>& rhs)
{
x = rhs.x;
y = rhs.y;
return *this;
}
Vector2<T> operator - () const {
return Vector2<T>(-x, -y);
}
XCAM_VECT2_OPERATOR_VECT2 (+)
XCAM_VECT2_OPERATOR_VECT2 (-)
XCAM_VECT2_OPERATOR_VECT2 (*)
XCAM_VECT2_OPERATOR_VECT2 ( / )
XCAM_VECT2_OPERATOR_SCALER (+)
XCAM_VECT2_OPERATOR_SCALER (-)
XCAM_VECT2_OPERATOR_SCALER (*)
XCAM_VECT2_OPERATOR_SCALER ( / )
bool operator == (const Vector2<T>& rhs) const {
return (x == rhs.x) && (y == rhs.y);
}
void reset () {
this->x = (T) 0;
this->y = (T) 0;
}
void set (T _x, T _y) {
this->x = _x;
this->y = _y;
}
T magnitude () const {
return (T) sqrtf(x * x + y * y);
}
float distance (const Vector2<T>& vec) const {
return sqrtf((vec.x - x) * (vec.x - x) + (vec.y - y) * (vec.y - y));
}
T dot (const Vector2<T>& vec) const {
return (x * vec.x + y * vec.y);
}
inline Vector2<T> lerp (T weight, const Vector2<T>& vec) const {
return (*this) + (vec - (*this)) * weight;
}
};
template<class T, uint32_t N>
class VectorN
{
public:
VectorN ();
VectorN (T x);
VectorN (T x, T y);
VectorN (T x, T y, T z);
VectorN (T x, T y, T z, T w);
VectorN (VectorN<T, 3> vec3, T w);
inline VectorN<T, N>& operator = (const VectorN<T, N>& rhs);
inline VectorN<T, N> operator - () const;
inline bool operator == (const VectorN<T, N>& rhs) const;
inline T& operator [] (uint32_t index) {
XCAM_ASSERT(index >= 0 && index < N);
return data[index];
}
inline const T& operator [] (uint32_t index) const {
XCAM_ASSERT(index >= 0 && index < N);
return data[index];
}
inline VectorN<T, N> operator + (const T rhs) const;
inline VectorN<T, N> operator - (const T rhs) const;
inline VectorN<T, N> operator * (const T rhs) const;
inline VectorN<T, N> operator / (const T rhs) const;
inline VectorN<T, N> operator += (const T rhs);
inline VectorN<T, N> operator -= (const T rhs);
inline VectorN<T, N> operator *= (const T rhs);
inline VectorN<T, N> operator /= (const T rhs);
inline VectorN<T, N> operator + (const VectorN<T, N>& rhs) const;
inline VectorN<T, N> operator - (const VectorN<T, N>& rhs) const;
inline VectorN<T, N> operator * (const VectorN<T, N>& rhs) const;
inline VectorN<T, N> operator / (const VectorN<T, N>& rhs) const;
inline VectorN<T, N> operator += (const VectorN<T, N>& rhs);
inline VectorN<T, N> operator -= (const VectorN<T, N>& rhs);
inline VectorN<T, N> operator *= (const VectorN<T, N>& rhs);
inline VectorN<T, N> operator /= (const VectorN<T, N>& rhs);
template <typename NEW> inline
VectorN<NEW, N> convert_to () const;
inline void zeros ();
inline void set (T x, T y);
inline void set (T x, T y, T z);
inline void set (T x, T y, T z, T w);
inline T magnitude () const;
inline float distance (const VectorN<T, N>& vec) const;
inline T dot (const VectorN<T, N>& vec) const;
inline VectorN<T, N> lerp (T weight, const VectorN<T, N>& vec) const;
private:
T data[N];
};
template<class T, uint32_t N> inline
VectorN<T, N>::VectorN ()
{
for (uint32_t i = 0; i < N; i++) {
data[i] = 0;
}
}
template<class T, uint32_t N> inline
VectorN<T, N>::VectorN (T x) {
data[0] = x;
}
template<class T, uint32_t N> inline
VectorN<T, N>::VectorN (T x, T y) {
if (N >= 2) {
data[0] = x;
data[1] = y;
}
}
template<class T, uint32_t N> inline
VectorN<T, N>::VectorN (T x, T y, T z) {
if (N >= 3) {
data[0] = x;
data[1] = y;
data[2] = z;
}
}
template<class T, uint32_t N> inline
VectorN<T, N>::VectorN (T x, T y, T z, T w) {
if (N >= 4) {
data[0] = x;
data[1] = y;
data[2] = z;
data[3] = w;
}
}
template<class T, uint32_t N> inline
VectorN<T, N>::VectorN (VectorN<T, 3> vec3, T w) {
if (N >= 4) {
data[0] = vec3.data[0];
data[1] = vec3.data[1];
data[2] = vec3.data[2];
data[3] = w;
}
}
template<class T, uint32_t N> inline
VectorN<T, N>& VectorN<T, N>::operator = (const VectorN<T, N>& rhs) {
for (uint32_t i = 0; i < N; i++) {
data[i] = rhs.data[i];
}
return *this;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator - () const {
for (uint32_t i = 0; i < N; i++) {
data[i] = -data[i];
}
return *this;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator + (const T rhs) const {
VectorN<T, N> result;
for (uint32_t i = 0; i < N; i++) {
result.data[i] = data[i] + rhs;
}
return result;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator - (const T rhs) const {
VectorN<T, N> result;
for (uint32_t i = 0; i < N; i++) {
result.data[i] = data[i] - rhs;
}
return result;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator * (const T rhs) const {
VectorN<T, N> result;
for (uint32_t i = 0; i < N; i++) {
result.data[i] = data[i] * rhs;
}
return result;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator / (const T rhs) const {
VectorN<T, N> result;
for (uint32_t i = 0; i < N; i++) {
result.data[i] = data[i] / rhs;
}
return result;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator += (const T rhs) {
for (uint32_t i = 0; i < N; i++) {
data[i] += rhs;
}
return *this;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator -= (const T rhs) {
for (uint32_t i = 0; i < N; i++) {
data[i] -= rhs;
}
return *this;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator *= (const T rhs) {
for (uint32_t i = 0; i < N; i++) {
data[i] *= rhs;
}
return *this;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator /= (const T rhs) {
for (uint32_t i = 0; i < N; i++) {
data[i] /= rhs;
}
return *this;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator + (const VectorN<T, N>& rhs) const {
VectorN<T, N> result;
for (uint32_t i = 0; i < N; i++) {
result.data[i] = data[i] + rhs.data[i];
}
return result;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator - (const VectorN<T, N>& rhs) const {
VectorN<T, N> result;
for (uint32_t i = 0; i < N; i++) {
result.data[i] = data[i] - rhs.data[i];
}
return result;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator * (const VectorN<T, N>& rhs) const {
VectorN<T, N> result;
for (uint32_t i = 0; i < N; i++) {
result.data[i] = data[i] * rhs.data[i];
}
return result;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator / (const VectorN<T, N>& rhs) const {
VectorN<T, N> result;
for (uint32_t i = 0; i < N; i++) {
result.data[i] = data[i] / rhs.data[i];
}
return result;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator += (const VectorN<T, N>& rhs) {
for (uint32_t i = 0; i < N; i++) {
data[i] += rhs.data[i];
}
return *this;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator -= (const VectorN<T, N>& rhs) {
for (uint32_t i = 0; i < N; i++) {
data[i] -= rhs.data[i];
}
return *this;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator *= (const VectorN<T, N>& rhs) {
for (uint32_t i = 0; i < N; i++) {
data[i] *= rhs.data[i];
}
return *this;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::operator /= (const VectorN<T, N>& rhs) {
for (uint32_t i = 0; i < N; i++) {
data[i] /= rhs.data[i];
}
return *this;
}
template<class T, uint32_t N> inline
bool VectorN<T, N>::operator == (const VectorN<T, N>& rhs) const {
for (uint32_t i = 0; i < N; i++) {
if (data[i] != rhs[i]) {
return false;
}
}
return true;
}
template <class T, uint32_t N>
template <typename NEW>
VectorN<NEW, N> VectorN<T, N>::convert_to () const {
VectorN<NEW, N> result;
for (uint32_t i = 0; i < N; i++) {
result[i] = (NEW)(this->data[i]);
}
return result;
}
template <class T, uint32_t N> inline
void VectorN<T, N>::zeros () {
for (uint32_t i = 0; i < N; i++) {
data[i] = (T)(0);
}
}
template<class T, uint32_t N> inline
void VectorN<T, N>::set (T x, T y) {
if (N >= 2) {
data[0] = x;
data[1] = y;
}
}
template<class T, uint32_t N> inline
void VectorN<T, N>::set (T x, T y, T z) {
if (N >= 3) {
data[0] = x;
data[1] = y;
data[2] = z;
}
}
template<class T, uint32_t N> inline
void VectorN<T, N>::set (T x, T y, T z, T w) {
if (N >= 4) {
data[0] - x;
data[1] = y;
data[2] = z;
data[3] = w;
}
}
template<class T, uint32_t N> inline
T VectorN<T, N>::magnitude () const {
T result = 0;
for (uint32_t i = 0; i < N; i++) {
result += (data[i] * data[i]);
}
return (T) sqrtf(result);
}
template<class T, uint32_t N> inline
float VectorN<T, N>::distance (const VectorN<T, N>& vec) const {
T result = 0;
for (uint32_t i = 0; i < N; i++) {
result += (vec.data[i] - data[i]) * (vec.data[i] - data[i]);
}
return sqrtf(result);
}
template<class T, uint32_t N> inline
T VectorN<T, N>::dot (const VectorN<T, N>& vec) const {
T result = 0;
for (uint32_t i = 0; i < N; i++) {
result += (vec.data[i] * data[i]);
}
return result;
}
template<class T, uint32_t N> inline
VectorN<T, N> VectorN<T, N>::lerp (T weight, const VectorN<T, N>& vec) const {
return (*this) + (vec - (*this)) * weight;
}
// NxN matrix in row major order
template<class T, uint32_t N>
class MatrixN
{
public:
MatrixN ();
MatrixN (VectorN<T, 2> a, VectorN<T, 2> b);
MatrixN (VectorN<T, 3> a, VectorN<T, 3> b, VectorN<T, 3> c);
MatrixN (VectorN<T, 4> a, VectorN<T, 4> b, VectorN<T, 4> c, VectorN<T, 4> d);
inline void zeros ();
inline void eye ();
inline T& at (uint32_t row, uint32_t col) {
XCAM_ASSERT(row >= 0 && row < N);
XCAM_ASSERT(col >= 0 && col < N);
return data[row * N + col];
};
inline const T& at (uint32_t row, uint32_t col) const {
XCAM_ASSERT(row >= 0 && row < N);
XCAM_ASSERT(col >= 0 && col < N);
return data[row * N + col];
};
inline T& operator () (uint32_t row, uint32_t col) {
return at (row, col);
};
inline const T& operator () (uint32_t row, uint32_t col) const {
return at (row, col);
};
inline MatrixN<T, N>& operator = (const MatrixN<T, N>& rhs);
inline MatrixN<T, N> operator - () const;
inline MatrixN<T, N> operator + (const MatrixN<T, N>& rhs) const;
inline MatrixN<T, N> operator - (const MatrixN<T, N>& rhs) const;
inline MatrixN<T, N> operator * (const T a) const;
inline MatrixN<T, N> operator / (const T a) const;
inline VectorN<T, N> operator * (const VectorN<T, N>& rhs) const;
inline MatrixN<T, N> operator * (const MatrixN<T, N>& rhs) const;
inline MatrixN<T, N> transpose ();
inline MatrixN<T, N> inverse ();
inline T trace ();
private:
inline MatrixN<T, 2> inverse (const MatrixN<T, 2>& mat);
inline MatrixN<T, 3> inverse (const MatrixN<T, 3>& mat);
inline MatrixN<T, 4> inverse (const MatrixN<T, 4>& mat);
private:
T data[N * N];
};
// NxN matrix in row major order
template<class T, uint32_t N>
MatrixN<T, N>::MatrixN () {
eye ();
}
template<class T, uint32_t N>
MatrixN<T, N>::MatrixN (VectorN<T, 2> a, VectorN<T, 2> b) {
if (N == 2) {
data[0] = a[0];
data[1] = a[1];
data[2] = b[0];
data[3] = b[1];
} else {
eye ();
}
}
template<class T, uint32_t N>
MatrixN<T, N>::MatrixN (VectorN<T, 3> a, VectorN<T, 3> b, VectorN<T, 3> c) {
if (N == 3) {
data[0] = a[0];
data[1] = a[1];
data[2] = a[2];
data[3] = b[0];
data[4] = b[1];
data[5] = b[2];
data[6] = c[0];
data[7] = c[1];
data[8] = c[2];
} else {
eye ();
}
}
template<class T, uint32_t N>
MatrixN<T, N>::MatrixN (VectorN<T, 4> a, VectorN<T, 4> b, VectorN<T, 4> c, VectorN<T, 4> d) {
if (N == 4) {
data[0] = a[0];
data[1] = a[1];
data[2] = a[2];
data[3] = a[3];
data[4] = b[0];
data[5] = b[1];
data[6] = b[2];
data[7] = b[3];
data[8] = c[0];
data[9] = c[1];
data[10] = c[2];
data[11] = c[3];
data[12] = d[0];
data[13] = d[1];
data[14] = d[2];
data[15] = d[3];
} else {
eye ();
}
}
template<class T, uint32_t N> inline
void MatrixN<T, N>::zeros () {
for (uint32_t i = 0; i < N * N; i++) {
data[i] = 0;
}
}
template<class T, uint32_t N> inline
void MatrixN<T, N>::eye () {
zeros ();
for (uint32_t i = 0; i < N; i++) {
data[i * N + i] = 1;
}
}
template<class T, uint32_t N> inline
MatrixN<T, N>& MatrixN<T, N>::operator = (const MatrixN<T, N>& rhs) {
for (uint32_t i = 0; i < N * N; i++) {
data[i] = rhs.data[i];
}
return *this;
}
template<class T, uint32_t N> inline
MatrixN<T, N> MatrixN<T, N>::operator - () const {
MatrixN<T, N> result;
for (uint32_t i = 0; i < N * N; i++) {
result.data[i] = -data[i];
}
return result;
}
template<class T, uint32_t N> inline
MatrixN<T, N> MatrixN<T, N>::operator + (const MatrixN<T, N>& rhs) const {
MatrixN<T, N> result;
for (uint32_t i = 0; i < N * N; i++) {
result.data[i] = data[i] + rhs.data[i];
}
return result;
}
template<class T, uint32_t N> inline
MatrixN<T, N> MatrixN<T, N>::operator - (const MatrixN<T, N>& rhs) const {
MatrixN<T, N> result;
for (uint32_t i = 0; i < N * N; i++) {
result.data[i] = data[i] - rhs.data[i];
}
return result;
}
template<class T, uint32_t N> inline
MatrixN<T, N> MatrixN<T, N>::operator * (const T a) const {
MatrixN<T, N> result;
for (uint32_t i = 0; i < N * N; i++) {
result.data[i] = data[i] * a;
}
return result;
}
template<class T, uint32_t N> inline
MatrixN<T, N> MatrixN<T, N>::operator / (const T a) const {
MatrixN<T, N> result;
for (uint32_t i = 0; i < N * N; i++) {
result.data[i] = data[i] / a;
}
return result;
}
template<class T, uint32_t N> inline
MatrixN<T, N> MatrixN<T, N>::operator * (const MatrixN<T, N>& rhs) const {
MatrixN<T, N> result;
result.zeros ();
for (uint32_t i = 0; i < N; i++) {
for (uint32_t j = 0; j < N; j++) {
T element = 0;
for (uint32_t k = 0; k < N; k++) {
element += at(i, k) * rhs(k, j);
}
result(i, j) = element;
}
}
return result;
}
template<class T, uint32_t N> inline
VectorN<T, N> MatrixN<T, N>::operator * (const VectorN<T, N>& rhs) const {
VectorN<T, N> result;
for (uint32_t i = 0; i < N; i++) { // row
for (uint32_t j = 0; j < N; j++) { // col
result.data[i] = data[i * N + j] * rhs.data[j];
}
}
return result;
}
template<class T, uint32_t N> inline
MatrixN<T, N> MatrixN<T, N>::transpose () {
MatrixN<T, N> result;
for (uint32_t i = 0; i < N; i++) {
for (uint32_t j = 0; j <= N; j++) {
result.data[i * N + j] = data[j * N + i];
}
}
return result;
}
// if the matrix is non-invertible, return identity matrix
template<class T, uint32_t N> inline
MatrixN<T, N> MatrixN<T, N>::inverse () {
MatrixN<T, N> result;
result = inverse (*this);
return result;
}
template<class T, uint32_t N> inline
T MatrixN<T, N>::trace () {
T t = 0;
for ( uint32_t i = 0; i < N; i++ ) {
t += data(i, i);
}
return t;
}
template<class T, uint32_t N> inline
MatrixN<T, 2> MatrixN<T, N>::inverse (const MatrixN<T, 2>& mat)
{
MatrixN<T, 2> result;
T det = mat(0, 0) * mat(1, 1) - mat(0, 1) * mat(1, 0);
if (det == (T)0) {
return result;
}
result(0, 0) = mat(1, 1);
result(0, 1) = -mat(0, 1);
result(1, 0) = -mat(1, 0);
result(1, 1) = mat(0, 0);
return result * (1.0f / det);
}
template<class T, uint32_t N> inline
MatrixN<T, 3> MatrixN<T, N>::inverse (const MatrixN<T, 3>& mat)
{
MatrixN<T, 3> result;
T det = mat(0, 0) * mat(1, 1) * mat(2, 2) +
mat(1, 0) * mat(2, 1) * mat(0, 2) +
mat(2, 0) * mat(0, 1) * mat(1, 2) -
mat(0, 0) * mat(2, 1) * mat(1, 2) -
mat(1, 0) * mat(0, 1) * mat(2, 2) -
mat(2, 0) * mat(1, 1) * mat(0, 2);
if (det == (T)0) {
return result;
}
result(0, 0) = mat(1, 1) * mat(2, 2) - mat(1, 2) * mat(2, 1);
result(1, 0) = mat(1, 2) * mat(2, 0) - mat(1, 0) * mat(2, 2);
result(2, 0) = mat(1, 0) * mat(2, 1) - mat(1, 1) * mat(2, 0);
result(0, 1) = mat(0, 2) * mat(2, 1) - mat(0, 1) * mat(2, 2);
result(1, 1) = mat(0, 0) * mat(2, 2) - mat(0, 2) * mat(2, 0);
result(2, 1) = mat(0, 1) * mat(2, 0) - mat(0, 0) * mat(2, 1);
result(0, 2) = mat(0, 1) * mat(1, 2) - mat(0, 2) * mat(1, 1);
result(1, 2) = mat(0, 2) * mat(1, 0) - mat(0, 0) * mat(1, 2);
result(2, 2) = mat(0, 0) * mat(1, 1) - mat(0, 1) * mat(1, 0);
return result * (1.0f / det);
}
template<class T, uint32_t N> inline
MatrixN<T, 4> MatrixN<T, N>::inverse (const MatrixN<T, 4>& mat)
{
MatrixN<T, 4> result;
T det = mat(0, 3) * mat(1, 2) * mat(2, 1) * mat(3, 1) -
mat(0, 2) * mat(1, 3) * mat(2, 1) * mat(3, 1) -
mat(0, 3) * mat(1, 1) * mat(2, 2) * mat(3, 1) +
mat(0, 1) * mat(1, 3) * mat(2, 2) * mat(3, 1) +
mat(0, 2) * mat(1, 1) * mat(2, 3) * mat(3, 1) -
mat(0, 1) * mat(1, 2) * mat(2, 3) * mat(3, 1) -
mat(0, 3) * mat(1, 2) * mat(2, 0) * mat(3, 1) +
mat(0, 2) * mat(1, 3) * mat(2, 0) * mat(3, 1) +
mat(0, 3) * mat(1, 0) * mat(2, 2) * mat(3, 1) -
mat(0, 0) * mat(1, 3) * mat(2, 2) * mat(3, 1) -
mat(0, 2) * mat(1, 0) * mat(2, 3) * mat(3, 1) +
mat(0, 0) * mat(1, 2) * mat(2, 3) * mat(3, 1) +
mat(0, 3) * mat(1, 1) * mat(2, 0) * mat(3, 2) -
mat(0, 1) * mat(1, 3) * mat(2, 0) * mat(3, 2) -
mat(0, 3) * mat(1, 0) * mat(2, 1) * mat(3, 2) +
mat(0, 0) * mat(1, 3) * mat(2, 1) * mat(3, 2) +
mat(0, 1) * mat(1, 0) * mat(2, 3) * mat(3, 2) -
mat(0, 0) * mat(1, 1) * mat(2, 3) * mat(3, 2) -
mat(0, 2) * mat(1, 1) * mat(2, 0) * mat(3, 3) +
mat(0, 1) * mat(1, 2) * mat(2, 0) * mat(3, 3) +
mat(0, 2) * mat(1, 0) * mat(2, 1) * mat(3, 3) -
mat(0, 0) * mat(1, 2) * mat(2, 1) * mat(3, 3) -
mat(0, 1) * mat(1, 0) * mat(2, 2) * mat(3, 3) +
mat(0, 0) * mat(1, 1) * mat(2, 2) * mat(3, 3);
if (det == (T)0) {
return result;
}
result(0, 0) = mat(1, 2) * mat(2, 3) * mat(3, 1) -
mat(1, 3) * mat(2, 2) * mat(3, 1) +
mat(1, 3) * mat(2, 1) * mat(3, 2) -
mat(1, 1) * mat(2, 3) * mat(3, 2) -
mat(1, 2) * mat(2, 1) * mat(3, 3) +
mat(1, 1) * mat(2, 2) * mat(3, 3);
result(0, 1) = mat(0, 3) * mat(2, 2) * mat(3, 1) -
mat(0, 2) * mat(2, 3) * mat(3, 1) -
mat(0, 3) * mat(2, 1) * mat(3, 2) +
mat(0, 1) * mat(2, 3) * mat(3, 2) +
mat(0, 2) * mat(2, 1) * mat(3, 3) -
mat(0, 1) * mat(2, 2) * mat(3, 3);
result(0, 2) = mat(0, 2) * mat(1, 3) * mat(3, 1) -
mat(0, 3) * mat(1, 2) * mat(3, 1) +
mat(0, 3) * mat(1, 1) * mat(3, 2) -
mat(0, 1) * mat(1, 3) * mat(3, 2) -
mat(0, 2) * mat(1, 1) * mat(3, 3) +
mat(0, 1) * mat(1, 2) * mat(3, 3);
result(0, 3) = mat(0, 3) * mat(1, 2) * mat(2, 1) -
mat(0, 2) * mat(1, 3) * mat(2, 1) -
mat(0, 3) * mat(1, 1) * mat(2, 2) +
mat(0, 1) * mat(1, 3) * mat(2, 2) +
mat(0, 2) * mat(1, 1) * mat(2, 3) -
mat(0, 1) * mat(1, 2) * mat(2, 3);
result(1, 0) = mat(1, 3) * mat(2, 2) * mat(3, 0) -
mat(1, 2) * mat(2, 3) * mat(3, 0) -
mat(1, 3) * mat(2, 0) * mat(3, 2) +
mat(1, 0) * mat(2, 3) * mat(3, 2) +
mat(1, 2) * mat(2, 0) * mat(3, 3) -
mat(1, 0) * mat(2, 2) * mat(3, 3);
result(1, 1) = mat(0, 2) * mat(2, 3) * mat(3, 0) -
mat(0, 3) * mat(2, 2) * mat(3, 0) +
mat(0, 3) * mat(2, 0) * mat(3, 2) -
mat(0, 0) * mat(2, 3) * mat(3, 2) -
mat(0, 2) * mat(2, 0) * mat(3, 3) +
mat(0, 0) * mat(2, 2) * mat(3, 3);
result(1, 2) = mat(0, 3) * mat(1, 2) * mat(3, 0) -
mat(0, 2) * mat(1, 3) * mat(3, 0) -
mat(0, 3) * mat(1, 0) * mat(3, 2) +
mat(0, 0) * mat(1, 3) * mat(3, 2) +
mat(0, 2) * mat(1, 0) * mat(3, 3) -
mat(0, 0) * mat(1, 2) * mat(3, 3);
result(1, 3) = mat(0, 2) * mat(1, 3) * mat(2, 0) -
mat(0, 3) * mat(1, 2) * mat(2, 0) +
mat(0, 3) * mat(1, 0) * mat(2, 2) -
mat(0, 0) * mat(1, 3) * mat(2, 2) -
mat(0, 2) * mat(1, 0) * mat(2, 3) +
mat(0, 0) * mat(1, 2) * mat(2, 3);
result(2, 0) = mat(1, 1) * mat(2, 3) * mat(3, 0) -
mat(1, 3) * mat(2, 1) * mat(3, 0) +
mat(1, 3) * mat(2, 0) * mat(3, 1) -
mat(1, 0) * mat(2, 3) * mat(3, 1) -
mat(1, 1) * mat(2, 0) * mat(3, 3) +
mat(1, 0) * mat(2, 1) * mat(3, 3);
result(2, 1) = mat(0, 3) * mat(2, 1) * mat(3, 0) -
mat(0, 1) * mat(2, 3) * mat(3, 0) -
mat(0, 3) * mat(2, 0) * mat(3, 1) +
mat(0, 0) * mat(2, 3) * mat(3, 1) +
mat(0, 1) * mat(2, 0) * mat(3, 3) -
mat(0, 0) * mat(2, 1) * mat(3, 3);
result(2, 2) = mat(0, 1) * mat(1, 3) * mat(3, 0) -
mat(0, 3) * mat(1, 1) * mat(3, 0) +
mat(0, 3) * mat(1, 0) * mat(3, 1) -
mat(0, 0) * mat(1, 3) * mat(3, 1) -
mat(0, 1) * mat(1, 0) * mat(3, 3) +
mat(0, 0) * mat(1, 1) * mat(3, 3);
result(2, 3) = mat(0, 3) * mat(1, 1) * mat(2, 0) -
mat(0, 1) * mat(1, 3) * mat(2, 0) -
mat(0, 3) * mat(1, 0) * mat(2, 1) +
mat(0, 0) * mat(1, 3) * mat(2, 1) +
mat(0, 1) * mat(1, 0) * mat(2, 3) -
mat(0, 0) * mat(1, 1) * mat(2, 3);
result(3, 0) = mat(1, 2) * mat(2, 1) * mat(3, 0) -
mat(1, 1) * mat(2, 2) * mat(3, 0) -
mat(1, 2) * mat(2, 0) * mat(3, 1) +
mat(1, 0) * mat(2, 2) * mat(3, 1) +
mat(1, 1) * mat(2, 0) * mat(3, 2) -
mat(1, 0) * mat(2, 1) * mat(3, 2);
result(3, 1) = mat(1, 1) * mat(2, 2) * mat(3, 0) -
mat(1, 2) * mat(2, 1) * mat(3, 0) +
mat(1, 2) * mat(2, 0) * mat(3, 1) -
mat(1, 0) * mat(2, 2) * mat(3, 1) -
mat(1, 1) * mat(2, 0) * mat(3, 2) +
mat(1, 0) * mat(2, 1) * mat(3, 2);
result(3, 2) = mat(0, 2) * mat(1, 1) * mat(3, 0) -
mat(0, 1) * mat(1, 2) * mat(3, 0) -
mat(0, 2) * mat(1, 0) * mat(3, 1) +
mat(0, 0) * mat(1, 2) * mat(3, 1) +
mat(0, 1) * mat(1, 0) * mat(3, 2) -
mat(0, 0) * mat(1, 1) * mat(3, 2);
result(3, 3) = mat(0, 1) * mat(1, 2) * mat(2, 0) -
mat(0, 2) * mat(1, 1) * mat(2, 0) +
mat(0, 2) * mat(1, 0) * mat(2, 1) -
mat(0, 0) * mat(1, 2) * mat(2, 1) -
mat(0, 1) * mat(1, 0) * mat(2, 2) +
mat(0, 0) * mat(1, 1) * mat(2, 2);
return result * (1.0f / det);
}
typedef VectorN<double, 2> Vec2d;
typedef VectorN<double, 3> Vec3d;
typedef VectorN<double, 4> Vec4d;
typedef MatrixN<double, 2> Mat2d;
typedef MatrixN<double, 3> Mat3d;
typedef MatrixN<double, 4> Mat4d;
typedef VectorN<float, 2> Vec2f;
typedef VectorN<float, 3> Vec3f;
typedef VectorN<float, 4> Vec4f;
typedef MatrixN<float, 3> Mat3f;
typedef MatrixN<float, 4> Mat4f;
template<class T>
class Quaternion
{
public:
Vec3d v;
T w;
Quaternion () : v(0, 0, 0), w(0) {};
Quaternion (const Quaternion<T>& q) : v(q.v), w(q.w) {};
Quaternion (const Vec3d& vec, T _w) : v(vec), w(_w) {};
Quaternion (const Vec4d& vec) : v(vec[0], vec[1], vec[2]), w(vec[3]) {};
Quaternion (T _x, T _y, T _z, T _w) : v(_x, _y, _z), w(_w) {};
inline void reset () {
v.zeros();
w = (T) 0;
}
inline Quaternion<T>& operator = (const Quaternion<T>& rhs) {
v = rhs.v;
w = rhs.w;
return *this;
}
inline Quaternion<T> operator + (const Quaternion<T>& rhs) const {
const Quaternion<T>& lhs = *this;
return Quaternion<T>(lhs.v + rhs.v, lhs.w + rhs.w);
}
inline Quaternion<T> operator - (const Quaternion<T>& rhs) const {
const Quaternion<T>& lhs = *this;
return Quaternion<T>(lhs.v - rhs.v, lhs.w - rhs.w);
}
inline Quaternion<T> operator * (T rhs) const {
return Quaternion<T>(v * rhs, w * rhs);
}
inline Quaternion<T> operator * (const Quaternion<T>& rhs) const {
const Quaternion<T>& lhs = *this;
return Quaternion<T>(lhs.w * rhs.v[0] + lhs.v[0] * rhs.w + lhs.v[1] * rhs.v[2] - lhs.v[2] * rhs.v[1],
lhs.w * rhs.v[1] - lhs.v[0] * rhs.v[2] + lhs.v[1] * rhs.w + lhs.v[2] * rhs.v[0],
lhs.w * rhs.v[2] + lhs.v[0] * rhs.v[1] - lhs.v[1] * rhs.v[0] + lhs.v[2] * rhs.w,
lhs.w * rhs.w - lhs.v[0] * rhs.v[0] - lhs.v[1] * rhs.v[1] - lhs.v[2] * rhs.v[2]);
}
/*
--------
/ --
|Qr| = \/ Qr.Qr
*/
inline T magnitude () const {
return (T) sqrtf(w * w + v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
inline void normalize ()
{
T length = magnitude ();
w = w / length;
v = v / length;
}
inline Quaternion<T> conjugate (const Quaternion<T>& quat) const {
return Quaternion<T>(-quat.v, quat.w);
}
inline Quaternion<T> inverse (const Quaternion<T>& quat) const {
return conjugate(quat) * ( 1.0f / magnitude(quat));
}
inline Quaternion<T> lerp (T weight, const Quaternion<T>& quat) const {
return Quaternion<T>(v.lerp(weight, quat.v), (1 - weight) * w + weight * quat.w);
}
inline Quaternion<T> slerp(T r, const Quaternion<T>& quat) const {
Quaternion<T> ret;
T cos_theta = w * quat.w + v[0] * quat.v[0] + v[1] * quat.v[1] + v[2] * quat.v[2];
T theta = (T) acos(cos_theta);
if (fabs(theta) < FLT_EPSILON)
{
ret = *this;
}
else
{
T sin_theta = (T) sqrt(1.0 - cos_theta * cos_theta);
if (fabs(sin_theta) < FLT_EPSILON)
{
ret.w = 0.5 * w + 0.5 * quat.w;
ret.v = v.lerp(0.5, quat.v);
}
else
{
T r0 = (T) sin((1.0 - r) * theta) / sin_theta;
T r1 = (T) sin(r * theta) / sin_theta;
ret.w = w * r0 + quat.w * r1;
ret.v[0] = v[0] * r0 + quat.v[0] * r1;
ret.v[1] = v[1] * r0 + quat.v[1] * r1;
ret.v[2] = v[2] * r0 + quat.v[2] * r1;
}
}
return ret;
}
static Quaternion<T> create_quaternion (Vec3d axis, T angle_rad) {
T theta_over_two = angle_rad / (T) 2.0;
T sin_theta_over_two = std::sin(theta_over_two);
T cos_theta_over_two = std::cos(theta_over_two);
return Quaternion<T>(axis * sin_theta_over_two, cos_theta_over_two);
}
static Quaternion<T> create_quaternion (Vec3d euler) {
return create_quaternion(Vec3d(1, 0, 0), euler[0]) *
create_quaternion(Vec3d(0, 1, 0), euler[1]) *
create_quaternion(Vec3d(0, 0, 1), euler[2]);
}
static Quaternion<T> create_quaternion (const Mat3d& mat) {
Quaternion<T> q;
T trace, s;
T diag1 = mat(0, 0);
T diag2 = mat(1, 1);
T diag3 = mat(2, 2);
trace = diag1 + diag2 + diag3;
if (trace >= FLT_EPSILON)
{
s = 2.0 * (T) sqrt(trace + 1.0);
q.w = 0.25 * s;
q.v[0] = (mat(2, 1) - mat(1, 2)) / s;
q.v[1] = (mat(0, 2) - mat(2, 0)) / s;
q.v[2] = (mat(1, 0) - mat(0, 1)) / s;
}
else
{
char max_diag = (diag1 > diag2) ? ((diag1 > diag3) ? 1 : 3) : ((diag2 > diag3) ? 2 : 3);
if (max_diag == 1)
{
s = 2.0 * (T) sqrt(1.0 + mat(0, 0) - mat(1, 1) - mat(2, 2));
q.w = (mat(2, 1) - mat(1, 2)) / s;
q.v[0] = 0.25 * s;
q.v[1] = (mat(0, 1) + mat(1, 0)) / s;
q.v[2] = (mat(0, 2) + mat(2, 0)) / s;
}
else if (max_diag == 2)
{
s = 2.0 * (T) sqrt(1.0 + mat(1, 1) - mat(0, 0) - mat(2, 2));
q.w = (mat(0, 2) - mat(2, 0)) / s;
q.v[0] = (mat(0, 1) + mat(1, 0)) / s;
q.v[1] = 0.25 * s;
q.v[2] = (mat(1, 2) + mat(2, 1)) / s;
}
else
{
s = 2.0 * (T) sqrt(1.0 + mat(2, 2) - mat(0, 0) - mat(1, 1));
q.w = (mat(1, 0) - mat(0, 1)) / s;
q.v[0] = (mat(0, 2) + mat(2, 0)) / s;
q.v[1] = (mat(1, 2) + mat(2, 1)) / s;
q.v[2] = 0.25 * s;
}
}
return q;
}
inline Vec4d rotation_axis () {
Vec4d rot_axis;
T cos_theta_over_two = w;
rot_axis[4] = (T) std::acos( cos_theta_over_two ) * 2.0f;
T sin_theta_over_two = (T) sqrt( 1.0 - cos_theta_over_two * cos_theta_over_two );
if ( fabs( sin_theta_over_two ) < 0.0005 ) sin_theta_over_two = 1;
rot_axis[0] = v[0] / sin_theta_over_two;
rot_axis[1] = v[1] / sin_theta_over_two;
rot_axis[2] = v[2] / sin_theta_over_two;
return rot_axis;
}
/*
psi=atan2(2.*(Q(:,1).*Q(:,4)-Q(:,2).*Q(:,3)),(Q(:,4).^2-Q(:,1).^2-Q(:,2).^2+Q(:,3).^2));
theta=asin(2.*(Q(:,1).*Q(:,3)+Q(:,2).*Q(:,4)));
phi=atan2(2.*(Q(:,3).*Q(:,4)-Q(:,1).*Q(:,2)),(Q(:,4).^2+Q(:,1).^2-Q(:,2).^2-Q(:,3).^2));
*/
inline Vec3d euler_angles () {
Vec3d euler;
// atan2(2*(qx*qw-qy*qz) , qw2-qx2-qy2+qz2)
euler[0] = atan2(2 * (v[0] * w - v[1] * v[2]),
w * w - v[0] * v[0] - v[1] * v[1] + v[2] * v[2]);
// asin(2*(qx*qz + qy*qw)
euler[1] = asin(2 * (v[0] * v[2] + v[1] * w));
// atan2(2*(qz*qw- qx*qy) , qw2 + qx2 - qy2 - qz2)
euler[2] = atan2(2 * (v[2] * w - v[0] * v[1]),
w * w + v[0] * v[0] - v[1] * v[1] - v[2] * v[2]);
return euler;
}
inline Mat3d rotation_matrix () {
Mat3d mat;
T xx = v[0] * v[0];
T xy = v[0] * v[1];
T xz = v[0] * v[2];
T xw = v[0] * w;
T yy = v[1] * v[1];
T yz = v[1] * v[2];
T yw = v[1] * w;
T zz = v[2] * v[2];
T zw = v[2] * w;
mat(0, 0) = 1 - 2 * (yy + zz);
mat(0, 1) = 2 * (xy - zw);
mat(0, 2) = 2 * (xz + yw);
mat(1, 0) = 2 * (xy + zw);
mat(1, 1) = 1 - 2 * (xx + zz);
mat(1, 2) = 2 * (yz - xw);
mat(2, 0) = 2 * (xz - yw);
mat(2, 1) = 2 * (yz + xw);
mat(2, 2) = 1 - 2 * (xx + yy);
return mat;
}
};
typedef Quaternion<double> Quaternd;
}
#endif //XCAM_VECTOR_MATRIX_H