quat_slerp.cpp File Reference
#include <iostream>
#include <Eigen/Geometry>
#include <bench/BenchTimer.h>

Macros

#define BENCH(FUNC)
 

Functions

template<typename Q >
EIGEN_DONT_INLINE Q nlerp (const Q &a, const Q &b, typename Q::Scalar t)
 
template<typename Q >
EIGEN_DONT_INLINE Q slerp_eigen (const Q &a, const Q &b, typename Q::Scalar t)
 
template<typename Q >
EIGEN_DONT_INLINE Q slerp_legacy (const Q &a, const Q &b, typename Q::Scalar t)
 
template<typename Q >
EIGEN_DONT_INLINE Q slerp_legacy_nlerp (const Q &a, const Q &b, typename Q::Scalar t)
 
template<typename T >
T sin_over_x (T x)
 
template<typename Q >
EIGEN_DONT_INLINE Q slerp_rw (const Q &a, const Q &b, typename Q::Scalar t)
 
template<typename Q >
EIGEN_DONT_INLINE Q slerp_gael (const Q &a, const Q &b, typename Q::Scalar t)
 
int main ()
 

Macro Definition Documentation

◆ BENCH

#define BENCH (   FUNC)
Value:
{ \
BenchTimer t; \
for (int k = 0; k < 2; ++k) { \
t.start(); \
for (int i = 0; i < 1000000; ++i) FUNC(a, b, s); \
t.stop(); \
} \
cout << " " << #FUNC << " => \t " << t.value() << "s\n"; \
}
int i
Definition: BiCGSTAB_step_by_step.cpp:9
Scalar * b
Definition: benchVecAdd.cpp:17
RealScalar s
Definition: level1_cplx_impl.h:130
const Scalar * a
Definition: level2_cplx_impl.h:32
char char char int int * k
Definition: level2_impl.h:374
t
Definition: plotPSD.py:36

Function Documentation

◆ main()

int main ( )
123  {
124  typedef double RefScalar;
125  typedef float TestScalar;
126 
127  typedef Quaternion<RefScalar> Qd;
128  typedef Quaternion<TestScalar> Qf;
129 
130  unsigned int g_seed = (unsigned int)time(NULL);
131  std::cout << g_seed << "\n";
132  // g_seed = 1259932496;
133  srand(g_seed);
134 
136  maxerr.setZero();
137 
139  avgerr.setZero();
140 
141  cout << "double=>float=>double nlerp eigen legacy(snap) legacy(nlerp) rightway "
142  " gael's criteria\n";
143 
144  int rep = 100;
145  int iters = 40;
146  for (int w = 0; w < rep; ++w) {
147  Qf a, b;
148  a.coeffs().setRandom();
149  a.normalize();
150  b.coeffs().setRandom();
151  b.normalize();
152 
153  Qf c[6];
154 
155  Qd ar(a.cast<RefScalar>());
156  Qd br(b.cast<RefScalar>());
157  Qd cr;
158 
159  cout.precision(8);
160  cout << std::scientific;
161  for (int i = 0; i < iters; ++i) {
162  RefScalar t = 0.65;
163  cr = slerp_rw(ar, br, t);
164 
165  Qf refc = cr.cast<TestScalar>();
166  c[0] = nlerp(a, b, t);
167  c[1] = slerp_eigen(a, b, t);
168  c[2] = slerp_legacy(a, b, t);
169  c[3] = slerp_legacy_nlerp(a, b, t);
170  c[4] = slerp_rw(a, b, t);
171  c[5] = slerp_gael(a, b, t);
172 
173  VectorXd err(7);
174  err[0] = (cr.coeffs() - refc.cast<RefScalar>().coeffs()).norm();
175  // std::cout << err[0] << " ";
176  for (int k = 0; k < 6; ++k) {
177  err[k + 1] = (c[k].coeffs() - refc.coeffs()).norm();
178  // std::cout << err[k+1] << " ";
179  }
180  maxerr = maxerr.cwise().max(err);
181  avgerr += err;
182  // std::cout << "\n";
183  b = cr.cast<TestScalar>();
184  br = cr;
185  }
186  // std::cout << "\n";
187  }
188  avgerr /= RefScalar(rep * iters);
189  cout << "\n\nAccuracy:\n"
190  << " max: " << maxerr.transpose() << "\n";
191  cout << " avg: " << avgerr.transpose() << "\n";
192 
193  // perf bench
194  Quaternionf a, b;
195  a.coeffs().setRandom();
196  a.normalize();
197  b.coeffs().setRandom();
198  b.normalize();
199  // b = a;
200  float s = 0.65;
201 
202 #define BENCH(FUNC) \
203  { \
204  BenchTimer t; \
205  for (int k = 0; k < 2; ++k) { \
206  t.start(); \
207  for (int i = 0; i < 1000000; ++i) FUNC(a, b, s); \
208  t.stop(); \
209  } \
210  cout << " " << #FUNC << " => \t " << t.value() << "s\n"; \
211  }
212 
213  cout << "\nSpeed:\n" << std::fixed;
214  BENCH(nlerp);
218  BENCH(slerp_rw);
219  BENCH(slerp_gael);
220 }
RowVector3d w
Definition: Matrix_resize_int.cpp:3
The matrix class, also used for vectors and row-vectors.
Definition: Eigen/Eigen/src/Core/Matrix.h:186
The quaternion class used to represent 3D orientations and rotations.
Definition: Eigen/Eigen/src/Geometry/Quaternion.h:285
return int(ret)+1
static unsigned int g_seed
Definition: main.h:192
int c
Definition: calibrate.py:100
#define BENCH(FUNC)
EIGEN_DONT_INLINE Q slerp_legacy(const Q &a, const Q &b, typename Q::Scalar t)
Definition: quat_slerp.cpp:19
EIGEN_DONT_INLINE Q nlerp(const Q &a, const Q &b, typename Q::Scalar t)
Definition: quat_slerp.cpp:9
EIGEN_DONT_INLINE Q slerp_legacy_nlerp(const Q &a, const Q &b, typename Q::Scalar t)
Definition: quat_slerp.cpp:38
EIGEN_DONT_INLINE Q slerp_gael(const Q &a, const Q &b, typename Q::Scalar t)
Definition: quat_slerp.cpp:94
EIGEN_DONT_INLINE Q slerp_rw(const Q &a, const Q &b, typename Q::Scalar t)
Definition: quat_slerp.cpp:72
EIGEN_DONT_INLINE Q slerp_eigen(const Q &a, const Q &b, typename Q::Scalar t)
Definition: quat_slerp.cpp:14

References a, b, BENCH, calibrate::c, Eigen::g_seed, i, int(), k, nlerp(), s, Eigen::PlainObjectBase< Derived >::setZero(), slerp_eigen(), slerp_gael(), slerp_legacy(), slerp_legacy_nlerp(), slerp_rw(), plotPSD::t, and w.

◆ nlerp()

template<typename Q >
EIGEN_DONT_INLINE Q nlerp ( const Q a,
const Q b,
typename Q::Scalar  t 
)
9  {
10  return Q((a.coeffs() * (1.0 - t) + b.coeffs() * t).normalized());
11 }
MatrixXf Q
Definition: HouseholderQR_householderQ.cpp:1

References a, b, Q, and plotPSD::t.

Referenced by main().

◆ sin_over_x()

template<typename T >
T sin_over_x ( T  x)
inline
64  {
65  if (T(1) + x * x == T(1))
66  return T(1);
67  else
68  return std::sin(x) / x;
69 }
AnnoyingScalar sin(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:137
Eigen::Triplet< double > T
Definition: EigenUnitTest.cpp:11
list x
Definition: plotDoE.py:28

References sin(), and plotDoE::x.

Referenced by slerp_rw().

◆ slerp_eigen()

template<typename Q >
EIGEN_DONT_INLINE Q slerp_eigen ( const Q a,
const Q b,
typename Q::Scalar  t 
)
14  {
15  return a.slerp(t, b);
16 }

References a, b, and plotPSD::t.

Referenced by main().

◆ slerp_gael()

template<typename Q >
EIGEN_DONT_INLINE Q slerp_gael ( const Q a,
const Q b,
typename Q::Scalar  t 
)
94  {
95  typedef typename Q::Scalar Scalar;
96 
97  Scalar d = a.dot(b);
98  Scalar theta;
99  // theta = Scalar(2) * atan2((a.coeffs()-b.coeffs()).norm(),(a.coeffs()+b.coeffs()).norm());
100  // if (d<0.0)
101  // theta = M_PI-theta;
102 
103  if (d < 0.0)
104  theta = /*M_PI -*/ Scalar(2) * std::asin((-a.coeffs() - b.coeffs()).norm() / 2);
105  else
106  theta = Scalar(2) * std::asin((a.coeffs() - b.coeffs()).norm() / 2);
107 
108  Scalar scale0;
109  Scalar scale1;
110  if (theta * theta - Scalar(6) == -Scalar(6)) {
111  scale0 = Scalar(1) - t;
112  scale1 = t;
113  } else {
114  Scalar sinTheta = std::sin(theta);
115  scale0 = internal::sin((Scalar(1) - t) * theta) / sinTheta;
116  scale1 = internal::sin((t * theta)) / sinTheta;
117  if (d < 0) scale1 = -scale1;
118  }
119 
120  return Quaternion<Scalar>(scale0 * a.coeffs() + scale1 * b.coeffs());
121 }
SCALAR Scalar
Definition: bench_gemm.cpp:45
double theta
Definition: two_d_biharmonic.cc:236
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 asin(const bfloat16 &a)
Definition: BFloat16.h:634

References a, Eigen::bfloat16_impl::asin(), b, sin(), plotPSD::t, and BiharmonicTestFunctions2::theta.

Referenced by main().

◆ slerp_legacy()

template<typename Q >
EIGEN_DONT_INLINE Q slerp_legacy ( const Q a,
const Q b,
typename Q::Scalar  t 
)
19  {
20  typedef typename Q::Scalar Scalar;
21  static const Scalar one = Scalar(1) - dummy_precision<Scalar>();
22  Scalar d = a.dot(b);
23  Scalar absD = internal::abs(d);
24  if (absD >= one) return a;
25 
26  // theta is the angle between the 2 quaternions
27  Scalar theta = std::acos(absD);
28  Scalar sinTheta = internal::sin(theta);
29 
30  Scalar scale0 = internal::sin((Scalar(1) - t) * theta) / sinTheta;
31  Scalar scale1 = internal::sin((t * theta)) / sinTheta;
32  if (d < 0) scale1 = -scale1;
33 
34  return Q(scale0 * a.coeffs() + scale1 * b.coeffs());
35 }
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
AnnoyingScalar acos(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:138

References a, abs(), acos(), b, Q, sin(), plotPSD::t, and BiharmonicTestFunctions2::theta.

Referenced by main().

◆ slerp_legacy_nlerp()

template<typename Q >
EIGEN_DONT_INLINE Q slerp_legacy_nlerp ( const Q a,
const Q b,
typename Q::Scalar  t 
)
38  {
39  typedef typename Q::Scalar Scalar;
40  static const Scalar one = Scalar(1) - epsilon<Scalar>();
41  Scalar d = a.dot(b);
42  Scalar absD = internal::abs(d);
43 
44  Scalar scale0;
45  Scalar scale1;
46 
47  if (absD >= one) {
48  scale0 = Scalar(1) - t;
49  scale1 = t;
50  } else {
51  // theta is the angle between the 2 quaternions
52  Scalar theta = std::acos(absD);
53  Scalar sinTheta = internal::sin(theta);
54 
55  scale0 = internal::sin((Scalar(1) - t) * theta) / sinTheta;
56  scale1 = internal::sin((t * theta)) / sinTheta;
57  if (d < 0) scale1 = -scale1;
58  }
59 
60  return Q(scale0 * a.coeffs() + scale1 * b.coeffs());
61 }

References a, abs(), acos(), b, Q, sin(), plotPSD::t, and BiharmonicTestFunctions2::theta.

Referenced by main().

◆ slerp_rw()

template<typename Q >
EIGEN_DONT_INLINE Q slerp_rw ( const Q a,
const Q b,
typename Q::Scalar  t 
)
72  {
73  typedef typename Q::Scalar Scalar;
74 
75  Scalar d = a.dot(b);
76  Scalar theta;
77  if (d < 0.0)
78  theta = /*M_PI -*/ Scalar(2) * std::asin((a.coeffs() + b.coeffs()).norm() / 2);
79  else
80  theta = Scalar(2) * std::asin((a.coeffs() - b.coeffs()).norm() / 2);
81 
82  // theta is the angle between the 2 quaternions
83  // Scalar theta = std::acos(absD);
84  Scalar sinOverTheta = sin_over_x(theta);
85 
86  Scalar scale0 = (Scalar(1) - t) * sin_over_x((Scalar(1) - t) * theta) / sinOverTheta;
87  Scalar scale1 = t * sin_over_x((t * theta)) / sinOverTheta;
88  if (d < 0) scale1 = -scale1;
89 
90  return Quaternion<Scalar>(scale0 * a.coeffs() + scale1 * b.coeffs());
91 }
T sin_over_x(T x)
Definition: quat_slerp.cpp:64

References a, Eigen::bfloat16_impl::asin(), b, sin_over_x(), plotPSD::t, and BiharmonicTestFunctions2::theta.

Referenced by main().