blob: 0c82a417a2c16bf6b3b94c757e8a8ed494528340 [file] [log] [blame]
Austin Schuh70cc9552019-01-21 19:46:48 -08001// Ceres Solver - A fast non-linear least squares minimizer
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08002// Copyright 2019 Google Inc. All rights reserved.
Austin Schuh70cc9552019-01-21 19:46:48 -08003// http://ceres-solver.org/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7//
8// * Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
12// and/or other materials provided with the distribution.
13// * Neither the name of Google Inc. nor the names of its contributors may be
14// used to endorse or promote products derived from this software without
15// specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27// POSSIBILITY OF SUCH DAMAGE.
28//
29// Author: keir@google.com (Keir Mierle)
30// sameeragarwal@google.com (Sameer Agarwal)
31//
32// Templated functions for manipulating rotations. The templated
33// functions are useful when implementing functors for automatic
34// differentiation.
35//
36// In the following, the Quaternions are laid out as 4-vectors, thus:
37//
38// q[0] scalar part.
39// q[1] coefficient of i.
40// q[2] coefficient of j.
41// q[3] coefficient of k.
42//
43// where: i*i = j*j = k*k = -1 and i*j = k, j*k = i, k*i = j.
44
45#ifndef CERES_PUBLIC_ROTATION_H_
46#define CERES_PUBLIC_ROTATION_H_
47
48#include <algorithm>
49#include <cmath>
50#include <limits>
51
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080052#include "glog/logging.h"
53
Austin Schuh70cc9552019-01-21 19:46:48 -080054namespace ceres {
55
56// Trivial wrapper to index linear arrays as matrices, given a fixed
57// column and row stride. When an array "T* array" is wrapped by a
58//
59// (const) MatrixAdapter<T, row_stride, col_stride> M"
60//
61// the expression M(i, j) is equivalent to
62//
63// arrary[i * row_stride + j * col_stride]
64//
65// Conversion functions to and from rotation matrices accept
66// MatrixAdapters to permit using row-major and column-major layouts,
67// and rotation matrices embedded in larger matrices (such as a 3x4
68// projection matrix).
69template <typename T, int row_stride, int col_stride>
70struct MatrixAdapter;
71
72// Convenience functions to create a MatrixAdapter that treats the
73// array pointed to by "pointer" as a 3x3 (contiguous) column-major or
74// row-major matrix.
75template <typename T>
76MatrixAdapter<T, 1, 3> ColumnMajorAdapter3x3(T* pointer);
77
78template <typename T>
79MatrixAdapter<T, 3, 1> RowMajorAdapter3x3(T* pointer);
80
81// Convert a value in combined axis-angle representation to a quaternion.
82// The value angle_axis is a triple whose norm is an angle in radians,
83// and whose direction is aligned with the axis of rotation,
84// and quaternion is a 4-tuple that will contain the resulting quaternion.
85// The implementation may be used with auto-differentiation up to the first
86// derivative, higher derivatives may have unexpected results near the origin.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080087template <typename T>
Austin Schuh70cc9552019-01-21 19:46:48 -080088void AngleAxisToQuaternion(const T* angle_axis, T* quaternion);
89
90// Convert a quaternion to the equivalent combined axis-angle representation.
91// The value quaternion must be a unit quaternion - it is not normalized first,
92// and angle_axis will be filled with a value whose norm is the angle of
93// rotation in radians, and whose direction is the axis of rotation.
94// The implementation may be used with auto-differentiation up to the first
95// derivative, higher derivatives may have unexpected results near the origin.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -080096template <typename T>
Austin Schuh70cc9552019-01-21 19:46:48 -080097void QuaternionToAngleAxis(const T* quaternion, T* angle_axis);
98
99// Conversions between 3x3 rotation matrix (in column major order) and
100// quaternion rotation representations. Templated for use with
101// autodifferentiation.
102template <typename T>
103void RotationMatrixToQuaternion(const T* R, T* quaternion);
104
105template <typename T, int row_stride, int col_stride>
106void RotationMatrixToQuaternion(
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800107 const MatrixAdapter<const T, row_stride, col_stride>& R, T* quaternion);
Austin Schuh70cc9552019-01-21 19:46:48 -0800108
109// Conversions between 3x3 rotation matrix (in column major order) and
110// axis-angle rotation representations. Templated for use with
111// autodifferentiation.
112template <typename T>
113void RotationMatrixToAngleAxis(const T* R, T* angle_axis);
114
115template <typename T, int row_stride, int col_stride>
116void RotationMatrixToAngleAxis(
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800117 const MatrixAdapter<const T, row_stride, col_stride>& R, T* angle_axis);
Austin Schuh70cc9552019-01-21 19:46:48 -0800118
119template <typename T>
120void AngleAxisToRotationMatrix(const T* angle_axis, T* R);
121
122template <typename T, int row_stride, int col_stride>
123void AngleAxisToRotationMatrix(
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800124 const T* angle_axis, const MatrixAdapter<T, row_stride, col_stride>& R);
Austin Schuh70cc9552019-01-21 19:46:48 -0800125
126// Conversions between 3x3 rotation matrix (in row major order) and
127// Euler angle (in degrees) rotation representations.
128//
129// The {pitch,roll,yaw} Euler angles are rotations around the {x,y,z}
130// axes, respectively. They are applied in that same order, so the
131// total rotation R is Rz * Ry * Rx.
132template <typename T>
133void EulerAnglesToRotationMatrix(const T* euler, int row_stride, T* R);
134
135template <typename T, int row_stride, int col_stride>
136void EulerAnglesToRotationMatrix(
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800137 const T* euler, const MatrixAdapter<T, row_stride, col_stride>& R);
Austin Schuh70cc9552019-01-21 19:46:48 -0800138
139// Convert a 4-vector to a 3x3 scaled rotation matrix.
140//
141// The choice of rotation is such that the quaternion [1 0 0 0] goes to an
142// identity matrix and for small a, b, c the quaternion [1 a b c] goes to
143// the matrix
144//
145// [ 0 -c b ]
146// I + 2 [ c 0 -a ] + higher order terms
147// [ -b a 0 ]
148//
149// which corresponds to a Rodrigues approximation, the last matrix being
150// the cross-product matrix of [a b c]. Together with the property that
151// R(q1 * q2) = R(q1) * R(q2) this uniquely defines the mapping from q to R.
152//
153// No normalization of the quaternion is performed, i.e.
154// R = ||q||^2 * Q, where Q is an orthonormal matrix
155// such that det(Q) = 1 and Q*Q' = I
156//
157// WARNING: The rotation matrix is ROW MAJOR
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800158template <typename T>
159inline void QuaternionToScaledRotation(const T q[4], T R[3 * 3]);
Austin Schuh70cc9552019-01-21 19:46:48 -0800160
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800161template <typename T, int row_stride, int col_stride>
162inline void QuaternionToScaledRotation(
163 const T q[4], const MatrixAdapter<T, row_stride, col_stride>& R);
Austin Schuh70cc9552019-01-21 19:46:48 -0800164
165// Same as above except that the rotation matrix is normalized by the
166// Frobenius norm, so that R * R' = I (and det(R) = 1).
167//
168// WARNING: The rotation matrix is ROW MAJOR
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800169template <typename T>
170inline void QuaternionToRotation(const T q[4], T R[3 * 3]);
Austin Schuh70cc9552019-01-21 19:46:48 -0800171
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800172template <typename T, int row_stride, int col_stride>
173inline void QuaternionToRotation(
174 const T q[4], const MatrixAdapter<T, row_stride, col_stride>& R);
Austin Schuh70cc9552019-01-21 19:46:48 -0800175
176// Rotates a point pt by a quaternion q:
177//
178// result = R(q) * pt
179//
180// Assumes the quaternion is unit norm. This assumption allows us to
181// write the transform as (something)*pt + pt, as is clear from the
182// formula below. If you pass in a quaternion with |q|^2 = 2 then you
183// WILL NOT get back 2 times the result you get for a unit quaternion.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800184//
185// Inplace rotation is not supported. pt and result must point to different
186// memory locations, otherwise the result will be undefined.
187template <typename T>
188inline void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]);
Austin Schuh70cc9552019-01-21 19:46:48 -0800189
190// With this function you do not need to assume that q has unit norm.
191// It does assume that the norm is non-zero.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800192//
193// Inplace rotation is not supported. pt and result must point to different
194// memory locations, otherwise the result will be undefined.
195template <typename T>
196inline void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]);
Austin Schuh70cc9552019-01-21 19:46:48 -0800197
198// zw = z * w, where * is the Quaternion product between 4 vectors.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800199//
200// Inplace quaternion product is not supported. The resulting quaternion zw must
201// not share the memory with the input quaternion z and w, otherwise the result
202// will be undefined.
203template <typename T>
204inline void QuaternionProduct(const T z[4], const T w[4], T zw[4]);
Austin Schuh70cc9552019-01-21 19:46:48 -0800205
206// xy = x cross y;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800207//
208// Inplace cross product is not supported. The resulting vector x_cross_y must
209// not share the memory with the input vectors x and y, otherwise the result
210// will be undefined.
211template <typename T>
212inline void CrossProduct(const T x[3], const T y[3], T x_cross_y[3]);
Austin Schuh70cc9552019-01-21 19:46:48 -0800213
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800214template <typename T>
215inline T DotProduct(const T x[3], const T y[3]);
Austin Schuh70cc9552019-01-21 19:46:48 -0800216
217// y = R(angle_axis) * x;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800218//
219// Inplace rotation is not supported. pt and result must point to different
220// memory locations, otherwise the result will be undefined.
221template <typename T>
222inline void AngleAxisRotatePoint(const T angle_axis[3],
223 const T pt[3],
224 T result[3]);
Austin Schuh70cc9552019-01-21 19:46:48 -0800225
226// --- IMPLEMENTATION
227
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800228template <typename T, int row_stride, int col_stride>
Austin Schuh70cc9552019-01-21 19:46:48 -0800229struct MatrixAdapter {
230 T* pointer_;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800231 explicit MatrixAdapter(T* pointer) : pointer_(pointer) {}
Austin Schuh70cc9552019-01-21 19:46:48 -0800232
233 T& operator()(int r, int c) const {
234 return pointer_[r * row_stride + c * col_stride];
235 }
236};
237
238template <typename T>
239MatrixAdapter<T, 1, 3> ColumnMajorAdapter3x3(T* pointer) {
240 return MatrixAdapter<T, 1, 3>(pointer);
241}
242
243template <typename T>
244MatrixAdapter<T, 3, 1> RowMajorAdapter3x3(T* pointer) {
245 return MatrixAdapter<T, 3, 1>(pointer);
246}
247
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800248template <typename T>
Austin Schuh70cc9552019-01-21 19:46:48 -0800249inline void AngleAxisToQuaternion(const T* angle_axis, T* quaternion) {
250 const T& a0 = angle_axis[0];
251 const T& a1 = angle_axis[1];
252 const T& a2 = angle_axis[2];
253 const T theta_squared = a0 * a0 + a1 * a1 + a2 * a2;
254
255 // For points not at the origin, the full conversion is numerically stable.
256 if (theta_squared > T(0.0)) {
257 const T theta = sqrt(theta_squared);
258 const T half_theta = theta * T(0.5);
259 const T k = sin(half_theta) / theta;
260 quaternion[0] = cos(half_theta);
261 quaternion[1] = a0 * k;
262 quaternion[2] = a1 * k;
263 quaternion[3] = a2 * k;
264 } else {
265 // At the origin, sqrt() will produce NaN in the derivative since
266 // the argument is zero. By approximating with a Taylor series,
267 // and truncating at one term, the value and first derivatives will be
268 // computed correctly when Jets are used.
269 const T k(0.5);
270 quaternion[0] = T(1.0);
271 quaternion[1] = a0 * k;
272 quaternion[2] = a1 * k;
273 quaternion[3] = a2 * k;
274 }
275}
276
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800277template <typename T>
Austin Schuh70cc9552019-01-21 19:46:48 -0800278inline void QuaternionToAngleAxis(const T* quaternion, T* angle_axis) {
279 const T& q1 = quaternion[1];
280 const T& q2 = quaternion[2];
281 const T& q3 = quaternion[3];
282 const T sin_squared_theta = q1 * q1 + q2 * q2 + q3 * q3;
283
284 // For quaternions representing non-zero rotation, the conversion
285 // is numerically stable.
286 if (sin_squared_theta > T(0.0)) {
287 const T sin_theta = sqrt(sin_squared_theta);
288 const T& cos_theta = quaternion[0];
289
290 // If cos_theta is negative, theta is greater than pi/2, which
291 // means that angle for the angle_axis vector which is 2 * theta
292 // would be greater than pi.
293 //
294 // While this will result in the correct rotation, it does not
295 // result in a normalized angle-axis vector.
296 //
297 // In that case we observe that 2 * theta ~ 2 * theta - 2 * pi,
298 // which is equivalent saying
299 //
300 // theta - pi = atan(sin(theta - pi), cos(theta - pi))
301 // = atan(-sin(theta), -cos(theta))
302 //
303 const T two_theta =
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800304 T(2.0) * ((cos_theta < T(0.0)) ? atan2(-sin_theta, -cos_theta)
305 : atan2(sin_theta, cos_theta));
Austin Schuh70cc9552019-01-21 19:46:48 -0800306 const T k = two_theta / sin_theta;
307 angle_axis[0] = q1 * k;
308 angle_axis[1] = q2 * k;
309 angle_axis[2] = q3 * k;
310 } else {
311 // For zero rotation, sqrt() will produce NaN in the derivative since
312 // the argument is zero. By approximating with a Taylor series,
313 // and truncating at one term, the value and first derivatives will be
314 // computed correctly when Jets are used.
315 const T k(2.0);
316 angle_axis[0] = q1 * k;
317 angle_axis[1] = q2 * k;
318 angle_axis[2] = q3 * k;
319 }
320}
321
322template <typename T>
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800323void RotationMatrixToQuaternion(const T* R, T* quaternion) {
324 RotationMatrixToQuaternion(ColumnMajorAdapter3x3(R), quaternion);
Austin Schuh70cc9552019-01-21 19:46:48 -0800325}
326
327// This algorithm comes from "Quaternion Calculus and Fast Animation",
328// Ken Shoemake, 1987 SIGGRAPH course notes
329template <typename T, int row_stride, int col_stride>
330void RotationMatrixToQuaternion(
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800331 const MatrixAdapter<const T, row_stride, col_stride>& R, T* quaternion) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800332 const T trace = R(0, 0) + R(1, 1) + R(2, 2);
333 if (trace >= 0.0) {
334 T t = sqrt(trace + T(1.0));
335 quaternion[0] = T(0.5) * t;
336 t = T(0.5) / t;
337 quaternion[1] = (R(2, 1) - R(1, 2)) * t;
338 quaternion[2] = (R(0, 2) - R(2, 0)) * t;
339 quaternion[3] = (R(1, 0) - R(0, 1)) * t;
340 } else {
341 int i = 0;
342 if (R(1, 1) > R(0, 0)) {
343 i = 1;
344 }
345
346 if (R(2, 2) > R(i, i)) {
347 i = 2;
348 }
349
350 const int j = (i + 1) % 3;
351 const int k = (j + 1) % 3;
352 T t = sqrt(R(i, i) - R(j, j) - R(k, k) + T(1.0));
353 quaternion[i + 1] = T(0.5) * t;
354 t = T(0.5) / t;
355 quaternion[0] = (R(k, j) - R(j, k)) * t;
356 quaternion[j + 1] = (R(j, i) + R(i, j)) * t;
357 quaternion[k + 1] = (R(k, i) + R(i, k)) * t;
358 }
359}
360
361// The conversion of a rotation matrix to the angle-axis form is
362// numerically problematic when then rotation angle is close to zero
363// or to Pi. The following implementation detects when these two cases
364// occurs and deals with them by taking code paths that are guaranteed
365// to not perform division by a small number.
366template <typename T>
367inline void RotationMatrixToAngleAxis(const T* R, T* angle_axis) {
368 RotationMatrixToAngleAxis(ColumnMajorAdapter3x3(R), angle_axis);
369}
370
371template <typename T, int row_stride, int col_stride>
372void RotationMatrixToAngleAxis(
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800373 const MatrixAdapter<const T, row_stride, col_stride>& R, T* angle_axis) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800374 T quaternion[4];
375 RotationMatrixToQuaternion(R, quaternion);
376 QuaternionToAngleAxis(quaternion, angle_axis);
377 return;
378}
379
380template <typename T>
381inline void AngleAxisToRotationMatrix(const T* angle_axis, T* R) {
382 AngleAxisToRotationMatrix(angle_axis, ColumnMajorAdapter3x3(R));
383}
384
385template <typename T, int row_stride, int col_stride>
386void AngleAxisToRotationMatrix(
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800387 const T* angle_axis, const MatrixAdapter<T, row_stride, col_stride>& R) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800388 static const T kOne = T(1.0);
389 const T theta2 = DotProduct(angle_axis, angle_axis);
390 if (theta2 > T(std::numeric_limits<double>::epsilon())) {
391 // We want to be careful to only evaluate the square root if the
392 // norm of the angle_axis vector is greater than zero. Otherwise
393 // we get a division by zero.
394 const T theta = sqrt(theta2);
395 const T wx = angle_axis[0] / theta;
396 const T wy = angle_axis[1] / theta;
397 const T wz = angle_axis[2] / theta;
398
399 const T costheta = cos(theta);
400 const T sintheta = sin(theta);
401
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800402 // clang-format off
Austin Schuh70cc9552019-01-21 19:46:48 -0800403 R(0, 0) = costheta + wx*wx*(kOne - costheta);
404 R(1, 0) = wz*sintheta + wx*wy*(kOne - costheta);
405 R(2, 0) = -wy*sintheta + wx*wz*(kOne - costheta);
406 R(0, 1) = wx*wy*(kOne - costheta) - wz*sintheta;
407 R(1, 1) = costheta + wy*wy*(kOne - costheta);
408 R(2, 1) = wx*sintheta + wy*wz*(kOne - costheta);
409 R(0, 2) = wy*sintheta + wx*wz*(kOne - costheta);
410 R(1, 2) = -wx*sintheta + wy*wz*(kOne - costheta);
411 R(2, 2) = costheta + wz*wz*(kOne - costheta);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800412 // clang-format on
Austin Schuh70cc9552019-01-21 19:46:48 -0800413 } else {
414 // Near zero, we switch to using the first order Taylor expansion.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800415 R(0, 0) = kOne;
416 R(1, 0) = angle_axis[2];
Austin Schuh70cc9552019-01-21 19:46:48 -0800417 R(2, 0) = -angle_axis[1];
418 R(0, 1) = -angle_axis[2];
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800419 R(1, 1) = kOne;
420 R(2, 1) = angle_axis[0];
421 R(0, 2) = angle_axis[1];
Austin Schuh70cc9552019-01-21 19:46:48 -0800422 R(1, 2) = -angle_axis[0];
423 R(2, 2) = kOne;
424 }
425}
426
427template <typename T>
428inline void EulerAnglesToRotationMatrix(const T* euler,
429 const int row_stride_parameter,
430 T* R) {
431 EulerAnglesToRotationMatrix(euler, RowMajorAdapter3x3(R));
432}
433
434template <typename T, int row_stride, int col_stride>
435void EulerAnglesToRotationMatrix(
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800436 const T* euler, const MatrixAdapter<T, row_stride, col_stride>& R) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800437 const double kPi = 3.14159265358979323846;
438 const T degrees_to_radians(kPi / 180.0);
439
440 const T pitch(euler[0] * degrees_to_radians);
441 const T roll(euler[1] * degrees_to_radians);
442 const T yaw(euler[2] * degrees_to_radians);
443
444 const T c1 = cos(yaw);
445 const T s1 = sin(yaw);
446 const T c2 = cos(roll);
447 const T s2 = sin(roll);
448 const T c3 = cos(pitch);
449 const T s3 = sin(pitch);
450
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800451 R(0, 0) = c1 * c2;
452 R(0, 1) = -s1 * c3 + c1 * s2 * s3;
453 R(0, 2) = s1 * s3 + c1 * s2 * c3;
Austin Schuh70cc9552019-01-21 19:46:48 -0800454
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800455 R(1, 0) = s1 * c2;
456 R(1, 1) = c1 * c3 + s1 * s2 * s3;
457 R(1, 2) = -c1 * s3 + s1 * s2 * c3;
Austin Schuh70cc9552019-01-21 19:46:48 -0800458
459 R(2, 0) = -s2;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800460 R(2, 1) = c2 * s3;
461 R(2, 2) = c2 * c3;
Austin Schuh70cc9552019-01-21 19:46:48 -0800462}
463
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800464template <typename T>
465inline void QuaternionToScaledRotation(const T q[4], T R[3 * 3]) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800466 QuaternionToScaledRotation(q, RowMajorAdapter3x3(R));
467}
468
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800469template <typename T, int row_stride, int col_stride>
470inline void QuaternionToScaledRotation(
471 const T q[4], const MatrixAdapter<T, row_stride, col_stride>& R) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800472 // Make convenient names for elements of q.
473 T a = q[0];
474 T b = q[1];
475 T c = q[2];
476 T d = q[3];
477 // This is not to eliminate common sub-expression, but to
478 // make the lines shorter so that they fit in 80 columns!
479 T aa = a * a;
480 T ab = a * b;
481 T ac = a * c;
482 T ad = a * d;
483 T bb = b * b;
484 T bc = b * c;
485 T bd = b * d;
486 T cc = c * c;
487 T cd = c * d;
488 T dd = d * d;
489
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800490 // clang-format off
491 R(0, 0) = aa + bb - cc - dd; R(0, 1) = T(2) * (bc - ad); R(0, 2) = T(2) * (ac + bd);
492 R(1, 0) = T(2) * (ad + bc); R(1, 1) = aa - bb + cc - dd; R(1, 2) = T(2) * (cd - ab);
493 R(2, 0) = T(2) * (bd - ac); R(2, 1) = T(2) * (ab + cd); R(2, 2) = aa - bb - cc + dd;
494 // clang-format on
Austin Schuh70cc9552019-01-21 19:46:48 -0800495}
496
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800497template <typename T>
498inline void QuaternionToRotation(const T q[4], T R[3 * 3]) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800499 QuaternionToRotation(q, RowMajorAdapter3x3(R));
500}
501
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800502template <typename T, int row_stride, int col_stride>
503inline void QuaternionToRotation(
504 const T q[4], const MatrixAdapter<T, row_stride, col_stride>& R) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800505 QuaternionToScaledRotation(q, R);
506
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800507 T normalizer = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
Austin Schuh70cc9552019-01-21 19:46:48 -0800508 normalizer = T(1) / normalizer;
509
510 for (int i = 0; i < 3; ++i) {
511 for (int j = 0; j < 3; ++j) {
512 R(i, j) *= normalizer;
513 }
514 }
515}
516
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800517template <typename T>
518inline void UnitQuaternionRotatePoint(const T q[4],
519 const T pt[3],
520 T result[3]) {
521 DCHECK_NE(pt, result) << "Inplace rotation is not supported.";
522
523 // clang-format off
Austin Schuh70cc9552019-01-21 19:46:48 -0800524 const T t2 = q[0] * q[1];
525 const T t3 = q[0] * q[2];
526 const T t4 = q[0] * q[3];
527 const T t5 = -q[1] * q[1];
528 const T t6 = q[1] * q[2];
529 const T t7 = q[1] * q[3];
530 const T t8 = -q[2] * q[2];
531 const T t9 = q[2] * q[3];
532 const T t1 = -q[3] * q[3];
533 result[0] = T(2) * ((t8 + t1) * pt[0] + (t6 - t4) * pt[1] + (t3 + t7) * pt[2]) + pt[0]; // NOLINT
534 result[1] = T(2) * ((t4 + t6) * pt[0] + (t5 + t1) * pt[1] + (t9 - t2) * pt[2]) + pt[1]; // NOLINT
535 result[2] = T(2) * ((t7 - t3) * pt[0] + (t2 + t9) * pt[1] + (t5 + t8) * pt[2]) + pt[2]; // NOLINT
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800536 // clang-format on
Austin Schuh70cc9552019-01-21 19:46:48 -0800537}
538
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800539template <typename T>
540inline void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
541 DCHECK_NE(pt, result) << "Inplace rotation is not supported.";
542
Austin Schuh70cc9552019-01-21 19:46:48 -0800543 // 'scale' is 1 / norm(q).
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800544 const T scale =
545 T(1) / sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
Austin Schuh70cc9552019-01-21 19:46:48 -0800546
547 // Make unit-norm version of q.
548 const T unit[4] = {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800549 scale * q[0],
550 scale * q[1],
551 scale * q[2],
552 scale * q[3],
Austin Schuh70cc9552019-01-21 19:46:48 -0800553 };
554
555 UnitQuaternionRotatePoint(unit, pt, result);
556}
557
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800558template <typename T>
559inline void QuaternionProduct(const T z[4], const T w[4], T zw[4]) {
560 DCHECK_NE(z, zw) << "Inplace quaternion product is not supported.";
561 DCHECK_NE(w, zw) << "Inplace quaternion product is not supported.";
562
563 // clang-format off
Austin Schuh70cc9552019-01-21 19:46:48 -0800564 zw[0] = z[0] * w[0] - z[1] * w[1] - z[2] * w[2] - z[3] * w[3];
565 zw[1] = z[0] * w[1] + z[1] * w[0] + z[2] * w[3] - z[3] * w[2];
566 zw[2] = z[0] * w[2] - z[1] * w[3] + z[2] * w[0] + z[3] * w[1];
567 zw[3] = z[0] * w[3] + z[1] * w[2] - z[2] * w[1] + z[3] * w[0];
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800568 // clang-format on
Austin Schuh70cc9552019-01-21 19:46:48 -0800569}
570
571// xy = x cross y;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800572template <typename T>
573inline void CrossProduct(const T x[3], const T y[3], T x_cross_y[3]) {
574 DCHECK_NE(x, x_cross_y) << "Inplace cross product is not supported.";
575 DCHECK_NE(y, x_cross_y) << "Inplace cross product is not supported.";
576
Austin Schuh70cc9552019-01-21 19:46:48 -0800577 x_cross_y[0] = x[1] * y[2] - x[2] * y[1];
578 x_cross_y[1] = x[2] * y[0] - x[0] * y[2];
579 x_cross_y[2] = x[0] * y[1] - x[1] * y[0];
580}
581
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800582template <typename T>
583inline T DotProduct(const T x[3], const T y[3]) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800584 return (x[0] * y[0] + x[1] * y[1] + x[2] * y[2]);
585}
586
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800587template <typename T>
588inline void AngleAxisRotatePoint(const T angle_axis[3],
589 const T pt[3],
590 T result[3]) {
591 DCHECK_NE(pt, result) << "Inplace rotation is not supported.";
592
Austin Schuh70cc9552019-01-21 19:46:48 -0800593 const T theta2 = DotProduct(angle_axis, angle_axis);
594 if (theta2 > T(std::numeric_limits<double>::epsilon())) {
595 // Away from zero, use the rodriguez formula
596 //
597 // result = pt costheta +
598 // (w x pt) * sintheta +
599 // w (w . pt) (1 - costheta)
600 //
601 // We want to be careful to only evaluate the square root if the
602 // norm of the angle_axis vector is greater than zero. Otherwise
603 // we get a division by zero.
604 //
605 const T theta = sqrt(theta2);
606 const T costheta = cos(theta);
607 const T sintheta = sin(theta);
608 const T theta_inverse = T(1.0) / theta;
609
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800610 const T w[3] = {angle_axis[0] * theta_inverse,
611 angle_axis[1] * theta_inverse,
612 angle_axis[2] * theta_inverse};
Austin Schuh70cc9552019-01-21 19:46:48 -0800613
614 // Explicitly inlined evaluation of the cross product for
615 // performance reasons.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800616 const T w_cross_pt[3] = {w[1] * pt[2] - w[2] * pt[1],
617 w[2] * pt[0] - w[0] * pt[2],
618 w[0] * pt[1] - w[1] * pt[0]};
Austin Schuh70cc9552019-01-21 19:46:48 -0800619 const T tmp =
620 (w[0] * pt[0] + w[1] * pt[1] + w[2] * pt[2]) * (T(1.0) - costheta);
621
622 result[0] = pt[0] * costheta + w_cross_pt[0] * sintheta + w[0] * tmp;
623 result[1] = pt[1] * costheta + w_cross_pt[1] * sintheta + w[1] * tmp;
624 result[2] = pt[2] * costheta + w_cross_pt[2] * sintheta + w[2] * tmp;
625 } else {
626 // Near zero, the first order Taylor approximation of the rotation
627 // matrix R corresponding to a vector w and angle w is
628 //
629 // R = I + hat(w) * sin(theta)
630 //
631 // But sintheta ~ theta and theta * w = angle_axis, which gives us
632 //
633 // R = I + hat(w)
634 //
635 // and actually performing multiplication with the point pt, gives us
636 // R * pt = pt + w x pt.
637 //
638 // Switching to the Taylor expansion near zero provides meaningful
639 // derivatives when evaluated using Jets.
640 //
641 // Explicitly inlined evaluation of the cross product for
642 // performance reasons.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800643 const T w_cross_pt[3] = {angle_axis[1] * pt[2] - angle_axis[2] * pt[1],
644 angle_axis[2] * pt[0] - angle_axis[0] * pt[2],
645 angle_axis[0] * pt[1] - angle_axis[1] * pt[0]};
Austin Schuh70cc9552019-01-21 19:46:48 -0800646
647 result[0] = pt[0] + w_cross_pt[0];
648 result[1] = pt[1] + w_cross_pt[1];
649 result[2] = pt[2] + w_cross_pt[2];
650 }
651}
652
653} // namespace ceres
654
655#endif // CERES_PUBLIC_ROTATION_H_