Fx2D
A C++20 2D rigid-body physics engine
Loading...
Searching...
No Matches
Math.h
Go to the documentation of this file.
1#pragma once
2#include <Eigen/Core>
3#include <algorithm>
4#include <concepts>
5#include <cstdint>
6#include <initializer_list>
7#include <iostream>
8#include <memory>
9#include <numbers>
10#include <stdexcept>
11#include <string>
12#include <type_traits>
13#include <vector>
14
15// Constant representing positive infinity
16static constexpr float FxInfinityf = std::numeric_limits<float>::infinity();
17static constexpr double FxInfinityd = std::numeric_limits<double>::infinity();
18
19// Constant representing pi
20static constexpr float FxPif = std::numbers::pi_v<float>;
21static constexpr double FxPid = std::numbers::pi_v<double>;
22
23// Wrap into [-pi, pi). In-range values pass through untouched (avoids float floor near pi).
24static inline float FxAngleWrap(float angle) {
25 if (angle >= -FxPif && angle < FxPif) return angle;
26 angle = std::fmod(angle + FxPif, 2.0f * FxPif);
27 if (angle < 0.0f) angle += 2.0f * FxPif;
28 return angle - FxPif;
29}
30
31// Add inc to a float accumulator in double, keeping whatever did not survive the rounding in
32// carry so the next call folds it back in. Returns the delta that actually landed.
33static inline float FxCarryAdd(float& dst, double inc, double& carry) {
34 double s = (double)dst + inc + carry;
35 float f = (float)s;
36 carry = s - (double)f;
37 float d = f - dst;
38 dst = f;
39 return d;
40}
41
42// concept to capture float, double, long double, int etc..
43template<typename T>
44concept Numeric = std::integral<T> || std::floating_point<T>;
45
46// Custom 2D float vector with .x() getter and .set_x() setter.
47class FxVec2f : public Eigen::Vector2f {
48 public:
49 // Inherit constructors
50 using Eigen::Vector2f::Vector2f;
51
52 // Constructor from single float (fills both components)
53 explicit FxVec2f(float a) : Eigen::Vector2f(a, a) {}
54
55 // Getter for x and y.
56 float& x() { return (*this)(0); }
57 float& y() { return (*this)(1); }
58
59 // Const getters.
60 float x() const { return (*this)(0); }
61 float y() const { return (*this)(1); }
62
63 // Setter for x and y.
64 void set_x(float val) { (*this)(0) = val; }
65 void set_y(float val) { (*this)(1) = val; }
66
67 // Radian‐based rotate (suffix "_rad")
68 FxVec2f& rotate_inplace_rad(float theta) noexcept {
69 const float c = std::cos(theta), s = std::sin(theta);
70 float xi = x(), yi = y();
71 set_x(xi * c - yi * s);
72 set_y(xi * s + yi * c);
73 return *this;
74 }
75
76 // Degree‐based rotate (default "rotate_inplace" uses degrees)
77 FxVec2f& rotate_inplace(float degrees) noexcept {
78 constexpr float FX_DEG2RAD = FxPif / 180.0f;
79 return rotate_inplace_rad(degrees * FX_DEG2RAD);
80 }
81
82 // — non-mutating rotation: returns a rotated copy
83 FxVec2f rotate(float theta) const noexcept { return FxVec2f(*this).rotate_inplace(theta); }
84 FxVec2f rotate_rad(float theta) const noexcept {
85 return FxVec2f(*this).rotate_inplace_rad(theta);
86 }
87
88 // Cross product with another 2D vector (returns scalar)
89 float cross(const FxVec2f& other) const { return x() * other.y() - y() * other.x(); }
90
91 // Perpendicular vectors
92 FxVec2f perp() const {
93 return FxVec2f(-y(), x()); // CCW perpendicular
94 }
95
96 FxVec2f perpCW() const {
97 return FxVec2f(y(), -x()); // CW perpendicular
98 }
99};
100
101// Custom 2D double vector with .x() getter and .set_x() setter.
102class FxVec2d : public Eigen::Vector2d {
103 public:
104 // Inherit constructors
105 using Eigen::Vector2d::Vector2d;
106
107 // Constructor from single double (fills both components)
108 explicit FxVec2d(double a) : Eigen::Vector2d(a, a) {}
109
110 // Getter for x and y.
111 double& x() { return (*this)(0); }
112 double& y() { return (*this)(1); }
113
114 // Const getters.
115 double x() const { return (*this)(0); }
116 double y() const { return (*this)(1); }
117
118 // Setter for x and y.
119 void set_x(double val) { (*this)(0) = val; }
120 void set_y(double val) { (*this)(1) = val; }
121
122 // Radian‐based rotate (suffix "_rad")
123 FxVec2d& rotate_inplace_rad(double theta) noexcept {
124 const double c = std::cos(theta), s = std::sin(theta);
125 double xi = x(), yi = y();
126 set_x(xi * c - yi * s);
127 set_y(xi * s + yi * c);
128 return *this;
129 }
130
131 // Degree‐based rotate (default "rotate_inplace" uses degrees)
132 FxVec2d& rotate_inplace(double degrees) noexcept {
133 constexpr double FX_DEG2RAD = FxPid / 180.0;
134 return rotate_inplace_rad(degrees * FX_DEG2RAD);
135 }
136
137 // — non-mutating rotation: returns a rotated copy
138 FxVec2d rotate(double theta) const noexcept { return FxVec2d(*this).rotate_inplace(theta); }
139 FxVec2d rotate_rad(double theta) const noexcept {
140 return FxVec2d(*this).rotate_inplace_rad(theta);
141 }
142
143 // Cross product with another 2D vector (returns scalar)
144 double cross(const FxVec2d& other) const { return x() * other.y() - y() * other.x(); }
145
146 // Perpendicular vectors
147 FxVec2d perp() const {
148 return FxVec2d(-y(), x()); // CCW perpendicular
149 }
150
151 FxVec2d perpCW() const {
152 return FxVec2d(y(), -x()); // CW perpendicular
153 }
154};
155
156using FxVec2fMap = Eigen::Map<Eigen::Vector2f>;
157
158// Custom 3D float vector with .x(), .y(), .z() getters and corresponding setters.
159class FxVec3f : public Eigen::Vector3f {
160 public:
161 using Eigen::Vector3f::Vector3f;
162
163 // Constructor from single float (fills all components)
164 explicit FxVec3f(float a) : Eigen::Vector3f(a, a, a) {}
165
166 // Getters.
167 float& x() { return (*this)(0); }
168 float& y() { return (*this)(1); }
169 float& z() { return (*this)(2); }
170 // to use the third value as orientation
171 float& theta() { return (*this)(2); }
172
173 // Const getters.
174 float x() const { return (*this)(0); }
175 float y() const { return (*this)(1); }
176 float z() const { return (*this)(2); }
177 float theta() const { return (*this)(2); }
178
179 // Setters.
180 void set_x(float val) { (*this)(0) = val; }
181 void set_y(float val) { (*this)(1) = val; }
182 void set_z(float val) { (*this)(2) = val; }
183 // when used as orientation
184 void set_theta(float val) { (*this)(2) = val; }
185
186 FxVec2fMap xy() { return FxVec2fMap(this->data()); }
187 FxVec2f get_xy() const { return FxVec2f(this->data()); }
188 FxVec2f xy() const { return this->head<2>(); }
189 void set_xy(const FxVec2f& v2) { this->head<2>() = v2; }
190};
191
192using FxVec2dMap = Eigen::Map<Eigen::Vector2d>;
193
194// Custom 3D double vector with .x(), .y(), .z() getters and corresponding setters.
195class FxVec3d : public Eigen::Vector3d {
196 public:
197 using Eigen::Vector3d::Vector3d;
198
199 // Constructor from single double (fills all components)
200 explicit FxVec3d(double a) : Eigen::Vector3d(a, a, a) {}
201
202 // Getters.
203 double& x() { return (*this)(0); }
204 double& y() { return (*this)(1); }
205 double& z() { return (*this)(2); }
206 // to use the third value as orientation
207 double& theta() { return (*this)(2); }
208
209 // Const getters.
210 double x() const { return (*this)(0); }
211 double y() const { return (*this)(1); }
212 double z() const { return (*this)(2); }
213 double theta() const { return (*this)(2); }
214
215 // Setters.
216 void set_x(double val) { (*this)(0) = val; }
217 void set_y(double val) { (*this)(1) = val; }
218 void set_z(double val) { (*this)(2) = val; }
219 // when used as orientation
220 void set_theta(double val) { (*this)(2) = val; }
221
222 FxVec2dMap xy() { return FxVec2dMap(this->data()); }
223 FxVec2d get_xy() const { return FxVec2d(this->data()); }
224 FxVec2d xy() const { return this->head<2>(); }
225 void set_xy(const FxVec2d& v2) { this->head<2>() = v2; }
226};
227
228// Custom 4D float vector with .x(), .y(), .z(), .a() getters and corresponding setters.
229class FxVec4f : public Eigen::Vector4f {
230 public:
231 using Eigen::Vector4f::Vector4f;
232
233 // Constructor from single float (fills all components)
234 explicit FxVec4f(float a) : Eigen::Vector4f(a, a, a, a) {}
235
236 // Getters.
237 float& x() { return (*this)(0); }
238 float& y() { return (*this)(1); }
239 float& z() { return (*this)(2); }
240 float& a() { return (*this)(3); }
241
242 // Const getters.
243 float x() const { return (*this)(0); }
244 float y() const { return (*this)(1); }
245 float z() const { return (*this)(2); }
246 float a() const { return (*this)(3); }
247
248 // Setters.
249 void set_x(float val) { (*this)(0) = val; }
250 void set_y(float val) { (*this)(1) = val; }
251 void set_z(float val) { (*this)(2) = val; }
252 void set_a(float val) { (*this)(3) = val; }
253};
254
255// FxVec2f scalar operations with generic Numeric s
256template<Numeric S>
257inline FxVec2f operator*(FxVec2f const& v, S s) {
258 return FxVec2f(v.array() * static_cast<float>(s));
259}
260template<Numeric S>
261inline FxVec2f operator*(S s, FxVec2f const& v) {
262 return v * s;
263}
264template<Numeric S>
265inline FxVec2f operator/(FxVec2f const& v, S s) {
266 return FxVec2f(v.array() / static_cast<float>(s));
267}
268template<Numeric S>
269inline FxVec2f operator+(FxVec2f const& v, S s) {
270 return FxVec2f(v.array() + static_cast<float>(s));
271}
272template<Numeric S>
273inline FxVec2f operator+(S s, FxVec2f const& v) {
274 return v + s;
275}
276template<Numeric S>
277inline FxVec2f operator-(FxVec2f const& v, S s) {
278 return FxVec2f(v.array() - static_cast<float>(s));
279}
280template<Numeric S>
281inline FxVec2f operator-(S s, FxVec2f const& v) {
282 return FxVec2f((FxVec2f::Scalar(static_cast<float>(s)) * FxVec2f::Ones()).array() - v.array());
283}
284
285// FxVec3f scalar operations with generic Numeric s
286template<Numeric S>
287inline FxVec3f operator*(FxVec3f const& v, S s) {
288 return FxVec3f(v.array() * static_cast<float>(s));
289}
290template<Numeric S>
291inline FxVec3f operator*(S s, FxVec3f const& v) {
292 return v * s;
293}
294template<Numeric S>
295inline FxVec3f operator/(FxVec3f const& v, S s) {
296 return FxVec3f(v.array() / static_cast<float>(s));
297}
298template<Numeric S>
299inline FxVec3f operator+(FxVec3f const& v, S s) {
300 return FxVec3f(v.array() + static_cast<float>(s));
301}
302template<Numeric S>
303inline FxVec3f operator+(S s, FxVec3f const& v) {
304 return v + s;
305}
306template<Numeric S>
307inline FxVec3f operator-(FxVec3f const& v, S s) {
308 return FxVec3f(v.array() - static_cast<float>(s));
309}
310template<Numeric S>
311inline FxVec3f operator-(S s, FxVec3f const& v) {
312 return FxVec3f((FxVec3f::Scalar(static_cast<float>(s)) * FxVec3f::Ones()).array() - v.array());
313}
314
315// FxVec2d scalar operations with generic Numeric s
316template<Numeric S>
317inline FxVec2d operator*(FxVec2d const& v, S s) {
318 return FxVec2d(v.array() * static_cast<double>(s));
319}
320template<Numeric S>
321inline FxVec2d operator*(S s, FxVec2d const& v) {
322 return v * s;
323}
324template<Numeric S>
325inline FxVec2d operator/(FxVec2d const& v, S s) {
326 return FxVec2d(v.array() / static_cast<double>(s));
327}
328template<Numeric S>
329inline FxVec2d operator+(FxVec2d const& v, S s) {
330 return FxVec2d(v.array() + static_cast<double>(s));
331}
332template<Numeric S>
333inline FxVec2d operator+(S s, FxVec2d const& v) {
334 return v + s;
335}
336template<Numeric S>
337inline FxVec2d operator-(FxVec2d const& v, S s) {
338 return FxVec2d(v.array() - static_cast<double>(s));
339}
340template<Numeric S>
341inline FxVec2d operator-(S s, FxVec2d const& v) {
342 return FxVec2d((FxVec2d::Scalar(static_cast<double>(s)) * FxVec2d::Ones()).array() - v.array());
343}
344
345// FxVec3d scalar operations with generic Numeric s
346template<Numeric S>
347inline FxVec3d operator*(FxVec3d const& v, S s) {
348 return FxVec3d(v.array() * static_cast<double>(s));
349}
350template<Numeric S>
351inline FxVec3d operator*(S s, FxVec3d const& v) {
352 return v * s;
353}
354template<Numeric S>
355inline FxVec3d operator/(FxVec3d const& v, S s) {
356 return FxVec3d(v.array() / static_cast<double>(s));
357}
358template<Numeric S>
359inline FxVec3d operator+(FxVec3d const& v, S s) {
360 return FxVec3d(v.array() + static_cast<double>(s));
361}
362template<Numeric S>
363inline FxVec3d operator+(S s, FxVec3d const& v) {
364 return v + s;
365}
366template<Numeric S>
367inline FxVec3d operator-(FxVec3d const& v, S s) {
368 return FxVec3d(v.array() - static_cast<double>(s));
369}
370template<Numeric S>
371inline FxVec3d operator-(S s, FxVec3d const& v) {
372 return FxVec3d((FxVec3d::Scalar(static_cast<double>(s)) * FxVec3d::Ones()).array() - v.array());
373}
374
375// FxVec4f scalar operations with generic Numeric s
376template<Numeric S>
377inline FxVec4f operator*(FxVec4f const& v, S s) {
378 return FxVec4f(v.array() * static_cast<float>(s));
379}
380template<Numeric S>
381inline FxVec4f operator*(S s, FxVec4f const& v) {
382 return v * s;
383}
384template<Numeric S>
385inline FxVec4f operator/(FxVec4f const& v, S s) {
386 return FxVec4f(v.array() / static_cast<float>(s));
387}
388template<Numeric S>
389inline FxVec4f operator+(FxVec4f const& v, S s) {
390 return FxVec4f(v.array() + static_cast<float>(s));
391}
392template<Numeric S>
393inline FxVec4f operator+(S s, FxVec4f const& v) {
394 return v + s;
395}
396template<Numeric S>
397inline FxVec4f operator-(FxVec4f const& v, S s) {
398 return FxVec4f(v.array() - static_cast<float>(s));
399}
400template<Numeric S>
401inline FxVec4f operator-(S s, FxVec4f const& v) {
402 return FxVec4f((FxVec4f::Scalar(static_cast<float>(s)) * FxVec4f::Ones()).array() - v.array());
403}
404
405// FxVec2f in-place scalar operations
406template<Numeric S>
407inline FxVec2f& operator+=(FxVec2f& v, S s) {
408 v.array() += static_cast<float>(s);
409 return v;
410}
411template<Numeric S>
412inline FxVec2f& operator-=(FxVec2f& v, S s) {
413 v.array() -= static_cast<float>(s);
414 return v;
415}
416template<Numeric S>
417inline FxVec2f& operator*=(FxVec2f& v, S s) {
418 v.array() *= static_cast<float>(s);
419 return v;
420}
421template<Numeric S>
422inline FxVec2f& operator/=(FxVec2f& v, S s) {
423 v.array() /= static_cast<float>(s);
424 return v;
425}
426
427// FxVec3f in-place scalar operations
428template<Numeric S>
429inline FxVec3f& operator+=(FxVec3f& v, S s) {
430 v.array() += static_cast<float>(s);
431 return v;
432}
433template<Numeric S>
434inline FxVec3f& operator-=(FxVec3f& v, S s) {
435 v.array() -= static_cast<float>(s);
436 return v;
437}
438template<Numeric S>
439inline FxVec3f& operator*=(FxVec3f& v, S s) {
440 v.array() *= static_cast<float>(s);
441 return v;
442}
443template<Numeric S>
444inline FxVec3f& operator/=(FxVec3f& v, S s) {
445 v.array() /= static_cast<float>(s);
446 return v;
447}
448
449// FxVec4f in-place scalar operations
450template<Numeric S>
451inline FxVec4f& operator+=(FxVec4f& v, S s) {
452 v.array() += static_cast<float>(s);
453 return v;
454}
455template<Numeric S>
456inline FxVec4f& operator-=(FxVec4f& v, S s) {
457 v.array() -= static_cast<float>(s);
458 return v;
459}
460template<Numeric S>
461inline FxVec4f& operator*=(FxVec4f& v, S s) {
462 v.array() *= static_cast<float>(s);
463 return v;
464}
465template<Numeric S>
466inline FxVec4f& operator/=(FxVec4f& v, S s) {
467 v.array() /= static_cast<float>(s);
468 return v;
469}
470
471// free non-member operators
472inline FxVec2f& operator*=(FxVec2f& lhs, const FxVec2f& rhs) {
473 lhs.array() *= rhs.array();
474 return lhs;
475}
476inline FxVec2f& operator/=(FxVec2f& lhs, const FxVec2f& rhs) {
477 lhs.array() /= rhs.array();
478 return lhs;
479}
480inline FxVec2f& operator+=(FxVec2f& lhs, const FxVec2f& rhs) {
481 lhs.array() += rhs.array();
482 return lhs;
483}
484inline FxVec2f& operator-=(FxVec2f& lhs, const FxVec2f& rhs) {
485 lhs.array() -= rhs.array();
486 return lhs;
487}
488// FxVec2f scalar/vector division: s / v
489template<Numeric S>
490inline FxVec2f operator/(S s, FxVec2f const& v) {
491 return FxVec2f((FxVec2f::Scalar(static_cast<float>(s)) * FxVec2f::Ones()).array() / v.array());
492}
493
494// FxVec3f scalar/vector division: s / v
495template<Numeric S>
496inline FxVec3f operator/(S s, FxVec3f const& v) {
497 return FxVec3f((FxVec3f::Scalar(static_cast<float>(s)) * FxVec3f::Ones()).array() / v.array());
498}
499
500// FxVec4f scalar/vector division: s / v
501template<Numeric S>
502inline FxVec4f operator/(S s, FxVec4f const& v) {
503 return FxVec4f((FxVec4f::Scalar(static_cast<float>(s)) * FxVec4f::Ones()).array() / v.array());
504}
505
506// Custom 2D unsigned int vector with .x() getter and .set_x() setter.
507class FxVec2ui : public Eigen::Matrix<unsigned int, 2, 1> {
508 public:
509 using Base = Eigen::Matrix<unsigned int, 2, 1>;
510 using Base::Base;
511
512 unsigned int& x() { return (*this)(0); }
513 unsigned int& y() { return (*this)(1); }
514
515 // Const getters.
516 unsigned int x() const { return (*this)(0); }
517 unsigned int y() const { return (*this)(1); }
518
519 void set_x(unsigned int val) { (*this)(0) = val; }
520 void set_y(unsigned int val) { (*this)(1) = val; }
521};
522
523// And a 4D 8-bit unsigned integer vector.
524class FxVec4ui8 : public Eigen::Matrix<uint8_t, 4, 1> {
525 public:
526 using Base = Eigen::Matrix<uint8_t, 4, 1>;
527 using Base::Base;
528
529 uint8_t& x() { return (*this)(0); }
530 uint8_t& y() { return (*this)(1); }
531 uint8_t& z() { return (*this)(2); }
532 uint8_t& a() { return (*this)(3); }
533
534 // Const getters.
535 uint8_t x() const { return (*this)(0); }
536 uint8_t y() const { return (*this)(1); }
537 uint8_t z() const { return (*this)(2); }
538 uint8_t a() const { return (*this)(3); }
539
540 void set_x(uint8_t val) { (*this)(0) = val; }
541 void set_y(uint8_t val) { (*this)(1) = val; }
542 void set_z(uint8_t val) { (*this)(2) = val; }
543 void set_a(uint8_t val) { (*this)(3) = val; }
544};
545
546class FxMat2f : public Eigen::Matrix2f {
547 public:
548 using Eigen::Matrix2f::Matrix2f;
549
550 float& a() { return (*this)(0, 0); }
551 float& b() { return (*this)(0, 1); }
552 float& c() { return (*this)(1, 0); }
553 float& d() { return (*this)(1, 1); }
554
555 // Const getters.
556 float a() const { return (*this)(0, 0); }
557 float b() const { return (*this)(0, 1); }
558 float c() const { return (*this)(1, 0); }
559 float d() const { return (*this)(1, 1); }
560
561 void set_a(float val) { (*this)(0, 0) = val; }
562 void set_b(float val) { (*this)(0, 1) = val; }
563 void set_c(float val) { (*this)(1, 0) = val; }
564 void set_d(float val) { (*this)(1, 1) = val; }
565
566 // The inverse (transpose) of the rotation matrix.
567 FxMat2f inv_rotation() const { return this->transpose(); }
568};
569
570class FxMat3f : public Eigen::Matrix3f {
571 public:
572 using Eigen::Matrix3f::Matrix3f;
573
574 // Accessors for each element of the 3x3 matrix
575 // Row 0
576 float& a() { return (*this)(0, 0); }
577 float& b() { return (*this)(0, 1); }
578 float& c() { return (*this)(0, 2); }
579 // Row 1
580 float& d() { return (*this)(1, 0); }
581 float& e() { return (*this)(1, 1); }
582 float& f() { return (*this)(1, 2); }
583 // Row 2
584 float& g() { return (*this)(2, 0); }
585 float& h() { return (*this)(2, 1); }
586 float& i() { return (*this)(2, 2); }
587
588 // Const getters.
589 float a() const { return (*this)(0, 0); }
590 float b() const { return (*this)(0, 1); }
591 float c() const { return (*this)(0, 2); }
592 float d() const { return (*this)(1, 0); }
593 float e() const { return (*this)(1, 1); }
594 float f() const { return (*this)(1, 2); }
595 float g() const { return (*this)(2, 0); }
596 float h() const { return (*this)(2, 1); }
597 float i() const { return (*this)(2, 2); }
598
599 // Setters for each element of the 3x3 matrix
600 // Row 0
601 void set_a(float val) { (*this)(0, 0) = val; }
602 void set_b(float val) { (*this)(0, 1) = val; }
603 void set_c(float val) { (*this)(0, 2) = val; }
604 // Row 1
605 void set_d(float val) { (*this)(1, 0) = val; }
606 void set_e(float val) { (*this)(1, 1) = val; }
607 void set_f(float val) { (*this)(1, 2) = val; }
608 // Row 2
609 void set_g(float val) { (*this)(2, 0) = val; }
610 void set_h(float val) { (*this)(2, 1) = val; }
611 void set_i(float val) { (*this)(2, 2) = val; }
612
613 // Upper-left 2x2 rotation of a homogeneous transform [R t; 0 1].
614 FxMat2f Rot() const { return this->block<2, 2>(0, 0).eval(); }
615 // Extract the translation vector (first two elements of the third column) as an FxVec2f
616 FxVec2f t() const { return FxVec2f((*this)(0, 2), (*this)(1, 2)); }
617
618 // set the rotation part from an FxMat2f
619 void set_Rot(const FxMat2f& R) {
620 (*this)(0, 0) = R(0, 0);
621 (*this)(0, 1) = R(0, 1);
622 (*this)(1, 0) = R(1, 0);
623 (*this)(1, 1) = R(1, 1);
624 }
625
626 // set the translation part from an FxVec2f
627 void set_t(const FxVec2f& trans) {
628 (*this)(0, 2) = trans.x(); // Assuming FxVec2f has x() method.
629 (*this)(1, 2) = trans.y(); // And a y() method.
630 }
631
632 // Compute and return the inverse transformation.
634 FxMat3f inv; // This will store the inverse.
635
636 // Compute the rotation transpose (which is the inverse of a rotation).
637 inv(0, 0) = (*this)(0, 0);
638 inv(0, 1) = (*this)(1, 0);
639 inv(1, 0) = (*this)(0, 1);
640 inv(1, 1) = (*this)(1, 1);
641
642 // Compute the new translation vector as -Rᵀt.
643 float t0 = (*this)(0, 2); // original translation x value.
644 float t1 = (*this)(1, 2); // original translation y value.
645 inv(0, 2) = -(inv(0, 0) * t0 + inv(0, 1) * t1);
646 inv(1, 2) = -(inv(1, 0) * t0 + inv(1, 1) * t1);
647
648 // Set the homogeneous row.
649 inv(2, 0) = 0;
650 inv(2, 1) = 0;
651 inv(2, 2) = 1;
652
653 return inv;
654 }
655};
656
657// ────────────────────────────────────────────────────────────────────────────
658// FxArray: numpy style array
659// ────────────────────────────────────────────────────────────────────────────
660
661// 1) define the concepts
662template<typename T>
664 std::integral<T> // all integer types
665 || std::floating_point<T> // float, double, long double
666 || std::same_as<T, FxVec2f> || std::same_as<T, FxVec3f> || std::same_as<T, FxVec4f>;
667// || std::same_as<T, FxVecXf>;
668
669template<typename T>
670concept FxVecT = std::same_as<T, FxVec2f> || std::same_as<T, FxVec3f> || std::same_as<T, FxVec4f>;
671
672template<typename U, typename T>
673concept ConvertibleOrNumeric = std::convertible_to<U, T> || Numeric<U>;
674
675// Custom deleter for aligned arrays
676template<class T>
678 std::size_t align;
679 void operator()(T* p) const noexcept { ::operator delete[](p, std::align_val_t(align)); }
680};
681
682// Helper function to create aligned arrays
683template<typename T>
684static std::unique_ptr<T[], FxArrayAlignedDelete<T>> FxArray_make_aligned(std::size_t n,
685 std::size_t align = 32) {
686 if (n == 0) return {nullptr, FxArrayAlignedDelete<T>{align}};
687 // allocation (ctors run)
688 T* p = static_cast<T*>(::operator new[](n * sizeof(T), std::align_val_t(align)));
689 return std::unique_ptr<T[], FxArrayAlignedDelete<T>>(p, FxArrayAlignedDelete<T>{align});
690}
691
692// define the FxArray class template
693template<NumericOrFxVec T>
694class FxArray {
695 private:
696 static constexpr std::size_t kAlign = 32; // compile-time alignment
697 std::size_t m_size = 0;
698 std::unique_ptr<T[], FxArrayAlignedDelete<T>> m_arr;
699
700 protected:
701 // throws if index is out of bounds
702 template<std::integral I>
703 std::size_t checkIndex(I idx) const {
704 auto i = static_cast<long long>(idx); // signed capture for error text
705 auto u = static_cast<std::size_t>(i); // cast for bounds test
706 if (i < 0 || u >= m_size) {
707 throw std::out_of_range("FxArray::[] index " + std::to_string(i) +
708 " out of range for [0," + std::to_string(m_size) + ")");
709 }
710 return u;
711 }
712
713 // throws if empty
714 void throw_if_empty(char const* what) const {
715 if (m_size == 0)
716 throw std::runtime_error(std::string("FxArray::") + what + " on empty array");
717 }
718
719 // throws if size mismatch
720 void throw_if_size_mismatch(char const* what, size_t o_size) const {
721 if (m_size != o_size)
722 throw std::invalid_argument(std::string("FxArray::operator") + what + " size mismatch");
723 }
724
725 // single scan to find (index, value) of best element
726 template<typename Compare>
727 std::pair<std::size_t, T> best_pair(Compare cmp, const char* name) const {
728 throw_if_empty(name);
729 T const* __restrict p = aligned_data();
730 std::size_t bestIdx = 0;
731 T bestVal = p[0];
732 for (std::size_t i = 1; i < m_size; ++i) {
733 if (cmp(p[i], bestVal)) {
734 bestVal = p[i];
735 bestIdx = i;
736 }
737 }
738 return {bestIdx, bestVal};
739 }
740
741 public:
742 // 1) default (empty)
743 FxArray() : m_arr(nullptr, FxArrayAlignedDelete<T>{kAlign}) {}
744 // 2) n sized ctor (all zeros)
745 explicit FxArray(std::size_t n) : m_size(n), m_arr(FxArray_make_aligned<T>(n, kAlign)) {}
746
747 // 3) Dedicated init_list ctor — for braced lists
748 FxArray(std::initializer_list<T> init) : FxArray(init.size()) {
749 std::copy(init.begin(), init.end(), aligned_data());
750 }
751
752 // 4) one ctor for std::vector
753 FxArray(std::vector<T> const& v) : FxArray(v.size()) {
754 std::copy(v.begin(), v.end(), aligned_data());
755 }
756
757 // 5) one overload for c style array
758 template<std::size_t N>
759 FxArray(T const (&arr)[N]) : FxArray(N) {
760 std::copy_n(arr, N, aligned_data());
761 }
762
763 // deep‐copy copy‐ctor using copy_n
764 FxArray(FxArray const& o) : FxArray(o.m_size) {
765 std::copy_n(o.aligned_data(), m_size, aligned_data());
766 }
767
768 // move-assignment (O(1) swap of pointers and size)
769 FxArray(FxArray&&) noexcept = default;
770
771 // Default destructor is sufficient now
772 ~FxArray() = default;
773
774 // = move-assignment
775 FxArray& operator=(FxArray const& o) {
776 if (&o == this) return *this;
777 FxArray tmp(o);
778 swap(tmp);
779 return *this;
780 }
781
782 // assign from std::vector<T>
783 FxArray& operator=(std::vector<T> const& v) {
784 // reuse your vector‐ctor + swap
785 FxArray tmp(v);
786 swap(tmp);
787 return *this;
788 }
789
790 // assign from initializer_list<T>
791 FxArray& operator=(std::initializer_list<T> init) {
792 FxArray tmp(init);
793 swap(tmp);
794 return *this;
795 }
796
797 FxArray& operator=(FxArray&&) noexcept = default;
798
799 // Aligned raw-data helpers
800 T* aligned_data() noexcept { return std::assume_aligned<kAlign>(m_arr.get()); }
801 T const* aligned_data() const noexcept { return std::assume_aligned<kAlign>(m_arr.get()); }
802
803 // 1) UNCHECKED, inlined, noexcept operator[] for hot loops
804 T& operator[](size_t i) noexcept { return aligned_data()[i]; }
805 T const& operator[](size_t i) const noexcept { return aligned_data()[i]; }
806
807 template<std::integral I>
808 T& operator()(I i) noexcept {
809 return aligned_data()[static_cast<size_t>(i)];
810 }
811
812 template<std::integral I>
813 T const& operator()(I i) const noexcept {
814 return aligned_data()[static_cast<size_t>(i)];
815 }
816
817 // 2) BOUNDS-CHECKED at(), still accepts *any* integral index
818 template<std::integral I>
819 T& at(I idx) {
820 return aligned_data()[checkIndex(idx)];
821 }
822 template<std::integral I>
823 T const& at(I idx) const {
824 return aligned_data()[checkIndex(idx)];
825 }
826
827 // Iterators use aligned_data (helps vectorizers in range-for)
828 T* begin() noexcept { return aligned_data(); }
829 T const* begin() const noexcept { return aligned_data(); }
830 T* end() noexcept { return aligned_data() + m_size; }
831 T const* end() const noexcept { return aligned_data() + m_size; }
832
833 // size & raw data
834 size_t size() const noexcept { return m_size; }
835 bool empty() const noexcept { return m_size == 0; }
836 T* data() noexcept { return m_arr.get(); }
837 T const* data() const noexcept { return m_arr.get(); }
838
839 void swap(FxArray& o) noexcept {
840 std::swap(m_size, o.m_size);
841 std::swap(m_arr, o.m_arr);
842 }
843
844 template<typename U>
845 requires(Numeric<T> && Numeric<U>)
846 FxArray<U> as() const {
847 FxArray<U> result(m_size);
848 T const* __restrict src = aligned_data();
849 U* __restrict dst = result.aligned_data();
850 for (std::size_t i = 0; i < m_size; ++i)
851 dst[i] = static_cast<U>(src[i]);
852 return result;
853 }
854
855 template<typename Compare>
856 T min(Compare cmp) const {
857 return best_pair(cmp, "min").second;
858 }
859
860 template<typename Compare>
861 T max(Compare cmp) const {
862 return best_pair([&](const T& a, const T& b) { return cmp(b, a); }, "max").second;
863 }
864
865 // default operator< versions
866 T min() const { return min(std::less<T>{}); }
867 T max() const { return max(std::less<T>{}); }
868
869 // ---------- index-only -> reuse best_pair ----------
870 template<typename Compare>
871 std::pair<std::size_t, T> argmin(Compare cmp) const {
872 return best_pair(cmp, "argmin");
873 }
874
875 template<typename Compare>
876 std::pair<std::size_t, T> argmax(Compare cmp) const {
877 return best_pair([&](const T& a, const T& b) { return cmp(b, a); }, "argmax");
878 }
879
880 // default operator< versions
881 std::pair<std::size_t, T> argmin() const { return argmin(std::less<T>{}); }
882 std::pair<std::size_t, T> argmax() const { return argmax(std::less<T>{}); }
883
884 // --- mean: requires T() + T+= U + T /= scalar ---
885 T mean() const {
886 throw_if_empty("mean");
887 T const* __restrict p = aligned_data();
888 T sum = p[0]; // initialize with first element
889 for (std::size_t i = 1; i < m_size; ++i)
890 sum += p[i];
891 return sum / m_size;
892 }
893
894 // mean as float (casts each element to double for accuracy, returns float)
895 float meanf() const
896 requires Numeric<T>
897 {
898 throw_if_empty("meanf");
899 T const* __restrict p = aligned_data();
900 double sum = 0.0;
901 for (std::size_t i = 0; i < m_size; ++i)
902 sum += static_cast<double>(p[i]);
903 return static_cast<float>(sum / m_size);
904 }
905
906 // population standard deviation as float
907 float stddev() const
908 requires Numeric<T>
909 {
910 throw_if_empty("stddev");
911 double m = meanf();
912 T const* __restrict p = aligned_data();
913 double acc = 0.0;
914 for (std::size_t i = 0; i < m_size; ++i) {
915 double d = static_cast<double>(p[i]) - m;
916 acc += d * d;
917 }
918 return static_cast<float>(std::sqrt(acc / m_size));
919 }
920
921 // --- unary minus (element‐wise negate) ---
923 FxArray result(m_size);
924 T const* __restrict src = aligned_data();
925 T* __restrict dst = result.aligned_data();
926 for (std::size_t i = 0; i < m_size; ++i)
927 dst[i] = -src[i];
928 return result;
929 }
930
931 // --- in-place with a single T ---
932 template<typename U>
934 FxArray& operator+=(U const& v) {
935 T* __restrict p = aligned_data();
936 const T vv = static_cast<T>(v);
937 for (std::size_t i = 0; i < m_size; ++i)
938 p[i] += vv;
939 return *this;
940 }
941
942 template<typename U>
944 FxArray& operator-=(U const& v) {
945 T* __restrict p = aligned_data();
946 const T vv = static_cast<T>(v);
947 for (std::size_t i = 0; i < m_size; ++i)
948 p[i] -= vv;
949 return *this;
950 }
951
952 template<typename U>
954 FxArray& operator*=(U const& v) {
955 T* __restrict p = aligned_data();
956 const T vv = static_cast<T>(v);
957 for (std::size_t i = 0; i < m_size; ++i)
958 p[i] *= vv;
959 return *this;
960 }
961
962 template<typename U>
964 FxArray& operator/=(U const& v) {
965 T* __restrict p = aligned_data();
966 const T vv = static_cast<T>(v);
967 for (std::size_t i = 0; i < m_size; ++i)
968 p[i] /= vv;
969 return *this;
970 }
971
972 // --- in-place element‐wise with another FxArray ---
973 template<typename U>
976 throw_if_size_mismatch("+=", o.size());
977 T* __restrict p = aligned_data();
978 U const* __restrict op = o.aligned_data();
979 for (std::size_t i = 0; i < m_size; ++i)
980 p[i] += op[i];
981 return *this;
982 }
983
984 template<typename U>
987 throw_if_size_mismatch("-=", o.size());
988 T* __restrict p = aligned_data();
989 U const* __restrict op = o.aligned_data();
990 for (std::size_t i = 0; i < m_size; ++i)
991 p[i] -= op[i];
992 return *this;
993 }
994
995 template<typename U>
998 throw_if_size_mismatch("*=", o.size());
999 T* __restrict p = aligned_data();
1000 U const* __restrict op = o.aligned_data();
1001 for (std::size_t i = 0; i < m_size; ++i)
1002 p[i] *= op[i];
1003 return *this;
1004 }
1005
1006 template<typename U>
1009 throw_if_size_mismatch("/=", o.size());
1010 T* __restrict p = aligned_data();
1011 U const* __restrict op = o.aligned_data();
1012 for (std::size_t i = 0; i < m_size; ++i)
1013 p[i] /= op[i];
1014 return *this;
1015 }
1016
1017 // dot with one FxVec2f → returns FxArray<float>
1018 FxArray<float> dot(T const& v) const
1019 requires FxVecT<T>
1020 {
1021 FxArray<float> out(this->size());
1022 T const* __restrict p = aligned_data();
1023 float* __restrict result = out.aligned_data();
1024 for (size_t i = 0; i < this->size(); ++i)
1025 result[i] = p[i].dot(v);
1026 return out;
1027 }
1028
1029 // element-wise dot with another FxVec2fArray
1031 requires FxVecT<T>
1032 {
1033 this->throw_if_size_mismatch("dot", o.size());
1034 FxArray<float> out(this->size());
1035 T const* __restrict p = aligned_data();
1036 T const* __restrict op = o.aligned_data();
1037 float* __restrict result = out.aligned_data();
1038 for (size_t i = 0; i < this->size(); ++i)
1039 result[i] = p[i].dot(op[i]);
1040 return out;
1041 }
1042
1043 // 1) In-place rotate by radians
1044 FxArray& rotate_inplace_rad(float theta_rad) noexcept
1045 requires std::same_as<T, FxVec2f>
1046 {
1047 const float c = std::cos(theta_rad);
1048 const float s = std::sin(theta_rad);
1049 T* __restrict p = aligned_data();
1050 for (std::size_t i = 0; i < m_size; ++i) {
1051 float xi = p[i].x(), yi = p[i].y();
1052 p[i].x() = xi * c - yi * s;
1053 p[i].y() = xi * s + yi * c;
1054 }
1055 return *this;
1056 }
1057
1058 // 2) In-place rotate by degrees
1059 FxArray& rotate_inplace(float degrees) noexcept
1060 requires std::same_as<T, FxVec2f>
1061 {
1062 constexpr float FX_DEG2RAD = FxPif / 180.0f;
1063 return rotate_inplace_rad(degrees * FX_DEG2RAD);
1064 }
1065
1066 // 3) In-place rotate by degrees
1068 requires std::same_as<T, FxVec2f>
1069 {
1070 T* __restrict p = aligned_data();
1071 for (std::size_t i = 0; i < m_size; ++i)
1072 p[i] = p[i].perp();
1073 return *this;
1074 }
1075
1076 // 4) Non-mutating perp → new array
1078 requires std::same_as<T, FxVec2f>
1079 {
1080 FxArray tmp = *this;
1081 tmp.perp_inplace();
1082 return tmp;
1083 }
1084
1085 // 5) Non-mutating rotate by radians → new array
1086 FxArray rotate_rad(float theta_rad) const
1087 requires std::same_as<T, FxVec2f>
1088 {
1089 FxArray tmp = *this;
1090 tmp.rotate_inplace_rad(theta_rad);
1091 return tmp;
1092 }
1093
1094 // 6) Non-mutating rotate by degrees → new array
1095 FxArray rotate(float degrees) const
1096 requires std::same_as<T, FxVec2f>
1097 {
1098 FxArray tmp = *this;
1099 tmp.rotate_inplace(degrees);
1100 return tmp;
1101 }
1102
1104 requires std::same_as<T, FxVec2f>
1105 {
1106 this->throw_if_empty("extrema");
1107 T const* __restrict p = aligned_data();
1108 const auto& v0 = p[0];
1109 float minx = v0.x(), maxx = v0.x();
1110 float miny = v0.y(), maxy = v0.y();
1111 for (size_t i = 1, n = this->size(); i < n; ++i) {
1112 const auto& v = p[i];
1113 float x = v.x(), y = v.y();
1114 if (x < minx) minx = x;
1115 else if (x > maxx) maxx = x;
1116 if (y < miny) miny = y;
1117 else if (y > maxy) maxy = y;
1118 }
1119 return {minx, miny, maxx, maxy};
1120 }
1121};
1122
1123template<NumericOrFxVec T>
1124void swap(FxArray<T>& a, FxArray<T>& b) noexcept {
1125 a.swap(b);
1126}
1127
1128// ────────────────────────────────────────────────────────────────────────────
1129// FxVec2fArray: fixed‐size array of FxVec2f
1130// ────────────────────────────────────────────────────────────────────────────
1132
1133// Scalar–Array
1134template<typename T, typename U>
1136inline FxArray<T> operator+(FxArray<T> a, U const& scalar) {
1137 return a += scalar;
1138}
1139
1140template<typename T, typename U>
1142inline FxArray<T> operator-(FxArray<T> a, U const& scalar) {
1143 return a -= scalar;
1144}
1145
1146template<typename T, typename U>
1148inline FxArray<T> operator*(FxArray<T> a, U const& scalar) {
1149 return a *= scalar;
1150}
1151
1152template<typename T, typename U>
1154inline FxArray<T> operator/(FxArray<T> a, U const& scalar) {
1155 return a /= scalar;
1156}
1157
1158// Scalar on the left
1159template<typename T, typename U>
1161inline FxArray<T> operator+(U const& scalar, FxArray<T> a) {
1162 return a += scalar;
1163}
1164
1165template<typename T, typename U>
1167inline FxArray<T> operator*(U const& scalar, FxArray<T> a) {
1168 return a *= scalar;
1169}
1170
1171template<typename T, typename U>
1173inline FxArray<T> operator-(U const& scalar, FxArray<T> a) {
1174 return -a + scalar;
1175}
1176
1177// Scalar–Array division: scalar / array
1178template<typename T, Numeric U>
1179inline FxArray<T> operator/(U const& scalar, FxArray<T> const& a) {
1180 FxArray<T> result(a.size());
1181 T const* __restrict src = a.aligned_data();
1182 T* __restrict dst = result.aligned_data();
1183 for (size_t i = 0; i < result.size(); ++i)
1184 dst[i] = scalar / src[i];
1185 return result;
1186}
1187
1188template<typename T>
1189inline FxArray<T> operator/(T const& scalar, FxArray<T> const& a) {
1190 FxArray<T> result(a.size());
1191 T const* __restrict src = a.aligned_data();
1192 T* __restrict dst = result.aligned_data();
1193 for (size_t i = 0; i < result.size(); ++i)
1194 dst[i] = scalar / src[i];
1195 return result;
1196}
1197
1198// Array–Array
1199template<typename T>
1201 return a += b;
1202}
1203
1204template<typename T>
1206 return a -= b;
1207}
1208
1209template<typename T>
1211 return a *= b;
1212}
1213
1214template<typename T>
1216 return a /= b;
1217}
1218
1219template<Numeric T>
1220inline std::ostream& operator<<(std::ostream& os, FxArray<T> const& a) {
1221 os << "FxArray { ";
1222 for (size_t i = 0; i < a.size(); ++i)
1223 os << a[i] << ", ";
1224 os << "}";
1225 return os;
1226}
1227
1228inline std::ostream& operator<<(std::ostream& os, FxVec2fArray const& a) {
1229 os << "FxVec2fArray { ";
1230 for (size_t i = 0; i < a.size(); ++i)
1231 os << "(" << a[i].x() << " " << a[i].y() << "), ";
1232 os << "} ";
1233 return os;
1234}
1235
1236inline std::ostream& operator<<(std::ostream& os, FxVec2f const& a) {
1237 os << "FxVec2f { ";
1238 os << a.x() << " " << a.y();
1239 os << " }";
1240 return os;
1241}
1242
1243inline std::ostream& operator<<(std::ostream& os, FxVec3f const& a) {
1244 os << "FxVec3f { ";
1245 os << a.x() << " " << a.y() << " " << a.z();
1246 os << " }";
1247 return os;
1248}
FxVec2f & operator/=(FxVec2f &v, S s)
Definition Math.h:422
FxVec2f operator*(FxVec2f const &v, S s)
Definition Math.h:257
void swap(FxArray< T > &a, FxArray< T > &b) noexcept
Definition Math.h:1124
FxVec2f & operator*=(FxVec2f &v, S s)
Definition Math.h:417
std::ostream & operator<<(std::ostream &os, FxArray< T > const &a)
Definition Math.h:1220
Eigen::Map< Eigen::Vector2f > FxVec2fMap
Definition Math.h:156
FxVec2f operator+(FxVec2f const &v, S s)
Definition Math.h:269
FxVec2f & operator+=(FxVec2f &v, S s)
Definition Math.h:407
Eigen::Map< Eigen::Vector2d > FxVec2dMap
Definition Math.h:192
FxVec2f operator/(FxVec2f const &v, S s)
Definition Math.h:265
FxVec2f operator-(FxVec2f const &v, S s)
Definition Math.h:277
FxVec2f & operator-=(FxVec2f &v, S s)
Definition Math.h:412
Fixed-size, aligned value array.
Definition Math.h:694
T * end() noexcept
Definition Math.h:830
T const & at(I idx) const
Definition Math.h:823
FxArray & operator=(std::vector< T > const &v)
Definition Math.h:783
FxArray & operator*=(FxArray< U > const &o)
Definition Math.h:997
FxArray< float > dot(FxArray< T > const &o) const
Definition Math.h:1030
T * data() noexcept
Definition Math.h:836
T & operator()(I i) noexcept
Definition Math.h:808
void throw_if_empty(char const *what) const
Definition Math.h:714
FxArray & rotate_inplace_rad(float theta_rad) noexcept
Definition Math.h:1044
T const & operator[](size_t i) const noexcept
Definition Math.h:805
FxArray & operator-=(FxArray< U > const &o)
Definition Math.h:986
std::pair< std::size_t, T > best_pair(Compare cmp, const char *name) const
Definition Math.h:727
T max() const
Definition Math.h:867
FxArray & operator=(FxArray &&) noexcept=default
T & at(I idx)
Definition Math.h:819
FxArray & operator-=(U const &v)
Definition Math.h:944
FxArray operator-() const
Definition Math.h:922
FxArray & perp_inplace() noexcept
Definition Math.h:1067
void throw_if_size_mismatch(char const *what, size_t o_size) const
Definition Math.h:720
FxArray rotate(float degrees) const
Definition Math.h:1095
T & operator[](size_t i) noexcept
Definition Math.h:804
T mean() const
Definition Math.h:885
T * begin() noexcept
Definition Math.h:828
T const * end() const noexcept
Definition Math.h:831
FxArray & operator/=(FxArray< U > const &o)
Definition Math.h:1008
FxArray rotate_rad(float theta_rad) const
Definition Math.h:1086
bool empty() const noexcept
Definition Math.h:835
FxArray(FxArray &&) noexcept=default
FxArray(std::size_t n)
Definition Math.h:745
T min(Compare cmp) const
Definition Math.h:856
std::pair< std::size_t, T > argmin() const
Definition Math.h:881
FxArray & operator*=(U const &v)
Definition Math.h:954
T const * begin() const noexcept
Definition Math.h:829
FxArray perp() const
Definition Math.h:1077
T * aligned_data() noexcept
Definition Math.h:800
T const & operator()(I i) const noexcept
Definition Math.h:813
FxArray & operator/=(U const &v)
Definition Math.h:964
FxArray & operator+=(FxArray< U > const &o)
Definition Math.h:975
FxArray< float > dot(T const &v) const
Definition Math.h:1018
void swap(FxArray &o) noexcept
Definition Math.h:839
std::size_t checkIndex(I idx) const
Definition Math.h:703
FxArray(T const (&arr)[N])
Definition Math.h:759
std::pair< std::size_t, T > argmin(Compare cmp) const
Definition Math.h:871
FxArray & operator=(std::initializer_list< T > init)
Definition Math.h:791
T const * data() const noexcept
Definition Math.h:837
T max(Compare cmp) const
Definition Math.h:861
size_t size() const noexcept
Definition Math.h:834
FxArray & rotate_inplace(float degrees) noexcept
Definition Math.h:1059
std::pair< std::size_t, T > argmax() const
Definition Math.h:882
FxArray(std::initializer_list< T > init)
Definition Math.h:748
float meanf() const
Definition Math.h:895
FxArray(std::vector< T > const &v)
Definition Math.h:753
FxArray & operator+=(U const &v)
Definition Math.h:934
T const * aligned_data() const noexcept
Definition Math.h:801
FxArray(FxArray const &o)
Definition Math.h:764
FxArray< U > as() const
Definition Math.h:846
std::pair< std::size_t, T > argmax(Compare cmp) const
Definition Math.h:876
FxArray< float > bounds() const
Definition Math.h:1103
T min() const
Definition Math.h:866
FxArray()
Definition Math.h:743
float stddev() const
Definition Math.h:907
2×2 floating-point matrix.
Definition Math.h:546
float & d()
Definition Math.h:553
void set_a(float val)
Definition Math.h:561
float & b()
Definition Math.h:551
void set_d(float val)
Definition Math.h:564
float & a()
Definition Math.h:550
float & c()
Definition Math.h:552
float d() const
Definition Math.h:559
void set_b(float val)
Definition Math.h:562
float c() const
Definition Math.h:558
float b() const
Definition Math.h:557
FxMat2f inv_rotation() const
Definition Math.h:567
void set_c(float val)
Definition Math.h:563
float a() const
Definition Math.h:556
3×3 floating-point matrix.
Definition Math.h:570
float & g()
Definition Math.h:584
float & b()
Definition Math.h:577
void set_e(float val)
Definition Math.h:606
float h() const
Definition Math.h:596
FxMat3f inv_transform() const
Definition Math.h:633
float & f()
Definition Math.h:582
FxMat2f Rot() const
Definition Math.h:614
FxVec2f t() const
Definition Math.h:616
float & e()
Definition Math.h:581
float & c()
Definition Math.h:578
float & a()
Definition Math.h:576
void set_g(float val)
Definition Math.h:609
float & h()
Definition Math.h:585
float i() const
Definition Math.h:597
float g() const
Definition Math.h:595
void set_Rot(const FxMat2f &R)
Definition Math.h:619
float c() const
Definition Math.h:591
float b() const
Definition Math.h:590
float & d()
Definition Math.h:580
void set_b(float val)
Definition Math.h:602
void set_f(float val)
Definition Math.h:607
float a() const
Definition Math.h:589
float f() const
Definition Math.h:594
float & i()
Definition Math.h:586
float d() const
Definition Math.h:592
float e() const
Definition Math.h:593
void set_h(float val)
Definition Math.h:610
void set_d(float val)
Definition Math.h:605
void set_a(float val)
Definition Math.h:601
void set_t(const FxVec2f &trans)
Definition Math.h:627
void set_i(float val)
Definition Math.h:611
void set_c(float val)
Definition Math.h:603
Double-precision 2D vector.
Definition Math.h:102
FxVec2d(double a)
Definition Math.h:108
FxVec2d rotate(double theta) const noexcept
Definition Math.h:138
double & x()
Definition Math.h:111
FxVec2d perp() const
Definition Math.h:147
double & y()
Definition Math.h:112
FxVec2d & rotate_inplace(double degrees) noexcept
Definition Math.h:132
double y() const
Definition Math.h:116
void set_x(double val)
Definition Math.h:119
double cross(const FxVec2d &other) const
Definition Math.h:144
double x() const
Definition Math.h:115
FxVec2d & rotate_inplace_rad(double theta) noexcept
Definition Math.h:123
FxVec2d perpCW() const
Definition Math.h:151
FxVec2d rotate_rad(double theta) const noexcept
Definition Math.h:139
void set_y(double val)
Definition Math.h:120
Single-precision 2D vector.
Definition Math.h:47
void set_x(float val)
Definition Math.h:64
float & y()
Definition Math.h:57
float & x()
Definition Math.h:56
FxVec2f & rotate_inplace(float degrees) noexcept
Definition Math.h:77
float cross(const FxVec2f &other) const
Definition Math.h:89
FxVec2f(float a)
Definition Math.h:53
FxVec2f & rotate_inplace_rad(float theta) noexcept
Definition Math.h:68
float x() const
Definition Math.h:60
FxVec2f rotate(float theta) const noexcept
Definition Math.h:83
void set_y(float val)
Definition Math.h:65
FxVec2f perp() const
Definition Math.h:92
FxVec2f rotate_rad(float theta) const noexcept
Definition Math.h:84
float y() const
Definition Math.h:61
FxVec2f perpCW() const
Definition Math.h:96
void set_x(unsigned int val)
Definition Math.h:519
unsigned int & x()
Definition Math.h:512
Eigen::Matrix< unsigned int, 2, 1 > Base
Definition Math.h:509
unsigned int & y()
Definition Math.h:513
unsigned int y() const
Definition Math.h:517
void set_y(unsigned int val)
Definition Math.h:520
unsigned int x() const
Definition Math.h:516
Double-precision three-component vector.
Definition Math.h:195
double & y()
Definition Math.h:204
double theta() const
Definition Math.h:213
FxVec2dMap xy()
Definition Math.h:222
FxVec2d get_xy() const
Definition Math.h:223
double z() const
Definition Math.h:212
void set_z(double val)
Definition Math.h:218
FxVec3d(double a)
Definition Math.h:200
FxVec2d xy() const
Definition Math.h:224
void set_xy(const FxVec2d &v2)
Definition Math.h:225
void set_x(double val)
Definition Math.h:216
void set_y(double val)
Definition Math.h:217
double & z()
Definition Math.h:205
double & x()
Definition Math.h:203
double & theta()
Definition Math.h:207
double y() const
Definition Math.h:211
double x() const
Definition Math.h:210
void set_theta(double val)
Definition Math.h:220
Single-precision three-component vector, including poses.
Definition Math.h:159
void set_y(float val)
Definition Math.h:181
FxVec3f(float a)
Definition Math.h:164
float & z()
Definition Math.h:169
void set_theta(float val)
Definition Math.h:184
float z() const
Definition Math.h:176
float y() const
Definition Math.h:175
float & x()
Definition Math.h:167
float x() const
Definition Math.h:174
void set_x(float val)
Definition Math.h:180
FxVec2fMap xy()
Definition Math.h:186
FxVec2f xy() const
Definition Math.h:188
void set_z(float val)
Definition Math.h:182
float & y()
Definition Math.h:168
void set_xy(const FxVec2f &v2)
Definition Math.h:189
float theta() const
Definition Math.h:177
FxVec2f get_xy() const
Definition Math.h:187
float & theta()
Definition Math.h:171
Four-component floating-point vector.
Definition Math.h:229
float x() const
Definition Math.h:243
float a() const
Definition Math.h:246
void set_y(float val)
Definition Math.h:250
void set_a(float val)
Definition Math.h:252
FxVec4f(float a)
Definition Math.h:234
float y() const
Definition Math.h:244
void set_z(float val)
Definition Math.h:251
float & x()
Definition Math.h:237
float & z()
Definition Math.h:239
float & y()
Definition Math.h:238
void set_x(float val)
Definition Math.h:249
float & a()
Definition Math.h:240
float z() const
Definition Math.h:245
uint8_t & x()
Definition Math.h:529
void set_z(uint8_t val)
Definition Math.h:542
void set_x(uint8_t val)
Definition Math.h:540
void set_y(uint8_t val)
Definition Math.h:541
uint8_t & z()
Definition Math.h:531
Eigen::Matrix< uint8_t, 4, 1 > Base
Definition Math.h:526
uint8_t & a()
Definition Math.h:532
uint8_t & y()
Definition Math.h:530
uint8_t a() const
Definition Math.h:538
void set_a(uint8_t val)
Definition Math.h:543
uint8_t x() const
Definition Math.h:535
uint8_t y() const
Definition Math.h:536
uint8_t z() const
Definition Math.h:537
Definition Math.h:670
Definition Math.h:44
std::size_t align
Definition Math.h:678
void operator()(T *p) const noexcept
Definition Math.h:679