From b17e49d1df2ce38781c333cdbc699ef261a54d52 Mon Sep 17 00:00:00 2001 From: josh Date: Fri, 18 Apr 2025 14:58:42 -0400 Subject: [PATCH] Document & Implement Vector4::Add, AngleBetween, IsZero4, IsZero, Sub, Div, Clamp01 --- include/J3ML/LinearAlgebra/Vector4.hpp | 33 +++++++++------ src/J3ML/LinearAlgebra/Vector4.cpp | 58 ++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/include/J3ML/LinearAlgebra/Vector4.hpp b/include/J3ML/LinearAlgebra/Vector4.hpp index b22f0c5..287866a 100644 --- a/include/J3ML/LinearAlgebra/Vector4.hpp +++ b/include/J3ML/LinearAlgebra/Vector4.hpp @@ -106,12 +106,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 +199,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 +207,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 +217,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 +244,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). */ diff --git a/src/J3ML/LinearAlgebra/Vector4.cpp b/src/J3ML/LinearAlgebra/Vector4.cpp index b4558f3..fb4e02d 100644 --- a/src/J3ML/LinearAlgebra/Vector4.cpp +++ b/src/J3ML/LinearAlgebra/Vector4.cpp @@ -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 \ No newline at end of file