3 #include <Eigen/Geometry>
4 #include <bench/BenchTimer.h>
11 EIGEN_DONT_INLINE Q
nlerp(const Q
& a
, const Q
& b
, typename
Q::Scalar t
)
13 return Q((a
.coeffs() * (1.0-t
) + b
.coeffs() * t
).normalized());
17 EIGEN_DONT_INLINE Q
slerp_eigen(const Q
& a
, const Q
& b
, typename
Q::Scalar t
)
23 EIGEN_DONT_INLINE Q
slerp_legacy(const Q
& a
, const Q
& b
, typename
Q::Scalar t
)
25 typedef typename
Q::Scalar Scalar
;
26 static const Scalar one
= Scalar(1) - dummy_precision
<Scalar
>();
28 Scalar absD
= internal::abs(d
);
32 // theta is the angle between the 2 quaternions
33 Scalar theta
= std::acos(absD
);
34 Scalar sinTheta
= internal::sin(theta
);
36 Scalar scale0
= internal::sin( ( Scalar(1) - t
) * theta
) / sinTheta
;
37 Scalar scale1
= internal::sin( ( t
* theta
) ) / sinTheta
;
41 return Q(scale0
* a
.coeffs() + scale1
* b
.coeffs());
45 EIGEN_DONT_INLINE Q
slerp_legacy_nlerp(const Q
& a
, const Q
& b
, typename
Q::Scalar t
)
47 typedef typename
Q::Scalar Scalar
;
48 static const Scalar one
= Scalar(1) - epsilon
<Scalar
>();
50 Scalar absD
= internal::abs(d
);
57 scale0
= Scalar(1) - t
;
62 // theta is the angle between the 2 quaternions
63 Scalar theta
= std::acos(absD
);
64 Scalar sinTheta
= internal::sin(theta
);
66 scale0
= internal::sin( ( Scalar(1) - t
) * theta
) / sinTheta
;
67 scale1
= internal::sin( ( t
* theta
) ) / sinTheta
;
72 return Q(scale0
* a
.coeffs() + scale1
* b
.coeffs());
76 inline T
sin_over_x(T x
)
78 if (T(1) + x
*x
== T(1))
85 EIGEN_DONT_INLINE Q
slerp_rw(const Q
& a
, const Q
& b
, typename
Q::Scalar t
)
87 typedef typename
Q::Scalar Scalar
;
92 theta
= /*M_PI -*/ Scalar(2)*std::asin( (a
.coeffs()+b
.coeffs()).norm()/2 );
94 theta
= Scalar(2)*std::asin( (a
.coeffs()-b
.coeffs()).norm()/2 );
96 // theta is the angle between the 2 quaternions
97 // Scalar theta = std::acos(absD);
98 Scalar sinOverTheta
= sin_over_x(theta
);
100 Scalar scale0
= (Scalar(1)-t
)*sin_over_x( ( Scalar(1) - t
) * theta
) / sinOverTheta
;
101 Scalar scale1
= t
* sin_over_x( ( t
* theta
) ) / sinOverTheta
;
105 return Quaternion
<Scalar
>(scale0
* a
.coeffs() + scale1
* b
.coeffs());
109 EIGEN_DONT_INLINE Q
slerp_gael(const Q
& a
, const Q
& b
, typename
Q::Scalar t
)
111 typedef typename
Q::Scalar Scalar
;
115 // theta = Scalar(2) * atan2((a.coeffs()-b.coeffs()).norm(),(a.coeffs()+b.coeffs()).norm());
117 // theta = M_PI-theta;
120 theta
= /*M_PI -*/ Scalar(2)*std::asin( (-a
.coeffs()-b
.coeffs()).norm()/2 );
122 theta
= Scalar(2)*std::asin( (a
.coeffs()-b
.coeffs()).norm()/2 );
127 if(theta
*theta
-Scalar(6)==-Scalar(6))
129 scale0
= Scalar(1) - t
;
134 Scalar sinTheta
= std::sin(theta
);
135 scale0
= internal::sin( ( Scalar(1) - t
) * theta
) / sinTheta
;
136 scale1
= internal::sin( ( t
* theta
) ) / sinTheta
;
141 return Quaternion
<Scalar
>(scale0
* a
.coeffs() + scale1
* b
.coeffs());
146 typedef double RefScalar
;
147 typedef float TestScalar
;
149 typedef Quaternion
<RefScalar
> Qd
;
150 typedef Quaternion
<TestScalar
> Qf
;
152 unsigned int g_seed
= (unsigned int) time(NULL
);
153 std::cout
<< g_seed
<< "\n";
154 // g_seed = 1259932496;
157 Matrix
<RefScalar
,Dynamic
,1> maxerr(7);
160 Matrix
<RefScalar
,Dynamic
,1> avgerr(7);
163 cout
<< "double=>float=>double nlerp eigen legacy(snap) legacy(nlerp) rightway gael's criteria\n";
167 for (int w
=0; w
<rep
; ++w
)
170 a
.coeffs().setRandom();
172 b
.coeffs().setRandom();
177 Qd
ar(a
.cast
<RefScalar
>());
178 Qd
br(b
.cast
<RefScalar
>());
184 cout
<< std::scientific
;
185 for (int i
=0; i
<iters
; ++i
)
188 cr
= slerp_rw(ar
,br
,t
);
190 Qf refc
= cr
.cast
<TestScalar
>();
192 c
[1] = slerp_eigen(a
,b
,t
);
193 c
[2] = slerp_legacy(a
,b
,t
);
194 c
[3] = slerp_legacy_nlerp(a
,b
,t
);
195 c
[4] = slerp_rw(a
,b
,t
);
196 c
[5] = slerp_gael(a
,b
,t
);
199 err
[0] = (cr
.coeffs()-refc
.cast
<RefScalar
>().coeffs()).norm();
200 // std::cout << err[0] << " ";
201 for (int k
=0; k
<6; ++k
)
203 err
[k
+1] = (c
[k
].coeffs()-refc
.coeffs()).norm();
204 // std::cout << err[k+1] << " ";
206 maxerr
= maxerr
.cwise().max(err
);
208 // std::cout << "\n";
209 b
= cr
.cast
<TestScalar
>();
212 // std::cout << "\n";
214 avgerr
/= RefScalar(rep
*iters
);
215 cout
<< "\n\nAccuracy:\n"
216 << " max: " << maxerr
.transpose() << "\n";
217 cout
<< " avg: " << avgerr
.transpose() << "\n";
221 a
.coeffs().setRandom();
223 b
.coeffs().setRandom();
228 #define BENCH(FUNC) {\
230 for(int k=0; k<2; ++k) {\
232 for(int i=0; i<1000000; ++i) \
236 cout << " " << #FUNC << " => \t " << t.value() << "s\n"; \
239 cout
<< "\nSpeed:\n" << std::fixed
;
243 BENCH(slerp_legacy_nlerp
);