Mitsuba Renderer  0.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
quat.h
Go to the documentation of this file.
1 /*
2  This file is part of Mitsuba, a physically based rendering system.
3 
4  Copyright (c) 2007-2014 by Wenzel Jakob and others.
5 
6  Mitsuba is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License Version 3
8  as published by the Free Software Foundation.
9 
10  Mitsuba is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 #if !defined(__MITSUBA_CORE_QUAT_H_)
21 #define __MITSUBA_CORE_QUAT_H_
22 
23 #include <mitsuba/core/transform.h>
24 
26 
27 /**
28  * \brief Parameterizable quaternion data structure
29  * \ingroup libcore
30  */
31 template <typename T> struct TQuaternion {
32  typedef T Scalar;
33 
34  /// Used by \ref TQuaternion::fromEulerAngles
36  EEulerXYZ = 0,
41  EEulerZYX
42  };
43 
44  /// Imaginary component
46 
47  /// Real component
48  T w;
49 
50  /// Create a unit quaternion
51  TQuaternion() : v(0.0f), w(1) { }
52 
53  /**
54  * Initialize the quaternion with the specified
55  * real and imaginary components
56  */
57  TQuaternion(const TVector3<T> &v, T w) : v(v), w(w) { }
58 
59  /// Unserialize a quaternion from a binary data stream
60  explicit TQuaternion(Stream *stream) {
61  v = TVector3<T>(stream);
62  w = stream->readElement<T>();
63  }
64 
65  /// Add two quaternions and return the result
66  TQuaternion operator+(const TQuaternion &q) const {
67  return TQuaternion(v + q.v, w + q.w);
68  }
69 
70  /// Subtract two quaternions and return the result
71  TQuaternion operator-(const TQuaternion &q) const {
72  return TQuaternion(v - q.v, w - q.w);
73  }
74 
75  /// Add another quaternions to the current one
77  v += q.v; w += q.w;
78  return *this;
79  }
80 
81  /// Subtract a quaternion
83  v -= q.v; w -= q.w;
84  return *this;
85  }
86 
87  /// Unary negation operator
89  return TQuaternion(-v, -w);
90  }
91 
92  /// Multiply the quaternion by the given scalar and return the result
93  TQuaternion operator*(T f) const {
94  return TQuaternion(v*f, w*f);
95  }
96 
97  /// Multiply the quaternion by the given scalar
99  v *= f; w *= f;
100  return *this;
101  }
102 
103  /// Divide the quaternion by the given scalar and return the result
104  TQuaternion operator/(T f) const {
105 #ifdef MTS_DEBUG
106  if (f == 0)
107  SLog(EWarn, "Quaternion: Division by zero!");
108 #endif
109  T recip = (T) 1 / f;
110  return TQuaternion(v * recip, w * recip);
111  }
112 
113  /// Divide the quaternion by the given scalar
115 #ifdef MTS_DEBUG
116  if (f == 0)
117  SLog(EWarn, "Quaternion: Division by zero!");
118 #endif
119  T recip = (T) 1 / f;
120  v *= recip; w *= recip;
121  return *this;
122  }
123 
124  /// Quaternion multiplication
126  Scalar tmp = w * q.w - dot(v, q.v);
127  v = cross(v, q.v) + q.w * v + w * q.v;
128  w = tmp;
129  return *this;
130  }
131 
132  /// Quaternion multiplication (creates a temporary)
134  return TQuaternion(cross(v, q.v) + q.w * v + w * q.v,
135  w * q.w - dot(v, q.v));
136  }
137 
138  /// Equality test
139  bool operator==(const TQuaternion &q) const {
140  return v == q.v && w == q.w;
141  }
142 
143  /// Inequality test
144  bool operator!=(const TQuaternion &q) const {
145  return v != q.v || w != q.w;
146  }
147 
148  /// Identity test
149  bool isIdentity() const {
150  return v.isZero() && w == 1;
151  }
152 
153  /// Return the rotation axis of this quaternion
154  inline TVector3<T> axis() const { return normalize(v); }
155 
156  /// Return the rotation angle of this quaternion (in radians)
157  inline Scalar angle() const { return 2 * math::safe_acos(w); }
158 
159  /**
160  * \brief Compute the exponential of a quaternion with
161  * scalar part w = 0.
162  *
163  * Based on code the appendix of
164  * "Quaternion Calculus for Computer Graphics" by Ken Shoemake
165  */
166  TQuaternion exp() const {
167  T theta = v.length();
168  T c = std::cos(theta);
169 
170  if (theta > Epsilon)
171  return TQuaternion(v * (std::sin(theta) / theta), c);
172  else
173  return TQuaternion(v, c);
174  }
175 
176  /**
177  * \brief Compute the natural logarithm of a unit quaternion
178  *
179  * Based on code the appendix of
180  * "Quaternion Calculus for Computer Graphics" by Ken Shoemake
181  */
182  TQuaternion log() const {
183  T scale = v.length();
184  T theta = std::atan2(scale, w);
185 
186  if (scale > 0)
187  scale = theta/scale;
188 
189  return TQuaternion<T>(v * scale, 0.0f);
190  }
191 
192  /**
193  * \brief Construct an unit quaternion, which represents a rotation
194  * around \a axis by \a angle radians.
195  */
196  static TQuaternion fromAxisAngle(const Vector &axis, Float angle) {
197  T sinValue = std::sin(angle/2.0f), cosValue = std::cos(angle/2.0f);
198  return TQuaternion(normalize(axis) * sinValue, cosValue);
199  }
200 
201  /**
202  * \brief Construct an unit quaternion, which rotates unit direction
203  * \a from onto \a to.
204  */
205  static TQuaternion fromDirectionPair(const Vector &from, const Vector &to) {
206  Float dp = dot(from, to);
207  if (dp > 1-Epsilon) {
208  // there is nothing to do
209  return TQuaternion();
210  } else if (dp < -(1-Epsilon)) {
211  // Use a better-conditioned method for opposite directions
212  Vector rotAxis = cross(from, Vector(1, 0, 0));
213  Float length = rotAxis.length();
214  if (length < Epsilon) {
215  rotAxis = cross(from, Vector(0, 1, 0));
216  length = rotAxis.length();
217  }
218  rotAxis /= length;
219  return TQuaternion(rotAxis, 0);
220  } else {
221  // Find cos(theta) and sin(theta) using half-angle formulae
222  Float cosTheta = std::sqrt(0.5f * (1 + dp));
223  Float sinTheta = std::sqrt(0.5f * (1 - dp));
224  Vector rotAxis = normalize(cross(from, to));
225  return TQuaternion(rotAxis * sinTheta, cosTheta);
226  }
227  }
228 
229  inline static TQuaternion fromTransform(const Transform &trafo) {
230  return fromMatrix(trafo.getMatrix());
231  }
232 
233  /**
234  * \brief Construct an unit quaternion matching the supplied
235  * rotation matrix.
236  */
237  static TQuaternion fromMatrix(const Matrix4x4 &m) {
238  // Implementation from PBRT, originally based on the matrix
239  // and quaternion FAQ (http://www.j3d.org/matrix_faq/matrfaq_latest.html)
240  T trace = m(0, 0) + m(1, 1) + m(2, 2);
241  TVector3<T> v; T w;
242 
243  if (trace > Epsilon) {
244  T s = std::sqrt(trace + 1.0f);
245  w = s * 0.5f;
246  s = 0.5f / s;
247  v.x = (m(2, 1) - m(1, 2)) * s;
248  v.y = (m(0, 2) - m(2, 0)) * s;
249  v.z = (m(1, 0) - m(0, 1)) * s;
250  } else {
251  const int nxt[3] = {1, 2, 0};
252  T q[3];
253  int i = 0;
254  if (m(1, 1) > m(0, 0)) i = 1;
255  if (m(2, 2) > m(i, i)) i = 2;
256  int j = nxt[i];
257  int k = nxt[j];
258  T s = std::sqrt((m(i, i) - (m(j, j) + m(k, k))) + 1.0f);
259  q[i] = s * 0.5f;
260  if (s != 0.f) s = 0.5f / s;
261  w = (m(k, j) - m(j, k)) * s;
262  q[j] = (m(j, i) + m(i, j)) * s;
263  q[k] = (m(k, i) + m(i, k)) * s;
264  v.x = q[0];
265  v.y = q[1];
266  v.z = q[2];
267  }
268  return TQuaternion(v, w);
269  }
270 
271  /**
272  * \brief Construct an unit quaternion matching the supplied
273  * rotation expressed in Euler angles (in radians)
274  */
276  Float x, Float y, Float z) {
277  Quaternion qx = fromAxisAngle(Vector(1.0, 0.0, 0.0), x);
278  Quaternion qy = fromAxisAngle(Vector(0.0, 1.0, 0.0), y);
279  Quaternion qz = fromAxisAngle(Vector(0.0, 0.0, 1.0), z);
280 
281  switch (conv) {
282  case EEulerXYZ:
283  return qz * qy * qx;
284  case EEulerXZY:
285  return qy * qz * qx;
286  case EEulerYXZ:
287  return qz * qx * qy;
288  case EEulerYZX:
289  return qx * qz * qy;
290  case EEulerZXY:
291  return qy * qx * qz;
292  case EEulerZYX:
293  return qx * qy * qz;
294  default:
295  SLog(EError, "Internal error!");
296  return TQuaternion();
297  }
298  }
299 
300  /// Compute the rotation matrix for the given quaternion
302  /// Implementation from PBRT
303  Float xx = v.x * v.x, yy = v.y * v.y, zz = v.z * v.z;
304  Float xy = v.x * v.y, xz = v.x * v.z, yz = v.y * v.z;
305  Float wx = v.x * w, wy = v.y * w, wz = v.z * w;
306 
307  Matrix4x4 m;
308  m.m[0][0] = 1.f - 2.f * (yy + zz);
309  m.m[0][1] = 2.f * (xy + wz);
310  m.m[0][2] = 2.f * (xz - wy);
311  m.m[0][3] = 0.0f;
312  m.m[1][0] = 2.f * (xy - wz);
313  m.m[1][1] = 1.f - 2.f * (xx + zz);
314  m.m[1][2] = 2.f * (yz + wx);
315  m.m[1][3] = 0.0f;
316  m.m[2][0] = 2.f * (xz + wy);
317  m.m[2][1] = 2.f * (yz - wx);
318  m.m[2][2] = 1.f - 2.f * (xx + yy);
319  m.m[2][3] = 0.0f;
320  m.m[3][0] = 0.0f;
321  m.m[3][1] = 0.0f;
322  m.m[3][2] = 0.0f;
323  m.m[3][3] = 1.0f;
324 
325  Matrix4x4 transp;
326  m.transpose(transp);
327  return Transform(transp, m);
328  }
329 
330  /// Serialize this quaternion to a binary data stream
331  void serialize(Stream *stream) const {
332  v.serialize(stream);
333  stream->writeElement<T>(w);
334  }
335 
336  /// Return a readable string representation of this quaternion
337  std::string toString() const {
338  std::ostringstream oss;
339  oss << "Quaternion[v=" << v.toString() << ", w=" << w << "]";
340  return oss.str();
341  }
342 };
343 
344 template <typename T> inline TQuaternion<T> operator*(T f, const TQuaternion<T> &v) {
345  return v*f;
346 }
347 
348 template <typename T> inline T dot(const TQuaternion<T> &q1, const TQuaternion<T> &q2) {
349  return dot(q1.v, q2.v) + q1.w * q2.w;
350 }
351 
352 template <typename T> inline TQuaternion<T> normalize(const TQuaternion<T> &q) {
353  return q / std::sqrt(dot(q, q));
354 }
355 
356 template <typename T> inline TQuaternion<T> slerp(const TQuaternion<T> &q1,
357  const TQuaternion<T> &_q2, Float t) {
358  TQuaternion<T> q2(_q2);
359 
360  T cosTheta = dot(q1, q2);
361  if (cosTheta < 0) {
362  /* Take the short way! */
363  q2 = -q2;
364  cosTheta = -cosTheta;
365  }
366  if (cosTheta > .9995f) {
367  // Revert to plain linear interpolation
368  return normalize(q1 * (1.0f - t) + q2 * t);
369  } else {
370  Float theta = math::safe_acos(math::clamp(cosTheta, (Float) -1.0f, (Float) 1.0f));
371  Float thetap = theta * t;
372  TQuaternion<T> qperp = normalize(q2 - q1 * cosTheta);
373  return q1 * std::cos(thetap) + qperp * std::sin(thetap);
374  }
375 }
376 
377 
379 
380 #endif /* __MITSUBA_CORE_QUAT_H_ */
#define Epsilon
Definition: constants.h:28
Definition: fwd.h:102
bool operator!=(const TQuaternion &q) const
Inequality test.
Definition: quat.h:144
T readElement()
Read an element from the stream (uses partial template specialization to select a method appropriate ...
Definition: stream.h:508
TQuaternion(Stream *stream)
Unserialize a quaternion from a binary data stream.
Definition: quat.h:60
Definition: quat.h:38
Transform toTransform() const
Compute the rotation matrix for the given quaternion.
Definition: quat.h:301
TQuaternion operator-() const
Unary negation operator.
Definition: quat.h:88
TQuaternion operator/(T f) const
Divide the quaternion by the given scalar and return the result.
Definition: quat.h:104
TQuaternion log() const
Compute the natural logarithm of a unit quaternion.
Definition: quat.h:182
Scalar angle() const
Return the rotation angle of this quaternion (in radians)
Definition: quat.h:157
T y
Definition: vector.h:455
TVector3< Float > Vector
Definition: fwd.h:113
TQuaternion exp() const
Compute the exponential of a quaternion with scalar part w = 0.
Definition: quat.h:166
TQuaternion operator+(const TQuaternion &q) const
Add two quaternions and return the result.
Definition: quat.h:66
TQuaternion< T > slerp(const TQuaternion< T > &q1, const TQuaternion< T > &_q2, Float t)
Definition: quat.h:356
#define SLog(level, fmt,...)
Write a Log message to the console (static version - to be used outside of classes that derive from O...
Definition: logger.h:49
Definition: quat.h:37
TQuaternion(const TVector3< T > &v, T w)
Definition: quat.h:57
TQuaternion operator-(const TQuaternion &q) const
Subtract two quaternions and return the result.
Definition: quat.h:71
static TQuaternion fromAxisAngle(const Vector &axis, Float angle)
Construct an unit quaternion, which represents a rotation around axis by angle radians.
Definition: quat.h:196
#define MTS_NAMESPACE_BEGIN
Definition: platform.h:137
static TQuaternion fromTransform(const Transform &trafo)
Definition: quat.h:229
TQuaternion()
Create a unit quaternion.
Definition: quat.h:51
TQuaternion< T > operator*(T f, const TQuaternion< T > &v)
Definition: quat.h:344
EEulerAngleConvention
Used by TQuaternion::fromEulerAngles.
Definition: quat.h:35
T Scalar
Definition: quat.h:32
TQuaternion & operator+=(const TQuaternion &q)
Add another quaternions to the current one.
Definition: quat.h:76
void serialize(Stream *stream) const
Serialize this quaternion to a binary data stream.
Definition: quat.h:331
void transpose(Matrix< N, M, T > &target) const
Compute the transpose of this matrix.
Definition: matrix.h:414
T z
Definition: vector.h:455
Parameterizable three-dimensional vector data structure.
Definition: vector.h:450
void writeElement(T value)
Write an element to the stream (uses partial template specialization to select a method appropriate t...
Definition: stream.h:512
const Matrix4x4 & getMatrix() const
Return the underlying matrix.
Definition: transform.h:317
TQuaternion & operator*=(T f)
Multiply the quaternion by the given scalar.
Definition: quat.h:98
Abstract seekable stream class.
Definition: stream.h:58
T m[M][N]
Definition: matrix.h:35
Warning message.
Definition: formatter.h:32
static TQuaternion fromEulerAngles(EEulerAngleConvention conv, Float x, Float y, Float z)
Construct an unit quaternion matching the supplied rotation expressed in Euler angles (in radians) ...
Definition: quat.h:275
T x
Definition: vector.h:455
Encapsulates a 4x4 linear transformation and its inverse.
Definition: transform.h:33
TQuaternion operator*(const TQuaternion &q) const
Quaternion multiplication (creates a temporary)
Definition: quat.h:133
TQuaternion operator*(T f) const
Multiply the quaternion by the given scalar and return the result.
Definition: quat.h:93
T w
Real component.
Definition: quat.h:48
bool isIdentity() const
Identity test.
Definition: quat.h:149
Definition: fwd.h:96
Error message, causes an exception to be thrown.
Definition: formatter.h:33
Parameterizable quaternion data structure.
Definition: quat.h:31
Basic 4x4 matrix data type.
Definition: matrix.h:656
Definition: quat.h:39
TQuaternion & operator/=(T f)
Divide the quaternion by the given scalar.
Definition: quat.h:114
TQuaternion< T > normalize(const TQuaternion< T > &q)
Definition: quat.h:352
TVector3< T > v
Imaginary component.
Definition: quat.h:45
static TQuaternion fromDirectionPair(const Vector &from, const Vector &to)
Construct an unit quaternion, which rotates unit direction from onto to.
Definition: quat.h:205
float safe_acos(float value)
Arccosine variant that gracefully handles arguments &gt; 1 that are due to roundoff errors.
Definition: math.h:250
TQuaternion & operator*=(const TQuaternion &q)
Quaternion multiplication.
Definition: quat.h:125
TVector3< T > cross(const TVector3< T > &v1, const TVector3< T > &v2)
Definition: vector.h:617
bool operator==(const TQuaternion &q) const
Equality test.
Definition: quat.h:139
Definition: quat.h:40
T dot(const TQuaternion< T > &q1, const TQuaternion< T > &q2)
Definition: quat.h:348
TQuaternion & operator-=(const TQuaternion &q)
Subtract a quaternion.
Definition: quat.h:82
#define MTS_NAMESPACE_END
Definition: platform.h:138
TVector3< T > axis() const
Return the rotation axis of this quaternion.
Definition: quat.h:154
static TQuaternion fromMatrix(const Matrix4x4 &m)
Construct an unit quaternion matching the supplied rotation matrix.
Definition: quat.h:237
Scalar clamp(Scalar value, Scalar min, Scalar max)
Generic clamping function.
Definition: math.h:51
std::string toString() const
Return a readable string representation of this quaternion.
Definition: quat.h:337