GteDualQuaternion.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.6.0 (2017/01/02)
7 
8 #pragma once
9 
11 
12 // A quaternion is of the form
13 // q = w + x * i + y * j + z * k
14 // where w, x, y, and z are real numbers. The scalar and vector parts are
15 // Scalar(q) = w
16 // Vector(q) = x * i + y * j + z * k
17 // I assume that you are familiar with the arithmetic and algebraic properties
18 // of quaternions. See
19 // https://www.geometrictools.com/Documentation/Quaternions.pdf
20 //
21 // A dual number (or dual scalar) is of the form
22 // v = a + b * e
23 // where e is a symbol representing a nonzero quantity but e*e = 0 and where
24 // (for the purposes of this code) a and b are real numbers. Addition,
25 // subtraction, and scalar multiplication are performed componentwise,
26 // (a0 + b0 * e) + (a1 + b1 * e) = (a0 + a1) + (b0 + b1) * e
27 // (a0 + b0 * e) - (a1 + b1 * e) = (a0 - a1) + (b0 - b1) * e
28 // c * (a + b * e) = (c * a) + (c * b) * e
29 // where c is a real number. Multiplication is
30 // (a0 + b0 * e) * (a1 + b1 * e) = (a0 * a1) + (a0 * b1 + b0 * a1) * e
31 // Function evaluation (for a differentiable function F) is
32 // F(a + b * e) = F(a) + [b * F'(a)] * e
33 // where F' is the derivative of F. This property is used for "automatic
34 // differentiation" of functions.
35 //
36 // A dual quaternion is of the form
37 // d = (w0+w1*e) + (x0+x1*e) * i + (y0+y1*e) * j + (z0+z1*e) * k
38 // where the coefficients are dual numbers. This has the same appearance as
39 // quaternions except that the real-valued coefficients of the quaternions are
40 // replace by dual-number-valued coefficients. Define the quaternions
41 // p0 = w0 + x0 * i + y0 * j + z0 * k and p1 = w1 + x1 * i + y1 * j + z1 * k;
42 // then d = p0 + p1 * e. By convention, the abstract symbol e commutes with
43 // i, j, and k.
44 //
45 // Define the dual quaternions
46 // A = a0 + a1*i + a2*j + a3*k = pa + qa * e
47 // B = b0 + b1*i + b2*j + b3*k = pb + qb * e
48 // C = c0 + c1*i + c2*j + c3*k = pc + qc * e
49 // where all coefficients are dual numbers.
50 //
51 // Scalar and vector parts.
52 // Scalar(A) = Scalar(pa) + Scalar(qa) * e
53 // Vector(A) = Vector(pa) + Vector(qa) * e
54 // A = Scalar(A) + Vector(A)
55 //
56 // Addition, subtraction, and scalar multiplication of dual quaternions are
57 // symbolically the same as for quaternions. For example,
58 // A + B = (a0 + b0) + (a1 + b1) * i + (a2 + b2) * j + (a3 + b3) * k
59 // NOTE: These operations are not implemented here, because the goal of the
60 // DualQuaternion class is to support representation of rigid transformations.
61 //
62 // Multiplication (noncommutative):
63 // A * B = (pa * pb) + (pa * qb + qa * pb) * e
64 // = (a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3) * 1
65 // + (a1 * b0 + a0 * b1 - a3 * b2 + a2 * b3) * i
66 // + (a2 * b0 + a3 * b1 + a0 * b2 - a1 * b3) * j
67 // = + (a3 * b0 - a2 * b1 + a1 * b2 - a0 * b3) * k
68 // which is the same symbolic formula for the multiplication of quaternions
69 // but with the real-valued coefficients replaced by the dual-number-valued
70 // coefficients. As with quaternions, it is not generally true that
71 // B * A = A * AB.
72 //
73 // Conjugate operation:
74 // conj(A) = conj(pa) + conj(qa) * e = Scalar(A) - Vector(A)
75 //
76 // Scalar product of dual quaternions:
77 // dot(A,B) = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3
78 // = (A * conj(B) + B * conj(A)) / 2
79 // = dot(B,A)
80 //
81 // Vector product of dual quaternions:
82 // cross(A,B) = (A * B - B * A) / 2
83 //
84 // Norm (squared magnitude):
85 // Norm(A) = A * conj(A) = conj(A) * A = dot(A, A)
86 // = (pa * conj(pa)) + (pa * conj(qa) + qa * conj(pa)) * e
87 // Note that this is a dual scalar of the form s0 + s1 * e, where s0 and s1
88 // are scalars.
89 //
90 // Function of a dual quaternion, which requires function F to be
91 // differentiable
92 // F(A) = F(pa + qa * e) = F(pa) + (qa * F'(pa)) * e
93 // This property is used in "automatic differentiation."
94 //
95 // Length (magnitude): The squared magnitude is Norm(A) = s0 + s1 * e,
96 // so we must compute the square root of this.
97 // Length(A) = sqrt(Norm(A)) = sqrt(s0) + (s1 / (2 * sqrt(s0))) * e
98 //
99 // A unit dual quaternion U = p + q * e has the property Norm(U) = 1. This
100 // happens when
101 // p * conj(p) = 1 [p is a unit quaternion] and
102 // p * conj(q) + q * conj(p) = 0
103 //
104 // For a dual quaternion A = p + q * e where p is not zero, the inverse is
105 // Inverse(A) = Inverse(p) - Inverse(p) * q * Inverse(p) * e
106 // Note that dual quaternions of the form 0 + q * e are not invertible.
107 //
108 // Application to rigid transformations in 3D, Y = R * X + T, where
109 // R is a 3x3 rotation matrix, T is a 3x1 translation vector, X is the
110 // 3x1 input, and Y is the 3x1 output.
111 //
112 // The rigid transformation is represented by the dual quaternion
113 // d = r + (t * r / 2) * e
114 // where r is a unit quaternion representing the rotation and t is a
115 // quaternion of the form t = 0 + T0 * i + T1 * j + T2 * k, where the
116 // translation as a 3-tuple is T = (T0,T1,T2). Given a dual quaternion,
117 // the quaternion for the rotation is the scalar part r. To extract the
118 // translation, the vector part is processed as follows,
119 // t = 2 * (t * r / 2) * conj(r)
120 //
121 // The product of rigid transformations d0 = r0 + (t0 * r0 / 2) * e and
122 // d1 = r1 + (t1 * r1 / 2) is
123 // d0 * d1 = (r0 * r1) + ((r0 * t1 * r1 + t0 * r0 * r1) / 2) * e
124 // The quaternion for rotation is r0 * r1, as expected. The translation t'
125 // is extracted as
126 // t' = 2 * ((r0 * t1 * r1 + t0 * r0 * r1) / 2) * conj(r0 * r1)
127 // = (r0 * t1 * r1 + t0 * r0 * r1) * (conj(r1) * conj(r0))
128 // = r0 * t1 * conj(r0) + t0
129 // This is consistent with the product of 4x4 affine matrices
130 // +- -+ +- -+ +- -+
131 // | R0 T0 | | R1 T1 | = | R0*R1 R0*T1+T0 |
132 // | 0 1 | | 0 1 | | 0 1 |
133 // +- -+ +- -+ +- -+
134 // The right-hand side is a rotation R0*R1, represented by quaternion
135 // r0*r1, followed by a translation R0*T1+T0, represented by quaternion
136 // r0*t1*conj(r0)+t0. The first term of this expression is a rotation
137 // of t1 by r0. The second term add in the tranlation t0.
138 //
139 // To apply a dual quaternion representing a rigid transformation to a
140 // 3-tuple point X = (X0,X1,X2) represented as a quaternion
141 // x = 0 + X0 * i + X1 * j + X2 * k, consider
142 // +- -+ +- -+ +- -+
143 // | R T | | I X | = | R R*X+T |
144 // | 0 1 | | 0 1 | | 0 1 |
145 // +- -+ +- -+ +- -+
146 // The rigid transformation is the translational component of the
147 // matrix, R*X+T = Y. The second matrix of the left-hand side can be
148 // represented as a dual quaternion 1+(x/2)*e, so the product on
149 // the left-hand side is
150 // [r + (t * r / 2) * e] * [1 + (x / 2) * e]
151 // = r + ((r * x + t * r) / 2) * e
152 // Extract the translation component by
153 // y = 2 * ((r * x + t * r) / 2) * conj(r)
154 // = r * x * conj(r) + t
155 // The first term of the right-hand side is the quaternion formulation
156 // for rotating X by R. The second term is the addition of the
157 // translation vector T.
158 //
159 // TODO: Interpolation of rigid transformations (using the geodesic
160 // idea similar to quaternions).
161 
162 namespace gte
163 {
164 
165 template <typename Real>
167 {
168 public:
169  // Construction. The default constructor creates the identiy dual
170  // quaternion 1+0*e.
171  DualQuaternion();
172 
173  DualQuaternion(DualQuaternion const& d);
174 
175  // Create the dual quaternion p+q*e.
177 
178  // Assignment.
180 
181  // Member access.
182  Quaternion<Real> const& operator[] (int i) const;
184 
185  // Special quaternions.
186  static DualQuaternion Zero(); // 0+0*e
187  static DualQuaternion Identity(); // 1+0*e
188 
189 private:
190  // The dual quaternion is mTuple[0] + mTuple[1] * e.
191  std::array<Quaternion<Real>, 2> mTuple;
192 };
193 
194 
195 // Unary operations.
196 template <typename Real>
198 
199 template <typename Real>
201 
202 // Linear-algebraic operations.
203 template <typename Real>
205 
206 template <typename Real>
208 
209 template <typename Real>
211 
212 template <typename Real>
214 
215 template <typename Real>
217 
218 template <typename Real>
220 
221 template <typename Real>
223 
224 template <typename Real>
226 
227 template <typename Real>
229 
230 // Multiplication of dual quaternions.
231 template <typename Real>
233 
234 // The conjugate of a dual quaternion
235 template <typename Real>
237 
238 // Inverse of a dual quaternion p+q*e for which p is not zero.
239 // If p is zero, the function returns the zero dual quaternion
240 // as a signal the inversion failed.
241 template <typename Real>
243 
244 // Geometric operations. See GteVector.h for a description of the
245 // 'robust' parameter.
246 template <int N, typename Real>
248 
249 template <int N, typename Real>
251 
252 template <int N, typename Real>
253 DualQuaternion<Real> Norm(DualQuaternion<Real>& d, bool robust = false);
254 
255 template <int N, typename Real>
256 DualQuaternion<Real> Length(DualQuaternion<Real> const& d, bool robust = false);
257 
258 // Transform a vector X by the rigid transformation Y = R * X + T represented
259 // by the input dual quaternion. X and Y are stored in point format (4-tuples
260 // whose w-components are 1).
261 template <typename Real>
263 
264 #if 0
265 template <typename Real>
267 {
268  // Uninitialized.
269 }
270 
271 template <typename Real>
273 {
274  this->mTuple[0] = q[0];
275  this->mTuple[1] = q[1];
276  this->mTuple[2] = q[2];
277  this->mTuple[3] = q[3];
278 }
279 
280 template <typename Real>
282 {
283  this->mTuple[0] = q[0];
284  this->mTuple[1] = q[1];
285  this->mTuple[2] = q[2];
286  this->mTuple[3] = q[3];
287 }
288 
289 template <typename Real>
290 Quaternion<Real>::Quaternion(Real x, Real y, Real z, Real w)
291 {
292  this->mTuple[0] = x;
293  this->mTuple[1] = y;
294  this->mTuple[2] = z;
295  this->mTuple[3] = w;
296 }
297 
298 template <typename Real>
300 {
302  return *this;
303 }
304 
305 template <typename Real>
307 {
309  return *this;
310 }
311 
312 template <typename Real>
314 {
315  return Quaternion((Real)0, (Real)0, (Real)0, (Real)0);
316 }
317 
318 template <typename Real>
320 {
321  return Quaternion((Real)1, (Real)0, (Real)0, (Real)0);
322 }
323 
324 template <typename Real>
326 {
327  return Quaternion((Real)0, (Real)1, (Real)0, (Real)0);
328 }
329 
330 template <typename Real>
332 {
333  return Quaternion((Real)0, (Real)0, (Real)1, (Real)0);
334 }
335 
336 template <typename Real>
338 {
339  return Quaternion((Real)0, (Real)0, (Real)0, (Real)1);
340 }
341 
342 template <typename Real>
344  Quaternion<Real> const& q1)
345 {
346  // (x0*i + y0*j + z0*k + w0)*(x1*i + y1*j + z1*k + w1)
347  // =
348  // i*(+x0*w1 + y0*z1 - z0*y1 + w0*x1) +
349  // j*(-x0*z1 + y0*w1 + z0*x1 + w0*y1) +
350  // k*(+x0*y1 - y0*x1 + z0*w1 + w0*z1) +
351  // 1*(-x0*x1 - y0*y1 - z0*z1 + w0*w1)
352 
353  return Quaternion<Real>
354  (
355  +q0[0] * q1[3] + q0[1] * q1[2] - q0[2] * q1[1] + q0[3] * q1[0],
356  -q0[0] * q1[2] + q0[1] * q1[3] + q0[2] * q1[0] + q0[3] * q1[1],
357  +q0[0] * q1[1] - q0[1] * q1[0] + q0[2] * q1[3] + q0[3] * q1[2],
358  -q0[0] * q1[0] - q0[1] * q1[1] - q0[2] * q1[2] + q0[3] * q1[3]
359  );
360 }
361 
362 template <typename Real>
364 {
365  Real sqrLen = Dot(q, q);
366  if (sqrLen > (Real)0)
367  {
368  Real invSqrLen = ((Real)1) / sqrLen;
369  Quaternion<Real> inverse = Conjugate(q)*invSqrLen;
370  return inverse;
371  }
372  else
373  {
374  return Quaternion<Real>::Zero();
375  }
376 }
377 
378 template <typename Real>
380 {
381  return Quaternion<Real>(-q[0], -q[1], -q[2], +q[3]);
382 }
383 
384 template <typename Real>
386 {
388 
389  // Zero-out the w-component in remove numerical round-off error.
390  u[3] = (Real)0;
391  return u;
392 }
393 
394 template <typename Real>
395 Quaternion<Real> Slerp(Real t, Quaternion<Real> const& q0,
396  Quaternion<Real> const& q1)
397 {
398  Real cosA = Dot(q0, q1);
399  Real sign;
400  if (cosA >= (Real)0)
401  {
402  sign = (Real)1;
403  }
404  else
405  {
406  cosA = -cosA;
407  sign = (Real)-1;
408  }
409 
410  Real f0, f1;
411  ChebyshevRatio<Real>::Get(t, cosA, f0, f1);
412  return q0 * f0 + q1 * (sign * f1);
413 }
414 
415 template <typename Real>
416 Quaternion<Real> SlerpR(Real t, Quaternion<Real> const& q0,
417  Quaternion<Real> const& q1)
418 {
419  Real f0, f1;
420  ChebyshevRatio<Real>::Get(t, Dot(q0, q1), f0, f1);
421  return q0 * f0 + q1 * f1;
422 }
423 
424 template <typename Real>
425 Quaternion<Real> SlerpRP(Real t, Quaternion<Real> const& q0,
426  Quaternion<Real> const& q1, Real cosA)
427 {
428  Real f0, f1;
429  ChebyshevRatio<Real>::Get(t, cosA, f0, f1);
430  return q0 * f0 + q1 * f1;
431 }
432 
433 #endif
434 
435 }
static Quaternion Zero()
static Quaternion J()
static Quaternion K()
DualQuaternion< Real > Conjugate(DualQuaternion< Real > const &d)
DualQuaternion< Real > & operator*=(DualQuaternion< Real > &d, Real scalar)
Quaternion< Real > Slerp(Real t, Quaternion< Real > const &q0, Quaternion< Real > const &q1)
static void Get(Real t, Real cosA, Real &f0, Real &f1)
GLint GLenum GLint x
Definition: glcorearb.h:404
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:852
static DualQuaternion Zero()
Quaternion< Real > SlerpR(Real t, Quaternion< Real > const &q0, Quaternion< Real > const &q1)
Vector< 4, Real > Rotate(Quaternion< Real > const &q, Vector< 4, Real > const &v)
DualQuaternion< Real > operator+(DualQuaternion< Real > const &d)
static DualQuaternion Identity()
DualQuaternion< Real > Norm(DualQuaternion< Real > &d, bool robust=false)
DualQuaternion< Real > & operator-=(DualQuaternion< Real > &d0, DualQuaternion< Real > const &d1)
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
GLdouble GLdouble t
Definition: glext.h:239
DualQuaternion< Real > Cross(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Vector< 4, Real > RigidTransform(DualQuaternion< Real > const &d, Vector< 4, Real > const &v)
static Quaternion I()
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:843
Quaternion< Real > const & operator[](int i) const
DualQuaternion< Real > Length(DualQuaternion< Real > const &d, bool robust=false)
const GLdouble * v
Definition: glcorearb.h:832
static Quaternion Identity()
DualQuaternion & operator=(DualQuaternion const &d)
DualQuaternion< Real > operator-(DualQuaternion< Real > const &d)
GLdouble GLdouble GLdouble GLdouble q
Definition: glext.h:255
DualQuaternion< Real > & operator+=(DualQuaternion< Real > &d0, DualQuaternion< Real > const &d1)
Quaternion< Real > Inverse(Quaternion< Real > const &d)
Quaternion< Real > SlerpRP(Real t, Quaternion< Real > const &q0, Quaternion< Real > const &q1, Real cosA)
DualQuaternion< Real > & operator/=(DualQuaternion< Real > &d, Real scalar)
GLfloat GLfloat p
Definition: glext.h:11668
Vector4< float > operator*(Transform const &M, Vector4< float > const &V)
GLint y
Definition: glcorearb.h:98
std::array< Quaternion< Real >, 2 > mTuple
DualQuaternion< Real > operator/(DualQuaternion< Real > const &d, Real scalar)
Quaternion & operator=(Quaternion const &q)


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:59