UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
vec.hpp
1
41#ifndef UFO_NUMERIC_VEC_HPP
42#define UFO_NUMERIC_VEC_HPP
43
44// UFO
45#include <ufo/numeric/math.hpp>
46
47// STL
48#include <algorithm>
49#include <array>
50#include <cmath>
51#include <concepts>
52#include <cstddef>
53#include <format>
54#include <functional>
55#include <limits>
56#include <ostream>
57#include <ranges>
58#include <type_traits>
59#include <utility>
60
66namespace ufo
67{
68
74template <std::size_t Dim, class T>
75 requires(Dim <= 4 && std::is_arithmetic_v<T>)
76struct Vec {
77 using value_type = T;
78 using size_type = std::size_t;
79
80 std::array<T, Dim> fields{};
81
85 constexpr Vec() noexcept = default;
86
96 template <std::convertible_to<T>... Args>
97 requires(sizeof...(Args) <= Dim)
98 explicit(sizeof...(Args) == 1) constexpr Vec(Args... args) noexcept
99 : fields{static_cast<T>(args)...}
100 {
101 }
102
110 template <class U>
111 constexpr explicit(!std::is_same_v<T, U>) Vec(Vec<Dim, U> const& other) noexcept
112 {
113 std::ranges::transform(other, begin(), [](U const& v) { return static_cast<T>(v); });
114 }
115
116 /**************************************************************************************
117 | |
118 | Accessors |
119 | |
120 **************************************************************************************/
121
127 constexpr auto& operator[](this auto& self, size_type i) noexcept
128 {
129 return self.fields[i];
130 }
131
136 [[nodiscard]] constexpr auto& x(this auto& self) noexcept
137 requires(Dim >= 1)
138 {
139 return self[0];
140 }
141
146 [[nodiscard]] constexpr auto& y(this auto& self) noexcept
147 requires(Dim >= 2)
148 {
149 return self[1];
150 }
151
156 [[nodiscard]] constexpr auto& z(this auto& self) noexcept
157 requires(Dim >= 3)
158 {
159 return self[2];
160 }
161
166 [[nodiscard]] constexpr auto& w(this auto& self) noexcept
167 requires(Dim >= 4)
168 {
169 return self[3];
170 }
171
176 [[nodiscard]] constexpr auto begin(this auto& self) noexcept
177 {
178 return self.fields.begin();
179 }
180
185 [[nodiscard]] constexpr auto end(this auto& self) noexcept { return self.fields.end(); }
186
191 [[nodiscard]] constexpr auto data(this auto& self) noexcept
192 {
193 return self.fields.data();
194 }
195
200 [[nodiscard]] static constexpr std::size_t size() noexcept { return Dim; }
201
207 constexpr bool operator==(Vec const&) const = default;
208
209 /**************************************************************************************
210 | |
211 | Unary arithmetic operator |
212 | |
213 **************************************************************************************/
214
219 constexpr Vec operator+() const noexcept { return *this; }
220
225 constexpr Vec operator-() const noexcept
226 {
227 Vec result;
228 std::ranges::transform(*this, result.begin(), std::negate{});
229 return result;
230 }
231
236 constexpr Vec operator~() const noexcept
237 requires std::is_integral_v<T>
238 {
239 Vec result;
240 std::ranges::transform(*this, result.begin(), std::bit_not{});
241 return result;
242 }
243
244 /**************************************************************************************
245 | |
246 | Compound assignment operator |
247 | |
248 **************************************************************************************/
249
255 constexpr Vec& operator+=(Vec const& rhs) noexcept
256 {
257 std::ranges::transform(*this, rhs, begin(), std::plus{});
258 return *this;
259 }
260
266 constexpr Vec& operator-=(Vec const& rhs) noexcept
267 {
268 std::ranges::transform(*this, rhs, begin(), std::minus{});
269 return *this;
270 }
271
277 constexpr Vec& operator*=(Vec const& rhs) noexcept
278 {
279 std::ranges::transform(*this, rhs, begin(), std::multiplies{});
280 return *this;
281 }
282
288 constexpr Vec& operator/=(Vec const& rhs) noexcept
289 {
290 std::ranges::transform(*this, rhs, begin(), std::divides{});
291 return *this;
292 }
293
300 constexpr Vec& operator%=(Vec const& rhs) noexcept
301 requires std::is_integral_v<T>
302 {
303 std::ranges::transform(*this, rhs, begin(), std::modulus{});
304 return *this;
305 }
306
313 constexpr Vec& operator&=(Vec const& rhs) noexcept
314 requires std::is_integral_v<T>
315 {
316 std::ranges::transform(*this, rhs, begin(), std::bit_and{});
317 return *this;
318 }
319
326 constexpr Vec& operator|=(Vec const& rhs) noexcept
327 requires std::is_integral_v<T>
328 {
329 std::ranges::transform(*this, rhs, begin(), std::bit_or{});
330 return *this;
331 }
332
339 constexpr Vec& operator^=(Vec const& rhs) noexcept
340 requires std::is_integral_v<T>
341 {
342 std::ranges::transform(*this, rhs, begin(), std::bit_xor{});
343 return *this;
344 }
345
352 constexpr Vec& operator<<=(Vec const& rhs) noexcept
353 requires std::is_integral_v<T>
354 {
355 std::ranges::transform(*this, rhs, begin(), [](T a, T b) { return a << b; });
356 return *this;
357 }
358
365 constexpr Vec& operator>>=(Vec const& rhs) noexcept
366 requires std::is_integral_v<T>
367 {
368 std::ranges::transform(*this, rhs, begin(), [](T a, T b) { return a >> b; });
369 return *this;
370 }
371
372 /**************************************************************************************
373 | |
374 | Scalar compound assignment operator |
375 | |
376 **************************************************************************************/
377
383 constexpr Vec& operator+=(T rhs) noexcept
384 {
385 std::ranges::transform(*this, begin(), [rhs](T v) { return v + rhs; });
386 return *this;
387 }
388
394 constexpr Vec& operator-=(T rhs) noexcept
395 {
396 std::ranges::transform(*this, begin(), [rhs](T v) { return v - rhs; });
397 return *this;
398 }
399
405 constexpr Vec& operator*=(T rhs) noexcept
406 {
407 std::ranges::transform(*this, begin(), [rhs](T v) { return v * rhs; });
408 return *this;
409 }
410
416 constexpr Vec& operator/=(T rhs) noexcept
417 {
418 std::ranges::transform(*this, begin(), [rhs](T v) { return v / rhs; });
419 return *this;
420 }
421
428 constexpr Vec& operator%=(T rhs) noexcept
429 requires std::is_integral_v<T>
430 {
431 std::ranges::transform(*this, begin(), [rhs](T v) { return v % rhs; });
432 return *this;
433 }
434
440 constexpr Vec& operator&=(T rhs) noexcept
441 requires std::is_integral_v<T>
442 {
443 std::ranges::transform(*this, begin(), [rhs](T v) { return v & rhs; });
444 return *this;
445 }
446
452 constexpr Vec& operator|=(T rhs) noexcept
453 requires std::is_integral_v<T>
454 {
455 std::ranges::transform(*this, begin(), [rhs](T v) { return v | rhs; });
456 return *this;
457 }
458
464 constexpr Vec& operator^=(T rhs) noexcept
465 requires std::is_integral_v<T>
466 {
467 std::ranges::transform(*this, begin(), [rhs](T v) { return v ^ rhs; });
468 return *this;
469 }
470
476 constexpr Vec& operator<<=(T rhs) noexcept
477 requires std::is_integral_v<T>
478 {
479 std::ranges::transform(*this, begin(), [rhs](T v) { return v <<= rhs; });
480 return *this;
481 }
482
488 constexpr Vec& operator>>=(T rhs) noexcept
489 requires std::is_integral_v<T>
490 {
491 std::ranges::transform(*this, begin(), [rhs](T v) { return v >>= rhs; });
492 return *this;
493 }
494};
495
496/**************************************************************************************
497| |
498| Type Aliases |
499| |
500**************************************************************************************/
501
502using Vec1b = Vec<1, bool>;
503using Vec2b = Vec<2, bool>;
504using Vec3b = Vec<3, bool>;
505using Vec4b = Vec<4, bool>;
506using Vec1i = Vec<1, int>;
507using Vec2i = Vec<2, int>;
508using Vec3i = Vec<3, int>;
509using Vec4i = Vec<4, int>;
510using Vec1u = Vec<1, unsigned>;
511using Vec2u = Vec<2, unsigned>;
512using Vec3u = Vec<3, unsigned>;
513using Vec4u = Vec<4, unsigned>;
514using Vec1f = Vec<1, float>;
515using Vec2f = Vec<2, float>;
516using Vec3f = Vec<3, float>;
517using Vec4f = Vec<4, float>;
518using Vec1d = Vec<1, double>;
519using Vec2d = Vec<2, double>;
520using Vec3d = Vec<3, double>;
521using Vec4d = Vec<4, double>;
522
523/**************************************************************************************
524| |
525| Binary operators |
526| |
527**************************************************************************************/
528
537template <std::size_t Dim, class T>
538[[nodiscard]] constexpr Vec<Dim, T> operator+(Vec<Dim, T> lhs,
539 Vec<Dim, T> const& rhs) noexcept
540{
541 lhs += rhs;
542 return lhs;
543}
544
553template <std::size_t Dim, class T>
554[[nodiscard]] constexpr Vec<Dim, T> operator-(Vec<Dim, T> lhs,
555 Vec<Dim, T> const& rhs) noexcept
556{
557 lhs -= rhs;
558 return lhs;
559}
560
569template <std::size_t Dim, class T>
570[[nodiscard]] constexpr Vec<Dim, T> operator*(Vec<Dim, T> lhs,
571 Vec<Dim, T> const& rhs) noexcept
572{
573 lhs *= rhs;
574 return lhs;
575}
576
585template <std::size_t Dim, class T>
586[[nodiscard]] constexpr Vec<Dim, T> operator/(Vec<Dim, T> lhs,
587 Vec<Dim, T> const& rhs) noexcept
588{
589 lhs /= rhs;
590 return lhs;
591}
592
601template <std::size_t Dim, std::integral T>
602[[nodiscard]] constexpr Vec<Dim, T> operator%(Vec<Dim, T> lhs,
603 Vec<Dim, T> const& rhs) noexcept
604{
605 lhs %= rhs;
606 return lhs;
607}
608
617template <std::size_t Dim, std::integral T>
618[[nodiscard]] constexpr Vec<Dim, T> operator&(Vec<Dim, T> lhs,
619 Vec<Dim, T> const& rhs) noexcept
620{
621 lhs &= rhs;
622 return lhs;
623}
624
633template <std::size_t Dim, std::integral T>
634[[nodiscard]] constexpr Vec<Dim, T> operator|(Vec<Dim, T> lhs,
635 Vec<Dim, T> const& rhs) noexcept
636{
637 lhs |= rhs;
638 return lhs;
639}
640
649template <std::size_t Dim, std::integral T>
650[[nodiscard]] constexpr Vec<Dim, T> operator^(Vec<Dim, T> lhs,
651 Vec<Dim, T> const& rhs) noexcept
652{
653 lhs ^= rhs;
654 return lhs;
655}
656
665template <std::size_t Dim, std::integral T>
666[[nodiscard]] constexpr Vec<Dim, T> operator<<(Vec<Dim, T> lhs,
667 Vec<Dim, T> const& rhs) noexcept
668{
669 lhs <<= rhs;
670 return lhs;
671}
672
681template <std::size_t Dim, std::integral T>
682[[nodiscard]] constexpr Vec<Dim, T> operator>>(Vec<Dim, T> lhs,
683 Vec<Dim, T> const& rhs) noexcept
684{
685 lhs >>= rhs;
686 return lhs;
687}
688
696template <std::size_t Dim>
697[[nodiscard]] constexpr Vec<Dim, bool> operator&&(Vec<Dim, bool> lhs,
698 Vec<Dim, bool> const& rhs) noexcept
699{
700 std::ranges::transform(lhs, rhs, lhs.begin(), std::logical_and{});
701 return lhs;
702}
703
711template <std::size_t Dim>
712[[nodiscard]] constexpr Vec<Dim, bool> operator||(Vec<Dim, bool> lhs,
713 Vec<Dim, bool> const& rhs) noexcept
714{
715 std::ranges::transform(lhs, rhs, lhs.begin(), std::logical_or{});
716 return lhs;
717}
718
719/**************************************************************************************
720| |
721| Scalar binary operators |
722| |
723**************************************************************************************/
724
733template <std::size_t Dim, class T>
734[[nodiscard]] constexpr Vec<Dim, T> operator+(Vec<Dim, T> lhs, T rhs) noexcept
735{
736 lhs += rhs;
737 return lhs;
738}
739
748template <std::size_t Dim, class T>
749[[nodiscard]] constexpr Vec<Dim, T> operator-(Vec<Dim, T> lhs, T rhs) noexcept
750{
751 lhs -= rhs;
752 return lhs;
753}
754
763template <std::size_t Dim, class T>
764[[nodiscard]] constexpr Vec<Dim, T> operator*(Vec<Dim, T> lhs, T rhs) noexcept
765{
766 lhs *= rhs;
767 return lhs;
768}
769
778template <std::size_t Dim, class T>
779[[nodiscard]] constexpr Vec<Dim, T> operator/(Vec<Dim, T> lhs, T rhs) noexcept
780{
781 lhs /= rhs;
782 return lhs;
783}
784
794template <std::size_t Dim, std::integral T>
795[[nodiscard]] constexpr Vec<Dim, T> operator%(Vec<Dim, T> lhs, T rhs) noexcept
796{
797 lhs %= rhs;
798 return lhs;
799}
800
809template <std::size_t Dim, std::integral T>
810[[nodiscard]] constexpr Vec<Dim, T> operator&(Vec<Dim, T> lhs, T rhs) noexcept
811{
812 lhs &= rhs;
813 return lhs;
814}
815
824template <std::size_t Dim, std::integral T>
825[[nodiscard]] constexpr Vec<Dim, T> operator|(Vec<Dim, T> lhs, T rhs) noexcept
826{
827 lhs |= rhs;
828 return lhs;
829}
830
839template <std::size_t Dim, std::integral T>
840[[nodiscard]] constexpr Vec<Dim, T> operator^(Vec<Dim, T> lhs, T rhs) noexcept
841{
842 lhs ^= rhs;
843 return lhs;
844}
845
854template <std::size_t Dim, std::integral T>
855[[nodiscard]] constexpr Vec<Dim, T> operator<<(Vec<Dim, T> lhs, T rhs) noexcept
856{
857 lhs <<= rhs;
858 return lhs;
859}
860
869template <std::size_t Dim, std::integral T>
870[[nodiscard]] constexpr Vec<Dim, T> operator>>(Vec<Dim, T> lhs, T rhs) noexcept
871{
872 lhs >>= rhs;
873 return lhs;
874}
875
884template <std::size_t Dim, class T>
885[[nodiscard]] constexpr Vec<Dim, T> operator+(T lhs, Vec<Dim, T> rhs) noexcept
886{
887 rhs += lhs;
888 return rhs;
889}
890
899template <std::size_t Dim, class T>
900[[nodiscard]] constexpr Vec<Dim, T> operator-(T lhs, Vec<Dim, T> rhs) noexcept
901{
902 std::ranges::transform(rhs, rhs.begin(), [lhs](T v) { return lhs - v; });
903 return rhs;
904}
905
914template <std::size_t Dim, class T>
915[[nodiscard]] constexpr Vec<Dim, T> operator*(T lhs, Vec<Dim, T> rhs) noexcept
916{
917 rhs *= lhs;
918 return rhs;
919}
920
929template <std::size_t Dim, class T>
930[[nodiscard]] constexpr Vec<Dim, T> operator/(T lhs, Vec<Dim, T> rhs) noexcept
931{
932 std::ranges::transform(rhs, rhs.begin(), [lhs](T v) { return lhs / v; });
933 return rhs;
934}
935
945template <std::size_t Dim, std::integral T>
946[[nodiscard]] constexpr Vec<Dim, T> operator%(T lhs, Vec<Dim, T> rhs) noexcept
947{
948 std::ranges::transform(rhs, rhs.begin(), [lhs](T v) { return lhs % v; });
949 return rhs;
950}
951
960template <std::size_t Dim, std::integral T>
961[[nodiscard]] constexpr Vec<Dim, T> operator&(T lhs, Vec<Dim, T> rhs) noexcept
962{
963 rhs &= lhs;
964 return rhs;
965}
966
975template <std::size_t Dim, std::integral T>
976[[nodiscard]] constexpr Vec<Dim, T> operator|(T lhs, Vec<Dim, T> rhs) noexcept
977{
978 rhs |= lhs;
979 return rhs;
980}
981
990template <std::size_t Dim, std::integral T>
991[[nodiscard]] constexpr Vec<Dim, T> operator^(T lhs, Vec<Dim, T> rhs) noexcept
992{
993 rhs ^= lhs;
994 return rhs;
995}
996
1005template <std::size_t Dim, std::integral T>
1006[[nodiscard]] constexpr Vec<Dim, T> operator<<(T lhs, Vec<Dim, T> rhs) noexcept
1007{
1008 std::ranges::transform(rhs, rhs.begin(), [lhs](T v) { return lhs << v; });
1009 return rhs;
1010}
1011
1020template <std::size_t Dim, std::integral T>
1021[[nodiscard]] constexpr Vec<Dim, T> operator>>(T lhs, Vec<Dim, T> rhs) noexcept
1022{
1023 std::ranges::transform(rhs, rhs.begin(), [lhs](T v) { return lhs >> v; });
1024 return rhs;
1025}
1026
1027/**************************************************************************************
1028| |
1029| Functions |
1030| |
1031**************************************************************************************/
1032
1041template <class T, std::size_t Dim, class U>
1042[[nodiscard]] constexpr Vec<Dim, T> cast(Vec<Dim, U> const& v) noexcept
1043{
1044 return Vec<Dim, T>(v);
1045}
1046
1058template <class To, std::size_t Dim, class U>
1059[[nodiscard]] constexpr To convert(Vec<Dim, U> const& v) noexcept
1060{
1061 using T = typename To::value_type;
1062 To res{};
1063 std::size_t const D = std::min(res.size(), v.size());
1064 for (std::size_t i{}; D > i; ++i) {
1065 res[i] = static_cast<T>(v[i]);
1066 }
1067 return res;
1068}
1069
1078template <std::size_t Dim, class T>
1079[[nodiscard]] constexpr T dot(Vec<Dim, T> const& a, Vec<Dim, T> const& b) noexcept
1080{
1081#if defined(__cpp_lib_ranges_zip) && defined(__cpp_lib_fold_left)
1082 return std::ranges::fold_left(std::views::zip_transform(std::multiplies{}, a, b), T{},
1083 std::plus{});
1084#else
1085 T res{};
1086 for (std::size_t i{}; Dim > i; ++i) {
1087 res += a[i] * b[i];
1088 }
1089 return res;
1090#endif
1091}
1092
1100template <std::size_t Dim, std::floating_point T>
1101[[nodiscard]] constexpr T length(Vec<Dim, T> const& v) noexcept
1102{
1103 return std::sqrt(dot(v, v));
1104}
1105
1114template <std::size_t Dim, class T>
1115 requires std::floating_point<T>
1116[[nodiscard]] constexpr T distance(Vec<Dim, T> const& a, Vec<Dim, T> const& b) noexcept
1117{
1118 return length(a - b);
1119}
1120
1131template <std::size_t Dim, class T>
1132[[nodiscard]] constexpr T distanceSquared(Vec<Dim, T> const& a,
1133 Vec<Dim, T> const& b) noexcept
1134{
1135 return dot(a - b, a - b);
1136}
1137
1147template <std::size_t Dim, std::floating_point T>
1148[[nodiscard]] constexpr Vec<Dim, T> normalize(Vec<Dim, T> const& v) noexcept
1149{
1150 return v / length(v);
1151}
1152
1161template <std::size_t Dim, class T>
1162[[nodiscard]] constexpr bool isNormalized(Vec<Dim, T> const& v) noexcept
1163{
1164 if constexpr (std::floating_point<T>) {
1165 return std::abs(dot(v, v) - T(1)) <= std::numeric_limits<T>::epsilon() * T(8);
1166 } else {
1167 return dot(v, v) == T(1);
1168 }
1169}
1170
1178template <class T>
1179[[nodiscard]] constexpr Vec<3, T> cross(Vec<3, T> const& a, Vec<3, T> const& b) noexcept
1180{
1181 return Vec<3, T>{(a[1] * b[2]) - (a[2] * b[1]), (a[2] * b[0]) - (a[0] * b[2]),
1182 (a[0] * b[1]) - (a[1] * b[0])};
1183}
1184
1193template <std::size_t Dim, std::floating_point T>
1194[[nodiscard]] constexpr Vec<Dim, T> reflect(Vec<Dim, T> const& v,
1195 Vec<Dim, T> const& n) noexcept
1196{
1197 return v - T(2) * dot(v, n) * n;
1198}
1199
1209template <std::size_t Dim, std::floating_point T>
1210[[nodiscard]] constexpr Vec<Dim, T> refract(Vec<Dim, T> const& v, Vec<Dim, T> const& n,
1211 T eta) noexcept
1212{
1213 assert(isNormalized(v) && isNormalized(n) && "Input vectors should be normalized");
1214 Vec<Dim, T> tmp = dot(v, n);
1215 Vec<Dim, T> k = T(1) - eta * eta * (T(1) - tmp * tmp);
1216 return k < T(0) ? Vec<Dim, T>{} : eta * v - (eta * tmp + sqrt(k)) * n;
1217}
1218
1227template <std::size_t Dim, class T>
1228[[nodiscard]] constexpr Vec<Dim, T> min(Vec<Dim, T> v1, Vec<Dim, T> const& v2) noexcept
1229{
1230 std::ranges::transform(v1, v2, v1.begin(), [](T a, T b) { return std::min(a, b); });
1231 return v1;
1232}
1233
1241template <std::size_t Dim, class T>
1242[[nodiscard]] constexpr T min(Vec<Dim, T> const& v) noexcept
1243{
1244 return *std::ranges::min_element(v);
1245}
1246
1255template <std::size_t Dim, class T>
1256[[nodiscard]] constexpr Vec<Dim, T> max(Vec<Dim, T> v1, Vec<Dim, T> const& v2) noexcept
1257{
1258 std::ranges::transform(v1, v2, v1.begin(), [](T a, T b) { return std::max(a, b); });
1259 return v1;
1260}
1261
1269template <std::size_t Dim, class T>
1270[[nodiscard]] constexpr T max(Vec<Dim, T> const& v) noexcept
1271{
1272 return *std::ranges::max_element(v);
1273}
1274
1282template <std::size_t Dim, class T>
1283[[nodiscard]] constexpr std::size_t minIndex(Vec<Dim, T> const& v) noexcept
1284{
1285 return static_cast<std::size_t>(std::ranges::min_element(v) - v.begin());
1286}
1287
1295template <std::size_t Dim, class T>
1296[[nodiscard]] constexpr std::size_t maxIndex(Vec<Dim, T> const& v) noexcept
1297{
1298 return static_cast<std::size_t>(std::ranges::max_element(v) - v.begin());
1299}
1300
1308template <std::size_t Dim, class T>
1309[[nodiscard]] constexpr T sum(Vec<Dim, T> const& v) noexcept
1310{
1311#ifdef __cpp_lib_fold_left
1312 return std::ranges::fold_left(v, T{}, std::plus{});
1313#else
1314 T res{};
1315 for (auto x : v) {
1316 res += x;
1317 }
1318 return res;
1319#endif
1320}
1321
1329template <std::size_t Dim, class T>
1330[[nodiscard]] constexpr T product(Vec<Dim, T> const& v) noexcept
1331{
1332#ifdef __cpp_lib_fold_left
1333 return std::ranges::fold_left(v, T{1}, std::multiplies{});
1334#else
1335 T res{1};
1336 for (auto x : v) {
1337 res *= x;
1338 }
1339 return res;
1340#endif
1341}
1342
1350template <std::size_t Dim, class T>
1351[[nodiscard]] constexpr Vec<Dim, T> abs(Vec<Dim, T> v) noexcept
1352{
1353 std::ranges::transform(v, v.begin(), [](T x) { return std::abs(x); });
1354 return v;
1355}
1356
1366template <std::size_t Dim, class T>
1367[[nodiscard]] constexpr Vec<Dim, T> clamp(Vec<Dim, T> v, Vec<Dim, T> const& lo,
1368 Vec<Dim, T> const& hi) noexcept
1369{
1370#ifdef __cpp_lib_ranges_zip
1371 for (auto [vi, li, hi_i] : std::views::zip(v, lo, hi)) {
1372 vi = std::clamp(vi, li, hi_i);
1373 }
1374#else
1375 for (std::size_t i{}; Dim > i; ++i) {
1376 v[i] = std::clamp(v[i], lo[i], hi[i]);
1377 }
1378#endif
1379 return v;
1380}
1381
1389template <std::size_t Dim, std::floating_point T>
1390[[nodiscard]] constexpr Vec<Dim, T> ceil(Vec<Dim, T> v) noexcept
1391{
1392 std::ranges::transform(v, v.begin(), [](T x) { return std::ceil(x); });
1393 return v;
1394}
1395
1403template <std::size_t Dim, std::floating_point T>
1404[[nodiscard]] constexpr Vec<Dim, T> floor(Vec<Dim, T> v) noexcept
1405{
1406 std::ranges::transform(v, v.begin(), [](T x) { return std::floor(x); });
1407 return v;
1408}
1409
1417template <std::size_t Dim, std::floating_point T>
1418[[nodiscard]] constexpr Vec<Dim, T> trunc(Vec<Dim, T> v) noexcept
1419{
1420 std::ranges::transform(v, v.begin(), [](T x) { return std::trunc(x); });
1421 return v;
1422}
1423
1432template <std::size_t Dim, std::floating_point T>
1433[[nodiscard]] constexpr Vec<Dim, T> round(Vec<Dim, T> v) noexcept
1434{
1435 std::ranges::transform(v, v.begin(), [](T x) { return std::round(x); });
1436 return v;
1437}
1438
1447template <std::size_t Dim, class T>
1448[[nodiscard]] constexpr Vec<Dim, bool> equal(Vec<Dim, T> const& v1,
1449 Vec<Dim, T> const& v2) noexcept
1450{
1451 Vec<Dim, bool> res;
1452 std::ranges::transform(v1, v2, res.begin(), std::equal_to{});
1453 return res;
1454}
1455
1464template <std::size_t Dim, class T>
1465[[nodiscard]] constexpr Vec<Dim, bool> notEqual(Vec<Dim, T> const& v1,
1466 Vec<Dim, T> const& v2) noexcept
1467{
1468 Vec<Dim, bool> res;
1469 std::ranges::transform(v1, v2, res.begin(), std::not_equal_to{});
1470 return res;
1471}
1472
1481template <std::size_t Dim, class T>
1482[[nodiscard]] constexpr Vec<Dim, bool> less(Vec<Dim, T> const& v1,
1483 Vec<Dim, T> const& v2) noexcept
1484{
1485 Vec<Dim, bool> res;
1486 std::ranges::transform(v1, v2, res.begin(), std::less{});
1487 return res;
1488}
1489
1498template <std::size_t Dim, class T>
1499[[nodiscard]] constexpr Vec<Dim, bool> lessEqual(Vec<Dim, T> const& v1,
1500 Vec<Dim, T> const& v2) noexcept
1501{
1502 Vec<Dim, bool> res;
1503 std::ranges::transform(v1, v2, res.begin(), std::less_equal{});
1504 return res;
1505}
1506
1515template <std::size_t Dim, class T>
1516[[nodiscard]] constexpr Vec<Dim, bool> greater(Vec<Dim, T> const& v1,
1517 Vec<Dim, T> const& v2) noexcept
1518{
1519 Vec<Dim, bool> res;
1520 std::ranges::transform(v1, v2, res.begin(), std::greater{});
1521 return res;
1522}
1523
1532template <std::size_t Dim, class T>
1533[[nodiscard]] constexpr Vec<Dim, bool> greaterEqual(Vec<Dim, T> const& v1,
1534 Vec<Dim, T> const& v2) noexcept
1535{
1536 Vec<Dim, bool> res;
1537 std::ranges::transform(v1, v2, res.begin(), std::greater_equal{});
1538 return res;
1539}
1540
1547template <std::size_t Dim>
1548[[nodiscard]] constexpr bool all(Vec<Dim, bool> const& v) noexcept
1549{
1550 return std::ranges::all_of(v, std::identity{});
1551}
1552
1559template <std::size_t Dim>
1560[[nodiscard]] constexpr bool any(Vec<Dim, bool> const& v) noexcept
1561{
1562 return std::ranges::any_of(v, std::identity{});
1563}
1564
1571template <std::size_t Dim>
1572[[nodiscard]] constexpr bool some(Vec<Dim, bool> const& v) noexcept
1573{
1574 return any(v) && !all(v);
1575}
1576
1583template <std::size_t Dim>
1584[[nodiscard]] constexpr bool none(Vec<Dim, bool> const& v) noexcept
1585{
1586 return std::ranges::none_of(v, std::identity{});
1587}
1588
1596template <std::size_t Dim, std::floating_point T>
1597[[nodiscard]] constexpr bool isnan(Vec<Dim, T> const& v) noexcept
1598{
1599 return std::ranges::any_of(v, [](T x) { return std::isnan(x); });
1600}
1601
1609template <std::size_t Dim, std::floating_point T>
1610[[nodiscard]] constexpr bool isfinite(Vec<Dim, T> const& v) noexcept
1611{
1612 return std::ranges::all_of(v, [](T x) { return std::isfinite(x); });
1613}
1614
1623template <std::size_t Dim, std::floating_point T>
1624[[nodiscard]] constexpr bool isnormal(Vec<Dim, T> const& v) noexcept
1625{
1626 return std::ranges::all_of(v, [](T x) { return std::isnormal(x); });
1627}
1628
1638template <std::size_t Dim, std::floating_point T>
1639[[nodiscard]] constexpr Vec<Dim, T> lerp(Vec<Dim, T> a, Vec<Dim, T> const& b,
1640 T t) noexcept
1641{
1642 std::ranges::transform(a, b, a.begin(), [t](T x, T y) { return std::lerp(x, y, t); });
1643 return a;
1644}
1645
1656template <std::size_t Dim, class T, class U>
1657[[nodiscard]] constexpr Vec<Dim, T> mix(Vec<Dim, T> const& x, Vec<Dim, T> const& y,
1658 Vec<Dim, U> const& a) noexcept
1659{
1660 return Vec<Dim, T>(Vec<Dim, U>(x) * (U{1} - a) + Vec<Dim, U>(y) * a);
1661}
1662
1672template <std::size_t Dim, class T>
1673[[nodiscard]] constexpr Vec<Dim, T> mix(Vec<Dim, T> const& x, Vec<Dim, T> const& y,
1674 Vec<Dim, bool> const& a) noexcept
1675{
1676 Vec<Dim, T> res;
1677 for (auto [ri, xi, yi, ai] : std::views::zip(res, x, y, a)) {
1678 ri = ai ? yi : xi;
1679 }
1680 return res;
1681}
1682
1690template <std::size_t Dim, class T>
1691[[nodiscard]] constexpr Vec<Dim, T> sign(Vec<Dim, T> const& x) noexcept
1692{
1693 Vec<Dim, T> res;
1694 std::ranges::transform(x, res.begin(), [](T v) { return static_cast<T>(sign(v)); });
1695 return res;
1696}
1697
1706template <std::size_t Dim, std::floating_point T>
1707[[nodiscard]] constexpr Vec<Dim, T> ldexp(Vec<Dim, T> v, int exp) noexcept
1708{
1709 std::ranges::transform(v, v.begin(), [exp](T x) { return std::ldexp(x, exp); });
1710 return v;
1711}
1712
1713/**************************************************************************************
1714| |
1715| Structured bindings |
1716| |
1717**************************************************************************************/
1718
1727template <std::size_t I, std::size_t Dim, class T>
1728 requires(I < Dim)
1729[[nodiscard]] constexpr T& get(Vec<Dim, T>& v) noexcept
1730{
1731 return v[I];
1732}
1733
1742template <std::size_t I, std::size_t Dim, class T>
1743 requires(I < Dim)
1744[[nodiscard]] constexpr T const& get(Vec<Dim, T> const& v) noexcept
1745{
1746 return v[I];
1747}
1748
1757template <std::size_t I, std::size_t Dim, class T>
1758 requires(I < Dim)
1759[[nodiscard]] constexpr T&& get(Vec<Dim, T>&& v) noexcept
1760{
1761 return std::move(v[I]);
1762}
1763
1764/**************************************************************************************
1765| |
1766| Print |
1767| |
1768**************************************************************************************/
1769
1782template <std::size_t Dim, class T>
1783std::ostream& operator<<(std::ostream& out, Vec<Dim, T> const& v)
1784{
1785 static constexpr std::array names = {'x', 'y', 'z', 'w'};
1786#ifdef __cpp_lib_ranges_enumerate
1787 for (auto const [i, name] : std::views::enumerate(names)) {
1788 if (i) out << ' ';
1789 out << name << ": " << v[i];
1790 }
1791#else
1792 for (std::size_t i{}; std::min(Dim, names.size()) > i; ++i) {
1793 if (i) out << ' ';
1794 out << names[i] << ": " << v[i];
1795 }
1796#endif
1797 return out;
1798}
1799} // namespace ufo
1800
1801template <std::size_t Dim, class T>
1802struct std::tuple_size<ufo::Vec<Dim, T>> : std::integral_constant<std::size_t, Dim> {
1803};
1804
1805template <std::size_t I, std::size_t Dim, class T>
1806struct std::tuple_element<I, ufo::Vec<Dim, T>> {
1807 using type = T;
1808};
1809
1810template <std::size_t Dim, class T>
1811 requires std::formattable<T, char>
1812struct std::formatter<ufo::Vec<Dim, T>> {
1813 constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
1814
1815 auto format(ufo::Vec<Dim, T> const& v, std::format_context& ctx) const
1816 {
1817 static constexpr std::array names = {'x', 'y', 'z', 'w'};
1818 auto out = ctx.out();
1819#ifdef __cpp_lib_ranges_enumerate
1820 for (auto const [i, name] : std::views::enumerate(names)) {
1821 if (i) out = std::format_to(out, " ");
1822 out = std::format_to(out, "{}: {}", name, v[i]);
1823 }
1824#else
1825 for (std::size_t i{}; std::min(Dim, names.size()) > i; ++i) {
1826 if (i) out = std::format_to(out, " ");
1827 out = std::format_to(out, "{}: {}", names[i], v[i]);
1828 }
1829#endif
1830 return out;
1831 }
1832};
1833
1838#endif // UFO_NUMERIC_VEC_HPP
constexpr Vec< Dim, T > cast(Vec< Dim, U > const &v) noexcept
Casts each element of a vector to a new type.
Definition vec.hpp:1042
constexpr int sign(T val) noexcept
Returns the sign of a value.
Definition math.hpp:70
Vec< 4, bool > isnan(Quat< T > const &q) noexcept
Returns a bool vector indicating which components are NaN.
Definition quat.hpp:1010
constexpr Vec & operator+=(Vec const &rhs) noexcept
Adds each component of rhs to the corresponding component.
Definition vec.hpp:255
constexpr Vec operator+() const noexcept
Unary identity operator.
Definition vec.hpp:219
constexpr auto & operator[](this auto &self, size_type i) noexcept
Accesses the element at index i.
Definition vec.hpp:127
Quat< T > mix(Quat< T > const &x, Quat< T > const &y, T a)
Spherical or linear interpolation between two quaternions.
Definition quat.hpp:746
constexpr Vec< Cols, T > & get(Mat< Rows, Cols, T > &m) noexcept
Structured-binding accessor — lvalue reference to row I.
Definition mat.hpp:1586
constexpr Vec & operator+=(T rhs) noexcept
Adds scalar rhs to every component.
Definition vec.hpp:383
constexpr T dot(Quat< T > const &a, Quat< T > const &b) noexcept
Computes the four-component dot product a.w*b.w + a.x*b.x + a.y*b.y + a.z*b.z.
Definition quat.hpp:643
STL namespace.
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr Vec< Dim, T > ldexp(Vec< Dim, T > v, int exp) noexcept
Multiplies each component of a floating-point vector by 2^exp.
Definition vec.hpp:1707
constexpr Vec< Dim, T > floor(Vec< Dim, T > v) noexcept
Returns the component-wise floor of a floating-point vector.
Definition vec.hpp:1404
constexpr Vec< Dim, T > trunc(Vec< Dim, T > v) noexcept
Returns the component-wise truncation toward zero of a floating-point vector.
Definition vec.hpp:1418
constexpr T b(Lab< T, Flags > color) noexcept
Returns the un-weighted blue–yellow axis value.
Definition lab.hpp:326
constexpr Vec< Dim, T > operator%(Vec< Dim, T > lhs, Vec< Dim, T > const &rhs) noexcept
Component-wise modulo of two integral vectors.
Definition vec.hpp:602
constexpr bool isnormal(Vec< Dim, T > const &v) noexcept
Returns true if all components of a floating-point vector are normal.
Definition vec.hpp:1624
constexpr Vec< Dim, bool > notEqual(Vec< Dim, T > const &v1, Vec< Dim, T > const &v2) noexcept
Returns a bool vector indicating component-wise inequality.
Definition vec.hpp:1465
constexpr bool any(Vec< Dim, bool > const &v) noexcept
Returns true if at least one component of a bool vector is true.
Definition vec.hpp:1560
constexpr Mat< Rows, Cols, T > operator*(Mat< Rows, Cols, T > lhs, T rhs) noexcept
Multiplies every element of lhs by scalar rhs.
Definition mat.hpp:863
constexpr Vec< Dim, T > ceil(Vec< Dim, T > v) noexcept
Returns the component-wise ceiling of a floating-point vector.
Definition vec.hpp:1390
constexpr Mat< Rows, Cols, T > operator/(Mat< Rows, Cols, T > lhs, T rhs) noexcept
Divides every element of lhs by scalar rhs.
Definition mat.hpp:880
constexpr Vec< Dim, T > reflect(Vec< Dim, T > const &v, Vec< Dim, T > const &n) noexcept
Reflects an incident vector about a surface normal.
Definition vec.hpp:1194
constexpr T a(Lab< T, Flags > color) noexcept
Returns the un-weighted green–red axis value.
Definition lab.hpp:310
constexpr std::size_t maxIndex(Vec< Dim, T > const &v) noexcept
Returns the index of the largest element in a vector.
Definition vec.hpp:1296
constexpr bool some(Vec< Dim, bool > const &v) noexcept
Returns true if some but not all components of a bool vector are true.
Definition vec.hpp:1572
constexpr Vec< Dim, T > round(Vec< Dim, T > v) noexcept
Returns the component-wise rounding to nearest integer of a floating-point vector.
Definition vec.hpp:1433
constexpr auto distanceSquared(A const &a, B const &b)
Computes the minimum squared distance between two shapes.
Definition distance.hpp:80
constexpr Vec< Dim, bool > greater(Vec< Dim, T > const &v1, Vec< Dim, T > const &v2) noexcept
Returns a bool vector indicating component-wise greater-than.
Definition vec.hpp:1516
constexpr T length(Vec< Dim, T > const &v) noexcept
Computes the Euclidean length (magnitude) of a vector.
Definition vec.hpp:1101
constexpr Vec< Dim, bool > less(Vec< Dim, T > const &v1, Vec< Dim, T > const &v2) noexcept
Returns a bool vector indicating component-wise less-than.
Definition vec.hpp:1482
constexpr Vec< Geometry::dimension(), typename Geometry::value_type > max(Geometry const &g)
Returns the maximum coordinate of the minimum spanning axis-aligned bounding box of a geometry.
Definition fun.hpp:72
constexpr Vec< Dim, bool > operator||(Vec< Dim, bool > lhs, Vec< Dim, bool > const &rhs) noexcept
Component-wise logical OR of two bool vectors.
Definition vec.hpp:712
constexpr Quat< T > normalize(Quat< T > const &q) noexcept
Returns a unit quaternion in the same direction as q.
Definition quat.hpp:679
constexpr Vec< Dim, bool > greaterEqual(Vec< Dim, T > const &v1, Vec< Dim, T > const &v2) noexcept
Returns a bool vector indicating component-wise greater-than-or-equal.
Definition vec.hpp:1533
constexpr Vec< Dim, T > abs(Vec< Dim, T > v) noexcept
Returns the component-wise absolute value of a vector.
Definition vec.hpp:1351
constexpr bool all(Vec< Dim, bool > const &v) noexcept
Returns true if all components of a bool vector are true.
Definition vec.hpp:1548
constexpr Vec< Dim, T > refract(Vec< Dim, T > const &v, Vec< Dim, T > const &n, T eta) noexcept
Computes the refraction vector for an incident ray entering a new medium.
Definition vec.hpp:1210
constexpr T product(Vec< Dim, T > const &v) noexcept
Computes the product of all elements in a vector.
Definition vec.hpp:1330
constexpr To convert(Vec< Dim, U > const &v) noexcept
Converts a vector to a different Vec type, truncating or zero-padding dimensions.
Definition vec.hpp:1059
constexpr Quat< T > cross(Quat< T > const &q1, Quat< T > const &q2) noexcept
Computes the Hamilton cross product of two quaternions.
Definition quat.hpp:721
constexpr Quat< T > lerp(Quat< T > const &x, Quat< T > const &y, T a) noexcept
Normalised linear interpolation (NLERP) between two quaternions.
Definition quat.hpp:770
constexpr Vec< Dim, T > clamp(Vec< Dim, T > v, Vec< Dim, T > const &lo, Vec< Dim, T > const &hi) noexcept
Clamps each component of a vector to the range [lo[i], hi[i]].
Definition vec.hpp:1367
constexpr bool isNormalized(Vec< Dim, T > const &v) noexcept
Checks whether a vector has unit length.
Definition vec.hpp:1162
constexpr Vec< Dim, bool > operator&&(Vec< Dim, bool > lhs, Vec< Dim, bool > const &rhs) noexcept
Component-wise logical AND of two bool vectors.
Definition vec.hpp:697
constexpr Vec< Dim, bool > lessEqual(Vec< Dim, T > const &v1, Vec< Dim, T > const &v2) noexcept
Returns a bool vector indicating component-wise less-than-or-equal.
Definition vec.hpp:1499
constexpr Vec< Dim, T > operator^(Vec< Dim, T > lhs, Vec< Dim, T > const &rhs) noexcept
Component-wise bitwise XOR of two integral vectors.
Definition vec.hpp:650
constexpr Vec< Geometry::dimension(), typename Geometry::value_type > min(Geometry const &g)
Returns the minimum coordinate of the minimum spanning axis-aligned bounding box of a geometry.
Definition fun.hpp:58
constexpr bool isfinite(Vec< Dim, T > const &v) noexcept
Returns true if all components of a floating-point vector are finite.
Definition vec.hpp:1610
constexpr std::size_t minIndex(Vec< Dim, T > const &v) noexcept
Returns the index of the smallest element in a vector.
Definition vec.hpp:1283
constexpr bool none(Vec< Dim, bool > const &v) noexcept
Returns true if no component of a bool vector is true.
Definition vec.hpp:1584
constexpr Vec< Dim, bool > equal(Vec< Dim, T > const &v1, Vec< Dim, T > const &v2) noexcept
Returns a bool vector indicating component-wise equality.
Definition vec.hpp:1448
constexpr T sum(Vec< Dim, T > const &v) noexcept
Computes the sum of all elements in a vector.
Definition vec.hpp:1309
constexpr auto distance(A const &a, B const &b)
Computes the minimum distance between two shapes.
Definition distance.hpp:61
A fixed-size arithmetic vector of up to 4 dimensions.
Definition vec.hpp:76
constexpr Vec & operator%=(T rhs) noexcept
Computes the remainder of every component divided by scalar rhs (integral types only).
Definition vec.hpp:428
constexpr Vec & operator%=(Vec const &rhs) noexcept
Computes the remainder of each component divided by the corresponding component of rhs (integral type...
Definition vec.hpp:300
constexpr Vec & operator-=(Vec const &rhs) noexcept
Subtracts each component of rhs from the corresponding component.
Definition vec.hpp:266
constexpr Vec & operator-=(T rhs) noexcept
Subtracts scalar rhs from every component.
Definition vec.hpp:394
constexpr auto & y(this auto &self) noexcept
Accesses the second component (y).
Definition vec.hpp:146
constexpr Vec & operator|=(Vec const &rhs) noexcept
Bitwise ORs each component with the corresponding component of rhs (integral types only).
Definition vec.hpp:326
constexpr Vec & operator/=(T rhs) noexcept
Divides every component by scalar rhs.
Definition vec.hpp:416
constexpr Vec & operator&=(T rhs) noexcept
Bitwise ANDs every component with scalar rhs (integral types only).
Definition vec.hpp:440
constexpr Vec & operator|=(T rhs) noexcept
Bitwise ORs every component with scalar rhs (integral types only).
Definition vec.hpp:452
constexpr Vec & operator<<=(T rhs) noexcept
Left-shifts every component by scalar rhs (integral types only).
Definition vec.hpp:476
static constexpr std::size_t size() noexcept
Returns the number of dimensions.
Definition vec.hpp:200
constexpr Vec & operator&=(Vec const &rhs) noexcept
Bitwise ANDs each component with the corresponding component of rhs (integral types only).
Definition vec.hpp:313
constexpr auto & z(this auto &self) noexcept
Accesses the third component (z).
Definition vec.hpp:156
constexpr auto end(this auto &self) noexcept
Returns a past-the-end iterator.
Definition vec.hpp:185
constexpr bool operator==(Vec const &) const =default
Compares two vectors for equality (component-wise).
constexpr auto & x(this auto &self) noexcept
Accesses the first component (x).
Definition vec.hpp:136
constexpr Vec & operator>>=(Vec const &rhs) noexcept
Right-shifts each component by the corresponding component of rhs (integral types only).
Definition vec.hpp:365
constexpr Vec & operator*=(Vec const &rhs) noexcept
Multiplies each component by the corresponding component of rhs.
Definition vec.hpp:277
constexpr auto & w(this auto &self) noexcept
Accesses the fourth component (w).
Definition vec.hpp:166
constexpr Vec & operator/=(Vec const &rhs) noexcept
Divides each component by the corresponding component of rhs.
Definition vec.hpp:288
constexpr Vec & operator^=(Vec const &rhs) noexcept
Bitwise XORs each component with the corresponding component of rhs (integral types only).
Definition vec.hpp:339
constexpr Vec & operator*=(T rhs) noexcept
Multiplies every component by scalar rhs.
Definition vec.hpp:405
constexpr Vec operator-() const noexcept
Unary negation operator.
Definition vec.hpp:225
constexpr Vec & operator>>=(T rhs) noexcept
Right-shifts every component by scalar rhs (integral types only).
Definition vec.hpp:488
constexpr Vec & operator<<=(Vec const &rhs) noexcept
Left-shifts each component by the corresponding component of rhs (integral types only).
Definition vec.hpp:352
constexpr auto data(this auto &self) noexcept
Returns a pointer to the underlying element array.
Definition vec.hpp:191
constexpr Vec & operator^=(T rhs) noexcept
Bitwise XORs every component with scalar rhs (integral types only).
Definition vec.hpp:464
constexpr Vec() noexcept=default
Default constructor; initializes all elements to zero.
constexpr auto begin(this auto &self) noexcept
Returns an iterator to the first element.
Definition vec.hpp:176
constexpr Vec operator~() const noexcept
Bitwise NOT operator (integral types only).
Definition vec.hpp:236