Fixed several recursive header issues, refactored Math lib, began implementing core mathematical functions as wrappers around stdmath, will implement SSE and lookup tables later.
This commit is contained in:
@@ -6,128 +6,265 @@
|
||||
#include <J3ML/LinearAlgebra/Common.h>
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
/// A 3D vector of form (x,y,z,w) in a 4D homogeneous coordinate space.
|
||||
/** This class has two sets of member functions. The functions ending in a suffix '3' operate only on the
|
||||
(x, y, z) part, ignoring the w component (or assuming a value of 0 or 1, where expectable). The functions
|
||||
without the '3' suffix operate on all four elements of the vector. */
|
||||
class Vector4 {
|
||||
public:
|
||||
// Default Constructor
|
||||
enum { Size = 4 };
|
||||
public:
|
||||
static const Vector4 Zero;
|
||||
static const Vector4 NaN;
|
||||
public:
|
||||
/// The default constructor does not initialize any members of this class.
|
||||
/** This means that the values of the members x, y, z, and w are all undefined after creating a new Vector4 using
|
||||
this default constructor. Remember to assign to them before use.
|
||||
@see x, y, z, w. */
|
||||
Vector4();
|
||||
// Constructs a new Vector4 with x,y,z values from a Vector3
|
||||
Vector4(const Vector3& xyz, float w = 0);
|
||||
// Constructs a new Vector4 with the value (X, Y, Z, W)
|
||||
/// Constructs a new Vector4 with x,y,z values from a Vector3
|
||||
explicit Vector4(const Vector3& xyz, float w = 0);
|
||||
/// Constructs a new Vector4 with the value (X, Y, Z, W)
|
||||
/** @note If you are constructing a float4 from an array of consecutive values, always prefer calling "float4(ptr);" instead of "float4(ptr[0], ptr[1], ptr[2], ptr[3]);"
|
||||
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(const Vector4& copy) = default;
|
||||
/// The Vector4 copy constructor.
|
||||
Vector4(const Vector4& copy) { Set(copy); }
|
||||
Vector4(Vector4&& move) = default;
|
||||
Vector4& operator=(const Vector4& rhs);
|
||||
|
||||
float* ptr()
|
||||
{
|
||||
return &x;
|
||||
}
|
||||
Vector3 XYZ() const;
|
||||
/// Constructs this Vector4 from a C array, to the value (data[0], data[1], data[2], data[3]).
|
||||
/** @param data An array containing four elements for x, y, z, and w. This pointer may not be null. */
|
||||
explicit Vector4(const float* data);
|
||||
|
||||
float GetX() const { return x; }
|
||||
float GetY() const { return y; }
|
||||
float GetZ() const { return z; }
|
||||
float GetW() const { return w; }
|
||||
#if MUTABLE
|
||||
/// Casts this Vector4 to a C array.
|
||||
/** This function does not allocate new memory or make a copy of this Vector4. This function simply
|
||||
returns a C pointer view to this data structure. Use ptr()[0] to access the x component of this Vector4,
|
||||
ptr()[1] to access y, ptr()[2] to access z, and ptr()[3] to access the w component of this Vector4.
|
||||
@note Since the returned pointer points to this class, do not dereference the pointer after this
|
||||
Vector has been deleted. You should never store a copy of the returned pointer.
|
||||
@note This function is provided for compatibility with other APIs which require raw C pointer access
|
||||
to vectors. Avoid using this function in general, and instead always use the operator [] of this
|
||||
class to access the elements of this vector by index. */
|
||||
inline float* ptr();
|
||||
[[nodiscard]] const float* ptr() const;
|
||||
|
||||
/// Accesses an element of this vector using array notation.
|
||||
/** @param index The element to get. Pass in 0 for x, 1 for y, 2 for z and 3 for w.
|
||||
@note If you have a non-const instance of this class, you can use this notation to set the elements of
|
||||
this vector as well, e.g. vec[1] = 10.f; would set the y-component of this vector. */
|
||||
float operator[](std::size_t index) const;
|
||||
float &operator[](std::size_t index);
|
||||
|
||||
/// Accesses an element of this vector.
|
||||
/** @param index The element to get. Pass in 0 for x, 1 for y, 2 for z and 3 for w.
|
||||
@note If you have a non-const instance of this class, you can use this notation to set the elements of
|
||||
this vector as well, e.g. vec.At(1) = 10.f; would set the y-component of this vector. */
|
||||
float At(int index) const;
|
||||
float& At(int index);
|
||||
|
||||
/// Returns the (x,y) part of this vector.
|
||||
[[nodiscard]] Vector2 XY() const;
|
||||
|
||||
/// Returns the (x,y,z) part of this vector.
|
||||
[[nodiscard]] Vector3 XYZ() const;
|
||||
|
||||
[[nodiscard]] float GetX() const { return x; }
|
||||
[[nodiscard]] float GetY() const { return y; }
|
||||
[[nodiscard]] float GetZ() const { return z; }
|
||||
[[nodiscard]] float GetW() const { return w; }
|
||||
void SetX(float newX) { x = newX;}
|
||||
void SetY(float newY) { y = newY;}
|
||||
void SetZ(float newZ) { z = newZ;}
|
||||
void SetW(float newW) { w = newW;}
|
||||
#endif
|
||||
static const Vector4 Zero;
|
||||
static const Vector4 NaN;
|
||||
|
||||
float operator[](std::size_t index) const;
|
||||
float &operator[](std::size_t index);
|
||||
/// Sets all elements of this vector.
|
||||
/** @see x, y, z, w, At(). */
|
||||
void Set(float x, float y, float z, float w);
|
||||
void Set(const Vector4& rhs);
|
||||
|
||||
bool IsWithinMarginOfError(const Vector4& rhs, float margin=0.0001f) const;
|
||||
|
||||
float LengthSqXYZ() const;
|
||||
|
||||
bool IsNormalized3(float epsilonSq = 1e-5f) const
|
||||
{
|
||||
return std::abs(LengthSqXYZ()-1.f) <= epsilonSq;
|
||||
}
|
||||
bool IsNormalized4(float epsilonSq = 1e-5f) const
|
||||
{
|
||||
return std::abs(LengthSquared()-1.f) <= epsilonSq;
|
||||
}
|
||||
bool IsNormalized(float epsilonSq = 1e-5f) const { return IsNormalized4(epsilonSq); }
|
||||
bool IsZero(float epsilonSq = 1e-6f) const;
|
||||
bool IsFinite() const;
|
||||
bool IsPerpendicular(const Vector4& other, float epsilonSq=1e-5f) const
|
||||
{
|
||||
float dot = Dot(other);
|
||||
return dot*dot <= epsilonSq * LengthSquared() * other.LengthSquared();
|
||||
}
|
||||
bool IsPerpendicular3(const Vector4& other, float epsilonSq = 1e-5f) const
|
||||
{
|
||||
|
||||
}
|
||||
[[nodiscard]] bool IsWithinMarginOfError(const Vector4& rhs, float margin=0.0001f) const;
|
||||
|
||||
/// Computes the squared length of the (x,y,z) part of this vector.
|
||||
[[nodiscard]] float LengthSqXYZ() const;
|
||||
|
||||
/// Tests if the length of the (x, y, z) part of this vector is one, up to the given epsilon.
|
||||
/** @see NormalizeW(), IsWZeroOrOne(), IsZero3(), IsZero4(), IsNormalized4(). */
|
||||
[[nodiscard]] bool IsNormalized3(float epsilonSq = 1e-5f) const;
|
||||
|
||||
/// Returns true if the length of this vector is 1, up to the given epsilon.
|
||||
/** This function takes into account all the four components of this vector when calculating the norm.
|
||||
@see NormalizeW(), IsWZeroOrOne(), IsZero3(), IsZero4(), IsNormalized3(). */
|
||||
[[nodiscard]] bool IsNormalized4(float epsilonSq = 1e-5f) const;
|
||||
[[nodiscard]] bool IsNormalized(float epsilonSq = 1e-5f) const;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Tests if the (x, y, z) parts of two vectors are perpendicular to each other.
|
||||
[[nodiscard]] bool IsPerpendicular(const Vector4& other, float epsilonSq=1e-5f) const;
|
||||
|
||||
[[nodiscard]] bool IsPerpendicular3(const Vector4& other, float epsilonSq = 1e-5f) const;
|
||||
|
||||
/// Divides each element by w to produce a Vector4 of form (x, y, z, 1).
|
||||
/** This function performs the <b>perspective divide</b> or the <b>homogeneous divide</b> on this vector, which is the
|
||||
process of dividing each element of this vector by w. If the w component of this vector is zero before division, the
|
||||
result of this vector will be undefined.
|
||||
@note This function operates in-place.
|
||||
@see IsWZeroOrOne(). */
|
||||
void NormalizeW();
|
||||
|
||||
bool operator==(const Vector4& rhs) const;
|
||||
bool operator!=(const Vector4& rhs) const;
|
||||
|
||||
bool Equals(const Vector4& rhs, float epsilon = 1e-3f) const;
|
||||
bool Equals(float _x, float _y, float _z, float _w, float epsilon = 1e-3f) const;
|
||||
[[nodiscard]] bool Equals(const Vector4& rhs, float epsilon = 1e-3f) const;
|
||||
[[nodiscard]] bool Equals(float _x, float _y, float _z, float _w, float epsilon = 1e-3f) const;
|
||||
|
||||
Vector4 Min(const Vector4& min) const;
|
||||
Vector4 Max(const Vector4& max) const;
|
||||
Vector4 Clamp(const Vector4& min, const Vector4& max) const;
|
||||
float Distance(const Vector4& to) const;
|
||||
float Length() const;
|
||||
float LengthSquared() const;
|
||||
float Magnitude() const;
|
||||
float Dot(const Vector4& rhs) const;
|
||||
Vector4 Project(const Vector4& rhs) const;
|
||||
/// Returns an element-wise minimum of this and the vector (ceil, ceil, ceil, ceil).
|
||||
/** Each element that is larger than ceil is replaced by ceil. */
|
||||
[[nodiscard]] Vector4 Min(float ceil) const;
|
||||
|
||||
/// Returns an element-wise minimum of this and the given vector.
|
||||
/** Each element that is larger than ceil is replaced by ceil.
|
||||
@see Max(), Clamp(). */
|
||||
[[nodiscard]] Vector4 Min(const Vector4& ceil) const;
|
||||
|
||||
/// Returns an element-wise maximum of this and the vector (floor, floor, floor, floor).
|
||||
/** Each element that is smaller than floor is replaced by floor. */
|
||||
[[nodiscard]] Vector4 Max(float floor) const;
|
||||
|
||||
/// Returns an element-wise maximum of this and the given vector.
|
||||
/** Each element that is smaller than floor is replaced by floor.
|
||||
@see Min(), Clamp(). */
|
||||
[[nodiscard]] Vector4 Max(const Vector4& floor) const;
|
||||
|
||||
/// Returns a vector that has floor <= this[i] <= ceil for each element.
|
||||
[[nodiscard]] Vector4 Clamp(float floor, float ceil) const;
|
||||
|
||||
/// Limits each element of this vector between the corresponding elements in floor and ceil.
|
||||
/** @see Min(), Max(), Clamp01(). */
|
||||
[[nodiscard]] Vector4 Clamp(const Vector4& floor, const Vector4& ceil) const;
|
||||
|
||||
/// Limits each element of this vector in the range [0, 1].
|
||||
/** @see Min(), Max(), Clamp(). */
|
||||
[[nodiscard]] Vector4 Clamp01() const;
|
||||
|
||||
[[nodiscard]] float Distance(const Vector4& to) const;
|
||||
|
||||
/// Computes the length of this vector.
|
||||
/** @return Sqrt(x*x + y*y + z*z + w*w).
|
||||
@see LengthSq3(), Length3(), LengthSq4(), Normalize3(), Normalize4(). */
|
||||
[[nodiscard]] float Length4() const;
|
||||
[[nodiscard]] float Length() const;
|
||||
|
||||
/// Computes the squared length of this vector.
|
||||
/** Calling this function is faster than calling Length4(), since this function avoids computing a square root.
|
||||
If you only need to compare lengths to each other, but are not interested in the actual length values,
|
||||
you can compare by using LengthSq4(), instead of Length4(), since Sqrt() is an order-preserving
|
||||
(monotonous and non-decreasing) function.
|
||||
@return x*x + y*y + z*z + w*w.
|
||||
@see Length3(), LengthSq3(), Length4(), Normalize3(), Normalize4(). */
|
||||
[[nodiscard]] float LengthSquared4() const;
|
||||
[[nodiscard]] float LengthSquared() const;
|
||||
[[nodiscard]] float LengthSq4() const;
|
||||
[[nodiscard]] float LengthSq() const;
|
||||
|
||||
/// Computes the length of the (x, y, z) part of this vector.
|
||||
/** @note This function ignores the w component of this vector.
|
||||
@return Sqrt(x*x + y*y + z*z).
|
||||
@see LengthSq3(), LengthSq4(), Length4(), Normalize3(), Normalize4(). */
|
||||
[[nodiscard]] float Length3() const { return std::sqrt(x*x + y*y + z*z); }
|
||||
|
||||
/// Computes the squared length of the (x, y, z) part of this vector.
|
||||
/** Calling this function is faster than calling Length3(), since this function avoids computing a square root.
|
||||
If you only need to compare lengths to each other, but are not interested in the actual length values,
|
||||
you can compare by using LengthSq3(), instead of Length3(), since Sqrt() is an order-preserving
|
||||
(monotonous and non-decreasing) function.
|
||||
@note This function ignores the w component of this vector.
|
||||
@return x*x + y*y + z*z.
|
||||
@see Length3(), LengthSq4(), Length4(), Normalize3(), Normalize4(). */
|
||||
[[nodiscard]] float LengthSq3() const;
|
||||
[[nodiscard]] float LengthSquared3() const;
|
||||
|
||||
[[nodiscard]] float Magnitude() const;
|
||||
[[nodiscard]] float Dot(const Vector4& rhs) const;
|
||||
/// 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(). */
|
||||
[[nodiscard]] float Dot3(const Vector3& rhs) const;
|
||||
[[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.
|
||||
Vector4 Cross3(const Vector3& rhs) const;
|
||||
Vector4 Cross3(const Vector4& rhs) const;
|
||||
Vector4 Cross(const Vector4& rhs) const { return Cross3(rhs); }
|
||||
Vector4 Normalize() const;
|
||||
Vector4 Lerp(const Vector4& goal, float alpha) const;
|
||||
[[nodiscard]] Vector4 Cross3(const Vector3& rhs) const;
|
||||
[[nodiscard]] Vector4 Cross3(const Vector4& rhs) const;
|
||||
[[nodiscard]] Vector4 Cross(const Vector4& rhs) const;
|
||||
|
||||
float AngleBetween(const Vector4& rhs) const;
|
||||
[[nodiscard]] Vector4 Normalize() const;
|
||||
[[nodiscard]] Vector4 Lerp(const Vector4& goal, float alpha) const;
|
||||
|
||||
// Adds two vectors
|
||||
Vector4 operator+(const Vector4& rhs) const;
|
||||
Vector4 Add(const Vector4& rhs) const;
|
||||
[[nodiscard]] float AngleBetween(const Vector4& rhs) const;
|
||||
|
||||
/// Adds two vectors. [indexTitle: operators +,-,*,/]
|
||||
/** This function is identical to the member function Add().
|
||||
@return float4(x + v.x, y + v.y, z + v.z, w + v.w); */
|
||||
Vector4 operator +(const Vector4& rhs) const;
|
||||
|
||||
/// Adds a vector to this vector. [IndexTitle: Add/Sub/Mul/Div]
|
||||
/// @return (x+v.x, y+v.y, z+v.z, w+v.w).
|
||||
[[nodiscard]] Vector4 Add(const Vector4& rhs) const;
|
||||
static Vector4 Add(const Vector4& lhs, const Vector4& rhs);
|
||||
|
||||
// Subtracts two vectors
|
||||
Vector4 operator-(const Vector4& rhs) const;
|
||||
Vector4 Sub(const Vector4& rhs) const;
|
||||
/// Subtracts the given vector from this vector. [similarOverload: operator+] [hideIndex]
|
||||
/** This function is identical to the member function Sub().
|
||||
@return float4(x - v.x, y - v.y, z - v.z, w - v.w); */
|
||||
Vector4 operator -(const Vector4& rhs) const;
|
||||
[[nodiscard]] Vector4 Sub(const Vector4& rhs) const;
|
||||
static Vector4 Sub(const Vector4& lhs, const Vector4& rhs);
|
||||
|
||||
// Multiplies this vector by a scalar value
|
||||
Vector4 operator*(float rhs) const;
|
||||
Vector4 Mul(float scalar) const;
|
||||
/// Multiplies this vector by a scalar. [similarOverload: operator+] [hideIndex]
|
||||
/** 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);
|
||||
|
||||
// Divides this vector by a scalar
|
||||
Vector4 operator/(float rhs) const;
|
||||
Vector4 Div(float scalar) const;
|
||||
/// 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);
|
||||
|
||||
Vector4 operator+() const; // Unary + Operator
|
||||
Vector4 operator-() const; // Unary - Operator (Negation)
|
||||
Vector4 operator +() const; // 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). */
|
||||
Vector4 operator -() const;
|
||||
|
||||
|
||||
public:
|
||||
#if MUTABLE
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
#else
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float z = 0;
|
||||
float w = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
Reference in New Issue
Block a user