Ridiculous Generic Vector class header - WIP.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has started running
Build Docs With Doxygen / Explore-Gitea-Actions (push) Has been cancelled

This commit is contained in:
2025-06-12 02:45:32 -05:00
parent 9ecb64a2fe
commit 0d4255e759
2 changed files with 166 additions and 3 deletions

View File

@@ -6,11 +6,158 @@
namespace J3ML::LinearAlgebra namespace J3ML::LinearAlgebra
{ {
template <size_t DIMS, typename T>
template <size_t D, typename T>
class Vector { class Vector {
static_assert(D > 1, "A vector cannot be of 1-dimension, it would be just a scalar!");
public: public:
enum { Dimensions = DIMS}; static constexpr bool IsAtLeast1D = D >= 1; // Should always be true for a proper vector.
T elems[DIMS]; static constexpr bool IsAtLeast2D = D >= 2; // Should always be true for a proper vector.
static constexpr bool IsAtLeast3D = D >= 3;
static constexpr bool IsAtLeast4D = D >= 4;
static constexpr bool Is1D = IsAtLeast1D; // Should always be true for a proper vector.
static constexpr bool Is2D = IsAtLeast2D; // Should always be true for a proper vector.
static constexpr bool Is3D = IsAtLeast3D;
static constexpr bool Is4D = IsAtLeast4D;
static constexpr bool IsExact1D = D == 1; // Should never be true for a proper vector.
static constexpr bool IsExact2D = D == 2;
static constexpr bool IsExact3D = D == 3;
static constexpr bool IsExact4D = D == 4;
static constexpr bool IsAtMost1D = D <= 1; // Should also never be true.
static constexpr bool IsAtMost2D = D <= 2;
static constexpr bool IsAtMost3D = D <= 3;
static constexpr bool IsAtMost4D = D <= 4;
static constexpr bool IsFloatingPoint = std::is_floating_point_v<T>;
static constexpr bool IsIntegral = std::is_integral_v<T>;
using value_type = T;
using self_type = Vector<D, T>;
static const Vector<D, T> Zero;
static const self_type One = self_type(1);
static const self_type UnitX;
static const self_type UnitY;
static const self_type NaN = self_type(std::numeric_limits<T>::signaling_NaN());
static const self_type Infinity = self_type(std::numeric_limits<T>::infinity());
static const self_type NegativeInfinity = self_type(-std::numeric_limits<T>::infinity());
static self_type GetUnitX() requires Is1D {}
static self_type GetUnitY() requires Is2D {}
static self_type GetUnitZ() requires Is3D {}
static self_type GetUnitW() requires Is4D {}
enum { Dimensions = D};
std::array<T, Dimensions> data;
/// Default constructor initializes all elements to zero.
Vector() : data{} {}
/// Initialize all elements to a single value.
explicit Vector(T value) { data.fill(value); }
Vector(T x, T y) requires Is2D: data{x, y} {}
Vector(T x, T y, T z) requires Is3D: data{x, y, z} {}
Vector(T x, T y, T z, T w) requires Is4D: data{x, y, z, w} {}
Vector(std::initializer_list<T> values);
T& operator[](size_t index) { return data[index]; }
const T& operator[](size_t index) const { return data[index]; }
T X() const requires Is1D { return At(0);}
T Y() const requires Is2D { return At(1);}
T Z() const requires Is3D { return At(2);}
T W() const requires Is4D { return At(3);}
T& X() requires Is1D { return At(0);}
T& Y() requires Is2D { return At(1);}
T& Z() requires Is3D { return At(2);}
T& W() requires Is4D { return At(3);}
Vector<2, T> XX() const requires Is1D { return {X()};}
Vector<2, T> YY() const requires Is2D { return {Y()};}
Vector<2, T> ZZ() const requires Is3D { return {Z()};}
Vector<2, T> WW() const requires Is4D { return {W()};}
Vector<3, T> XXX() const requires Is1D { return {X()};}
Vector<3, T> YYY() const requires Is2D { return {Y()};}
Vector<3, T> ZZZ() const requires Is3D { return {Z()};}
Vector<3, T> WWW() const requires Is4D { return {W()};}
Vector<4, T> XXXX() const requires Is1D { return {X()};}
Vector<4, T> YYYY() const requires Is2D { return {Y()};}
Vector<4, T> ZZZZ() const requires Is3D { return {Z()};}
Vector<4, T> WWWW() const requires Is4D { return {W()};}
Vector<2, T> XY() const requires Is2D { return {X(), Y()};}
Vector<2, T> XYZ() const requires Is3D { return {X(), Y(), Z()};}
Vector<2, T> XYZW() const requires Is4D { return {X(), Y(), Z(), W()};}
self_type& operator+=(const self_type& other);
T* ptr();
[[nodiscard]] const T* ptr() const;
[[nodiscard]]T At(size_t index) const;
T& At(size_t index);
[[nodiscard]] T Dot(const self_type& other) const;
[[nodiscard]] T LengthSquared() const;
[[nodiscard]] T LengthSq() const;
[[nodiscard]] T Length() const;
[[nodiscard]] self_type& Normalized() const;
void Normalize();
template <size_t N> void Normalize();
bool IsNormalized() const;
template <size_t N> bool IsNormalized() const;
bool IsFinite() const;
bool IsZero();
bool IsPerpendicular() const;
bool IsPerp();
self_type Min(const self_type& ceil) const;
self_type Max(const self_type& floor) const;
self_type Min(T ceil) const;
self_type Max(T floor) const;
self_type Clamp(const self_type& floor, const self_type& ceil) const;
self_type Clamp(T floor, T ceil) const;
T Distance(const self_type& other) const requires IsFloatingPoint;
int ManhattanDistance(const self_type& other) const requires IsIntegral;
self_type Cross(const self_type& other) const requires Is3D && IsFloatingPoint {
return {
At(1) * other.At(2) - At(2) * other.At(1),
At(2) * other.At(0) - At(0) * other.At(2),
At(0) * other.At(1) - At(1) * other.At(0),
};
}
static bool AreOrthonormal(const self_type& A, const self_type& B, float epsilon = 1e-3f);
self_type Abs() const;
}; };
template<size_t DIMS, typename T>
Vector<DIMS, T>::Vector(std::initializer_list<T> values) {
size_t i = 0;
for (const T& value : values) {
if (i < DIMS) {
data[i++] = value;
} else {
break;
}
}
}
template<size_t DIMS, typename T>
Vector<DIMS, T> & Vector<DIMS, T>::operator+=(const Vector &other) {
return {0};
}
using v2f = Vector<2, float>;
using v3f = Vector<3, float>;
using v4f = Vector<4, float>;
using v2d = Vector<2, double>;
using v3d = Vector<3, double>;
using v4d = Vector<4, double>;
using v2i = Vector<2, int>;
using v3i = Vector<3, int>;
using v4i = Vector<4, int>;
const v2f Vector<2, float>::Zero = v2f(0);
const v3f Vector<3, float>::Zero = v3f(0);
const v4f Vector<4, float>::Zero = v4f(0);
const v2f Vector<2, float>::One = v2f(1);
const v3f Vector<3, float>::One = v3f(1);
const v4f Vector<4, float>::One = v4f(1);
} }

View File

@@ -16,6 +16,7 @@
#include <J3ML/J3ML.hpp> #include <J3ML/J3ML.hpp>
#include <jlog/Logger.hpp> #include <jlog/Logger.hpp>
#include <J3ML/LinearAlgebra/Matrix.hpp> #include <J3ML/LinearAlgebra/Matrix.hpp>
#include <J3ML/LinearAlgebra/Vector.hpp>
int main(int argc, char** argv) int main(int argc, char** argv)
@@ -70,10 +71,25 @@ int main(int argc, char** argv)
auto C = A*B; auto C = A*B;
using Matrix2x3f = Matrix<2, 3, float>;
std::cout << C << std::endl; std::cout << C << std::endl;
std::cout << "j3ml demo coming soon" << std::endl; std::cout << "j3ml demo coming soon" << std::endl;
v2f _v2f{1.f};
v3f _v3f{1.f};
v4f _v4f(1);
v2i ipair (420, 420);
v3i ipair3(0,0,0);
v4i ipair4(1,2,3,4);
return 0; return 0;
} }