6#include <initializer_list>
16static constexpr float FxInfinityf = std::numeric_limits<float>::infinity();
17static constexpr double FxInfinityd = std::numeric_limits<double>::infinity();
20static constexpr float FxPif = std::numbers::pi_v<float>;
21static constexpr double FxPid = std::numbers::pi_v<double>;
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;
33static inline float FxCarryAdd(
float& dst,
double inc,
double& carry) {
34 double s = (double)dst + inc + carry;
36 carry = s - (double)f;
44concept Numeric = std::integral<T> || std::floating_point<T>;
50 using Eigen::Vector2f::Vector2f;
53 explicit FxVec2f(
float a) : Eigen::Vector2f(a, a) {}
56 float&
x() {
return (*
this)(0); }
57 float&
y() {
return (*
this)(1); }
60 float x()
const {
return (*
this)(0); }
61 float y()
const {
return (*
this)(1); }
64 void set_x(
float val) { (*this)(0) = val; }
65 void set_y(
float val) { (*this)(1) = val; }
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);
78 constexpr float FX_DEG2RAD = FxPif / 180.0f;
105 using Eigen::Vector2d::Vector2d;
108 explicit FxVec2d(
double a) : Eigen::Vector2d(a, a) {}
111 double&
x() {
return (*
this)(0); }
112 double&
y() {
return (*
this)(1); }
115 double x()
const {
return (*
this)(0); }
116 double y()
const {
return (*
this)(1); }
119 void set_x(
double val) { (*this)(0) = val; }
120 void set_y(
double val) { (*this)(1) = val; }
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);
133 constexpr double FX_DEG2RAD = FxPid / 180.0;
161 using Eigen::Vector3f::Vector3f;
164 explicit FxVec3f(
float a) : Eigen::Vector3f(a, a, a) {}
167 float&
x() {
return (*
this)(0); }
168 float&
y() {
return (*
this)(1); }
169 float&
z() {
return (*
this)(2); }
171 float&
theta() {
return (*
this)(2); }
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); }
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; }
197 using Eigen::Vector3d::Vector3d;
200 explicit FxVec3d(
double a) : Eigen::Vector3d(a, a, a) {}
203 double&
x() {
return (*
this)(0); }
204 double&
y() {
return (*
this)(1); }
205 double&
z() {
return (*
this)(2); }
207 double&
theta() {
return (*
this)(2); }
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); }
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; }
231 using Eigen::Vector4f::Vector4f;
237 float&
x() {
return (*
this)(0); }
238 float&
y() {
return (*
this)(1); }
239 float&
z() {
return (*
this)(2); }
240 float&
a() {
return (*
this)(3); }
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); }
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; }
258 return FxVec2f(v.array() *
static_cast<float>(s));
266 return FxVec2f(v.array() /
static_cast<float>(s));
270 return FxVec2f(v.array() +
static_cast<float>(s));
278 return FxVec2f(v.array() -
static_cast<float>(s));
282 return FxVec2f((FxVec2f::Scalar(
static_cast<float>(s)) * FxVec2f::Ones()).array() - v.array());
288 return FxVec3f(v.array() *
static_cast<float>(s));
296 return FxVec3f(v.array() /
static_cast<float>(s));
300 return FxVec3f(v.array() +
static_cast<float>(s));
308 return FxVec3f(v.array() -
static_cast<float>(s));
312 return FxVec3f((FxVec3f::Scalar(
static_cast<float>(s)) * FxVec3f::Ones()).array() - v.array());
318 return FxVec2d(v.array() *
static_cast<double>(s));
326 return FxVec2d(v.array() /
static_cast<double>(s));
330 return FxVec2d(v.array() +
static_cast<double>(s));
338 return FxVec2d(v.array() -
static_cast<double>(s));
342 return FxVec2d((FxVec2d::Scalar(
static_cast<double>(s)) * FxVec2d::Ones()).array() - v.array());
348 return FxVec3d(v.array() *
static_cast<double>(s));
356 return FxVec3d(v.array() /
static_cast<double>(s));
360 return FxVec3d(v.array() +
static_cast<double>(s));
368 return FxVec3d(v.array() -
static_cast<double>(s));
372 return FxVec3d((FxVec3d::Scalar(
static_cast<double>(s)) * FxVec3d::Ones()).array() - v.array());
378 return FxVec4f(v.array() *
static_cast<float>(s));
386 return FxVec4f(v.array() /
static_cast<float>(s));
390 return FxVec4f(v.array() +
static_cast<float>(s));
398 return FxVec4f(v.array() -
static_cast<float>(s));
402 return FxVec4f((FxVec4f::Scalar(
static_cast<float>(s)) * FxVec4f::Ones()).array() - v.array());
408 v.array() +=
static_cast<float>(s);
413 v.array() -=
static_cast<float>(s);
418 v.array() *=
static_cast<float>(s);
423 v.array() /=
static_cast<float>(s);
430 v.array() +=
static_cast<float>(s);
435 v.array() -=
static_cast<float>(s);
440 v.array() *=
static_cast<float>(s);
445 v.array() /=
static_cast<float>(s);
452 v.array() +=
static_cast<float>(s);
457 v.array() -=
static_cast<float>(s);
462 v.array() *=
static_cast<float>(s);
467 v.array() /=
static_cast<float>(s);
473 lhs.array() *= rhs.array();
477 lhs.array() /= rhs.array();
481 lhs.array() += rhs.array();
485 lhs.array() -= rhs.array();
491 return FxVec2f((FxVec2f::Scalar(
static_cast<float>(s)) * FxVec2f::Ones()).array() / v.array());
497 return FxVec3f((FxVec3f::Scalar(
static_cast<float>(s)) * FxVec3f::Ones()).array() / v.array());
503 return FxVec4f((FxVec4f::Scalar(
static_cast<float>(s)) * FxVec4f::Ones()).array() / v.array());
507class FxVec2ui :
public Eigen::Matrix<unsigned int, 2, 1> {
509 using Base = Eigen::Matrix<unsigned int, 2, 1>;
512 unsigned int&
x() {
return (*
this)(0); }
513 unsigned int&
y() {
return (*
this)(1); }
516 unsigned int x()
const {
return (*
this)(0); }
517 unsigned int y()
const {
return (*
this)(1); }
519 void set_x(
unsigned int val) { (*this)(0) = val; }
520 void set_y(
unsigned int val) { (*this)(1) = val; }
526 using Base = Eigen::Matrix<uint8_t, 4, 1>;
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); }
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); }
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; }
548 using Eigen::Matrix2f::Matrix2f;
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); }
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); }
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; }
572 using Eigen::Matrix3f::Matrix3f;
576 float&
a() {
return (*
this)(0, 0); }
577 float&
b() {
return (*
this)(0, 1); }
578 float&
c() {
return (*
this)(0, 2); }
580 float&
d() {
return (*
this)(1, 0); }
581 float&
e() {
return (*
this)(1, 1); }
582 float&
f() {
return (*
this)(1, 2); }
584 float&
g() {
return (*
this)(2, 0); }
585 float&
h() {
return (*
this)(2, 1); }
586 float&
i() {
return (*
this)(2, 2); }
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); }
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; }
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; }
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; }
614 FxMat2f Rot()
const {
return this->block<2, 2>(0, 0).eval(); }
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);
628 (*this)(0, 2) = trans.
x();
629 (*this)(1, 2) = trans.
y();
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);
643 float t0 = (*this)(0, 2);
644 float t1 = (*this)(1, 2);
645 inv(0, 2) = -(inv(0, 0) * t0 + inv(0, 1) * t1);
646 inv(1, 2) = -(inv(1, 0) * t0 + inv(1, 1) * t1);
665 || std::floating_point<T>
666 || std::same_as<T, FxVec2f> || std::same_as<T, FxVec3f> || std::same_as<T, FxVec4f>;
670concept FxVecT = std::same_as<T, FxVec2f> || std::same_as<T, FxVec3f> || std::same_as<T, FxVec4f>;
672template<
typename U,
typename T>
684static std::unique_ptr<T[], FxArrayAlignedDelete<T>> FxArray_make_aligned(std::size_t n,
685 std::size_t align = 32) {
688 T* p =
static_cast<T*
>(::operator
new[](n *
sizeof(
T), std::align_val_t(align)));
693template<NumericOrFxVec T>
696 static constexpr std::size_t kAlign = 32;
697 std::size_t m_size = 0;
698 std::unique_ptr<T[], FxArrayAlignedDelete<T>> m_arr;
702 template<std::
integral I>
704 auto i =
static_cast<long long>(idx);
705 auto u =
static_cast<std::size_t
>(i);
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) +
")");
716 throw std::runtime_error(std::string(
"FxArray::") + what +
" on empty array");
721 if (m_size != o_size)
722 throw std::invalid_argument(std::string(
"FxArray::operator") + what +
" size mismatch");
726 template<
typename Compare>
727 std::pair<std::size_t, T>
best_pair(Compare cmp,
const char* name)
const {
730 std::size_t bestIdx = 0;
732 for (std::size_t i = 1; i < m_size; ++i) {
733 if (cmp(p[i], bestVal)) {
738 return {bestIdx, bestVal};
745 explicit FxArray(std::size_t n) : m_size(n), m_arr(FxArray_make_aligned<
T>(n, kAlign)) {}
758 template<std::
size_t N>
776 if (&o ==
this)
return *
this;
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()); }
807 template<std::
integral I>
812 template<std::
integral I>
818 template<std::
integral I>
822 template<std::
integral I>
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(); }
840 std::swap(m_size, o.m_size);
841 std::swap(m_arr, o.m_arr);
850 for (std::size_t i = 0; i < m_size; ++i)
851 dst[i] =
static_cast<U>(src[i]);
855 template<
typename Compare>
860 template<
typename Compare>
862 return best_pair([&](
const T& a,
const T& b) {
return cmp(b, a); },
"max").second;
870 template<
typename Compare>
871 std::pair<std::size_t, T>
argmin(Compare cmp)
const {
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");
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>{}); }
889 for (std::size_t i = 1; i < m_size; ++i)
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);
914 for (std::size_t i = 0; i < m_size; ++i) {
915 double d =
static_cast<double>(p[i]) - m;
918 return static_cast<float>(std::sqrt(acc / m_size));
926 for (std::size_t i = 0; i < m_size; ++i)
936 const T vv =
static_cast<T>(v);
937 for (std::size_t i = 0; i < m_size; ++i)
946 const T vv =
static_cast<T>(v);
947 for (std::size_t i = 0; i < m_size; ++i)
956 const T vv =
static_cast<T>(v);
957 for (std::size_t i = 0; i < m_size; ++i)
966 const T vv =
static_cast<T>(v);
967 for (std::size_t i = 0; i < m_size; ++i)
979 for (std::size_t i = 0; i < m_size; ++i)
990 for (std::size_t i = 0; i < m_size; ++i)
1001 for (std::size_t i = 0; i < m_size; ++i)
1006 template<
typename U>
1012 for (std::size_t i = 0; i < m_size; ++i)
1024 for (
size_t i = 0; i < this->
size(); ++i)
1025 result[i] = p[i].
dot(v);
1036 T const* __restrict op = o.aligned_data();
1038 for (
size_t i = 0; i < this->
size(); ++i)
1039 result[i] = p[i].
dot(op[i]);
1045 requires std::same_as<T, FxVec2f>
1047 const float c = std::cos(theta_rad);
1048 const float s = std::sin(theta_rad);
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;
1060 requires std::same_as<T, FxVec2f>
1062 constexpr float FX_DEG2RAD = FxPif / 180.0f;
1071 for (std::size_t i = 0; i < m_size; ++i)
1087 requires std::same_as<T, FxVec2f>
1096 requires std::same_as<T, FxVec2f>
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;
1119 return {minx, miny, maxx, maxy};
1123template<NumericOrFxVec T>
1134template<
typename T,
typename U>
1140template<
typename T,
typename U>
1146template<
typename T,
typename U>
1152template<
typename T,
typename U>
1159template<
typename T,
typename U>
1165template<
typename T,
typename U>
1171template<
typename T,
typename U>
1178template<
typename T, Numeric U>
1183 for (
size_t i = 0; i < result.
size(); ++i)
1184 dst[i] = scalar / src[i];
1193 for (
size_t i = 0; i < result.
size(); ++i)
1194 dst[i] = scalar / src[i];
1222 for (
size_t i = 0; i < a.
size(); ++i)
1229 os <<
"FxVec2fArray { ";
1230 for (
size_t i = 0; i < a.
size(); ++i)
1231 os <<
"(" << a[i].x() <<
" " << a[i].y() <<
"), ";
1238 os << a.
x() <<
" " << a.
y();
1245 os << a.
x() <<
" " << a.
y() <<
" " << a.
z();
FxVec2f & operator/=(FxVec2f &v, S s)
FxVec2f operator*(FxVec2f const &v, S s)
void swap(FxArray< T > &a, FxArray< T > &b) noexcept
FxVec2f & operator*=(FxVec2f &v, S s)
std::ostream & operator<<(std::ostream &os, FxArray< T > const &a)
Eigen::Map< Eigen::Vector2f > FxVec2fMap
FxVec2f operator+(FxVec2f const &v, S s)
FxVec2f & operator+=(FxVec2f &v, S s)
Eigen::Map< Eigen::Vector2d > FxVec2dMap
FxVec2f operator/(FxVec2f const &v, S s)
FxVec2f operator-(FxVec2f const &v, S s)
FxVec2f & operator-=(FxVec2f &v, S s)
Fixed-size, aligned value array.
T const & at(I idx) const
FxArray & operator=(std::vector< T > const &v)
FxArray & operator*=(FxArray< U > const &o)
FxArray< float > dot(FxArray< T > const &o) const
T & operator()(I i) noexcept
void throw_if_empty(char const *what) const
FxArray & rotate_inplace_rad(float theta_rad) noexcept
T const & operator[](size_t i) const noexcept
FxArray & operator-=(FxArray< U > const &o)
std::pair< std::size_t, T > best_pair(Compare cmp, const char *name) const
FxArray & operator=(FxArray &&) noexcept=default
FxArray & operator-=(U const &v)
FxArray operator-() const
FxArray & perp_inplace() noexcept
void throw_if_size_mismatch(char const *what, size_t o_size) const
FxArray rotate(float degrees) const
T & operator[](size_t i) noexcept
T const * end() const noexcept
FxArray & operator/=(FxArray< U > const &o)
FxArray rotate_rad(float theta_rad) const
bool empty() const noexcept
FxArray(FxArray &&) noexcept=default
std::pair< std::size_t, T > argmin() const
FxArray & operator*=(U const &v)
T const * begin() const noexcept
T * aligned_data() noexcept
T const & operator()(I i) const noexcept
FxArray & operator/=(U const &v)
FxArray & operator+=(FxArray< U > const &o)
FxArray< float > dot(T const &v) const
void swap(FxArray &o) noexcept
std::size_t checkIndex(I idx) const
FxArray(T const (&arr)[N])
std::pair< std::size_t, T > argmin(Compare cmp) const
FxArray & operator=(std::initializer_list< T > init)
T const * data() const noexcept
size_t size() const noexcept
FxArray & rotate_inplace(float degrees) noexcept
std::pair< std::size_t, T > argmax() const
FxArray(std::initializer_list< T > init)
FxArray(std::vector< T > const &v)
FxArray & operator+=(U const &v)
T const * aligned_data() const noexcept
FxArray(FxArray const &o)
std::pair< std::size_t, T > argmax(Compare cmp) const
FxArray< float > bounds() const
2×2 floating-point matrix.
FxMat2f inv_rotation() const
3×3 floating-point matrix.
FxMat3f inv_transform() const
void set_Rot(const FxMat2f &R)
void set_t(const FxVec2f &trans)
Double-precision 2D vector.
FxVec2d rotate(double theta) const noexcept
FxVec2d & rotate_inplace(double degrees) noexcept
double cross(const FxVec2d &other) const
FxVec2d & rotate_inplace_rad(double theta) noexcept
FxVec2d rotate_rad(double theta) const noexcept
Single-precision 2D vector.
FxVec2f & rotate_inplace(float degrees) noexcept
float cross(const FxVec2f &other) const
FxVec2f & rotate_inplace_rad(float theta) noexcept
FxVec2f rotate(float theta) const noexcept
FxVec2f rotate_rad(float theta) const noexcept
void set_x(unsigned int val)
Eigen::Matrix< unsigned int, 2, 1 > Base
void set_y(unsigned int val)
Double-precision three-component vector.
void set_xy(const FxVec2d &v2)
void set_theta(double val)
Single-precision three-component vector, including poses.
void set_theta(float val)
void set_xy(const FxVec2f &v2)
Four-component floating-point vector.
Eigen::Matrix< uint8_t, 4, 1 > Base
void operator()(T *p) const noexcept