Valkyrie 2026
Loading...
Searching...
No Matches
UnitVector.h
1#pragma once
2
3#include <span>
4#include <tuple>
5
6#include <Eigen/Core>
7#include <valkyrie/util/eigenunit/Common.h>
8
9namespace valor {
10namespace EigenUnit {
11
20template <typename... UnitTags>
22 public:
24 static constexpr std::size_t Size = sizeof...(UnitTags);
26 using StorageType = Eigen::Matrix<double, Size, 1>;
28 using UnitTuple = std::tuple<UnitTags...>;
29
33 constexpr UnitVector() { data.setZero(); }
34
39 constexpr explicit UnitVector(const StorageType& d) : data(d) {}
40
45 constexpr explicit UnitVector(StorageType&& d) : data(std::move(d)) {}
46
48 constexpr UnitVector(const UnitVector&) = default;
50 constexpr UnitVector(UnitVector&&) = default;
52 constexpr UnitVector& operator=(const UnitVector&) = default;
54 constexpr UnitVector& operator=(UnitVector&&) = default;
55
61 constexpr UnitVector(units::unit_t<UnitTags>... args) {
62 std::size_t i = 0;
63 ((data[i++] = args.value()), ...);
64 }
65
70 static constexpr UnitVector Zero() {
72 d.setZero();
73 return UnitVector(d);
74 }
75
82 static UnitVector FromArray(const std::array<double, Size>& arr) {
83 StorageType d = Eigen::Map<const StorageType>(arr.data());
84 return UnitVector(d);
85 }
86
93 static UnitVector FromSpan(const std::span<double, Size>& s) {
94 StorageType d = Eigen::Map<const StorageType>(s.data());
95 return UnitVector(d);
96 }
97
102 constexpr const StorageType& Raw() const { return data; }
103
108 constexpr StorageType& Raw() { return data; }
109
115 template <std::size_t N>
116 requires ValidIndex<N, UnitTags...>
117 constexpr auto Get() const {
118 using T = std::tuple_element_t<N, UnitTuple>;
119 return units::unit_t<T>(data[N]);
120 }
121
127 template <std::size_t N>
128 requires ValidIndex<N, UnitTags...>
129 void Set(units::unit_t<std::tuple_element_t<N, UnitTuple>> val) {
130 data[N] = val.value();
131 }
132
139 template <typename T = std::tuple_element_t<0, UnitTuple>>
140 requires AllSameUnits<UnitTags...>
141 [[nodiscard]]
142 auto Norm() const {
143 return units::unit_t<T>(data.norm());
144 }
145
151 auto Normalized() const
152 requires AllSameUnits<UnitTags...>
153 {
154 return data.normalized();
155 }
156
164 template <typename... OtherTags>
165 requires(sizeof...(UnitTags) == sizeof...(OtherTags)) && AllSameUnits<MultiplyResult<UnitTags, OtherTags>...>
166 [[nodiscard]]
167 auto Dot(const UnitVector<OtherTags...>& other) const {
168 using T1 = std::tuple_element_t<0, UnitTuple>;
169 using T2 = std::tuple_element_t<0, std::tuple<OtherTags...>>;
170 using ResultUnit = MultiplyResult<T1, T2>;
171 return units::unit_t<ResultUnit>(data.dot(other.Raw()));
172 }
173
179 template <std::size_t N>
180 requires ValidSize<N, UnitTags...>
181 constexpr auto Head() const {
182 return slice_impl<0>(std::make_index_sequence<N>{});
183 }
184
190 template <std::size_t N>
191 requires ValidSize<N, UnitTags...>
192 constexpr auto Tail() const {
193 return slice_impl<Size - N>(std::make_index_sequence<N>{});
194 }
195
202 template <std::size_t Start, std::size_t N>
203 requires ValidSize<Start + N, UnitTags...>
204 constexpr auto Slice() const {
205 return slice_impl<Start>(std::make_index_sequence<N>{});
206 }
207
209 template <typename... OtherTags>
210 [[nodiscard]]
211 constexpr UnitVector operator+(const UnitVector<OtherTags...>& other) const
212 requires UnitEquality<UnitTuple, std::tuple<OtherTags...>>
213 {
214 return UnitVector<UnitTags...>(data + other.Raw());
215 }
216
218 template <typename... OtherTags>
219 [[nodiscard]]
220 constexpr UnitVector operator-(const UnitVector<OtherTags...>& other) const
221 requires UnitEquality<UnitTuple, std::tuple<OtherTags...>>
222 {
223 return UnitVector<UnitTags...>(data - other.Raw());
224 }
225
227 constexpr UnitVector operator-() const { return UnitVector<UnitTags...>(-data); }
228
230 template <typename... OtherTags>
232 requires UnitEquality<UnitTuple, std::tuple<OtherTags...>>
233 {
234 data += other.Raw();
235 return *this;
236 }
237
239 template <typename... OtherTags>
241 requires UnitEquality<UnitTuple, std::tuple<OtherTags...>>
242 {
243 data -= other.Raw();
244 return *this;
245 }
246
253 template <typename ScalarTag>
254 [[nodiscard]]
255 constexpr auto operator*(const units::unit_t<ScalarTag>& scalar) const {
257 return ResultType(data * scalar.value());
258 }
259
266 template <typename ScalarTag>
267 [[nodiscard]]
268 constexpr auto operator/(const units::unit_t<ScalarTag>& scalar) const {
270 return ResultType(data / scalar.value());
271 }
272
278 [[nodiscard]]
279 constexpr UnitVector operator*(double scalar) const {
280 return UnitVector(data * scalar);
281 }
282
288 [[nodiscard]]
289 constexpr UnitVector operator/(double scalar) const {
290 return UnitVector(data / scalar);
291 }
292
299 friend std::ostream& operator<<(std::ostream& os, const UnitVector& vec) {
300 os << "[";
301 vec.print_impl(os, std::make_index_sequence<Size>{});
302 os << "]";
303 return os;
304 }
305
307 template <typename... OtherTags>
308 bool operator==(const UnitVector<OtherTags...>& other) const
309 requires UnitEquality<UnitTuple, std::tuple<OtherTags...>>
310 {
311 return data == other.Raw();
312 }
313
320 template <typename... OtherTags>
321 [[nodiscard]]
322 constexpr auto CWiseProduct(const UnitVector<OtherTags...>& other) const {
323 return UnitVector<MultiplyResult<UnitTags, OtherTags>...>(data.CWiseProduct(other.Raw()));
324 }
325
332 template <typename... OtherTags>
333 [[nodiscard]]
334 constexpr auto CWiseQuotient(const UnitVector<OtherTags...>& other) const {
335 return UnitVector<DivideResult<UnitTags, OtherTags>...>(data.CWiseQuotient(other.Raw()));
336 }
337
339 [[nodiscard]]
340 constexpr UnitVector CWiseAbs() const {
341 return UnitVector(data.CWiseAbs());
342 }
343
345 [[nodiscard]]
346 constexpr UnitVector CWiseMin(const UnitVector& other) const {
347 return UnitVector(data.CWiseMin(other.Raw()));
348 }
349
351 [[nodiscard]]
352 constexpr UnitVector CWiseMax(const UnitVector& other) const {
353 return UnitVector(data.CWiseMax(other.Raw()));
354 }
355
361 [[nodiscard]]
362 constexpr UnitVector Clamp(const UnitVector& lo, const UnitVector& hi) const
363 requires AllSameUnits<UnitTags...>
364 {
365 return UnitVector(data.CWiseMax(lo.Raw()).CWiseMin(hi.Raw()));
366 }
367
373 [[nodiscard]]
374 constexpr UnitVector Clamp(units::unit_t<std::tuple_element_t<0, UnitTuple>> lo,
375 units::unit_t<std::tuple_element_t<0, UnitTuple>> hi) const
376 requires AllSameUnits<UnitTags...>
377 {
378 return UnitVector(data.cwiseMax(lo.value()).cwiseMin(hi.value()));
379 }
380
387 bool IsApprox(const UnitVector& other,
388 units::unit_t<std::tuple_element_t<0, UnitTuple>> tol = units::unit_t<std::tuple_element_t<0, UnitTuple>>{1e-9}) const
390 {
391 return data.isApprox(other.Raw(), tol.value());
392 }
393
400 static UnitVector Constant(units::unit_t<typename std::tuple_element_t<0, UnitTuple>> val)
401 requires AllSameUnits<UnitTags...>
402 {
403 return UnitVector(StorageType::Constant(val.value()));
404 }
405
407 template <typename T = std::tuple_element_t<0, UnitTuple>>
408 requires AllSameUnits<UnitTags...>
409 [[nodiscard]]
410 auto Sum() const {
411 return units::unit_t<T>(data.sum());
412 }
413
415 template <typename T = std::tuple_element_t<0, UnitTuple>>
416 requires AllSameUnits<UnitTags...>
417 [[nodiscard]]
418 auto Mean() const {
419 return units::unit_t<T>(data.mean());
420 }
421
423 constexpr auto X() const
424 requires(Size >= 1)
425 {
426 return this->Get<0>();
427 }
428
430 void X(units::unit_t<std::tuple_element_t<Size >= 1 ? 0 : 0, UnitTuple>> val)
431 requires(Size >= 1)
432 {
433 this->Set<0>(val);
434 }
435
437 constexpr auto Y() const
438 requires(Size >= 2)
439 {
440 return this->Get<1>();
441 }
442
444 void Y(units::unit_t<std::tuple_element_t<Size >= 2 ? 1 : 0, UnitTuple>> val)
445 requires(Size >= 2)
446 {
447 this->Set<1>(val);
448 }
449
451 constexpr auto Z() const
452 requires(Size >= 3)
453 {
454 return this->Get<2>();
455 }
456
458 void Z(units::unit_t<std::tuple_element_t<Size >= 3 ? 2 : 0, UnitTuple>> val)
459 requires(Size >= 3)
460 {
461 this->Set<2>(val);
462 }
463
465 constexpr auto W() const
466 requires(Size >= 4)
467 {
468 return this->Get<3>();
469 }
470
472 void W(units::unit_t<std::tuple_element_t<Size >= 4 ? 3 : 0, UnitTuple>> val)
473 requires(Size >= 4)
474 {
475 this->Set<3>(val);
476 }
477
482 auto AsDiagonal() const;
483
488 static auto Skew(const UnitVector<UnitTags...>& vec)
489 requires(Size == 3) && AllSameUnits<UnitTags...>
490 {
492 typename Mat::StorageType d;
493 d << 0, -vec.data[2], vec.data[1], vec.data[2], 0, -vec.data[0], -vec.data[1], vec.data[0], 0;
494 return Mat(std::move(d));
495 }
496
498 template <typename ScalarTag>
499 [[nodiscard]]
500 constexpr UnitVector operator+(const units::unit_t<ScalarTag>& scalar) const
502 {
503 return UnitVector<UnitTags...>(data.array() + scalar.value());
504 }
505
507 template <typename ScalarTag>
508 [[nodiscard]]
509 constexpr UnitVector operator-(const units::unit_t<ScalarTag>& scalar) const
511 {
512 return UnitVector<UnitTags...>(data.array() - scalar.value());
513 }
514
516 template <typename ScalarTag>
517 constexpr UnitVector& operator+=(const units::unit_t<ScalarTag>& scalar)
519 {
520 data.array() += scalar.value();
521 return *this;
522 }
523
525 template <typename ScalarTag>
526 constexpr UnitVector& operator-=(const units::unit_t<ScalarTag>& scalar)
528 {
529 data.array() -= scalar.value();
530 return *this;
531 }
532
537 template <int P, typename T = std::tuple_element_t<0, UnitTuple>>
538 requires AllSameUnits<UnitTags...>
539 [[nodiscard]]
540 auto LPNorm() const {
541 return units::unit_t<T>(data.template lpNorm<P>());
542 }
543
545 template <typename T = std::tuple_element_t<0, UnitTuple>>
546 requires AllSameUnits<UnitTags...>
547 [[nodiscard]]
548 auto StableNorm() const {
549 return units::unit_t<T>(data.stableNorm());
550 }
551
552 constexpr auto Begin() { return data.begin(); }
553
554 constexpr auto End() { return data.end(); }
555
556 constexpr auto Begin() const { return data.begin(); }
557
558 constexpr auto End() const { return data.end(); }
559
560 private:
561 template <std::size_t Offset, std::size_t... Is>
562 auto slice_impl(std::index_sequence<Is...>) const {
563 return UnitVector<std::tuple_element_t<Offset + Is, UnitTuple>...>(data.template segment<sizeof...(Is)>(Offset));
564 }
565
566 template <std::size_t... Is>
567 void print_impl(std::ostream& os, std::index_sequence<Is...>) const {
568 ((os << units::unit_t<std::tuple_element_t<Is, UnitTuple>>(data[Is]).value() << (Is == Size - 1 ? "" : ", ")), ...);
569 }
570
571 StorageType data;
572};
573
579template <typename T, std::size_t N>
580using VectorN = typename detail::VectorN_Builder<T, std::make_index_sequence<N>>::type;
581
585using UnitQuaternion = VectorN<units::dimensionless::scalar, 4>;
586
590template <typename... T>
591 requires(requires { typename T::unit_type; } && ...)
592UnitVector(T...) -> UnitVector<typename T::unit_type...>;
593
597template <std::size_t I, typename... UnitTags>
598constexpr auto Get(const UnitVector<UnitTags...>& vec) {
599 return vec.template Get<I>();
600}
601
611template <typename... TagsA, typename... TagsB>
612[[nodiscard]]
613constexpr auto Cross(const UnitVector<TagsA...>& a, const UnitVector<TagsB...>& b)
614 requires ThreeDimensionalVector<TagsA...> && ThreeDimensionalVector<TagsB...>
615{
616 using T1 = std::tuple_element_t<0, std::tuple<TagsA...>>;
617 using T2 = std::tuple_element_t<0, std::tuple<TagsB...>>;
618 using ResultUnit = MultiplyResult<T1, T2>;
619
620 return UnitVector<ResultUnit, ResultUnit, ResultUnit>(a.Raw().cross(b.Raw()));
621}
622
631template <typename ScalarTag, typename... UnitTags>
632[[nodiscard]]
633constexpr auto operator*(const units::unit_t<ScalarTag>& scalar, const UnitVector<UnitTags...>& vec) {
634 return vec * scalar;
635}
636
644template <typename... UnitTags>
645[[nodiscard]]
646constexpr auto operator*(double scalar, const UnitVector<UnitTags...>& vec) {
647 return vec * scalar;
648}
649
653template <typename ScalarTag, typename... UnitTags>
654[[nodiscard]]
655constexpr auto operator+(const units::unit_t<ScalarTag>& scalar, const UnitVector<UnitTags...>& vec)
656 requires AllSameUnits<UnitTags...> && UnitEquality<ScalarTag, std::tuple_element_t<0, std::tuple<UnitTags...>>>
657{
658 return vec + scalar;
659}
660
665template <typename ScalarTag, typename... UnitTags>
666[[nodiscard]]
667constexpr auto operator-(const units::unit_t<ScalarTag>& scalar, const UnitVector<UnitTags...>& vec)
668 requires AllSameUnits<UnitTags...> && UnitEquality<ScalarTag, std::tuple_element_t<0, std::tuple<UnitTags...>>>
669{
670 return UnitVector<UnitTags...>(scalar.value() - vec.Raw().array());
671}
672
673template <typename Derived, typename Base>
674struct NamedPhysicalVector : Base {
675 using Base::Base;
676
677 NamedPhysicalVector(const Base& b) : Base(b.Raw()) {}
678};
679
680} // namespace EigenUnit
681} // namespace valor
682
686template <typename... UnitTags>
687struct std::tuple_size<valor::EigenUnit::UnitVector<UnitTags...>> : std::integral_constant<std::size_t, sizeof...(UnitTags)> {};
688
692template <std::size_t N, typename... UnitTags>
693struct std::tuple_element<N, valor::EigenUnit::UnitVector<UnitTags...>> {
695 using type = decltype(std::declval<valor::EigenUnit::UnitVector<UnitTags...>>().template get<N>());
696};
A matrix wrapper representing a linear map between two UnitVectors.
Definition UnitMatrix.h:22
A vector wrapper that enforces units for each element.
Definition UnitVector.h:21
auto Norm() const
Computes the L2 norm (magnitude). Requires all elements to have the same unit tag.
Definition UnitVector.h:142
constexpr UnitVector operator-() const
Unary negation.
Definition UnitVector.h:227
auto Mean() const
Computes the mean of all elements. Only valid if all units are the same.
Definition UnitVector.h:418
auto Sum() const
Computes the sum of all elements. Only valid if all units are the same.
Definition UnitVector.h:410
constexpr UnitVector(units::unit_t< UnitTags >... args)
Construct from individual unit values. Values are automatically converted to the units specified by U...
Definition UnitVector.h:61
constexpr UnitVector operator-(const units::unit_t< ScalarTag > &scalar) const
Vector - scalar subtraction (broadcasting).
Definition UnitVector.h:509
constexpr auto Get() const
Get the value of the N-th element with its unit.
Definition UnitVector.h:117
constexpr UnitVector & operator+=(const units::unit_t< ScalarTag > &scalar)
In-place vector + scalar addition (broadcasting).
Definition UnitVector.h:517
auto AsDiagonal() const
Converts the vector to a diagonal matrix.
Definition UnitMatrix.h:614
bool IsApprox(const UnitVector &other, units::unit_t< std::tuple_element_t< 0, UnitTuple > > tol=units::unit_t< std::tuple_element_t< 0, UnitTuple > >{1e-9}) const
Check if two vectors are approximately equal.
Definition UnitVector.h:387
constexpr UnitVector(const UnitVector &)=default
Copy constructor.
constexpr UnitVector()
Default constructor. Initializes all elements to zero.
Definition UnitVector.h:33
constexpr auto W() const
Access the fourth element (w).
Definition UnitVector.h:465
constexpr UnitVector & operator=(const UnitVector &)=default
Copy assignment.
constexpr auto Head() const
Extract the first N elements as a new UnitVector.
Definition UnitVector.h:181
constexpr UnitVector(StorageType &&d)
Construct from a raw Eigen matrix (move).
Definition UnitVector.h:45
constexpr auto CWiseQuotient(const UnitVector< OtherTags... > &other) const
Component-wise quotient with another UnitVector.
Definition UnitVector.h:334
constexpr auto operator*(const units::unit_t< ScalarTag > &scalar) const
Multiplication by a scalar unit.
Definition UnitVector.h:255
void W(units::unit_t< std::tuple_element_t< Size >=4 ? 3 :0, UnitTuple > > val)
Set the fourth element (w).
Definition UnitVector.h:472
constexpr UnitVector & operator+=(const UnitVector< OtherTags... > &other)
In-place vector addition.
Definition UnitVector.h:231
constexpr UnitVector & operator-=(const units::unit_t< ScalarTag > &scalar)
In-place vector - scalar subtraction (broadcasting).
Definition UnitVector.h:526
auto StableNorm() const
Computes the stable norm.
Definition UnitVector.h:548
constexpr UnitVector(UnitVector &&)=default
Move constructor.
static constexpr std::size_t Size
Definition UnitVector.h:24
constexpr UnitVector operator*(double scalar) const
Raw scaling (multiplication by double).
Definition UnitVector.h:279
constexpr auto Slice() const
Extract N elements after the Start as a new UnitVector.
Definition UnitVector.h:204
constexpr auto Tail() const
Extract the last N elements as a new UnitVector.
Definition UnitVector.h:192
auto Normalized() const
Returns a normalized (unit-length) vector. Result is dimensionless. Only valid if all elements have t...
Definition UnitVector.h:151
constexpr UnitVector(const StorageType &d)
Construct from a raw Eigen matrix.
Definition UnitVector.h:39
constexpr UnitVector CWiseAbs() const
Component-wise absolute value.
Definition UnitVector.h:340
constexpr UnitVector operator-(const UnitVector< OtherTags... > &other) const
Vector subtraction.
Definition UnitVector.h:220
auto Dot(const UnitVector< OtherTags... > &other) const
Dot product with another UnitVector. Resulting unit is the product of the first tags of both vectors.
Definition UnitVector.h:167
constexpr UnitVector & operator-=(const UnitVector< OtherTags... > &other)
In-place vector subtraction.
Definition UnitVector.h:240
bool operator==(const UnitVector< OtherTags... > &other) const
Equality operator.
Definition UnitVector.h:308
void Z(units::unit_t< std::tuple_element_t< Size >=3 ? 2 :0, UnitTuple > > val)
Set the third element (z).
Definition UnitVector.h:458
auto LPNorm() const
Computes the Lp norm.
Definition UnitVector.h:540
friend std::ostream & operator<<(std::ostream &os, const UnitVector &vec)
Debug printing support.
Definition UnitVector.h:299
constexpr UnitVector CWiseMax(const UnitVector &other) const
Component-wise maximum.
Definition UnitVector.h:352
void X(units::unit_t< std::tuple_element_t< Size >=1 ? 0 :0, UnitTuple > > val)
Set the first element (x).
Definition UnitVector.h:430
constexpr auto Y() const
Access the second element (y).
Definition UnitVector.h:437
constexpr StorageType & Raw()
Get a reference to the underlying raw Eigen data.
Definition UnitVector.h:108
static constexpr UnitVector Zero()
Create a zero-initialized vector.
Definition UnitVector.h:70
constexpr const StorageType & Raw() const
Get a constant reference to the underlying raw Eigen data.
Definition UnitVector.h:102
constexpr UnitVector operator/(double scalar) const
Raw scaling (division by double).
Definition UnitVector.h:289
static UnitVector FromArray(const std::array< double, Size > &arr)
Construct a UnitVector from a std::array of doubles. Values are assumed to be in the target units.
Definition UnitVector.h:82
constexpr UnitVector CWiseMin(const UnitVector &other) const
Component-wise minimum.
Definition UnitVector.h:346
void Set(units::unit_t< std::tuple_element_t< N, UnitTuple > > val)
Set the value of the N-th element.
Definition UnitVector.h:129
Eigen::Matrix< double, Size, 1 > StorageType
Definition UnitVector.h:26
constexpr UnitVector operator+(const units::unit_t< ScalarTag > &scalar) const
Vector + scalar addition (broadcasting).
Definition UnitVector.h:500
constexpr auto operator/(const units::unit_t< ScalarTag > &scalar) const
Division by a scalar unit.
Definition UnitVector.h:268
constexpr UnitVector operator+(const UnitVector< OtherTags... > &other) const
Vector addition.
Definition UnitVector.h:211
constexpr UnitVector Clamp(units::unit_t< std::tuple_element_t< 0, UnitTuple > > lo, units::unit_t< std::tuple_element_t< 0, UnitTuple > > hi) const
Clamp each element between lo and hi unit values.
Definition UnitVector.h:374
constexpr UnitVector & operator=(UnitVector &&)=default
Move assignment.
static auto Skew(const UnitVector< UnitTags... > &vec)
Converts a 3D vector to a skew-symmetric matrix.
Definition UnitVector.h:488
static UnitVector FromSpan(const std::span< double, Size > &s)
Construct a UnitVector from a std::span of doubles. Values are assumed to be in the target units.
Definition UnitVector.h:93
constexpr auto X() const
Access the first element (x).
Definition UnitVector.h:423
std::tuple< UnitTags... > UnitTuple
Definition UnitVector.h:28
constexpr UnitVector Clamp(const UnitVector &lo, const UnitVector &hi) const
Clamp each element between lo and hi vectors.
Definition UnitVector.h:362
constexpr auto CWiseProduct(const UnitVector< OtherTags... > &other) const
Component-wise product with another UnitVector.
Definition UnitVector.h:322
static UnitVector Constant(units::unit_t< typename std::tuple_element_t< 0, UnitTuple > > val)
Create a vector where all elements are set to a constant value. Only valid if all units are the same.
Definition UnitVector.h:400
constexpr auto Z() const
Access the third element (z).
Definition UnitVector.h:451
void Y(units::unit_t< std::tuple_element_t< Size >=2 ? 1 :0, UnitTuple > > val)
Set the second element (y).
Definition UnitVector.h:444
Concept verifying that all units in a pack are identical.
Definition Common.h:204
Concept verifying that a pack contains exactly three elements.
Definition Common.h:210
Concept verifying that two tuple-based unit types match exactly.
Definition Common.h:216
Concept verifying that index N is within the bounds of a pack.
Definition Common.h:192
Concept verifying that size N is within the bounds of a pack.
Definition Common.h:198
Template specializations for std::tuple_size and std::tuple_element to support UnitVector.
Definition Formatters.h:8
decltype(std::declval< valor::EigenUnit::UnitVector< UnitTags... > >().template get< N >()) type
The type of the N-th element.
Definition UnitVector.h:695
Builder for N-dimensional UnitVectors with uniform units.
Definition Common.h:126