17 template <
class TScalar>
35 using Tangent = Eigen::Vector<Scalar, kDof>;
36 using Params = Eigen::Vector<Scalar, kNumParams>;
37 using Point = Eigen::Vector<Scalar, kPointDim>;
39 template <
class TCompatibleScalar>
41 ScalarBinaryOpTraits<Scalar, TCompatibleScalar>::ReturnType;
43 template <
class TCompatibleScalar>
45 Eigen::Vector<ScalarReturn<TCompatibleScalar>,
kNumParams>;
47 template <
class TCompatibleScalar>
50 template <
class TCompatibleScalar>
57 return Eigen::Vector<Scalar, 4>(
62 -> sophus::Expected<Success> {
63 static const Scalar kThr = kEpsilonSqrt<Scalar>;
64 const Scalar squared_norm = unit_quaternion.squaredNorm();
66 if (!(abs(squared_norm - 1.0) <= kThr)) {
68 "quaternion number (({}), {}) is not unit length.\n"
69 "Squared norm: {}, thr: {}",
70 unit_quaternion.template head<3>(),
75 return sophus::Expected<Success>{};
81 TScalar
const k_pi = kPi<TScalar>;
82 return abs(angle - k_pi) / (angle + k_pi) < kEpsilon<TScalar>;
93 Scalar theta_sq = omega.squaredNorm();
97 if (theta_sq < kEpsilon<Scalar> * kEpsilon<Scalar>) {
99 Scalar theta_po4 = theta_sq * theta_sq;
100 imag_factor =
Scalar(0.5) -
Scalar(1.0 / 48.0) * theta_sq +
101 Scalar(1.0 / 3840.0) * theta_po4;
102 real_factor =
Scalar(1) -
Scalar(1.0 / 8.0) * theta_sq +
103 Scalar(1.0 / 384.0) * theta_po4;
105 theta = sqrt(theta_sq);
107 Scalar sin_half_theta = sin(half_theta);
108 imag_factor = sin_half_theta / (theta);
109 real_factor = cos(half_theta);
113 imag_factor * omega.x(),
114 imag_factor * omega.y(),
115 imag_factor * omega.z(),
123 Eigen::Vector3<Scalar> ivec = unit_quaternion.template head<3>();
125 Scalar squared_n = ivec.squaredNorm();
126 Scalar w = unit_quaternion.w();
128 Scalar two_atan_nbyw_by_n;
136 if (squared_n < kEpsilon<Scalar> * kEpsilon<Scalar>) {
140 abs(w) >= kEpsilon<Scalar>,
141 "Quaternion ({}) should be normalized!",
145 Scalar(2) / w -
Scalar(2.0 / 3.0) * (squared_n) / (w * squared_w);
147 Scalar n = sqrt(squared_n);
159 two_atan_nbyw_by_n =
Scalar(2) * atan_nbyw / n;
161 return two_atan_nbyw_by_n * ivec;
165 -> Eigen::Matrix<Scalar, kAmbientDim, kAmbientDim> {
166 Eigen::Matrix<Scalar, kAmbientDim, kAmbientDim> mat_omega;
169 Scalar(0), -omega(2), omega(1),
170 omega(2),
Scalar(0), -omega(0),
171 -omega(1), omega(0),
Scalar(0);
177 Eigen::Matrix<Scalar, kAmbientDim, kAmbientDim>
const& mat_omega)
178 -> Eigen::Matrix<Scalar, kDof, 1> {
179 return Eigen::Matrix<Scalar, kDof, 1>(
180 mat_omega(2, 1), mat_omega(0, 2), mat_omega(1, 0));
189 template <
class TCompatibleScalar>
192 Eigen::Vector<TCompatibleScalar, 4>
const& rhs_params)
197 SReturn
const squared_norm = result.squaredNorm();
206 if (squared_norm != SReturn(1.0)) {
207 SReturn
const scale = SReturn(2.0) / (SReturn(1.0) + squared_norm);
208 return scale * result;
213 static auto adj(
Params const& params) -> Eigen::Matrix<Scalar, kDof, kDof> {
219 template <
class TCompatibleScalar>
222 Eigen::Vector<TCompatibleScalar, kPointDim>
const& point)
224 Eigen::Vector3<Scalar> ivec = unit_quat.template head<3>();
228 return point + unit_quat.w() * uv + ivec.cross(uv);
231 template <
class TCompatibleScalar>
239 action(unit_quat, direction_vector.params()));
243 -> Eigen::Vector<Scalar, kAmbientDim> {
250 -> Eigen::Matrix<Scalar, kPointDim, kPointDim> {
251 Eigen::Vector3<Scalar> ivec = unit_quat.template head<3>();
252 Scalar real = unit_quat.w();
253 return Eigen::Matrix<Scalar, 3, 3>{
254 {
Scalar(1.0 - 2.0 * (ivec[1] * ivec[1]) - 2.0 * (ivec[2] * ivec[2])),
255 Scalar(2.0 * ivec[0] * ivec[1] - 2.0 * ivec[2] * real),
256 Scalar(2.0 * ivec[0] * ivec[2] + 2.0 * ivec[1] * real)},
258 Scalar(2.0 * ivec[0] * ivec[1] + 2.0 * ivec[2] * real),
259 Scalar(1.0 - 2.0 * (ivec[0] * ivec[0]) - 2.0 * (ivec[2] * ivec[2])),
260 Scalar(2.0 * ivec[1] * ivec[2] - 2.0 * ivec[0] * real),
262 {
Scalar(2.0 * ivec[0] * ivec[2] - 2.0 * ivec[1] * real),
263 Scalar(2.0 * ivec[1] * ivec[2] + 2.0 * ivec[0] * real),
264 Scalar(1.0 - 2.0 * (ivec[0] * ivec[0]) - 2.0 * (ivec[1] * ivec[1]))}};
268 -> Eigen::Matrix<Scalar, kPointDim, kPointDim> {
274 -> Eigen::Matrix<Scalar, kPointDim, kPointDim> {
279 Scalar const theta_sq = omega.squaredNorm();
280 Eigen::Matrix3<Scalar>
const mat_omega =
hat(omega);
281 Eigen::Matrix3<Scalar>
const mat_omega_sq = mat_omega * mat_omega;
282 Eigen::Matrix3<Scalar> v;
284 if (theta_sq < kEpsilon<Scalar> * kEpsilon<Scalar>) {
285 v = Eigen::Matrix3<Scalar>::Identity() +
Scalar(0.5) * mat_omega;
287 Scalar theta = sqrt(theta_sq);
288 v = Eigen::Matrix3<Scalar>::Identity() +
289 (
Scalar(1) - cos(theta)) / theta_sq * mat_omega +
290 (theta - sin(theta)) / (theta_sq * theta) * mat_omega_sq;
296 -> Eigen::Matrix<Scalar, kPointDim, kPointDim> {
300 Scalar const theta_sq = omega.squaredNorm();
301 Eigen::Matrix3<Scalar>
const mat_omega =
hat(omega);
303 Eigen::Matrix3<Scalar> v_inv;
304 if (theta_sq < kEpsilon<Scalar> * kEpsilon<Scalar>) {
305 v_inv = Eigen::Matrix3<Scalar>::Identity() -
Scalar(0.5) * mat_omega +
306 Scalar(1. / 12.) * (mat_omega * mat_omega);
309 Scalar const theta = sqrt(theta_sq);
312 v_inv = Eigen::Matrix3<Scalar>::Identity() -
Scalar(0.5) * mat_omega +
314 Scalar(0.5) * theta * cos(half_theta) / sin(half_theta)) /
315 (theta * theta) * (mat_omega * mat_omega);
321 -> Eigen::Matrix<Scalar, kPointDim, kDof> {
326 -> Eigen::Matrix<Scalar, kPointDim, kDof> {
331 static auto ad(
Tangent const& omega) -> Eigen::Matrix<Scalar, kDof, kDof> {
336 -> Eigen::Matrix<Scalar, kNumParams, kDof> {
341 Scalar const c0 = omega[0] * omega[0];
342 Scalar const c1 = omega[1] * omega[1];
343 Scalar const c2 = omega[2] * omega[2];
344 Scalar const c3 = c0 + c1 + c2;
346 if (c3 < kEpsilon<Scalar>) {
350 Scalar const c4 = sqrt(c3);
351 Scalar const c5 = 1.0 / c4;
352 Scalar const c6 = 0.5 * c4;
353 Scalar const c7 = sin(c6);
354 Scalar const c8 = c5 * c7;
355 Scalar const c9 = pow(c3, -3.0L / 2.0L);
356 Scalar const c10 = c7 * c9;
358 Scalar const c12 = cos(c6);
360 Scalar const c14 = c7 * c9 * omega[0];
362 Scalar const c16 = -c14 * omega[1] + c15 * omega[1];
363 Scalar const c17 = -c14 * omega[2] + c15 * omega[2];
364 Scalar const c18 = omega[1] * omega[2];
365 Scalar const c19 = -c10 * c18 + c13 * c18;
368 Eigen::Matrix<Scalar, 4, 3> j;
370 j(0, 0) = -c0 * c10 + c0 * c13 + c8;
374 j(1, 1) = -c1 * c10 + c1 * c13 + c8;
378 j(2, 2) = -c10 * c2 + c13 * c2 + c8;
379 j(3, 0) = -c20 * omega[0];
380 j(3, 1) = -c20 * omega[1];
381 j(3, 2) = -c20 * omega[2];
385 static auto dxExpXAt0() -> Eigen::Matrix<Scalar, kNumParams, kDof> {
386 Eigen::Matrix<Scalar, 4, 3> j;
397 -> Eigen::Matrix<Scalar, kPointDim, kDof> {
402 -> Eigen::Matrix<Scalar, kNumParams, kDof> {
403 Eigen::Matrix<Scalar, 4, 3> j;
427 -> Eigen::Matrix<Scalar, kDof, kNumParams> {
428 Eigen::Matrix<Scalar, 3, 4> j;
430 j << q.w(), q.z(), -q.y(), -q.x(),
431 -q.z(), q.w(), q.x(), -q.y(),
432 q.y(), -q.x(), q.w(), -q.z();
442 return std::vector<Tangent>({
458 return std::vector<Params>(
479 return std::vector<Params>({
482 2.0 * Params::UnitX(),