Vulcan
Aerospace Engineering Utilities Built on Janus
Loading...
Searching...
No Matches
AxisAngle.hpp
Go to the documentation of this file.
1// Vulcan Axis-Angle Utilities
2// Axis-angle and rotation vector conversions using Rodrigues' formula
3#pragma once
4
7
8#include <janus/math/Arithmetic.hpp>
9#include <janus/math/Linalg.hpp>
10#include <janus/math/Logic.hpp>
11#include <janus/math/Quaternion.hpp>
12#include <janus/math/Trig.hpp>
13
14#include <utility>
15
16namespace vulcan {
17
18// =============================================================================
19// Quaternion from Axis-Angle
20// =============================================================================
21
28template <typename Scalar>
29janus::Quaternion<Scalar> quaternion_from_axis_angle(const Vec3<Scalar> &axis,
30 Scalar angle) {
31 return janus::Quaternion<Scalar>::from_axis_angle(axis, angle);
32}
33
39template <typename Scalar>
40janus::Quaternion<Scalar>
41quaternion_from_rotation_vector(const Vec3<Scalar> &rot_vec) {
42 return janus::Quaternion<Scalar>::from_rotation_vector(rot_vec);
43}
44
45// =============================================================================
46// DCM from Axis-Angle (Rodrigues' Formula)
47// =============================================================================
48
59template <typename Scalar>
60Mat3<Scalar> dcm_from_axis_angle(const Vec3<Scalar> &axis, Scalar angle) {
61 // Normalize axis (with small-angle protection)
62 Scalar axis_norm = janus::norm(axis);
63 Scalar eps = Scalar(1e-12);
64 Scalar safe_norm = axis_norm + eps;
65
66 Vec3<Scalar> k;
67 k(0) = axis(0) / safe_norm;
68 k(1) = axis(1) / safe_norm;
69 k(2) = axis(2) / safe_norm;
70
71 // Skew matrix of unit axis
72 Mat3<Scalar> K = skew(k);
73 Mat3<Scalar> K2 = K * K;
74
75 // Rodrigues' formula
76 Scalar s = janus::sin(angle);
77 Scalar c = janus::cos(angle);
78
79 return Mat3<Scalar>::Identity() + s * K + (Scalar(1) - c) * K2;
80}
81
87template <typename Scalar>
88Mat3<Scalar> dcm_from_rotation_vector(const Vec3<Scalar> &rot_vec) {
89 Scalar angle = janus::norm(rot_vec);
90 Scalar eps = Scalar(1e-12);
91 Scalar safe_angle = angle + eps;
92
93 Vec3<Scalar> axis;
94 axis(0) = rot_vec(0) / safe_angle;
95 axis(1) = rot_vec(1) / safe_angle;
96 axis(2) = rot_vec(2) / safe_angle;
97
98 return dcm_from_axis_angle(axis, angle);
99}
100
101// =============================================================================
102// Axis-Angle from Quaternion
103// =============================================================================
104
110template <typename Scalar>
111std::pair<Vec3<Scalar>, Scalar>
112axis_angle_from_quaternion(const janus::Quaternion<Scalar> &q) {
113 // angle = 2 * acos(w)
114 Scalar w = q.w;
115 Scalar angle = Scalar(2) * janus::acos(w);
116
117 // axis = [x, y, z] / sin(angle/2)
118 Scalar sin_half = janus::sqrt(Scalar(1) - w * w);
119 Scalar eps = Scalar(1e-12);
120 Scalar safe_sin_half = sin_half + eps;
121
122 Vec3<Scalar> axis;
123 axis(0) = q.x / safe_sin_half;
124 axis(1) = q.y / safe_sin_half;
125 axis(2) = q.z / safe_sin_half;
126
127 // For small angles, default to Z-axis (arbitrary but consistent)
128 Scalar is_small = sin_half < eps;
129 axis(0) = janus::where(is_small, Scalar(0), axis(0));
130 axis(1) = janus::where(is_small, Scalar(0), axis(1));
131 axis(2) = janus::where(is_small, Scalar(1), axis(2));
132
133 return {axis, angle};
134}
135
141template <typename Scalar>
142Vec3<Scalar>
143rotation_vector_from_quaternion(const janus::Quaternion<Scalar> &q) {
144 auto [axis, angle] = axis_angle_from_quaternion(q);
145 Vec3<Scalar> rot_vec;
146 rot_vec(0) = axis(0) * angle;
147 rot_vec(1) = axis(1) * angle;
148 rot_vec(2) = axis(2) * angle;
149 return rot_vec;
150}
151
152// =============================================================================
153// Axis-Angle from DCM
154// =============================================================================
155
164template <typename Scalar>
165std::pair<Vec3<Scalar>, Scalar> axis_angle_from_dcm(const Mat3<Scalar> &R) {
166 // angle from trace: trace(R) = 1 + 2*cos(θ) => cos(θ) = (trace - 1) / 2
167 Scalar trace = R.trace();
168 Scalar cos_angle = (trace - Scalar(1)) * Scalar(0.5);
169
170 // Clamp to [-1, 1] for numerical stability
171 cos_angle = janus::where(cos_angle > Scalar(1), Scalar(1), cos_angle);
172 cos_angle = janus::where(cos_angle < Scalar(-1), Scalar(-1), cos_angle);
173
174 Scalar angle = janus::acos(cos_angle);
175
176 // Axis from anti-symmetric part
177 Vec3<Scalar> raw_axis;
178 raw_axis(0) = R(2, 1) - R(1, 2);
179 raw_axis(1) = R(0, 2) - R(2, 0);
180 raw_axis(2) = R(1, 0) - R(0, 1);
181
182 Scalar sin_angle = janus::sin(angle);
183 Scalar eps = Scalar(1e-12);
184 Scalar safe_sin = sin_angle + eps;
185
186 Vec3<Scalar> axis;
187 axis(0) = raw_axis(0) / (Scalar(2) * safe_sin);
188 axis(1) = raw_axis(1) / (Scalar(2) * safe_sin);
189 axis(2) = raw_axis(2) / (Scalar(2) * safe_sin);
190
191 // Normalize axis
192 Scalar axis_norm = janus::norm(axis);
193 Scalar safe_norm = axis_norm + eps;
194 axis(0) = axis(0) / safe_norm;
195 axis(1) = axis(1) / safe_norm;
196 axis(2) = axis(2) / safe_norm;
197
198 // For small angles (angle ≈ 0), use small-angle approximation
199 Scalar is_small = janus::abs(sin_angle) < eps;
200 axis(0) = janus::where(is_small, Scalar(0), axis(0));
201 axis(1) = janus::where(is_small, Scalar(0), axis(1));
202 axis(2) = janus::where(is_small, Scalar(1), axis(2));
203
204 return {axis, angle};
205}
206
212template <typename Scalar>
213Vec3<Scalar> rotation_vector_from_dcm(const Mat3<Scalar> &R) {
214 auto [axis, angle] = axis_angle_from_dcm(R);
215 Vec3<Scalar> rot_vec;
216 rot_vec(0) = axis(0) * angle;
217 rot_vec(1) = axis(1) * angle;
218 rot_vec(2) = axis(2) * angle;
219 return rot_vec;
220}
221
222} // namespace vulcan
Definition Aerodynamics.hpp:11
std::pair< Vec3< Scalar >, Scalar > axis_angle_from_dcm(const Mat3< Scalar > &R)
Definition AxisAngle.hpp:165
janus::Quaternion< Scalar > quaternion_from_rotation_vector(const Vec3< Scalar > &rot_vec)
Definition AxisAngle.hpp:41
Mat3< Scalar > skew(const Vec3< Scalar > &v)
Definition DCMUtils.hpp:32
Mat3< Scalar > dcm_from_rotation_vector(const Vec3< Scalar > &rot_vec)
Definition AxisAngle.hpp:88
Vec3< Scalar > rotation_vector_from_quaternion(const janus::Quaternion< Scalar > &q)
Definition AxisAngle.hpp:143
Vec3< Scalar > rotation_vector_from_dcm(const Mat3< Scalar > &R)
Definition AxisAngle.hpp:213
janus::Quaternion< Scalar > quaternion_from_axis_angle(const Vec3< Scalar > &axis, Scalar angle)
Definition AxisAngle.hpp:29
std::pair< Vec3< Scalar >, Scalar > axis_angle_from_quaternion(const janus::Quaternion< Scalar > &q)
Definition AxisAngle.hpp:112
Mat3< Scalar > dcm_from_axis_angle(const Vec3< Scalar > &axis, Scalar angle)
Definition AxisAngle.hpp:60