Valkyrie 2026
Loading...
Searching...
No Matches
UnitVector.h
1#pragma once
2
3#include <span>
4#include <tuple>
5
6#include <Eigen/Core>
7
8#include "valkyrie/util/eigenunit/Common.h"
9
10namespace valor {
11namespace EigenUnit {
12
21template <typename... UnitTags>
23 public:
25 static constexpr std::size_t Size = sizeof...(UnitTags);
27 using StorageType = Eigen::Matrix<double, Size, 1>;
29 using UnitTuple = std::tuple<UnitTags...>;
30
34 constexpr UnitVector() { data.setZero(); }
35
40 constexpr explicit UnitVector(const StorageType& d) : data(d) {}
41
46 constexpr explicit UnitVector(StorageType&& d) : data(std::move(d)) {}
47
49 constexpr UnitVector(const UnitVector&) = default;
51 constexpr UnitVector(UnitVector&&) = default;
53 constexpr UnitVector& operator=(const UnitVector&) = default;
55 constexpr UnitVector& operator=(UnitVector&&) = default;
56
62 constexpr UnitVector(units::unit_t<UnitTags>... args) {
63 std::size_t i = 0;
64 ((data[i++] = args.value()), ...);
65 }
66
71 static constexpr UnitVector Zero() {
73 d.setZero();
74 return UnitVector(d);
75 }
76
83 static UnitVector FromArray(const std::array<double, Size>& arr) {
84 StorageType d = Eigen::Map<const StorageType>(arr.data());
85 return UnitVector(d);
86 }
87
94 static UnitVector FromSpan(const std::span<double, Size>& s) {
95 StorageType d = Eigen::Map<const StorageType>(s.data());
96 return UnitVector(d);
97 }
98
103 constexpr const StorageType& Raw() const { return data; }
104
109 constexpr StorageType& Raw() { return data; }
110
116 template <std::size_t N>
117 requires ValidIndex<N, UnitTags...>
118 constexpr auto Get() const {
119 using T = std::tuple_element_t<N, UnitTuple>;
120 return units::unit_t<T>(data[N]);
121 }
122
128 template <std::size_t N>
129 requires ValidIndex<N, UnitTags...>
130 void Set(units::unit_t<std::tuple_element_t<N, UnitTuple>> val) {
131 data[N] = val.value();
132 }
133
140 template <typename T = std::tuple_element_t<0, UnitTuple>>
141 requires AllSameUnits<UnitTags...>
142 [[nodiscard]]
143 auto Norm() const {
144 return units::unit_t<T>(data.norm());
145 }
146
152 auto Normalized() const
153 requires AllSameUnits<UnitTags...>
154 {
155 return data.normalized();
156 }
157
165 template <typename... OtherTags>
166 requires(sizeof...(UnitTags) == sizeof...(OtherTags)) && AllSameUnits<MultiplyResult<UnitTags, OtherTags>...>
167 [[nodiscard]]
168 auto Dot(const UnitVector<OtherTags...>& other) const {
169 using T1 = std::tuple_element_t<0, UnitTuple>;
170 using T2 = std::tuple_element_t<0, std::tuple<OtherTags...>>;
171 using ResultUnit = MultiplyResult<T1, T2>;
172 return units::unit_t<ResultUnit>(data.dot(other.Raw()));
173 }
174
180 template <std::size_t N>
181 requires ValidSize<N, UnitTags...>
182 constexpr auto Head() const {
183 return slice_impl<0>(std::make_index_sequence<N>{});
184 }
185
191 template <std::size_t N>
192 requires ValidSize<N, UnitTags...>
193 constexpr auto Tail() const {
194 return slice_impl<Size - N>(std::make_index_sequence<N>{});
195 }
196
203 template <std::size_t Start, std::size_t N>
204 requires ValidSize<Start + N, UnitTags...>
205 constexpr auto Slice() const {
206 return slice_impl<Start>(std::make_index_sequence<N>{});
207 }
208
210 template <typename... OtherTags>
211 [[nodiscard]]
212 constexpr UnitVector operator+(const UnitVector<OtherTags...>& other) const
213 requires UnitEquality<UnitTuple, std::tuple<OtherTags...>>
214 {
215 return UnitVector<UnitTags...>(data + other.Raw());
216 }
217
219 template <typename... OtherTags>
220 [[nodiscard]]
221 constexpr UnitVector operator-(const UnitVector<OtherTags...>& other) const
222 requires UnitEquality<UnitTuple, std::tuple<OtherTags...>>
223 {
224 return UnitVector<UnitTags...>(data - other.Raw());
225 }
226
228 constexpr UnitVector operator-() const { return UnitVector<UnitTags...>(-data); }
229
231 template <typename... OtherTags>
233 requires UnitEquality<UnitTuple, std::tuple<OtherTags...>>
234 {
235 data += other.Raw();
236 return *this;
237 }
238
240 template <typename... OtherTags>
242 requires UnitEquality<UnitTuple, std::tuple<OtherTags...>>
243 {
244 data -= other.Raw();
245 return *this;
246 }
247
254 template <typename ScalarTag>
255 [[nodiscard]]
256 constexpr auto operator*(const units::unit_t<ScalarTag>& scalar) const {
258 return ResultType(data * scalar.value());
259 }
260
267 template <typename ScalarTag>
268 [[nodiscard]]
269 constexpr auto operator/(const units::unit_t<ScalarTag>& scalar) const {
271 return ResultType(data / scalar.value());
272 }
273
279 [[nodiscard]]
280 constexpr UnitVector operator*(double scalar) const {
281 return UnitVector(data * scalar);
282 }
283
289 [[nodiscard]]
290 constexpr UnitVector operator/(double scalar) const {
291 return UnitVector(data / scalar);
292 }
293
300 friend std::ostream& operator<<(std::ostream& os, const UnitVector& vec) {
301 os << "[";
302 vec.print_impl(os, std::make_index_sequence<Size>{});
303 os << "]";
304 return os;
305 }
306
308 template <typename... OtherTags>
309 bool operator==(const UnitVector<OtherTags...>& other) const
310 requires UnitEquality<UnitTuple, std::tuple<OtherTags...>>
311 {
312 return data == other.Raw();
313 }
314
321 template <typename... OtherTags>
322 [[nodiscard]]
323 constexpr auto CWiseProduct(const UnitVector<OtherTags...>& other) const {
324 return UnitVector<MultiplyResult<UnitTags, OtherTags>...>(data.CWiseProduct(other.Raw()));
325 }
326
333 template <typename... OtherTags>
334 [[nodiscard]]
335 constexpr auto CWiseQuotient(const UnitVector<OtherTags...>& other) const {
336 return UnitVector<DivideResult<UnitTags, OtherTags>...>(data.CWiseQuotient(other.Raw()));
337 }
338
340 [[nodiscard]]
341 constexpr UnitVector CWiseAbs() const {
342 return UnitVector(data.CWiseAbs());
343 }
344
346 [[nodiscard]]
347 constexpr UnitVector CWiseMin(const UnitVector& other) const {
348 return UnitVector(data.CWiseMin(other.Raw()));
349 }
350
352 [[nodiscard]]
353 constexpr UnitVector CWiseMax(const UnitVector& other) const {
354 return UnitVector(data.CWiseMax(other.Raw()));
355 }
356
362 [[nodiscard]]
363 constexpr UnitVector Clamp(const UnitVector& lo, const UnitVector& hi) const
364 requires AllSameUnits<UnitTags...>
365 {
366 return UnitVector(data.CWiseMax(lo.Raw()).CWiseMin(hi.Raw()));
367 }
368
374 [[nodiscard]]
375 constexpr UnitVector Clamp(units::unit_t<std::tuple_element_t<0, UnitTuple>> lo,
376 units::unit_t<std::tuple_element_t<0, UnitTuple>> hi) const
377 requires AllSameUnits<UnitTags...>
378 {
379 return UnitVector(data.cwiseMax(lo.value()).cwiseMin(hi.value()));
380 }
381
388 bool IsApprox(const UnitVector& other,
389 units::unit_t<std::tuple_element_t<0, UnitTuple>> tol = units::unit_t<std::tuple_element_t<0, UnitTuple>>{1e-9}) const
391 {
392 return data.isApprox(other.Raw(), tol.value());
393 }
394
401 static UnitVector Constant(units::unit_t<typename std::tuple_element_t<0, UnitTuple>> val)
402 requires AllSameUnits<UnitTags...>
403 {
404 return UnitVector(StorageType::Constant(val.value()));
405 }
406
408 template <typename T = std::tuple_element_t<0, UnitTuple>>
409 requires AllSameUnits<UnitTags...>
410 [[nodiscard]]
411 auto Sum() const {
412 return units::unit_t<T>(data.sum());
413 }
414
416 template <typename T = std::tuple_element_t<0, UnitTuple>>
417 requires AllSameUnits<UnitTags...>
418 [[nodiscard]]
419 auto Mean() const {
420 return units::unit_t<T>(data.mean());
421 }
422
424 constexpr auto X() const
425 requires(Size >= 1)
426 {
427 return this->Get<0>();
428 }
429
431 void X(units::unit_t<std::tuple_element_t<Size >= 1 ? 0 : 0, UnitTuple>> val)
432 requires(Size >= 1)
433 {
434 this->Set<0>(val);
435 }
436
438 constexpr auto Y() const
439 requires(Size >= 2)
440 {
441 return this->Get<1>();
442 }
443
445 void Y(units::unit_t<std::tuple_element_t<Size >= 2 ? 1 : 0, UnitTuple>> val)
446 requires(Size >= 2)
447 {
448 this->Set<1>(val);
449 }
450
452 constexpr auto Z() const
453 requires(Size >= 3)
454 {
455 return this->Get<2>();
456 }
457
459 void Z(units::unit_t<std::tuple_element_t<Size >= 3 ? 2 : 0, UnitTuple>> val)
460 requires(Size >= 3)
461 {
462 this->Set<2>(val);
463 }
464
466 constexpr auto W() const
467 requires(Size >= 4)
468 {
469 return this->Get<3>();
470 }
471
473 void W(units::unit_t<std::tuple_element_t<Size >= 4 ? 3 : 0, UnitTuple>> val)
474 requires(Size >= 4)
475 {
476 this->Set<3>(val);
477 }
478
483 auto AsDiagonal() const;
484
489 static auto Skew(const UnitVector<UnitTags...>& vec)
490 requires(Size == 3) && AllSameUnits<UnitTags...>
491 {
493 typename Mat::StorageType d;
494 d << 0, -vec.data[2], vec.data[1], vec.data[2], 0, -vec.data[0], -vec.data[1], vec.data[0], 0;
495 return Mat(std::move(d));
496 }
497
499 template <typename ScalarTag>
500 [[nodiscard]]
501 constexpr UnitVector operator+(const units::unit_t<ScalarTag>& scalar) const
503 {
504 return UnitVector<UnitTags...>(data.array() + scalar.value());
505 }
506
508 template <typename ScalarTag>
509 [[nodiscard]]
510 constexpr UnitVector operator-(const units::unit_t<ScalarTag>& scalar) const
512 {
513 return UnitVector<UnitTags...>(data.array() - scalar.value());
514 }
515
517 template <typename ScalarTag>
518 constexpr UnitVector& operator+=(const units::unit_t<ScalarTag>& scalar)
520 {
521 data.array() += scalar.value();
522 return *this;
523 }
524
526 template <typename ScalarTag>
527 constexpr UnitVector& operator-=(const units::unit_t<ScalarTag>& scalar)
529 {
530 data.array() -= scalar.value();
531 return *this;
532 }
533
538 template <int P, typename T = std::tuple_element_t<0, UnitTuple>>
539 requires AllSameUnits<UnitTags...>
540 [[nodiscard]]
541 auto LPNorm() const {
542 return units::unit_t<T>(data.template lpNorm<P>());
543 }
544
546 template <typename T = std::tuple_element_t<0, UnitTuple>>
547 requires AllSameUnits<UnitTags...>
548 [[nodiscard]]
549 auto StableNorm() const {
550 return units::unit_t<T>(data.stableNorm());
551 }
552
553 constexpr auto Begin() { return data.begin(); }
554
555 constexpr auto End() { return data.end(); }
556
557 constexpr auto Begin() const { return data.begin(); }
558
559 constexpr auto End() const { return data.end(); }
560
561 private:
562 template <std::size_t Offset, std::size_t... Is>
563 auto slice_impl(std::index_sequence<Is...>) const {
564 return UnitVector<std::tuple_element_t<Offset + Is, UnitTuple>...>(data.template segment<sizeof...(Is)>(Offset));
565 }
566
567 template <std::size_t... Is>
568 void print_impl(std::ostream& os, std::index_sequence<Is...>) const {
569 ((os << units::unit_t<std::tuple_element_t<Is, UnitTuple>>(data[Is]).value() << (Is == Size - 1 ? "" : ", ")), ...);
570 }
571
572 StorageType data;
573};
574
580template <typename T, std::size_t N>
581using VectorN = typename detail::VectorN_Builder<T, std::make_index_sequence<N>>::type;
582
586using UnitQuaternion = VectorN<units::dimensionless::scalar, 4>;
587
591template <typename... T>
592 requires(requires { typename T::unit_type; } && ...)
593UnitVector(T...) -> UnitVector<typename T::unit_type...>;
594
598template <std::size_t I, typename... UnitTags>
599constexpr auto Get(const UnitVector<UnitTags...>& vec) {
600 return vec.template Get<I>();
601}
602
612template <typename... TagsA, typename... TagsB>
613[[nodiscard]]
614constexpr auto Cross(const UnitVector<TagsA...>& a, const UnitVector<TagsB...>& b)
615 requires ThreeDimensionalVector<TagsA...> && ThreeDimensionalVector<TagsB...>
616{
617 using T1 = std::tuple_element_t<0, std::tuple<TagsA...>>;
618 using T2 = std::tuple_element_t<0, std::tuple<TagsB...>>;
619 using ResultUnit = MultiplyResult<T1, T2>;
620
621 return UnitVector<ResultUnit, ResultUnit, ResultUnit>(a.Raw().cross(b.Raw()));
622}
623
632template <typename ScalarTag, typename... UnitTags>
633[[nodiscard]]
634constexpr auto operator*(const units::unit_t<ScalarTag>& scalar, const UnitVector<UnitTags...>& vec) {
635 return vec * scalar;
636}
637
645template <typename... UnitTags>
646[[nodiscard]]
647constexpr auto operator*(double scalar, const UnitVector<UnitTags...>& vec) {
648 return vec * scalar;
649}
650
654template <typename ScalarTag, typename... UnitTags>
655[[nodiscard]]
656constexpr auto operator+(const units::unit_t<ScalarTag>& scalar, const UnitVector<UnitTags...>& vec)
657 requires AllSameUnits<UnitTags...> && UnitEquality<ScalarTag, std::tuple_element_t<0, std::tuple<UnitTags...>>>
658{
659 return vec + scalar;
660}
661
666template <typename ScalarTag, typename... UnitTags>
667[[nodiscard]]
668constexpr auto operator-(const units::unit_t<ScalarTag>& scalar, const UnitVector<UnitTags...>& vec)
669 requires AllSameUnits<UnitTags...> && UnitEquality<ScalarTag, std::tuple_element_t<0, std::tuple<UnitTags...>>>
670{
671 return UnitVector<UnitTags...>(scalar.value() - vec.Raw().array());
672}
673
674template <typename Derived, typename Base>
675struct NamedPhysicalVector : Base {
676 using Base::Base;
677
678 NamedPhysicalVector(const Base& b) : Base(b.Raw()) {}
679};
680
681} // namespace EigenUnit
682} // namespace valor
683
687template <typename... UnitTags>
688struct std::tuple_size<valor::EigenUnit::UnitVector<UnitTags...>> : std::integral_constant<std::size_t, sizeof...(UnitTags)> {};
689
693template <std::size_t N, typename... UnitTags>
694struct std::tuple_element<N, valor::EigenUnit::UnitVector<UnitTags...>> {
696 using type = decltype(std::declval<valor::EigenUnit::UnitVector<UnitTags...>>().template get<N>());
697};
A matrix wrapper representing a linear map between two UnitVectors.
Definition UnitMatrix.h:23
A vector wrapper that enforces units for each element.
Definition UnitVector.h:22
auto Norm() const
Computes the L2 norm (magnitude). Requires all elements to have the same unit tag.
Definition UnitVector.h:143
constexpr UnitVector operator-() const
Unary negation.
Definition UnitVector.h:228
auto Mean() const
Computes the mean of all elements. Only valid if all units are the same.
Definition UnitVector.h:419
auto Sum() const
Computes the sum of all elements. Only valid if all units are the same.
Definition UnitVector.h:411
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:62
constexpr UnitVector operator-(const units::unit_t< ScalarTag > &scalar) const
Vector - scalar subtraction (broadcasting).
Definition UnitVector.h:510
constexpr auto Get() const
Get the value of the N-th element with its unit.
Definition UnitVector.h:118
constexpr UnitVector & operator+=(const units::unit_t< ScalarTag > &scalar)
In-place vector + scalar addition (broadcasting).
Definition UnitVector.h:518
auto AsDiagonal() const
Converts the vector to a diagonal matrix.
Definition UnitMatrix.h:615
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:388
constexpr UnitVector(const UnitVector &)=default
Copy constructor.
constexpr UnitVector()
Default constructor. Initializes all elements to zero.
Definition UnitVector.h:34
constexpr auto W() const
Access the fourth element (w).
Definition UnitVector.h:466
constexpr UnitVector & operator=(const UnitVector &)=default
Copy assignment.
constexpr auto Head() const
Extract the first N elements as a new UnitVector.
Definition UnitVector.h:182
constexpr UnitVector(StorageType &&d)
Construct from a raw Eigen matrix (move).
Definition UnitVector.h:46
constexpr auto CWiseQuotient(const UnitVector< OtherTags... > &other) const
Component-wise quotient with another UnitVector.
Definition UnitVector.h:335
constexpr auto operator*(const units::unit_t< ScalarTag > &scalar) const
Multiplication by a scalar unit.
Definition UnitVector.h:256
void W(units::unit_t< std::tuple_element_t< Size >=4 ? 3 :0, UnitTuple > > val)
Set the fourth element (w).
Definition UnitVector.h:473
constexpr UnitVector & operator+=(const UnitVector< OtherTags... > &other)
In-place vector addition.
Definition UnitVector.h:232
constexpr UnitVector & operator-=(const units::unit_t< ScalarTag > &scalar)
In-place vector - scalar subtraction (broadcasting).
Definition UnitVector.h:527
auto StableNorm() const
Computes the stable norm.
Definition UnitVector.h:549
constexpr UnitVector(UnitVector &&)=default
Move constructor.
static constexpr std::size_t Size
Definition UnitVector.h:25
constexpr UnitVector operator*(double scalar) const
Raw scaling (multiplication by double).
Definition UnitVector.h:280
constexpr auto Slice() const
Extract N elements after the Start as a new UnitVector.
Definition UnitVector.h:205
constexpr auto Tail() const
Extract the last N elements as a new UnitVector.
Definition UnitVector.h:193
auto Normalized() const
Returns a normalized (unit-length) vector. Result is dimensionless. Only valid if all elements have t...
Definition UnitVector.h:152
constexpr UnitVector(const StorageType &d)
Construct from a raw Eigen matrix.
Definition UnitVector.h:40
constexpr UnitVector CWiseAbs() const
Component-wise absolute value.
Definition UnitVector.h:341
constexpr UnitVector operator-(const UnitVector< OtherTags... > &other) const
Vector subtraction.
Definition UnitVector.h:221
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:168
constexpr UnitVector & operator-=(const UnitVector< OtherTags... > &other)
In-place vector subtraction.
Definition UnitVector.h:241
bool operator==(const UnitVector< OtherTags... > &other) const
Equality operator.
Definition UnitVector.h:309
void Z(units::unit_t< std::tuple_element_t< Size >=3 ? 2 :0, UnitTuple > > val)
Set the third element (z).
Definition UnitVector.h:459
auto LPNorm() const
Computes the Lp norm.
Definition UnitVector.h:541
friend std::ostream & operator<<(std::ostream &os, const UnitVector &vec)
Debug printing support.
Definition UnitVector.h:300
constexpr UnitVector CWiseMax(const UnitVector &other) const
Component-wise maximum.
Definition UnitVector.h:353
void X(units::unit_t< std::tuple_element_t< Size >=1 ? 0 :0, UnitTuple > > val)
Set the first element (x).
Definition UnitVector.h:431
constexpr auto Y() const
Access the second element (y).
Definition UnitVector.h:438
constexpr StorageType & Raw()
Get a reference to the underlying raw Eigen data.
Definition UnitVector.h:109
static constexpr UnitVector Zero()
Create a zero-initialized vector.
Definition UnitVector.h:71
constexpr const StorageType & Raw() const
Get a constant reference to the underlying raw Eigen data.
Definition UnitVector.h:103
constexpr UnitVector operator/(double scalar) const
Raw scaling (division by double).
Definition UnitVector.h:290
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:83
constexpr UnitVector CWiseMin(const UnitVector &other) const
Component-wise minimum.
Definition UnitVector.h:347
void Set(units::unit_t< std::tuple_element_t< N, UnitTuple > > val)
Set the value of the N-th element.
Definition UnitVector.h:130
Eigen::Matrix< double, Size, 1 > StorageType
Definition UnitVector.h:27
constexpr UnitVector operator+(const units::unit_t< ScalarTag > &scalar) const
Vector + scalar addition (broadcasting).
Definition UnitVector.h:501
constexpr auto operator/(const units::unit_t< ScalarTag > &scalar) const
Division by a scalar unit.
Definition UnitVector.h:269
constexpr UnitVector operator+(const UnitVector< OtherTags... > &other) const
Vector addition.
Definition UnitVector.h:212
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:375
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:489
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:94
constexpr auto X() const
Access the first element (x).
Definition UnitVector.h:424
std::tuple< UnitTags... > UnitTuple
Definition UnitVector.h:29
constexpr UnitVector Clamp(const UnitVector &lo, const UnitVector &hi) const
Clamp each element between lo and hi vectors.
Definition UnitVector.h:363
constexpr auto CWiseProduct(const UnitVector< OtherTags... > &other) const
Component-wise product with another UnitVector.
Definition UnitVector.h:323
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:401
constexpr auto Z() const
Access the third element (z).
Definition UnitVector.h:452
void Y(units::unit_t< std::tuple_element_t< Size >=2 ? 1 :0, UnitTuple > > val)
Set the second element (y).
Definition UnitVector.h:445
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:696
Builder for N-dimensional UnitVectors with uniform units.
Definition Common.h:126