Lugdunum  0.1.0
Quaternion.inl
Go to the documentation of this file.
1 template <typename T>
2 Quaternion<T>::Quaternion(T w, T x, T y, T z) : _data{w, x, y, z} {}
3 
4 template <typename T>
6  _data[0] = data[0];
7  _data[1] = data[1];
8  _data[2] = data[2];
9  _data[3] = data[3];
10 
11  normalize();
12 }
13 
14 template <typename T>
15 Quaternion<T>::Quaternion(T angle, const Vector<3, T>& axis) {
16  const T halfAngle = angle / 2;
17  const T sinHalf = std::sin(halfAngle);
18 
19  _data[0] = std::cos(halfAngle);
20  _data[1] = axis(0) * sinHalf;
21  _data[2] = axis(1) * sinHalf;
22  _data[3] = axis(2) * sinHalf;
23 
24  normalize();
25 }
26 
27 template <typename T>
28 inline T& Quaternion<T>::operator[](std::size_t idx) {
29  return _data[idx];
30 }
31 
32 template <typename T>
33 inline const T& Quaternion<T>::operator[](std::size_t idx) const {
34  return _data[idx];
35 }
36 
37 template <typename T>
38 inline void Quaternion<T>::conjugate() {
39  *this = ::lug::Math::conjugate(*this);
40 }
41 
42 template <typename T>
43 inline void Quaternion<T>::inverse() {
44  *this = ::lug::Math::conjugate(*this);
45 }
46 
47 template <typename T>
48 inline void Quaternion<T>::normalize() {
49  *this = ::lug::Math::normalize(*this);
50 }
51 
52 template <typename T>
53 inline constexpr T Quaternion<T>::length() const {
54  return std::sqrt(squaredLength());
55 }
56 
57 template <typename T>
58 inline constexpr T Quaternion<T>::squaredLength() const {
59  return _data[0] * _data[0] + _data[1] * _data[1] + _data[2] * _data[2] + _data[3] * _data[3];
60 }
61 
62 template <typename T>
63 inline T Quaternion<T>::getAngle() const {
64  return std::acos(_data[0]) * 2;
65 }
66 
67 template <typename T>
69  const T asinHalf = std::asin(getAngle() / 2);
70  return {
71  _data[1] / asinHalf,
72  _data[2] / asinHalf,
73  _data[3] / asinHalf
74  };
75 }
76 
77 template <typename T>
78 inline Mat4x4<T> Quaternion<T>::transform() const {
79  Mat4x4<T> result{Mat4x4<T>::identity()};
80 
81  const T xx = _data[1] * _data[1];
82  const T xy = _data[1] * _data[2];
83  const T xz = _data[1] * _data[3];
84  const T wx = _data[0] * _data[1];
85 
86  const T yy = _data[2] * _data[2];
87  const T yz = _data[2] * _data[3];
88  const T wy = _data[0] * _data[2];
89 
90  const T zz = _data[3] * _data[3];
91  const T wz = _data[0] * _data[3];
92 
93  result(0, 0) = T(1) - T(2) * (yy + zz);
94  result(1, 0) = T(2) * (xy + wz);
95  result(2, 0) = T(2) * (xz - wy);
96 
97  result(0, 1) = T(2) * (xy - wz);
98  result(1, 1) = T(1) - T(2) * (xx + zz);
99  result(2, 1) = T(2) * (yz + wx);
100 
101  result(0, 2) = T(2) * (xz + wy);
102  result(1, 2) = T(2) * (yz - wx);
103  result(2, 2) = T(1) - T(2) * (xx + yy);
104 
105  return result;
106 }
107 
108 template <typename T>
110  return {T(1), T(0), T(0), T(0)};
111 }
112 
113 template <typename T>
114 inline Quaternion<T> Quaternion<T>::fromAxes(const Vector<3, T>& xAxis, const Vector<3, T>& yAxis, const Vector<3, T>& zAxis) {
116 
117  rotMatrix(0, 0) = xAxis.x();
118  rotMatrix(1, 0) = xAxis.y();
119  rotMatrix(2, 0) = xAxis.z();
120 
121  rotMatrix(0, 1) = yAxis.x();
122  rotMatrix(1, 1) = yAxis.y();
123  rotMatrix(2, 1) = yAxis.z();
124 
125  rotMatrix(0, 2) = zAxis.x();
126  rotMatrix(1, 2) = zAxis.y();
127  rotMatrix(2, 2) = zAxis.z();
128 
129  return fromRotationMatrix(rotMatrix);
130 }
131 
132 template <typename T>
134  const T tr = rotMatrix(0, 0) + rotMatrix(1, 1) + rotMatrix(2, 2);
135 
136  if (tr > 0.0f) {
137  const T s = sqrt(T(1) + tr) * T(2);
138 
139  return Quaternion<T>(
140  T(0.25f) * s,
141  (rotMatrix(2, 1) - rotMatrix(1, 2)) / s,
142  (rotMatrix(0, 2) - rotMatrix(2, 0)) / s,
143  (rotMatrix(1, 0) - rotMatrix(0, 1)) / s
144  );
145  } else if ((rotMatrix(0, 0) > rotMatrix(1, 1)) && (rotMatrix(0, 0) > rotMatrix(2, 2))) {
146  const T s = sqrt(T(1) + rotMatrix(0, 0) - rotMatrix(1, 1) - rotMatrix(2, 2)) * T(2);
147 
148  return Quaternion<T>(
149  (rotMatrix(2, 1) - rotMatrix(1, 2)) / s,
150  T(0.25) * s,
151  (rotMatrix(0, 1) + rotMatrix(1, 0)) / s,
152  (rotMatrix(0, 2) + rotMatrix(2, 0)) / s
153  );
154  } else if (rotMatrix(1, 1) > rotMatrix(2, 2)) {
155  const T s = sqrt(T(1) + rotMatrix(1, 1) - rotMatrix(0, 0) - rotMatrix(2, 2)) * T(2);
156 
157  return Quaternion<T>(
158  (rotMatrix(0, 2) - rotMatrix(2, 0)) / s,
159  (rotMatrix(0, 1) + rotMatrix(1, 0)) / s,
160  T(0.25) * s,
161  (rotMatrix(1, 2) + rotMatrix(2, 1)) / s
162  );
163  } else {
164  const T s = sqrt(T(1) + rotMatrix(2, 2) - rotMatrix(0, 0) - rotMatrix(1, 1)) * T(2);
165 
166  return Quaternion<T>(
167  (rotMatrix(1, 0) - rotMatrix(0, 1)) / s,
168  (rotMatrix(0, 2) + rotMatrix(2, 0)) / s,
169  (rotMatrix(1, 2) + rotMatrix(2, 1)) / s,
170  T(0.25) * s
171  );
172  }
173 }
174 
175 template <typename T>
176 inline Quaternion<T> conjugate(const Quaternion<T>& lhs) {
177  return {lhs.w(), -lhs.x(), -lhs.y(), -lhs.z()};
178 }
179 
180 template <typename T>
181 inline Quaternion<T> normalize(const Quaternion<T>& lhs) {
182  const T length = lhs.length();
183  return {lhs[0] / length, lhs[1] / length, lhs[2] / length, lhs[3] / length};
184 }
185 
186 template <typename T>
187 inline Quaternion<T> inverse(const Quaternion<T>& lhs) {
188  Quaternion<T> result{lhs};
189 
190  result.conjugate();
191 
192  const T length = result.squaredLength();
193 
194  result[0] /= length * length;
195  result[1] /= length * length;
196  result[2] /= length * length;
197  result[3] /= length * length;
198 
199  result.normalize();
200 
201  return result;
202 }
203 
204 template <typename T>
205 inline T dot(const Quaternion<T>& lhs, const Quaternion<T>& rhs) {
206  return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2] + lhs[3] * rhs[3];
207 }
208 
209 template <typename T>
210 Quaternion<T> directionTo(const Vector<3, T>& original, const Vector<3, T>& expected) {
211  Quaternion<T> result;
212 
213  Vector<3, T> v0 = normalize(original);
214  Vector<3, T> v1 = normalize(expected);
215 
216  T cosTheta = dot(v0, v1);
217 
218  if (cosTheta >= T(1) - epsilon<T>()) {
219  // Same vectors
220  return Quaternion<T>::identity();
221  }
222 
223  if (cosTheta < T(-1) + epsilon<T>()) {
224  // Generate a fallback vector
225  Vector<3, T> axis = cross(Vector<3, T>{0.0f, 0.0f, 1.0f}, v0);
226  if (axis.squaredLength() <= (1e-06 * 1e-06)) {
227  axis = cross(Vector<3, T>{1.0f, 0.0f, 0.0f}, v0);
228  }
229 
230  axis.normalize();
231  result = Quaternion<T>(pi<T>(), axis);
232  } else {
233  T s = sqrt((T(1) + cosTheta) * T(2));
234  T invs = T(1) / s;
235 
236  Vector<3, T> c = cross(v0, v1);
237 
238  result.w() = s * 0.5f;
239  result.x() = c.x() * invs;
240  result.y() = c.y() * invs;
241  result.z() = c.z() * invs;
242 
243  result.normalize();
244  }
245 
246  return result;
247 }
248 
249 template <typename T>
250 inline Quaternion<T> operator-(const Quaternion<T>& lhs) {
251  return {-lhs[0], -lhs[1], -lhs[2], -lhs[3]};
252 }
253 
254 template <typename T>
255 inline Quaternion<T> operator+(const Quaternion<T>& lhs, const Quaternion<T>& rhs) {
256  return {lhs[0] + rhs[0], lhs[1] + rhs[1], lhs[2] + rhs[2], lhs[3] + rhs[3]};
257 }
258 
259 template <typename T>
260 inline Quaternion<T> operator-(const Quaternion<T>& lhs, const Quaternion<T>& rhs) {
261  return {lhs[0] - rhs[0], lhs[1] - rhs[1], lhs[2] - rhs[2], lhs[3] - rhs[3]};
262 }
263 
264 template <typename T>
265 inline Quaternion<T> operator*(const Quaternion<T>& lhs, const Quaternion<T>& rhs) {
266  return {
267  lhs[0] * rhs[0] - lhs[1] * rhs[1] - lhs[2] * rhs[2] - lhs[3] * rhs[3],
268  lhs[0] * rhs[1] + lhs[1] * rhs[0] + lhs[2] * rhs[3] - lhs[3] * rhs[2],
269  lhs[0] * rhs[2] - lhs[1] * rhs[3] + lhs[2] * rhs[0] + lhs[3] * rhs[1],
270  lhs[0] * rhs[3] + lhs[1] * rhs[2] - lhs[2] * rhs[1] + lhs[3] * rhs[0]
271  };
272 }
273 
274 template <typename T>
275 inline Quaternion<T> operator/(const Quaternion<T>& lhs, const Quaternion<T>& rhs) {
276  return lhs * conjugate(rhs);
277 }
278 
279 template <typename T>
280 inline bool operator==(const Quaternion<T>& lhs, const Quaternion<T>& rhs) {
281  return lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2] && lhs[3] == rhs[3];
282 }
283 
284 template <typename T>
285 inline bool operator!=(const Quaternion<T>& lhs, const Quaternion<T>& rhs) {
286  return lhs[0] != rhs[0] || lhs[1] != rhs[1] || lhs[2] != rhs[2] || lhs[3] != rhs[3];
287 }
288 
289 template <typename T>
290 std::ostream& operator<<(std::ostream& os, const Quaternion<T>& quaternion) {
291  os << "{w: " << quaternion.w() << ", x: " << quaternion.x() << ", y: " << quaternion.y() << ", z: " << quaternion.z() << "}";
292  return os;
293 }
bool operator!=(const Matrix< Rows, Columns, T > &lhs, const Matrix< Rows, Columns, T > &rhs)
Quaternion< T > conjugate(const Quaternion< T > &lhs)
Definition: Quaternion.inl:176
T sin(T radians)
bool operator==(const Matrix< Rows, Columns, T > &lhs, const Matrix< Rows, Columns, T > &rhs)
constexpr Vector< 3, T > cross(const Vector< 3, T > &lhs, const Vector< 3, T > &rhs)
T & operator[](std::size_t idx)
Definition: Quaternion.inl:28
static Quaternion< T > fromAxes(const Vector< 3, T > &xAxis, const Vector< 3, T > &yAxis, const Vector< 3, T > &zAxis)
Definition: Quaternion.inl:114
Matrix< Rows, Columns, T > operator-(const Matrix< Rows, Columns, T > &lhs)
static std::enable_if<(Rows==Columns) &&EnableBool, Matrix< Rows, Columns, T > >::type identity()
T cos(T radians)
static Quaternion< T > identity()
Definition: Quaternion.inl:109
Vector< 3, T > getAxis() const
Definition: Quaternion.inl:68
Mat4x4< T > transform() const
Definition: Quaternion.inl:78
Quaternion< T > directionTo(const Vector< 3, T > &original, const Vector< 3, T > &expected)
constexpr T length() const
Definition: Quaternion.inl:53
Matrix< Rows, Columns, T > operator+(const Matrix< Rows, Columns, T > &lhs, T rhs)
T asin(T radians)
Matrix< Rows, Columns, T > operator/(const Matrix< Rows, Columns, T > &lhs, T rhs)
Matrix< Rows, Columns, T > operator*(const Matrix< Rows, Columns, T > &lhs, T rhs)
T dot(const Quaternion< T > &lhs, const Quaternion< T > &rhs)
constexpr T squaredLength() const
Definition: Quaternion.inl:58
T acos(T radians)
Quaternion< T > normalize(const Quaternion< T > &lhs)
Definition: Quaternion.inl:181
static Quaternion< T > fromRotationMatrix(const Matrix< 4, 4, T > &rotMatrix)
Definition: Quaternion.inl:133