EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
UnitQuaternion.h
Go to the documentation of this file.
1#pragma once
2
16
17#include <concepts>
18#include <type_traits>
19
20#include <Eigen/Core>
21#include <Eigen/Geometry>
22
27
28namespace Emrys
29{
30
53{
54 static constexpr int FixedValueDimension = 4;
55 static constexpr int ValueDimensionStep = 0;
56 static constexpr int MaxValueDimension = 4;
57
59 [[nodiscard]] static constexpr Eigen::Index
61 {
62 return 4;
63 }
64
66 [[nodiscard]] Linear<3>
67 difference() const
68 {
69 return {};
70 }
71
75 template <typename Derived>
76 void
77 normalize(Eigen::MatrixBase<Derived> const & block) const
78 {
79 using T = typename Derived::Scalar;
80 auto & q = writable(block);
81 for (Eigen::Index j = 0; j < q.cols(); ++j)
82 {
83 T const sign = q(3, j) < T(0) ? T(-1) : T(1);
84 q.col(j) *= sign / q.col(j).norm();
85 }
86 }
87
91 template <typename X, typename D, typename Out>
92 void
93 plus(Eigen::MatrixBase<X> const & x, Eigen::MatrixBase<D> const & d, Eigen::MatrixBase<Out> const & out) const
94 {
95 using T = typename Out::Scalar;
96 auto & o = writable(out);
97 for (Eigen::Index j = 0; j < o.cols(); ++j)
98 {
99 o.col(j) = (quaternionOf<T>(x.col(j)) * exponential(d.col(j).template cast<T>())).coeffs();
100 }
101 normalize(o);
102 }
103
107 template <typename A, typename B, typename Out>
108 void
109 minus(Eigen::MatrixBase<A> const & a, Eigen::MatrixBase<B> const & b, Eigen::MatrixBase<Out> const & out) const
110 {
111 using T = typename Out::Scalar;
112 auto & o = writable(out);
113 for (Eigen::Index j = 0; j < o.cols(); ++j)
114 {
115 o.col(j) = logarithm(quaternionOf<T>(b.col(j)).conjugate() * quaternionOf<T>(a.col(j)));
116 }
117 }
118
122 template <typename X, typename D, typename Out>
123 void
125 Eigen::MatrixBase<X> const &,
126 Eigen::MatrixBase<D> const & d,
127 Eigen::MatrixBase<Out> const & out
128 ) const
129 {
130 using T = typename Out::Scalar;
131 writable(out) = rightJacobian(d.template cast<T>());
132 }
133
140 template <typename Derived>
141 [[nodiscard]] static Eigen::Quaternion<typename Derived::Scalar>
142 exponential(Eigen::MatrixBase<Derived> const & d)
143 {
144 using T = typename Derived::Scalar;
145 T const angle2 = d.squaredNorm();
146 if (angle2 < T(1e-12))
147 {
148 T const scale = T(0.5) - angle2 / T(48);
149 return Eigen::Quaternion<T>{T(1) - angle2 / T(8), d(0) * scale, d(1) * scale, d(2) * scale};
150 }
151 T const angle = Eigen::numext::sqrt(angle2);
152 T const scale = T(Eigen::numext::sin(T(angle / T(2))) / angle);
153 return Eigen::Quaternion<T>{Eigen::numext::cos(T(angle / T(2))), d(0) * scale, d(1) * scale, d(2) * scale};
154 }
155
159 template <typename Derived>
160 [[nodiscard]] static Eigen::Matrix<typename Derived::Scalar, 3, 1>
161 logarithm(Eigen::QuaternionBase<Derived> const & q)
162 {
163 using T = typename Derived::Scalar;
164 T const sign = q.w() < T(0) ? T(-1) : T(1);
165 T const w = sign * q.w();
166 Eigen::Matrix<T, 3, 1> const v = sign * q.vec();
167 T const s2 = v.squaredNorm();
168 if (s2 < T(1e-12))
169 {
170 return v * T(T(2) / w);
171 }
172 T const s = Eigen::numext::sqrt(s2);
173 T const angle = T(2) * Eigen::numext::atan2(s, w);
174 return v * T(angle / s);
175 }
176
185 template <typename Derived>
186 [[nodiscard]] static Eigen::Matrix<typename Derived::Scalar, 3, 3>
187 rightJacobian(Eigen::MatrixBase<Derived> const & d)
188 {
189 using T = typename Derived::Scalar;
190 auto skew = Eigen::Matrix<T, 3, 3>{};
191 skew << T(0), -d(2), d(1), d(2), T(0), -d(0), -d(1), d(0), T(0);
192 T const angle2 = d.squaredNorm();
193 if (angle2 < T(1e-8))
194 {
195 return Eigen::Matrix<T, 3, 3>::Identity() - T(0.5) * skew + (skew * skew) / T(6);
196 }
197 T const angle = Eigen::numext::sqrt(angle2);
198 return Eigen::Matrix<T, 3, 3>::Identity() - T((T(1) - Eigen::numext::cos(angle)) / angle2) * skew
199 + T((angle - Eigen::numext::sin(angle)) / (angle2 * angle)) * (skew * skew);
200 }
201
205 template <typename Scalar = double>
206 [[nodiscard]] static Eigen::Matrix<Scalar, 4, 1>
208 {
209 return Eigen::Matrix<Scalar, 4, 1>{Scalar(0), Scalar(0), Scalar(0), Scalar(1)};
210 }
211
216 template <typename Derived>
217 [[nodiscard]] static Eigen::Matrix<typename Derived::Scalar, 4, 1>
218 coefficientsOf(Eigen::QuaternionBase<Derived> const & q)
219 {
220 return q.coeffs();
221 }
222
238 template <typename Block>
239 [[nodiscard]] static auto
240 map(Block && block)
241 {
242 using Derived = std::remove_cvref_t<Block>;
243 static_assert(MatrixExpression<Block>, "map() takes an Eigen vector of four coordinates");
244 static_assert(
245 Derived::ColsAtCompileTime == 1
246 && (Derived::RowsAtCompileTime == 4 || Derived::RowsAtCompileTime == Eigen::Dynamic),
247 "map() takes one column of four coordinates (x, y, z, w)"
248 );
249 static_assert(
250 (Derived::Flags & Eigen::DirectAccessBit) && Derived::InnerStrideAtCompileTime == 1,
251 "map() needs coefficients in memory with unit stride; evaluate the expression first"
252 );
253 static_assert(
254 std::is_lvalue_reference_v<Block> || !std::derived_from<Derived, Eigen::PlainObjectBase<Derived>>,
255 "map() of a temporary matrix would dangle; store it first"
256 );
257 EMRYS_FILTER_ASSERT(block.size() == 4 && "a unit quaternion has four coordinates");
258 using Scalar = typename Derived::Scalar;
259 if constexpr (!std::is_const_v<std::remove_reference_t<Block>> && bool(Derived::Flags & Eigen::LvalueBit))
260 {
261 return Eigen::Map<Eigen::Quaternion<Scalar>>{block.derived().data()};
262 }
263 else
264 {
265 return Eigen::Map<Eigen::Quaternion<Scalar> const>{block.derived().data()};
266 }
267 }
268
269private:
270
275 template <typename T, typename Derived>
276 [[nodiscard]] static Eigen::Quaternion<T>
277 quaternionOf(Eigen::MatrixBase<Derived> const & coefficients)
278 {
279 Eigen::Matrix<T, 4, 1> const fixed = coefficients.template cast<T>();
280 return Eigen::Quaternion<T>{fixed};
281 }
282
283public:
284
286 friend bool
287 operator==(UnitQuaternion const &, UnitQuaternion const &) = default;
288};
289
290} // namespace Emrys
The coordinate types (decisions.md [no-bounded-coordinates]): Linear, plain coordinates,...
How a function that stores a matrix argument takes it (decisions.md [forwarded-matrices]): the concep...
The macros every header includes first.
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
A dense matrix or matrix expression, possibly cv- or reference-qualified: what a const Eigen::MatrixB...
Definition Forwarding.h:39
Eigen::MatrixBase< Derived > & writable(Eigen::MatrixBase< Derived > const &block)
block, writable: Eigen's idiom for a function that writes through an expression passed as const&.
Definition Space.h:389
auto block(Space auto const &space, X &&x)
Definition TagPath.h:979
Dimension_ plain coordinates, or a resizable run of at most MaxDimension_ of them if Dimension_ is Ei...
Definition Coordinates.h:87
An attitude: a unit quaternion of four coordinates whose differences are three-coordinate rotation ve...
Definition UnitQuaternion.h:53
static constexpr Eigen::Index valueDimension()
Definition UnitQuaternion.h:60
static Eigen::Matrix< typename Derived::Scalar, 4, 1 > coefficientsOf(Eigen::QuaternionBase< Derived > const &q)
Definition UnitQuaternion.h:218
friend bool operator==(UnitQuaternion const &, UnitQuaternion const &)=default
Spaces compare equal: a UnitQuaternion has no parameters.
static auto map(Block &&block)
Definition UnitQuaternion.h:240
static Eigen::Matrix< Scalar, 4, 1 > identity()
Definition UnitQuaternion.h:207
static Eigen::Matrix< typename Derived::Scalar, 3, 3 > rightJacobian(Eigen::MatrixBase< Derived > const &d)
Definition UnitQuaternion.h:187
static Eigen::Quaternion< typename Derived::Scalar > exponential(Eigen::MatrixBase< Derived > const &d)
Definition UnitQuaternion.h:142
static constexpr int ValueDimensionStep
not resizable
Definition UnitQuaternion.h:55
static constexpr int MaxValueDimension
the value dimension, as for any fixed space
Definition UnitQuaternion.h:56
void minus(Eigen::MatrixBase< A > const &a, Eigen::MatrixBase< B > const &b, Eigen::MatrixBase< Out > const &out) const
Writes through out, column by column.
Definition UnitQuaternion.h:109
static constexpr int FixedValueDimension
four coordinates, (x, y, z, w)
Definition UnitQuaternion.h:54
static Eigen::Matrix< typename Derived::Scalar, 3, 1 > logarithm(Eigen::QuaternionBase< Derived > const &q)
Definition UnitQuaternion.h:161
void plus(Eigen::MatrixBase< X > const &x, Eigen::MatrixBase< D > const &d, Eigen::MatrixBase< Out > const &out) const
Writes through out, column by column, normalized.
Definition UnitQuaternion.h:93
Linear< 3 > difference() const
Definition UnitQuaternion.h:67
void resetJacobian(Eigen::MatrixBase< X > const &, Eigen::MatrixBase< D > const &d, Eigen::MatrixBase< Out > const &out) const
Writes the reset Jacobian at the step d through out: rightJacobian() of d, whatever the value.
Definition UnitQuaternion.h:124
void normalize(Eigen::MatrixBase< Derived > const &block) const
Scales each column of block, a value (x, y, z, w) per column, to unit norm with , writing through the...
Definition UnitQuaternion.h:77