282 lines
15 KiB
C++
282 lines
15 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <cmath>
|
|
|
|
#include <J3ML/LinearAlgebra/Forward.hpp>
|
|
|
|
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:
|
|
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
|
|
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(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;
|
|
Vector4& operator=(const Vector4& rhs);
|
|
|
|
/// 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);
|
|
|
|
/// 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. */
|
|
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;}
|
|
|
|
/// 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);
|
|
|
|
|
|
|
|
|
|
[[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;
|
|
[[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;
|
|
|
|
[[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;
|
|
|
|
/// 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;
|
|
[[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(). */
|
|
[[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.
|
|
[[nodiscard]] Vector4 Cross3(const Vector3& rhs) const;
|
|
[[nodiscard]] Vector4 Cross3(const Vector4& rhs) const;
|
|
[[nodiscard]] Vector4 Cross(const Vector4& rhs) const;
|
|
|
|
[[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().
|
|
@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 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. [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 { 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 { return *this / scalar; }
|
|
static Vector4 Div(const Vector4& rhs, float scalar) { return rhs / scalar; }
|
|
|
|
/// 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). */
|
|
Vector4 operator -() const;
|
|
|
|
|
|
public:
|
|
float x = 0;
|
|
float y = 0;
|
|
float z = 0;
|
|
float w = 0;
|
|
|
|
void Normalize();
|
|
};
|
|
|
|
} |