Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Quaternion.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 
26 #include "Quaternion.hh"
27 
28 
29 using namespace BIAS;
30 using namespace std;
31 
32 
33 template<class QUAT_TYPE>
35 {}
36 
37 template<class QUAT_TYPE>
39 : Vector4<QUAT_TYPE>()
40 {}
41 
42 template<class QUAT_TYPE>
44  : Vector4<QUAT_TYPE>(q)
45 {}
46 
47 
48 template<class QUAT_TYPE>
49 Quaternion<QUAT_TYPE>::Quaternion(QUAT_TYPE i, QUAT_TYPE j,
50  QUAT_TYPE k, QUAT_TYPE r)
51  : Vector4<QUAT_TYPE>(i, j, k, r)
52 {}
53 
54 template<class QUAT_TYPE>
56 {
58 
59  res[0][0] = (*this)[3];
60  res[0][1] = -(*this)[2];
61  res[0][2] = (*this)[1];
62  res[0][3] = (*this)[0];
63 
64  res[1][0] = (*this)[2];
65  res[1][1] = (*this)[3];
66  res[1][2] = -(*this)[0];
67  res[1][3] = (*this)[1];
68 
69  res[2][0] = -(*this)[1];
70  res[2][1] = (*this)[0];
71  res[2][2] = (*this)[3];
72  res[2][3] = (*this)[2];
73 
74  res[3][0] = -(*this)[0];
75  res[3][1] = -(*this)[1];
76  res[3][2] = -(*this)[2];
77  res[3][3] = (*this)[3];
78 
79  return res;
80 }
81 
82 template<class QUAT_TYPE>
84 {
86 
87  res[0][0] = (*this)[3];
88  res[0][1] = (*this)[2];
89  res[0][2] = -(*this)[1];
90  res[0][3] = (*this)[0];
91 
92  res[1][0] = -(*this)[2];
93  res[1][1] = (*this)[3];
94  res[1][2] = (*this)[0];
95  res[1][3] = (*this)[1];
96 
97  res[2][0] = (*this)[1];
98  res[2][1] = -(*this)[0];
99  res[2][2] = (*this)[3];
100  res[2][3] = (*this)[2];
101 
102  res[3][0] = -(*this)[0];
103  res[3][1] = -(*this)[1];
104  res[3][2] = -(*this)[2];
105  res[3][3] = (*this)[3];
106 
107  return res;
108 }
109 
110 template<class QUAT_TYPE>
112  QUAT_TYPE& angle) const
113 {
114  // nicked from OpenSG
115  int res=0;
116  Vector3<QUAT_TYPE> q((*this)[0], (*this)[1], (*this)[2]);
117  QUAT_TYPE len = QUAT_TYPE(q.NormL2());
118 
119  if(len > QUATERNION_EPSILON) {
120  q /= len;
121  axis[0] = q[0];
122  axis[1] = q[1];
123  axis[2] = q[2];
124  angle = QUAT_TYPE(2.0 * acos((*this)[3]));
125  } else {
126  axis[0] = 0.0;
127  axis[1] = 0.0;
128  axis[2] = 1.0;
129  angle = 0.0;
130  }
131  return res;
132 }
133 
134 template<class QUAT_TYPE>
136 {
137  Vector3<QUAT_TYPE> r((*this)[0], (*this)[1], (*this)[2]);
138  QUAT_TYPE len = QUAT_TYPE(r.NormL2());
139  if (len > QUATERNION_EPSILON)
140  return r / len;
141  else
142  return Vector3<QUAT_TYPE>(0,0,1);
143 }
144 
145 template<class QUAT_TYPE>
147 {
148  const QUAT_TYPE angle = QUAT_TYPE(2.0 * acos((*this)[3]));
149  if (isnan(angle) && fabs(fabs((*this)[3]) - 1.0) < QUATERNION_EPSILON)
150  return QUAT_TYPE(0);
151  else
152  return angle;
153 }
154 
155 template<class QUAT_TYPE>
157 {
158  BIASERR("Quaternion<QUAT_TYPE>::GetRotationMatrix() is deprecated, because"
159  <<" it returned a TRANSPOSED matrix. To prevent code duplication "
160  <<" this function will be removed in the future. Check your code."
161  <<"Use RMatrixBase::SetFromQuaternion instead.");
162  BIASABORT;
163  return 1;
164 }
165 
166 template<class QUAT_TYPE> Quaternion<QUAT_TYPE>
167 Quaternion<QUAT_TYPE>::Power(const QUAT_TYPE & scale) const
168 {
169  Quaternion<QUAT_TYPE> res = *this;
170  if ((scale < 1e-7) && (scale > -1e-7)) {
171  //scale near zero -> return identity
172  res.SetIdentity();
173  } else if ((res[3] > 0.999999) || (res[3] < -0.999999)) {
174  //this is near identity (numerical unstable) -> return identity
175  //res = *this
176  } else {
177  //else use slerp interpolation between identity and this with scale
178  QUAT_TYPE temp1 = sin(scale * acos(res[3]))/sin(acos(res[3]));
179  QUAT_TYPE res3 = res[3];
180  res *= temp1;
181  res[3] += QUAT_TYPE(sin((1.0-scale) * acos(res3))/sin(acos(res3)));
182  }
183  return res;
184 }
185 
186 template<class QUAT_TYPE>
188 InterpolateLinear(const Quaternion<QUAT_TYPE> &to, const QUAT_TYPE & t) const
189 {
190  BIASASSERT(t >= 0.0 && t <= 1.0);
191  Quaternion<QUAT_TYPE> p = *this;
192  Quaternion<QUAT_TYPE> q = to;
193  //p.Normalize();
194  //q.Normalize();
195  if (t < 1e-7) {
196  //t near zero -> return p
197  return p;
198  } else if (1.0-t < 1e-7) {
199  //t near one -> return q
200  return q;
201  }
202  //else use linear interpolation between this and q
204  const QUAT_TYPE cosPhi = (QUAT_TYPE)p.ScalarProduct(q);
205  const QUAT_TYPE a = (QUAT_TYPE)1.0 - t;
206  const QUAT_TYPE b = (cosPhi < 0 ? -t : t);
207  res[0] = a*p[0] + b*q[0];
208  res[1] = a*p[1] + b*q[1];
209  res[2] = a*p[2] + b*q[2];
210  res[3] = a*p[3] + b*q[3];
211  res.Normalize();
212  return res;
213 }
214 
215 template<class QUAT_TYPE>
217 Interpolate(const Quaternion<QUAT_TYPE> &to, const QUAT_TYPE & t) const
218 {
219  BIASASSERT(t >= 0.0 && t <= 1.0);
220  Quaternion<QUAT_TYPE> p = *this;
221  Quaternion<QUAT_TYPE> q = to;
222  //p.Normalize();
223  //q.Normalize();
224  if (t < 1e-7) {
225  //t near zero -> return p
226  return p;
227  } else if (1.0-t < 1e-7) {
228  //t near one -> return q
229  return q;
230  }
232  QUAT_TYPE a, b;
233  QUAT_TYPE cosPhi = (QUAT_TYPE)p.ScalarProduct(q);
234  //adjust angle if neccessary
235  if (cosPhi < 0) {
236  q.MultiplyIP(-1.0);
237  cosPhi = -cosPhi;
238  }
239  if (cosPhi > 0.9999 || cosPhi < -0.9999) {
240  // p is very close to q, do linear interpolation instead of slerp
241  a = (QUAT_TYPE)1.0 - t;
242  b = (cosPhi < 0 ? -t : t);
243  } else {
244  //else use slerp interpolation between p and q
245  const QUAT_TYPE phi = acos(cosPhi < 0 ? -cosPhi : cosPhi);
246  const QUAT_TYPE sinPhi = sin(phi);
247  a = sin(((QUAT_TYPE)1.0 - t) * phi) / sinPhi;
248  b = sin(t * phi) / sinPhi;
249  if (cosPhi < 0) b = -b;
250  }
251  res[0] = a*p[0] + b*q[0];
252  res[1] = a*p[1] + b*q[1];
253  res[2] = a*p[2] + b*q[2];
254  res[3] = a*p[3] + b*q[3];
255  res.Normalize();
256  return res;
257 }
258 
259 template<class QUAT_TYPE>
261 SetXYZ(QUAT_TYPE radX, QUAT_TYPE radY, QUAT_TYPE radZ)
262 {
266 
267  q_x.SetValueAsAxisRad( 1.,0.,0., radX );
268  q_y.SetValueAsAxisRad( 0.,1.,0., radY );
269  q_z.SetValueAsAxisRad( 0.,0.,1., radZ );
270 
271  q_x.Mult(q_y);
272  q_x.Mult(q_z);
273 
274  (*this) = q_x;
275 
276  return 0;
277 }
278 
279 template<class QUAT_TYPE>
281 SetZYX(QUAT_TYPE radX, QUAT_TYPE radY, QUAT_TYPE radZ)
282 {
286 
287  q_x.SetValueAsAxisRad( 1.,0.,0., radX );
288  q_y.SetValueAsAxisRad( 0.,1.,0., radY );
289  q_z.SetValueAsAxisRad( 0.,0.,1., radZ );
290 
291  q_z.Mult(q_y);
292  q_z.Mult(q_x);
293 
294  (*this) = q_z;
295 
296  return 0;
297 }
298 
299 template<class QUAT_TYPE>
302 {
303  memcpy((void *)this->data_, (void *)vec.GetData(),
304  VECTOR4SIZE*sizeof(QUAT_TYPE));
305  return *this;
306 }
307 
308 template<class QUAT_TYPE> void
311  bool useOtherAngle)
312 {
313  // @todo check unit norm constraint of this and other quaternion!!
314 
315  // make this and other quaternion unique
316  MakeUnique();
317  other.MakeUnique();
318 
319  // get aliases for both quaternions
320  Quaternion<QUAT_TYPE> &q0 = *this, &q1 = other;
321 
322  // interpolate equal angle
323  if (useOtherAngle)
324  q0[3] = q1[3];
325  else
326  q0[3] = q1[3] = QUAT_TYPE(0.5) * (q0[3] + q1[3]);
327 
328  // re-enforce unit length constraint for q0 and q1
329  QUAT_TYPE q0norm = q0[0]*q0[0] + q0[1]*q0[1] + q0[2]*q0[2];
330  QUAT_TYPE q1norm = q1[0]*q1[0] + q1[1]*q1[1] + q1[2]*q1[2];
331  if (q0norm > QUAT_TYPE(1e-8) && q1norm > QUAT_TYPE(1e-8)) {
332  QUAT_TYPE qscale0 = (QUAT_TYPE)sqrt(double((1-q0[3]*q0[3])/q0norm));
333  QUAT_TYPE qscale1 = (QUAT_TYPE)sqrt(double((1-q1[3]*q1[3])/q1norm));
334  for (register int l = 0; l < 3; l++) {
335  q0[l] *= qscale0;
336  q1[l] *= qscale1;
337  }
338  }
339 
340  // @todo check unit norm constraint of resulting quaternions!!
341 }
342 
343 template<class QUAT_TYPE> void
346  bool useFirstAngle)
347 {
348  // @todo check unit norm constraint of all quaternions!!
349  if (quats.empty()) return;
350 
351  // make all quaternions unique
352  const int n = quats.size();
353  for (int i = 0; i < n; i++)
354  quats[i].MakeUnique();
355 
356  // interpolate equal angle
357  QUAT_TYPE a = quats[0][3];
358  if (!useFirstAngle) {
359  for (int i = 1; i < n; i++)
360  a += quats[i][3];
361  a /= QUAT_TYPE(n);
362  }
363  for (int i = 0; i < n; i++)
364  quats[i][3] = a;
365 
366  // re-enforce unit length constraint for all quaternions
367  for (int i = 0; i < n; i++) {
368  Quaternion<QUAT_TYPE> &q = quats[i];
369  QUAT_TYPE qnorm = q[0]*q[0] + q[1]*q[1] + q[2]*q[2];
370  if (qnorm > QUAT_TYPE(1e-8)) {
371  QUAT_TYPE qscale = (QUAT_TYPE)sqrt(double((1-q[3]*q[3])/qnorm));
372  for (register int l = 0; l < 3; l++)
373  q[l] *= qscale;
374  }
375  }
376 
377  // @todo check unit norm constraint of resulting quaternions!!
378 }
379 
380 // instance definitions
381 template class BIASGeometryBase_EXPORT BIAS::Quaternion<float>;
382 template class BIASGeometryBase_EXPORT BIAS::Quaternion<double>;
void Normalize()
Scales quaternion to unit length, i.e.
Definition: Quaternion.hh:236
void MakeUnique()
makes Quaternion-representation uniqe, ensuring vector lies in upper (by real part) hemisphere...
Definition: Quaternion.hh:50
class Vector4 contains a Vector of dim.
Definition: Vector4.hh:65
const unsigned int size() const
Definition: Vector4.hh:436
void Mult(const Quaternion< QUAT_TYPE > &quat)
quaternion multiplication: this= this * quat
Definition: Quaternion.hh:73
class Vector3 contains a Vector of fixed dim.
Definition: Matrix.hh:53
void ScalarProduct(const Vector4< T > &argvec, T &result) const
scalar product (=inner product) of two vectors, storing the result in result
Definition: Vector4.hh:475
const T * GetData() const
get the data pointer the member function itself is const (before {..}) because it doesn&#39;t change the...
Definition: Vector4.hh:177
void MultiplyIP(const T &scalar)
Multiplication (in place) of an scalar.
Definition: Vector4.hh:609
Implements a 3D rotation matrix.
Definition: RMatrixBase.hh:44
is a &#39;fixed size&#39; quadratic matrix of dim.
Definition: Matrix4x4.hh:54
class for rotation with axis and angle
double NormL2() const
the L2 norm sqrt(a^2 + b^2 + c^2)
Definition: Vector3.hh:633
void SetValueAsAxisRad(const Vector3< QUAT_TYPE > &axis, QUAT_TYPE angle)
sets the quaternion with given rotation axis and angle (in rad)
Definition: Quaternion.hh:183