Scene Fusion 2 API Reference
ksQuaternion.h
1 /*************************************************************************
2  *
3  * KINEMATICOUP CONFIDENTIAL
4  * __________________
5  *
6  * Copyright (2016-2021) KinematicSoup Technologies Incorporated
7  * All Rights Reserved.
8  *
9  * NOTICE: All information contained herein is, and remains
10  * the property of KinematicSoup Technologies Incorporated and its
11  * suppliers, if any. The intellectual and technical concepts contained
12  * herein are proprietary to KinematicSoup Technologies Incorporated
13  * and its suppliers and may be covered by Canadian and Foreign Patents,
14  * patents in process, and are protected by trade secret or copyright law.
15  * Dissemination of this information or reproduction of this material
16  * is strictly forbidden unless prior written permission is obtained
17  * from KinematicSoup Technologies Incorporated.
18  */
19 #pragma once
20 
21 #include <iostream>
22 #include <cmath>
23 #include <string>
24 #include <stdexcept>
25 #include "Exports.h"
26 #include "ksVector3.h"
27 
28 #define KS_PI 3.14159265358979323846264338327950288419716939937510
29 #define KS_DEGREES_TO_RADIANS 0.01745329251994329576923690768489
30 #define KS_RADIANS_TO_DEGREES 57.295779513082320876798154814105
31 #define KS_FDEGREES_TO_RADIANS 0.01745329251994329576923690768489f
32 #define KS_FRADIANS_TO_DEGREES 57.295779513082320876798154814105f
33 
34 namespace KS
35 {
36  class EXTERNAL ksQuaternion
37  {
38  private:
39  Scalar m_values[4];
40  enum{ X = 0, Y = 1, Z = 2, W = 3 };
41  public:
46  {
47  m_values[X] = (Scalar)0.0;
48  m_values[Y] = (Scalar)0.0;
49  m_values[Z] = (Scalar)0.0;
50  m_values[W] = (Scalar)1.0;
51  }
52 
57  {
58  m_values[X] = q.x();
59  m_values[Y] = q.y();
60  m_values[Z] = q.z();
61  m_values[W] = q.w();
62  }
63 
67  ksQuaternion(Scalar x, Scalar y, Scalar z, Scalar w)
68  {
69  m_values[X] = x;
70  m_values[Y] = y;
71  m_values[Z] = z;
72  m_values[W] = w;
73  }
74 
79 
80  /* Component access */
81  Scalar& x() { return m_values[X]; }
82  Scalar& y() { return m_values[Y]; }
83  Scalar& z() { return m_values[Z]; }
84  Scalar& w() { return m_values[W]; }
85  const Scalar& x() const { return m_values[X]; }
86  const Scalar& y() const { return m_values[Y]; }
87  const Scalar& z() const { return m_values[Z]; }
88  const Scalar& w() const { return m_values[W]; }
89  Scalar& operator[] (const int index) { return m_values[index]; }
90 
91 
97  ksVector3 Vec() const
98  {
99  return ksVector3{ m_values[X], m_values[Y], m_values[Z] };
100  }
101 
108  {
109  for (int i = 0; i < 4; i++)
110  {
111  if (m_values[i] != 0)
112  {
113  return m_values[i] > 0;
114  }
115  }
116  return true;
117  }
118 
119 
126  inline ksQuaternion operator* (const ksQuaternion& q) const
127  {
128  double _x = (double)m_values[X];
129  double _y = (double)m_values[Y];
130  double _z = (double)m_values[Z];
131  double _w = (double)m_values[W];
132 
133  double qx = (double)q.x();
134  double qy = (double)q.y();
135  double qz = (double)q.z();
136  double qw = (double)q.w();
137 
138  ksQuaternion result;
139  result.w() = (Scalar)((qw * _w) - (qx * _x) - (qy * _y) - (qz * _z));
140  result.x() = (Scalar)((qw * _x) + (qx * _w) - (qy * _z) + (qz * _y));
141  result.y() = (Scalar)((qw * _y) + (qx * _z) + (qy * _w) - (qz * _x));
142  result.z() = (Scalar)((qw * _z) - (qx * _y) + (qy * _x) + (qz * _w));
143  return result;
144  }
145 
153  {
154  double _x = (double)m_values[X];
155  double _y = (double)m_values[Y];
156  double _z = (double)m_values[Z];
157  double _w = (double)m_values[W];
158  double _2x = _x * 2.0;
159  double _2y = _y * 2.0;
160  double _2z = _z * 2.0;
161  double _x2x = _x * _2x;
162  double _y2y = _y * _2y;
163  double _z2z = _z * _2z;
164  double _x2y = _x * _2y;
165  double _x2z = _x * _2z;
166  double _y2z = _y * _2z;
167  double _w2x = _w * _2x;
168  double _w2y = _w * _2y;
169  double _w2z = _w * _2z;
170 
171  double px = (double)point.x();
172  double py = (double)point.y();
173  double pz = (double)point.z();
174 
175  ksVector3 result;
176  result.x() = (Scalar)((1.0 - (_y2y + _z2z)) * px + (_x2y - _w2z) * py + (_x2z + _w2y) * pz);
177  result.y() = (Scalar)((_x2y + _w2z) * px + (1.0 - (_x2x + _z2z)) * py + (_y2z - _w2x) * pz);
178  result.z() = (Scalar)((_x2z - _w2y) * px + (_y2z + _w2x) * py + (1.0 - (_x2x + _y2y)) * pz);
179  return result;
180  }
181 
182 
188  inline ksQuaternion operator- () const
189  {
190  return ksQuaternion{ -m_values[X], -m_values[Y], -m_values[Z], -m_values[W] };
191  }
192 
193 
200  inline ksQuaternion& operator*= (const ksQuaternion& q)
201  {
202  double _x = (double)m_values[X];
203  double _y = (double)m_values[Y];
204  double _z = (double)m_values[Z];
205  double _w = (double)m_values[W];
206 
207  double qx = (double)q.x();
208  double qy = (double)q.y();
209  double qz = (double)q.z();
210  double qw = (double)q.w();
211 
212  double tw = (qw * _w) - (qx * _x) - (qy * _y) - (qz * _z);
213  double tx = (qw * _x) + (qx * _w) - (qy * _z) + (qz * _y);
214  double ty = (qw * _y) + (qx * _z) + (qy * _w) - (qz * _x);
215  double tz = (qw * _z) - (qx * _y) + (qy * _x) + (qz * _w);
216 
217  m_values[X] = (Scalar)tx;
218  m_values[Y] = (Scalar)ty;
219  m_values[Z] = (Scalar)tz;
220  m_values[W] = (Scalar)tw;
221  return *this;
222  }
223 
230  inline bool operator== (const ksQuaternion& q)
231  {
232  return m_values[X] == q.x() && m_values[Y] == q.y() && m_values[Z] == q.z() && m_values[W] == q.w();
233  }
234 
241  inline bool operator!= (const ksQuaternion& q)
242  {
243  return !(*this == q);
244  }
245 
246 
250  void Normalize()
251  {
252  // Computation of length can overflow easily because it
253  // first computes squared length, so we first divide by
254  // the largest coefficient.
255  Scalar m = (m_values[X] < 0.0f) ? -m_values[X] : m_values[X];
256  Scalar absy = (m_values[Y] < 0.0f) ? -m_values[Y] : m_values[Y];
257  Scalar absz = (m_values[Z] < 0.0f) ? -m_values[Z] : m_values[Z];
258  Scalar absw = (m_values[W] < 0.0f) ? -m_values[W] : m_values[W];
259 
260  m = (absy > m) ? absy : m;
261  m = (absz > m) ? absz : m;
262  m = (absw > m) ? absw : m;
263 
264  //std::cout << " m = " << m << ", absy = " << absy << ", absz = " << absz << ", absw = " << absw << std::endl;
265 
266  // Scaling
267  m_values[X] /= m;
268  m_values[Y] /= m;
269  m_values[Z] /= m;
270  m_values[W] /= m;
271 
272  // Normalize
273  Scalar length = (Scalar)sqrt(
274  m_values[X] * m_values[X]
275  + m_values[Y] * m_values[Y]
276  + m_values[Z] * m_values[Z]
277  + m_values[W] * m_values[W]);
278 
279  m_values[X] /= length;
280  m_values[Y] /= length;
281  m_values[Z] /= length;
282  m_values[W] /= length;
283  }
284 
291  {
292  ksQuaternion ksQuaternion2;
293  float num2 = (((m_values[X] * m_values[X])
294  + (m_values[Y] * m_values[Y]))
295  + (m_values[Z] * m_values[Z]))
296  + (m_values[W] * m_values[W]);
297  float num = 1 / num2;
298 
299  ksQuaternion2.x() = (m_values[X] == 0.0f) ? 0.0f : -m_values[X] * num;
300  ksQuaternion2.y() = (m_values[Y] == 0.0f) ? 0.0f : -m_values[Y] * num;
301  ksQuaternion2.z() = (m_values[Z] == 0.0f) ? 0.0f : -m_values[Z] * num;
302  ksQuaternion2.w() = m_values[W] * num;
303  return ksQuaternion2;
304  }
305 
313  static ksQuaternion FromVectorDelta(ksVector3 startDirection, ksVector3 endDirection)
314  {
315  ksQuaternion q;
316  ksVector3 a = ksVector3::Cross(startDirection, endDirection);
317  q.w() = (float)std::sqrt((startDirection.MagnitudeSquared()) * (endDirection.MagnitudeSquared())) + ksVector3::Dot(startDirection, endDirection);
318  q.x() = a.x();
319  q.y() = a.y();
320  q.z() = a.z();
321  q.Normalize();
322  return q;
323  }
324 
332  static ksQuaternion FromAxisAngle(ksVector3 axis, float angle)
333  {
334  angle *= (float)KS_DEGREES_TO_RADIANS;
335  return FromAxisAngleRadians(axis, angle);
336  }
337 
345  static ksQuaternion FromAxisAngleRadians(ksVector3 axis, float angle)
346  {
347  if (axis.MagnitudeSquared() == 0)
348  throw std::runtime_error("axis cannot be 0 vector");
349  axis.Normalize();
350  ksVector3 v = axis * (float)std::sin(0.5 * angle);
351  ksQuaternion result(v.x(), v.y(), v.z(), (float)std::cos(0.5 * angle));
352  result.Normalize();
353  return result;
354  }
355 
362  void ToAxisAngle(ksVector3 &axis, float &angle)
363  {
364  ToAxisAngleRadians(axis, angle);
365  angle *= (float)KS_RADIANS_TO_DEGREES;
366  }
367 
374  void ToAxisAngleRadians(ksVector3 &axis, float &angle)
375  {
376  if (m_values[X] == 0 && m_values[Y] == 0 && m_values[Z] == 0)
377  {
378  axis.x() = 1.0f;
379  axis.y() = 0.0f;
380  axis.z() = 0.0f;
381  }
382  else
383  {
384  ksVector3 v(m_values[X], m_values[Y], m_values[Z]);
385  v.Normalize();
386  axis = v;
387  }
388 
389  double msin = std::sqrt(m_values[X] * m_values[X] + m_values[Y] * m_values[Y] + m_values[Z] * m_values[Z]);
390  double mcos = m_values[W];
391 
392  if (msin != msin)
393  {
394  double maxcoeff = std::fmax(std::abs(m_values[X]), std::fmax(std::abs(m_values[Y]), std::abs(m_values[Z])));
395  double _x = m_values[X] / maxcoeff;
396  double _y = m_values[Y] / maxcoeff;
397  double _z = m_values[Z] / maxcoeff;
398  msin = std::sqrt(_x * _x + _y * _y + _z * _z);
399  mcos = m_values[W] / maxcoeff;
400  }
401 
402  angle = (float)std::atan2(msin, mcos) * 2;
403  if (angle > KS_PI)
404  angle -= 2 * (float)KS_PI;
405  else if (angle <= -KS_PI)
406  angle += 2 * (float)KS_PI;
407  }
408 
409 
417  static Scalar Dot(const ksQuaternion& q1, const ksQuaternion& q2)
418  {
419  return q1.x() * q2.x() + q1.y() * q2.y() + q1.z() * q2.z() + q1.w() * q2.w();
420  }
421 
422 
430  static ksVector3 TransformVector(const ksVector3& v, const ksQuaternion& q)
431  {
432  ksVector3 t = 2.0f * ksVector3::Cross(q.Vec(), v);
433  return v + (q.w() * t) + ksVector3::Cross(q.Vec(), t);
434  }
435 
436 
445  static ksQuaternion Slerp(const ksQuaternion& from, const ksQuaternion& to, float t)
446  {
447  float num2;
448  float num3;
450  float num = t;
451  float num4 = (((from.x() * to.x()) + (from.y() * to.y())) + (from.z() * to.z())) + (from.w() * to.w());
452  bool flag = false;
453  if (num4 < 0.0f)
454  {
455  flag = true;
456  num4 = -num4;
457  }
458  if (num4 > 0.999999f)
459  {
460  num3 = 1.0f - num;
461  num2 = flag ? -num : num;
462  }
463  else
464  {
465  float num5 = std::acos(num4);
466  float num6 = 1.0f / std::sin(num5);
467  num3 = std::sin((1.0f - num) * num5) * num6;
468  num2 = flag ? (-std::sin(num * num5) * num6) : std::sin(num * num5) * num6;
469  }
470  ksQuaternion.x() = (num3 * from.x()) + (num2 * to.x());
471  ksQuaternion.y() = (num3 * from.y()) + (num2 * to.y());
472  ksQuaternion.z() = (num3 * from.z()) + (num2 * to.z());
473  ksQuaternion.w() = (num3 * from.w()) + (num2 * to.w());
474  return ksQuaternion;
475  }
476 
477 
486  const ksVector3& angularDisplacement)
487  {
488  float x = angularDisplacement.x();
489  float y = angularDisplacement.y();
490  float z = angularDisplacement.z();
491  float magnitude = std::sqrt(x * x + y * y + z * z);
492  if (magnitude <= 0)
493  return quaternion;
494  float cos = std::cos(magnitude / 2.0f );
495  float sin = std::sin(magnitude / 2.0f );
496  ksQuaternion rot;
497  rot.x() = x * sin / magnitude;
498  rot.y() = y * sin / magnitude;
499  rot.z() = z * sin / magnitude;
500  rot.w() = cos;
501 
502  ksQuaternion result;
503  result.x() = rot.w() * quaternion.x() + rot.x() * quaternion.w()
504  + rot.y() * quaternion.z() - rot.z() * quaternion.y();
505  result.y() = rot.w() * quaternion.y() - rot.x() * quaternion.z()
506  + rot.y() * quaternion.w() + rot.z() * quaternion.x();
507  result.z() = rot.w() * quaternion.z() + rot.x() * quaternion.y()
508  - rot.y() * quaternion.x() + rot.z() * quaternion.w();
509  result.w() = rot.w() * quaternion.w() - rot.x() * quaternion.x()
510  - rot.y() * quaternion.y() - rot.z() * quaternion.z();
511  return result;
512  }
513 
514 
520  std::string ToString()
521  {
522  return "X=" + std::to_string(m_values[X]) +
523  ", Y=" + std::to_string(m_values[Y]) +
524  ", Z=" + std::to_string(m_values[Z]) +
525  ", W=" + std::to_string(m_values[W]);
526  }
527  };
528 }
529 
530 #undef KS_PI
531 #undef KS_DEGREES_TO_RADIANS
532 #undef KS_RADIANS_TO_DEGREES
533 #undef KS_FDEGREES_TO_RADIANS
534 #undef KS_FRADIANS_TO_DEGREES
Definition: ksQuaternion.h:37
static ksQuaternion FromAxisAngle(ksVector3 axis, float angle)
Definition: ksQuaternion.h:332
bool GetFirstNonZeroComponentSign()
Definition: ksQuaternion.h:107
~ksQuaternion()
Definition: ksQuaternion.h:78
void ToAxisAngle(ksVector3 &axis, float &angle)
Definition: ksQuaternion.h:362
ksQuaternion Inverse() const
Definition: ksQuaternion.h:290
static ksQuaternion FromVectorDelta(ksVector3 startDirection, ksVector3 endDirection)
Definition: ksQuaternion.h:313
void ToAxisAngleRadians(ksVector3 &axis, float &angle)
Definition: ksQuaternion.h:374
std::string ToString()
Definition: ksQuaternion.h:520
void Normalize()
Definition: ksQuaternion.h:250
static Scalar Dot(const ksQuaternion &q1, const ksQuaternion &q2)
Definition: ksQuaternion.h:417
ksQuaternion(Scalar x, Scalar y, Scalar z, Scalar w)
Definition: ksQuaternion.h:67
static ksQuaternion FromAxisAngleRadians(ksVector3 axis, float angle)
Definition: ksQuaternion.h:345
ksQuaternion(const ksQuaternion &q)
Definition: ksQuaternion.h:56
static ksVector3 TransformVector(const ksVector3 &v, const ksQuaternion &q)
Definition: ksQuaternion.h:430
static ksQuaternion AddAngularDisplacementRadians(const ksQuaternion &quaternion, const ksVector3 &angularDisplacement)
Definition: ksQuaternion.h:485
static ksQuaternion Slerp(const ksQuaternion &from, const ksQuaternion &to, float t)
Definition: ksQuaternion.h:445
ksQuaternion()
Definition: ksQuaternion.h:45
ksVector3 Vec() const
Definition: ksQuaternion.h:97
Definition: ksVector3.h:32
static Scalar Dot(const ksVector3 &v1, const ksVector3 &v2)
Definition: ksVector3.h:314
float MagnitudeSquared()
Definition: ksVector3.h:227
void Normalize()
Definition: ksVector3.h:243
static ksVector3 Cross(const ksVector3 &v1, const ksVector3 &v2)
Definition: ksVector3.h:326
Definition: sfDictionaryProperty.h:24
ksVector3 operator*(const Scalar &c, const ksVector3 &v)
Definition: ksVector3.h:352