Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
c7919a0928 | |||
db7078ff46 | |||
0d4255e759 | |||
9ecb64a2fe | |||
2886bbb397 | |||
966f6fc77d | |||
1bbe237510 | |||
d3527ab32c | |||
e4dd7058e1 | |||
3259a8e980 | |||
b17e49d1df | |||
16419b2476 |
@@ -7,8 +7,7 @@
|
||||
|
||||
/// @file AABB2D.hpp
|
||||
/// @desc A 2D Axis-Aligned Bounding Box structure.
|
||||
/// @edit 2024-08-01
|
||||
/// @note On backlog, low-priority.
|
||||
/// @edit 2025-04-18
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -23,8 +22,6 @@
|
||||
template <typename Matrix>
|
||||
void AABB2DTransformAsAABB2D(AABB2D& aabb, Matrix& m);
|
||||
|
||||
|
||||
|
||||
namespace J3ML::Geometry
|
||||
{
|
||||
using LinearAlgebra::Vector2;
|
||||
@@ -46,7 +43,7 @@ namespace J3ML::Geometry
|
||||
[[nodiscard]] float Width() const;
|
||||
[[nodiscard]] float Height() const;
|
||||
|
||||
Vector2 Centroid();
|
||||
Vector2 Centroid() const;
|
||||
|
||||
[[nodiscard]] float DistanceSq(const Vector2& pt) const;
|
||||
|
||||
|
86
include/J3ML/Geometry/Rect2D.hpp
Normal file
86
include/J3ML/Geometry/Rect2D.hpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/// Josh's 3D Math Library
|
||||
/// A C++20 Library for 3D Math, Computer Graphics, and Scientific Computing.
|
||||
/// Developed and Maintained by Josh O'Leary @ Redacted Software.
|
||||
/// Special Thanks to William Tomasine II and Maxine Hayes.
|
||||
/// (c) 2024 Redacted Software
|
||||
/// This work is dedicated to the public domain.
|
||||
|
||||
/// @file Rect2D.hpp
|
||||
/// @desc A 2D AABB, represented by a top-left origin, and a w,h size.
|
||||
/// @edit 2025-04-18
|
||||
/// @note On backlog, low-priority.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2i.hpp>
|
||||
#include <J3ML/Geometry/Forward.hpp>
|
||||
#include <J3ML/Geometry/AABB2D.hpp>
|
||||
namespace J3ML::Geometry
|
||||
{
|
||||
|
||||
/// A specialized type of 2D AABB structure, which represents a box from it's top-left point, and a size as width and height.
|
||||
/// This is more natural for manipulation in 2D games, for bounding-boxes, sprite-quads, etc.
|
||||
struct Rect2D {
|
||||
/// The top-left origin point of this Rect2D.
|
||||
Vector2 position;
|
||||
/// The width and height of this Rect2D.
|
||||
Vector2 size;
|
||||
|
||||
/// Constructs a Rect2D from a given Vector2 position, and size.
|
||||
Rect2D(const Vector2& pos, const Vector2& size);
|
||||
/// Constructs a Rect2D from a given position {x, y}, and size {w, h}
|
||||
/// @param x The X-axis of the position.
|
||||
/// @param y The Y-axis of the position.
|
||||
/// @param w The width of the Rect2D.
|
||||
/// @param h The height of the Rect2D.
|
||||
Rect2D(float x, float y, float w, float h);
|
||||
/// Constructs a Rect2D from a desired centroid, and a Vector2 specifying half-width, and half-height.
|
||||
static Rect2D FromCentroidAndRadii(const Vector2& centroid, const Vector2& radii);
|
||||
|
||||
|
||||
[[nodiscard]] float HorizontalRadius() const;
|
||||
[[nodiscard]] float VerticalRadius() const;
|
||||
[[nodiscard]] float HalfWidth() const;
|
||||
[[nodiscard]] float HalfHeight() const;
|
||||
[[nodiscard]] Vector2 Centroid() const;
|
||||
[[nodiscard]] float Width() const;
|
||||
[[nodiscard]] float Height() const;
|
||||
[[nodiscard]] Vector2 MinPoint() const;
|
||||
[[nodiscard]] Vector2 MaxPoint() const;
|
||||
[[nodiscard]] AABB2D GetAsAABB() const;
|
||||
|
||||
float Area() const { return size.x * size.y;}
|
||||
float Perimeter() const { return 2.f * (size.x + size.y); }
|
||||
|
||||
bool Intersects(const Rect2D& rhs) const;
|
||||
bool Intersects(const AABB2D& rhs) const;
|
||||
bool Contains(const Vector2& rhs) const;
|
||||
bool Contains(int x, int y) const;
|
||||
|
||||
Vector2 PosInside(const Vector2 &normalizedPos) const;
|
||||
|
||||
Vector2 ToNormalizedLocalSpace(const Vector2 &pt) const;
|
||||
|
||||
Vector2 CornerPoint(int cornerIndex);
|
||||
|
||||
bool IsDegenerate() const;
|
||||
bool HasNegativeVolume() const;
|
||||
bool IsFinite() const;
|
||||
|
||||
|
||||
|
||||
Rect2D operator + (const Vector2& pt) const;
|
||||
Rect2D& operator + (const Vector2& pt);
|
||||
Rect2D operator - (const Vector2& pt) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct Rect2Di {
|
||||
Vector2i position;
|
||||
Vector2i size;
|
||||
};
|
||||
|
||||
}
|
@@ -382,10 +382,6 @@ namespace J3ML::Math::Functions {
|
||||
/// 2241 -> 2.2k, 55421 -> 55.4k, 1000000 -> 1.0M
|
||||
std::string Truncate(float input);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
float RecipFast(float x);
|
||||
|
||||
|
||||
@@ -486,28 +482,5 @@ namespace J3ML::Math::Types {
|
||||
|
||||
}
|
||||
|
||||
namespace J3ML::Math {
|
||||
struct Rotation {
|
||||
Rotation();
|
||||
Rotation(float value);
|
||||
Rotation(const Types::Radians& radians);
|
||||
|
||||
Rotation(const Types::Degrees& degrees);
|
||||
|
||||
float valueInRadians;
|
||||
float ValueInRadians() const { return valueInRadians; }
|
||||
Types::Radians Radians() const { return {valueInRadians}; }
|
||||
float Degrees() const { return Functions::Degrees(valueInRadians); }
|
||||
|
||||
Rotation operator+(const Rotation& rhs);
|
||||
};
|
||||
|
||||
Rotation operator ""_rad(long double rads);
|
||||
|
||||
Rotation operator ""_radians(long double rads);
|
||||
|
||||
Rotation operator ""_deg(long double rads);
|
||||
|
||||
Rotation operator ""_degrees(long double rads);
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "J3ML/LinearAlgebra/Vector2.hpp"
|
||||
#include "J3ML/LinearAlgebra/Vector3.hpp"
|
||||
#include "J3ML/LinearAlgebra/Vector4.hpp"
|
||||
@@ -19,5 +18,6 @@
|
||||
#include "J3ML/LinearAlgebra/Matrix3x3.hpp"
|
||||
#include "J3ML/LinearAlgebra/Matrix4x4.hpp"
|
||||
#include "J3ML/LinearAlgebra/Transform2D.hpp"
|
||||
#include "J3ML/LinearAlgebra/Vector2i.hpp"
|
||||
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
|
@@ -15,6 +15,9 @@
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
#include <initializer_list>
|
||||
|
||||
#include "Vector.hpp"
|
||||
|
||||
namespace J3ML::LinearAlgebra
|
||||
@@ -22,8 +25,8 @@ namespace J3ML::LinearAlgebra
|
||||
|
||||
|
||||
template <uint ROWS, uint COLS, typename T>
|
||||
class Matrix
|
||||
{
|
||||
class Matrix {
|
||||
public:
|
||||
static constexpr uint Diag = std::min(ROWS, COLS);
|
||||
|
||||
using RowVector = Vector<ROWS, T>;
|
||||
@@ -33,6 +36,22 @@ namespace J3ML::LinearAlgebra
|
||||
enum { Rows = ROWS };
|
||||
enum { Cols = COLS };
|
||||
|
||||
|
||||
Matrix(std::initializer_list<T> arg) {
|
||||
int iterator = 0;
|
||||
for (T entry : arg) {
|
||||
int x = iterator % ROWS;
|
||||
int y = iterator / ROWS;
|
||||
|
||||
elems[x][y] = entry;
|
||||
|
||||
iterator++;
|
||||
}
|
||||
}
|
||||
|
||||
Matrix(const std::vector<T>& entries);
|
||||
Matrix(const std::vector<RowVector>& rows);
|
||||
|
||||
void AssertRowSize(uint rows)
|
||||
{
|
||||
assert(rows < Rows && "");
|
||||
|
@@ -5,6 +5,8 @@
|
||||
#include <J3ML/Algorithm/RNG.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <bits/ostream.tcc>
|
||||
|
||||
using namespace J3ML::Algorithm;
|
||||
|
||||
@@ -569,10 +571,15 @@ namespace J3ML::LinearAlgebra {
|
||||
/// Returns true if this Matrix4x4 is equal to the given Matrix4x4, up to given per-element epsilon.
|
||||
bool Equals(const Matrix4x4& other, float epsilon = 1e-3f) const;
|
||||
|
||||
|
||||
[[nodiscard]] std::string ToString() const;
|
||||
|
||||
protected:
|
||||
float elems[4][4];
|
||||
|
||||
|
||||
Vector3 TransformDir(float tx, float ty, float tz) const;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& out, const Matrix4x4& rhs);
|
||||
}
|
@@ -4,36 +4,52 @@
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
/// A class that performs and represents translations, rotations, and scaling operations in two dimensions.
|
||||
class Transform2D {
|
||||
protected:
|
||||
// TODO: Verify column-major order (or transpose it) for compatibility with OpenGL.
|
||||
Matrix3x3 transformation;
|
||||
public:
|
||||
|
||||
const static Transform2D Identity;
|
||||
const static Transform2D FlipX;
|
||||
const static Transform2D FlipY;
|
||||
|
||||
Transform2D(float rotation, const Vector2& pos);
|
||||
Transform2D(float px, float py, float sx, float sy, float ox, float oy, float kx, float ky, float rotation)
|
||||
{
|
||||
transformation = Matrix3x3(px, py, rotation, sx, sy, ox, oy, kx, ky);
|
||||
}
|
||||
/// Default constructor initializes to an Identity transformation.
|
||||
Transform2D();
|
||||
|
||||
Transform2D(const Vector2& pos, const Vector2& scale, const Vector2& origin, const Vector2& skew, float rotation);
|
||||
Transform2D(const Matrix3x3& transform);
|
||||
explicit Transform2D(const Matrix3x3& transform);
|
||||
|
||||
static Transform2D FromScale(float sx, float sy);
|
||||
static Transform2D FromScale(const Vector2& scale);
|
||||
static Transform2D FromRotation(float radians);
|
||||
static Transform2D FromTranslation(const Vector2& translation);
|
||||
static Transform2D FromTranslation(float tx, float ty);
|
||||
|
||||
/// Returns a Transform2D
|
||||
Transform2D Translate(const Vector2& offset) const;
|
||||
Transform2D Translate(float x, float y) const;
|
||||
Transform2D Scale(float scale); // Perform Uniform Scale
|
||||
Transform2D Scale(float x, float y); // Perform Nonunform Scale
|
||||
Transform2D Scale(const Vector2& scales); // Perform Nonuniform Scale
|
||||
Transform2D Rotate();
|
||||
Vector2 Transform(const Vector2& input) const;
|
||||
Transform2D Scale(float scale);
|
||||
Transform2D Scale(float x, float y);
|
||||
Transform2D Scale(const Vector2& scales);
|
||||
Transform2D Rotate(float radians);
|
||||
|
||||
/// Transforms a given 2D point by this transformation.
|
||||
Vector2 Transform(const Vector2& point) const;
|
||||
Transform2D Inverse() const;
|
||||
Transform2D AffineInverse() const;
|
||||
|
||||
Vector2 ForwardVector() const;
|
||||
Vector2 UpVector() const;
|
||||
|
||||
float Determinant() const;
|
||||
Vector2 GetOrigin() const;
|
||||
float& At(int row, int col);
|
||||
[[nodiscard]] float At(int row, int col) const;
|
||||
|
||||
Vector2 GetTranslation() const;
|
||||
float GetRotation() const;
|
||||
Vector2 GetScale() const;
|
||||
float GetSkew() const;
|
||||
Transform2D OrthoNormalize();
|
||||
};
|
||||
}
|
||||
|
@@ -1,15 +1,163 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace J3ML::LinearAlgebra
|
||||
{
|
||||
template <uint DIMS, typename T>
|
||||
|
||||
template <size_t D, typename T>
|
||||
class Vector {
|
||||
static_assert(D > 1, "A vector cannot be of 1-dimension, it would be just a scalar!");
|
||||
public:
|
||||
enum { Dimensions = DIMS};
|
||||
T elems[DIMS];
|
||||
static constexpr bool IsAtLeast1D = D >= 1; // Should always be true for a proper vector.
|
||||
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;
|
||||
static const self_type UnitX;
|
||||
static const self_type UnitY;
|
||||
static const self_type NaN;
|
||||
static const self_type Infinity;
|
||||
static const self_type NegativeInfinity;
|
||||
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>;
|
||||
|
||||
template<> const v2f Vector<2, float>::Zero = v2f(0);
|
||||
template<> const v3f Vector<3, float>::Zero = v3f(0);
|
||||
template<> const v4f Vector<4, float>::Zero = v4f(0);
|
||||
|
||||
template<> const v2f Vector<2, float>::One = v2f(1);
|
||||
template<> const v3f Vector<3, float>::One = v3f(1);
|
||||
template<> const v4f Vector<4, float>::One = v4f(1);
|
||||
|
||||
|
||||
}
|
||||
|
@@ -55,11 +55,12 @@ namespace J3ML::LinearAlgebra {
|
||||
Vector2(float X, float Y);
|
||||
/// Constructs this float2 from a C array, to the value (data[0], data[1]).
|
||||
explicit Vector2(const float* data);
|
||||
// Constructs a new Vector2 with the value {scalar, scalar}
|
||||
/// Constructs a new Vector2 with the value {scalar, scalar}
|
||||
explicit Vector2(float scalar);
|
||||
Vector2(const Vector2& rhs); // Copy Constructor
|
||||
explicit Vector2(const Vector2i& rhs);
|
||||
//Vector2(Vector2&&) = default; // Move Constructor
|
||||
/// Constructs a new Vector2 from std::pair<float, float>,.
|
||||
explicit Vector2(const std::pair<float, float>& rhs) : x(rhs.first), y(rhs.second) {}
|
||||
|
||||
[[nodiscard]] float GetX() const;
|
||||
[[nodiscard]] float GetY() const;
|
||||
@@ -383,6 +384,7 @@ namespace J3ML::LinearAlgebra {
|
||||
static Vector2 RandomBox(Algorithm::RNG& rng, float minElem, float maxElem);
|
||||
|
||||
[[nodiscard]] std::string ToString() const;
|
||||
|
||||
};
|
||||
|
||||
Vector2 operator*(float lhs, const Vector2 &rhs);
|
||||
|
@@ -14,6 +14,7 @@ public:
|
||||
Vector2i(int x, int y) : x(x), y(y) {}
|
||||
explicit Vector2i(int rhs) : x(rhs), y(rhs) {}
|
||||
explicit Vector2i(const Vector2& rhs) : x(rhs.x), y(rhs.y) { }
|
||||
explicit Vector2i(const std::pair<int, int>& rhs) : x(rhs.first), y(rhs.second) {}
|
||||
public:
|
||||
bool operator == (const Vector2i& rhs) const;
|
||||
bool operator != (const Vector2i& rhs) const;
|
||||
|
@@ -30,6 +30,9 @@ namespace J3ML::LinearAlgebra {
|
||||
because there is a considerable SIMD performance benefit in the first form.
|
||||
@see x, y, z, w. */
|
||||
Vector4(float X, float Y, float Z, float W);
|
||||
Vector4(float XYZW) : x(XYZW), y(0), z(0), w(0) {}
|
||||
Vector4(float X, float Y) : x(X), y(Y), z(0), w(0) {}
|
||||
Vector4(float X, float Y, float Z) : x(X), y(Y), z(Z), w(0) {}
|
||||
/// The Vector4 copy constructor.
|
||||
Vector4(const Vector4& copy) { Set(copy); }
|
||||
Vector4(Vector4&& move) = default;
|
||||
@@ -106,12 +109,9 @@ namespace J3ML::LinearAlgebra {
|
||||
/// Tests if the (x, y, z) part of this vector is equal to (0,0,0), up to the given epsilon.
|
||||
/** @see NormalizeW(), IsWZeroOrOne(), IsZero4(), IsNormalized3(), IsNormalized4(). */
|
||||
[[nodiscard]] bool IsZero3(float epsilonSq = 1e-6f) const;
|
||||
|
||||
|
||||
/// Returns true if this vector is equal to (0,0,0,0), up to the given epsilon.
|
||||
/** @see NormalizeW(), IsWZeroOrOne(), IsZero3(), IsNormalized3(), IsNormalized4(). */
|
||||
[[nodiscard]] bool IsZero(float epsilonSq = 1e-6f) const;
|
||||
[[nodiscard]] bool IsZero4(float epsilonSq = 1e-6f) const;
|
||||
|
||||
/// Tests if this vector contains valid finite elements.
|
||||
[[nodiscard]] bool IsFinite() const;
|
||||
|
||||
@@ -202,6 +202,7 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
[[nodiscard]] float Magnitude() const;
|
||||
[[nodiscard]] float Dot(const Vector4& rhs) const;
|
||||
[[nodiscard]] float Dot4(const Vector4& rhs) const { return this->Dot(rhs); }
|
||||
/// Computes the dot product of the (x, y, z) parts of this and the given float4.
|
||||
/** @note This function ignores the w component of this vector (assumes w=0).
|
||||
@see Dot4(), Cross3(). */
|
||||
@@ -209,10 +210,9 @@ namespace J3ML::LinearAlgebra {
|
||||
[[nodiscard]] float Dot3(const Vector4& rhs) const;
|
||||
|
||||
[[nodiscard]] Vector4 Project(const Vector4& rhs) const;
|
||||
// While it is feasable to compute a cross-product in four dimensions
|
||||
// the cross product only has the orthogonality property in 3 and 7 dimensions
|
||||
// You should consider instead looking at Gram-Schmidt Orthogonalization
|
||||
// to find orthonormal vectors.
|
||||
|
||||
/// While it is feasable to compute a cross-product in four dimensions the cross product only has the orthogonality property in 3 and 7 dimensions.
|
||||
/// You should consider instead looking at Gram-Schmidt Orthogonalization to find orthonormal vectors.
|
||||
[[nodiscard]] Vector4 Cross3(const Vector3& rhs) const;
|
||||
[[nodiscard]] Vector4 Cross3(const Vector4& rhs) const;
|
||||
[[nodiscard]] Vector4 Cross(const Vector4& rhs) const;
|
||||
@@ -220,7 +220,11 @@ namespace J3ML::LinearAlgebra {
|
||||
[[nodiscard]] Vector4 Normalized() const;
|
||||
[[nodiscard]] Vector4 Lerp(const Vector4& goal, float alpha) const;
|
||||
|
||||
/// Returns the angle between this vector and the specified vector, in radians.
|
||||
/// @note This function takes into account that this vector or the other vector can be un-normalized, and normalizes the computations.
|
||||
/// @see Dot3(), AngleBetween3(), AngleBetweenNorm3(), AngleBetweenNorm().
|
||||
[[nodiscard]] float AngleBetween(const Vector4& rhs) const;
|
||||
[[nodiscard]] float AngleBetween4(const Vector4& rhs) const;
|
||||
|
||||
/// Adds two vectors. [indexTitle: operators +,-,*,/]
|
||||
/** This function is identical to the member function Add().
|
||||
@@ -243,17 +247,23 @@ namespace J3ML::LinearAlgebra {
|
||||
/** This function is identical to the member function Mul().
|
||||
@return float4(x * scalar, y * scalar, z * scalar, w * scalar); */
|
||||
Vector4 operator *(float rhs) const;
|
||||
[[nodiscard]] Vector4 Mul(float scalar) const;
|
||||
static Vector4 Mul(const Vector4& lhs, float rhs);
|
||||
[[nodiscard]] Vector4 Mul(float scalar) const { return *this * scalar;}
|
||||
static Vector4 Mul(const Vector4& lhs, float rhs) {return lhs * rhs; }
|
||||
|
||||
/// Divides this vector by a scalar. [similarOverload: operator+] [hideIndex]
|
||||
/** This function is identical to the member function Div().
|
||||
@return float4(x / scalar, y / scalar, z / scalar, w * scalar); */
|
||||
Vector4 operator /(float rhs) const;
|
||||
[[nodiscard]] Vector4 Div(float scalar) const;
|
||||
static Vector4 Div(const Vector4& rhs, float scalar);
|
||||
[[nodiscard]] Vector4 Div(float scalar) const { return *this / scalar; }
|
||||
static Vector4 Div(const Vector4& rhs, float scalar) { return rhs / scalar; }
|
||||
|
||||
Vector4 operator +() const; // Unary + Operator
|
||||
/// Divides this vector by a vector, element-wise.
|
||||
/// @note Mathematically, the division of two vectors is not defined in linear space structures,
|
||||
/// but this function is provided here for syntactical convenience.
|
||||
Vector4 Div(const Vector4& rhs) const;
|
||||
static Vector4 Div(const Vector4& lhs, const Vector4& rhs);
|
||||
|
||||
Vector4 operator +() const { return *this;} // Unary + Operator
|
||||
/// Performs an unary negation of this vector. [similarOverload: operator+] [hideIndex]
|
||||
/** This function is identical to the member function Neg().
|
||||
@return float4(-x, -y, -z, -w). */
|
||||
|
56
include/J3ML/Rotation.hpp
Normal file
56
include/J3ML/Rotation.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
#include "J3ML.hpp"
|
||||
#include "LinearAlgebra/Vector2.hpp"
|
||||
|
||||
namespace J3ML::Math {
|
||||
|
||||
/// Rotation is a class that represents a single axis of rotation.
|
||||
/// The class is designed to behave very similarly to a float literal, and
|
||||
/// primarily help organize code involving rotations by handling common boilerplate
|
||||
/// and providing mathematical expressions.
|
||||
struct Rotation {
|
||||
|
||||
constexpr Rotation();
|
||||
constexpr Rotation(float value);
|
||||
constexpr explicit Rotation(const Vector2& direction_vector);
|
||||
|
||||
constexpr Rotation FromDegrees(float degrees);
|
||||
|
||||
constexpr Rotation FromRadians(float radians);
|
||||
|
||||
//Rotation(const Types::Radians& radians);
|
||||
//Rotation(const Types::Degrees& degrees);
|
||||
|
||||
|
||||
constexpr float Radians() const { return value;}
|
||||
//Types::Radians Radians() const { return {value}; }
|
||||
constexpr float Degrees() const { return Math::Degrees(value); }
|
||||
|
||||
constexpr Rotation operator+(const Rotation& rhs) const;
|
||||
constexpr Rotation operator-(const Rotation& rhs) const;
|
||||
constexpr Rotation operator*(float scalar) const;
|
||||
constexpr Rotation operator/(float scalar) const;
|
||||
constexpr bool operator==(const Rotation& rhs) const = default;
|
||||
constexpr Rotation operator-() const;
|
||||
|
||||
/// Rotates a given Vector2 by this Rotation.
|
||||
Vector2 Rotate(const Vector2& rhs) const;
|
||||
|
||||
float operator()() const { return value; }
|
||||
Rotation& operator=(const Rotation& rhs) {
|
||||
this->value = rhs.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
float value;
|
||||
};
|
||||
|
||||
constexpr Rotation operator ""_rad(long double rads);
|
||||
|
||||
constexpr Rotation operator ""_radians(long double rads);
|
||||
|
||||
constexpr Rotation operator ""_deg(long double rads);
|
||||
|
||||
constexpr Rotation operator ""_degrees(long double rads);
|
||||
}
|
46
main.cpp
46
main.cpp
@@ -15,6 +15,10 @@
|
||||
#include <J3ML/Geometry.hpp>
|
||||
#include <J3ML/J3ML.hpp>
|
||||
#include <jlog/Logger.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector.hpp>
|
||||
|
||||
#include "J3ML/Rotation.hpp"
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
@@ -50,10 +54,48 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
Ray a({420, 0, 0}, {1, 0, 0});
|
||||
|
||||
|
||||
std::cout << a << std::endl;
|
||||
|
||||
Matrix4x4 A {
|
||||
1, 2, 0, 1,
|
||||
3, 1, 2, 0,
|
||||
0, 4, 1, 2,
|
||||
2, 0, 3, 1
|
||||
};
|
||||
|
||||
Matrix4x4 B {
|
||||
0, 1, 2, 3,
|
||||
1, 0, 1, 0,
|
||||
2, 3, 0, 1,
|
||||
1, 2, 1, 0
|
||||
};
|
||||
|
||||
|
||||
auto C = A*B;
|
||||
|
||||
using Matrix2x3f = Matrix<2, 3, float>;
|
||||
|
||||
|
||||
std::cout << C << 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);
|
||||
|
||||
using namespace J3ML::Math;
|
||||
|
||||
Rotation my_rot = 25_degrees;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -78,7 +78,7 @@ namespace J3ML::Geometry
|
||||
return a;
|
||||
}
|
||||
|
||||
Vector2 AABB2D::Centroid() {
|
||||
Vector2 AABB2D::Centroid() const {
|
||||
return (minPoint + (maxPoint / 2.f));
|
||||
}
|
||||
|
||||
|
50
src/J3ML/Geometry/Rect2D.cpp
Normal file
50
src/J3ML/Geometry/Rect2D.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <J3ML/Geometry/Rect2D.hpp>
|
||||
|
||||
namespace J3ML::Geometry
|
||||
{
|
||||
Rect2D Rect2D::operator+(const J3ML::LinearAlgebra::Vector2 &pt) const {
|
||||
return {position+pt, size};
|
||||
}
|
||||
|
||||
Rect2D &Rect2D::operator+(const Vector2 &pt) {
|
||||
position += pt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AABB2D Rect2D::GetAsAABB() const { return {MinPoint(), MaxPoint()};}
|
||||
|
||||
Rect2D Rect2D::FromCentroidAndRadii(const Vector2 ¢roid, const Vector2 &radii) {
|
||||
return Rect2D(centroid.x - (radii.x), centroid.y - (radii.y),
|
||||
radii.x*2.f, radii.y*2.f);
|
||||
}
|
||||
|
||||
Rect2D::Rect2D(float x, float y, float w, float h) {
|
||||
this->position = {x,y};
|
||||
this->size = {w,h};
|
||||
}
|
||||
|
||||
Rect2D::Rect2D(const Vector2 &pos, const Vector2 &size) {
|
||||
this->position = pos;
|
||||
this->size = size;
|
||||
}
|
||||
|
||||
float Rect2D::HorizontalRadius() const { return Width()/2.f;}
|
||||
|
||||
float Rect2D::VerticalRadius() const { return Height()/2.f;}
|
||||
|
||||
float Rect2D::HalfWidth() const { return HorizontalRadius();}
|
||||
|
||||
float Rect2D::HalfHeight() const { return VerticalRadius();}
|
||||
|
||||
Vector2 Rect2D::Centroid() const { return position + (size / 2.f);}
|
||||
|
||||
float Rect2D::Width() const { return size.x;}
|
||||
|
||||
float Rect2D::Height() const { return size.y;}
|
||||
|
||||
Vector2 Rect2D::MinPoint() const { return position; }
|
||||
|
||||
Vector2 Rect2D::MaxPoint() const { return position + size;}
|
||||
|
||||
|
||||
}
|
@@ -136,14 +136,6 @@ namespace J3ML::Math::Functions { }
|
||||
|
||||
namespace J3ML {
|
||||
|
||||
Math::Rotation Math::operator ""_degrees(long double rads) { return {Functions::Radians((float)rads)}; }
|
||||
|
||||
Math::Rotation Math::operator ""_deg(long double rads) { return {Functions::Radians((float)rads)}; }
|
||||
|
||||
Math::Rotation Math::operator ""_radians(long double rads) { return {(float)rads}; }
|
||||
|
||||
Math::Rotation Math::operator ""_rad(long double rads) { return {(float)rads}; }
|
||||
|
||||
float Math::Functions::FastRSqrt(float x) {
|
||||
return 1.f / FastSqrt(x);
|
||||
}
|
||||
@@ -305,17 +297,7 @@ namespace J3ML {
|
||||
return 1.f / x;
|
||||
}
|
||||
|
||||
Math::Rotation::Rotation() : valueInRadians(0) {}
|
||||
|
||||
Math::Rotation::Rotation(float value) : valueInRadians(value) {}
|
||||
|
||||
Math::Rotation::Rotation(const Types::Radians &radians): valueInRadians(radians.value) {}
|
||||
|
||||
Math::Rotation::Rotation(const Types::Degrees °rees): valueInRadians(Functions::Radians(degrees.value)) {}
|
||||
|
||||
Math::Rotation Math::Rotation::operator+(const Math::Rotation &rhs) {
|
||||
return {valueInRadians + rhs.valueInRadians};
|
||||
}
|
||||
|
||||
// int BitTwiddling::CountBitsSet(u32 value) { }
|
||||
|
||||
|
@@ -1,9 +1,10 @@
|
||||
#include <iomanip>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrices.inl>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
@@ -679,6 +680,11 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, const Matrix4x4 &rhs) {
|
||||
out << rhs.ToString();
|
||||
return out;
|
||||
}
|
||||
|
||||
void Matrix4x4::InverseOrthonormal()
|
||||
{
|
||||
//assert(!ContainsProjection());
|
||||
@@ -1014,6 +1020,46 @@ namespace J3ML::LinearAlgebra {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string trim_trailing_zeros(const std::string &value) {
|
||||
std::string str = value;
|
||||
// Ensure that there is a decimal point somewhere (there should be)
|
||||
if(str.find('.') != std::string::npos)
|
||||
{
|
||||
// Remove trailing zeroes
|
||||
str = str.substr(0, str.find_last_not_of('0')+1);
|
||||
// If the decimal point is now the last character, remove that as well
|
||||
if(str.find('.') == str.size()-1)
|
||||
{
|
||||
str = str.substr(0, str.size()-1);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string Matrix4x4::ToString() const {
|
||||
|
||||
// Determine the maximum width for any element in the matrix.
|
||||
size_t max_width = 0;
|
||||
for (size_t row = 0; row < 4; ++row) {
|
||||
for (size_t col = 0; col < 4; ++col) {
|
||||
std::string s = std::to_string(At(row, col));
|
||||
s = trim_trailing_zeros(s);
|
||||
max_width = std::max(max_width, s.length());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t row = 0; row < 4; ++row) {
|
||||
for (size_t col = 0; col < 4; ++col) {
|
||||
auto val = this->At(row, col);
|
||||
|
||||
|
||||
std::cout << std::right << std::setw(static_cast<int>(max_width)) << val << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::Set(float _00, float _01, float _02, float _03, float _10, float _11, float _12, float _13, float _20,
|
||||
float _21, float _22, float _23, float _30, float _31, float _32, float _33) {
|
||||
|
@@ -27,4 +27,73 @@ namespace J3ML::LinearAlgebra {
|
||||
Transform2D Transform2D::Translate(const LinearAlgebra::Vector2 &input) const {
|
||||
return Translate(input.x, input.y);
|
||||
}
|
||||
|
||||
Transform2D::Transform2D() {
|
||||
transformation = Matrix3x3::Identity;
|
||||
}
|
||||
|
||||
Transform2D Transform2D::FromRotation(float radians) {
|
||||
float c = Math::Cos(radians);
|
||||
float s = Math::Sin(radians);
|
||||
return Transform2D(Matrix3x3(
|
||||
c, s, 0.f,
|
||||
-s, c, 0.f,
|
||||
0.f, 0.f, 1.f));
|
||||
}
|
||||
|
||||
Transform2D Transform2D::FromScale(const Vector2 &scale) {
|
||||
return FromScale(scale.x, scale.y);
|
||||
}
|
||||
|
||||
Transform2D Transform2D::FromScale(float sx, float sy) {
|
||||
Transform2D s;
|
||||
s.transformation[0][0] = sx;
|
||||
s.transformation[1][1] = sy;
|
||||
return s;
|
||||
}
|
||||
|
||||
Transform2D Transform2D::FromTranslation(const Vector2 &translation) {
|
||||
return FromTranslation(translation.x, translation.y);
|
||||
}
|
||||
|
||||
Transform2D Transform2D::FromTranslation(float tx, float ty) {
|
||||
return Transform2D(Matrix3x3(
|
||||
1.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f,
|
||||
tx, ty, 1.f));
|
||||
}
|
||||
|
||||
Vector2 Transform2D::GetScale() const {
|
||||
return {
|
||||
Math::Sqrt(At(0,0) * At(0,0) + At(0,1) * At(0,1)),
|
||||
Math::Sqrt(At(1,0) * At(1,0) + At(1,1) * At(1,1))
|
||||
};
|
||||
}
|
||||
|
||||
float Transform2D::GetRotation() const {
|
||||
return Math::Atan2(At(1, 0), At(0, 0));
|
||||
}
|
||||
|
||||
Vector2 Transform2D::GetTranslation() const {
|
||||
return {At(2,0), At(2, 1)};
|
||||
}
|
||||
|
||||
float &Transform2D::At(int row, int col) { return transformation.At(row, col); }
|
||||
|
||||
float Transform2D::At(int row, int col) const { return transformation.At(row, col); }
|
||||
|
||||
float Transform2D::Determinant() const { return transformation.Determinant(); }
|
||||
|
||||
/*
|
||||
Vector2 Transform2D::Transform(const Vector2 &point) const {
|
||||
Vector2 result;
|
||||
result.x = At(0,0) * point.x + At(0,1) * point.y + At(0,2);
|
||||
result.y = At(1,0) * point.x + At(1,1) * point.y + At(1,2);
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
Vector2 Transform2D::ForwardVector() const { return {At(0,0), At(1,0)}; }
|
||||
|
||||
Vector2 Transform2D::UpVector() const { return {At(0,1), At(1,1)}; }
|
||||
}
|
@@ -331,5 +331,63 @@ Vector4 Vector4::operator-(const Vector4& rhs) const
|
||||
}
|
||||
|
||||
Vector4 Vector4::Cross(const Vector4 &rhs) const { return Cross3(rhs); }
|
||||
|
||||
Vector4 Vector4::Add(const Vector4 &rhs) const { return *this + rhs;}
|
||||
|
||||
Vector4 Vector4::Add(const Vector4 &lhs, const Vector4 &rhs) {
|
||||
return lhs + rhs;
|
||||
}
|
||||
|
||||
float Vector4::AngleBetween(const Vector4 &rhs) const {
|
||||
float cosa = this->Dot4(rhs) / Math::Sqrt(LengthSq4() * rhs.LengthSq4());
|
||||
|
||||
if (cosa >= 1.f)
|
||||
return 0.f;
|
||||
else if (cosa <= -1.f)
|
||||
return Math::Pi;
|
||||
else
|
||||
return Math::Acos(cosa);
|
||||
}
|
||||
|
||||
float Vector4::AngleBetween4(const Vector4 &rhs) const { return AngleBetween(rhs);}
|
||||
|
||||
bool Vector4::IsZero4(float epsilonSq) const {
|
||||
return LengthSq4() <= epsilonSq;
|
||||
}
|
||||
|
||||
bool Vector4::IsZero(float epsilonSq) const { return IsZero4(epsilonSq);}
|
||||
|
||||
Vector4 Vector4::Clamp01() const {
|
||||
return Vector4(
|
||||
Math::Clamp01(x),
|
||||
Math::Clamp01(y),
|
||||
Math::Clamp01(z),
|
||||
Math::Clamp01(w) );
|
||||
}
|
||||
|
||||
Vector4 Vector4::Sub(const Vector4 &rhs) const { return *this - rhs;}
|
||||
|
||||
Vector4 Vector4::Sub(const Vector4 &lhs, const Vector4 &rhs) { return lhs - rhs;}
|
||||
|
||||
Vector4 Vector4::operator/(float rhs) const {
|
||||
float invScalar = 1.f / rhs;
|
||||
return Vector4(x * invScalar, y * invScalar, z * invScalar, w * invScalar);
|
||||
}
|
||||
|
||||
Vector4 Vector4::Div(const Vector4 &rhs) const {
|
||||
return Vector4(
|
||||
x / rhs.x,
|
||||
y / rhs.y,
|
||||
z / rhs.z,
|
||||
w / rhs.w );
|
||||
}
|
||||
|
||||
Vector4 Vector4::Div(const Vector4 &lhs, const Vector4 &rhs) {
|
||||
return lhs.Div(rhs);
|
||||
}
|
||||
|
||||
Vector4 Vector4::operator-() const {
|
||||
return Vector4(-x,-y,-z,-w);
|
||||
}
|
||||
}
|
||||
#pragma endregion
|
44
src/J3ML/Rotation.cpp
Normal file
44
src/J3ML/Rotation.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include <J3ML/Rotation.hpp>
|
||||
|
||||
namespace J3ML {
|
||||
Math::Rotation Math::operator ""_degrees(long double rads) { return {Functions::Radians((float)rads)}; }
|
||||
|
||||
Math::Rotation Math::operator ""_deg(long double rads) { return {Functions::Radians((float)rads)}; }
|
||||
|
||||
Math::Rotation Math::operator ""_radians(long double rads) { return {(float)rads}; }
|
||||
|
||||
Vector2 Math::Rotation::Rotate(const Vector2 &rhs) const {
|
||||
float cos_a = Math::Cos(value);
|
||||
float sin_a = Math::Sin(value);
|
||||
|
||||
return Vector2(
|
||||
rhs.x * cos_a - rhs.y * sin_a,
|
||||
rhs.x * sin_a + rhs.y * cos_a);
|
||||
}
|
||||
|
||||
Math::Rotation Math::operator ""_rad(long double rads) { return {(float)rads}; }
|
||||
|
||||
Math::Rotation::Rotation() : value(0) {}
|
||||
|
||||
Math::Rotation::Rotation(float value) : value(value) {}
|
||||
|
||||
constexpr Math::Rotation::Rotation(const Vector2 &direction_vector) {
|
||||
value = Math::Atan2(direction_vector.y, direction_vector.x);
|
||||
}
|
||||
|
||||
constexpr Math::Rotation Math::Rotation::FromDegrees(float degrees) {
|
||||
return Rotation(Math::Radians(degrees));
|
||||
}
|
||||
|
||||
constexpr Math::Rotation Math::Rotation::FromRadians(float radians) { return Rotation(value);}
|
||||
|
||||
|
||||
Math::Rotation Math::Rotation::operator+(const Math::Rotation &rhs) const {
|
||||
return {value + rhs.value};
|
||||
}
|
||||
|
||||
Math::Rotation Math::Rotation::operator-(const Math::Rotation &rhs) const {
|
||||
return {value - rhs.value};
|
||||
|
||||
}
|
||||
}
|
@@ -11,8 +11,7 @@ namespace Matrix4x4Tests {
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
using namespace J3ML::Math;
|
||||
|
||||
Matrix4x4Unit += Test("Add_Unary", []
|
||||
{
|
||||
Matrix4x4Unit += Test("Add_Unary", [] {
|
||||
Matrix4x4 m(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
||||
Matrix4x4 m2 = +m;
|
||||
jtest::check(m.Equals(m2));
|
||||
@@ -111,13 +110,52 @@ namespace Matrix4x4Tests {
|
||||
});
|
||||
|
||||
|
||||
Matrix4x4Unit += Test("CtorFromQuatTrans", [] {});
|
||||
Matrix4x4Unit += Test("Translate", [] {});
|
||||
Matrix4x4Unit += Test("Scale", [] {});
|
||||
Matrix4x4Unit += Test("InverseOrthogonalUniformScale", [] {});
|
||||
Matrix4x4Unit += Test("InverseOrthonormal", [] {});
|
||||
Matrix4x4Unit += Test("DeterminantCorrectness", [] { });
|
||||
Matrix4x4Unit += Test("MulMat3x3", [] {});
|
||||
Matrix4x4Unit += Test("CtorFromQuatTrans", [] {
|
||||
RNG rng;
|
||||
constexpr float SCALE = 1e2f;
|
||||
Vector3 t = Vector3::RandomBox(rng, Vector3(-SCALE, -SCALE, -SCALE), Vector3(SCALE, SCALE, SCALE));
|
||||
Quaternion q = Quaternion::RandomRotation(rng);
|
||||
|
||||
Matrix4x4 m (q, t);
|
||||
|
||||
Vector3 v = Vector3(-1, 5, 20.f);
|
||||
Vector3 v1 = q * v + t;
|
||||
Vector3 v2 = m.Transform(v);
|
||||
jtest::check(v1.Equals(v2));
|
||||
|
||||
});
|
||||
Matrix4x4Unit += Test("Translate", [] {
|
||||
RNG rng;
|
||||
constexpr float SCALE = 1e2f;
|
||||
Vector3 t = Vector3::RandomBox(rng, Vector3(-SCALE, -SCALE, -SCALE), Vector3(SCALE, SCALE, SCALE));
|
||||
Vector3 t2 = Vector3::RandomBox(rng, Vector3(-SCALE, -SCALE, -SCALE), Vector3(SCALE, SCALE, SCALE));
|
||||
|
||||
Matrix4x4 m = Matrix4x4::Translate(t);
|
||||
Matrix4x4 m2 = Matrix4x4::Translate({t.x, t.y, t.z});
|
||||
|
||||
Vector3 v = t + t2;
|
||||
Vector3 v1 = m.Transform(t2);
|
||||
Vector3 v2 = m2.Transform(t2);
|
||||
|
||||
jtest::check(v1.Equals(v2));
|
||||
jtest::check(v.Equals(v1));
|
||||
});
|
||||
Matrix4x4Unit += Test("Scale", [] {
|
||||
Matrix4x4 m = Matrix4x4::Scale({2, 4, 6});
|
||||
Matrix4x4 m2(2,0,0,0, 0,4,0,0, 0,0,6,0, 0,0,0,1);
|
||||
jtest::check(m.Equals(m2));
|
||||
});
|
||||
Matrix4x4Unit += Test("MulMat3x3", [] {
|
||||
RNG rng;
|
||||
Matrix3x3 m = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
Matrix4x4 m_ = m;
|
||||
Matrix4x4 m2 = Matrix4x4::RandomGeneral(rng, -10.f, 10.f);
|
||||
|
||||
Matrix4x4 test = m2 * m;
|
||||
Matrix4x4 correct = m2 * m_;
|
||||
|
||||
jtest::check(test.Equals(correct));
|
||||
});
|
||||
}
|
||||
|
||||
inline void Run() {
|
||||
|
Reference in New Issue
Block a user