Implement Vector3::ScaleToLength & ToString()

This commit is contained in:
2024-07-10 14:12:47 -04:00
parent a6612fac4d
commit 27efa7da92
2 changed files with 81 additions and 40 deletions

View File

@@ -5,7 +5,7 @@
#include <cstddef>
#include <cstdlib>
#include <J3ML/LinearAlgebra/Angle2D.h>
#include <J3ML/Algorithm/RNG.h>
#include <J3ML/Algorithm/RNG.hpp>
using namespace J3ML::Algorithm;
@@ -144,7 +144,7 @@ public:
@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.
@see ptr(), operator [](). */
float At(int index) const;
[[nodiscard]] float At(int index) const;
float &At(int index);
/// Makes the given vectors linearly independent and normalized in length.
@@ -161,36 +161,47 @@ public:
static bool AreOrthonormal(const Vector3& a, const Vector3& b, float epsilon = 1e-3f);
static bool AreOrthonormal(const Vector3& a, const Vector3& b, const Vector3& c, float epsilon = 1e-3f);
Vector3 Abs() const;
[[nodiscard]] Vector3 Abs() const;
static Vector3 Abs(const Vector3& rhs);
/// Returns the DirectionVector for a given angle.
static Vector3 Direction(const Vector3 &rhs) ;
/// Scales this vector so that its new length is as given.
/** Calling this function is effectively the same as normalizing the vector first and then multiplying by newLength.
In the case of failure, this vector is set to (newLength, 0, 0), so calling this function will never result in an
unnormalized vector.
@note This function operates in-place.
@return The old length of this vector. If this function returns 0, the scaling failed, and this vector is arbitrarily
reset to (newLength, 0, 0). In case of failure, no error message is generated. You are expected to handle the failure
yourself.
@see ScaledToLength(). */
float ScaleToLength(float newLength);
[[nodiscard]] Vector3 ProjectToNorm(const Vector3& direction) const;
Vector3 ProjectToNorm(const Vector3& direction) const;
float GetX() const;
float GetY() const;
float GetZ() const;
[[nodiscard]] float GetX() const;
[[nodiscard]] float GetY() const;
[[nodiscard]] float GetZ() const;
void SetX(float newX);
void SetY(float newY);
void SetZ(float newZ);
bool IsWithinMarginOfError(const Vector3& rhs, float margin=0.001f) const;
bool IsNormalized(float epsilonSq = 1e-5f) const;
bool IsZero(float epsilonSq = 1e-6f) const;
bool IsPerpendicular(const Vector3& other, float epsilonSq=1e-5f) const;
[[nodiscard]] Vector2 XY() const { return {x, y};}
[[nodiscard]] bool IsWithinMarginOfError(const Vector3& rhs, float margin=0.001f) const;
[[nodiscard]] bool IsNormalized(float epsilonSq = 1e-5f) const;
[[nodiscard]] bool IsZero(float epsilonSq = 1e-6f) const;
[[nodiscard]] bool IsPerpendicular(const Vector3& other, float epsilonSq=1e-5f) const;
bool operator == (const Vector3& rhs) const;
bool operator != (const Vector3& rhs) const;
bool IsFinite() const;
float MinElement() const;
[[nodiscard]] bool IsFinite() const;
[[nodiscard]] float MinElement() const;
static float MinElement(const Vector3& of);
/// Normalizes this Vector3.
@@ -207,62 +218,62 @@ public:
/// Computes a new normalized direction vector that is perpendicular to this vector and the specified hint vector.
/** If this vector points toward the hint vector, the vector hint2 is returned instead.
@see AnotherPerpendicular(), Cross(). */
Vector3 Perpendicular(const Vector3 &hint = Vector3(0,1,0), const Vector3 &hint2 = Vector3(0,0,1)) const;
[[nodiscard]] Vector3 Perpendicular(const Vector3 &hint = Vector3(0,1,0), const Vector3 &hint2 = Vector3(0,0,1)) const;
Vector3 Min(const Vector3& min) const;
[[nodiscard]] Vector3 Min(const Vector3& min) const;
static Vector3 Min(const Vector3& a, const Vector3& b, const Vector3& c);
static Vector3 Min(const Vector3& lhs, const Vector3& rhs);
Vector3 Max(const Vector3& max) const;
[[nodiscard]] Vector3 Max(const Vector3& max) const;
static Vector3 Max(const Vector3& a, const Vector3& b, const Vector3& c);
static Vector3 Max(const Vector3& lhs, const Vector3& rhs);
Vector3 Clamp(const Vector3& min, const Vector3& max) const;
[[nodiscard]] Vector3 Clamp(const Vector3& min, const Vector3& max) const;
static Vector3 Clamp(const Vector3& min, const Vector3& input, const Vector3& max);
/// Returns the magnitude between the two vectors.
float Distance(const Vector3& to) const;
[[nodiscard]] float Distance(const Vector3& to) const;
static float Distance(const Vector3& from, const Vector3& to);
//float Distance(const Ray&) const;
//float Distance(const LineSegment&) const;
//float Distance(const Plane&) const;
//float DIstance(const Triangle&) const;
float DistanceSquared(const Vector3& to) const;
[[nodiscard]] float DistanceSquared(const Vector3& to) const;
// Function Alias for DistanceSquared
float DistanceSq(const Vector3& to) const { return DistanceSquared(to); }
[[nodiscard]] float DistanceSq(const Vector3& to) const { return DistanceSquared(to); }
static float DistanceSquared(const Vector3& from, const Vector3& to);
float Length() const;
[[nodiscard]] float Length() const;
static float Length(const Vector3& of);
float LengthSquared() const;
[[nodiscard]] float LengthSquared() const;
static float LengthSquared(const Vector3& of);
/// Returns the length of the vector, which is sqrt(x^2 + y^2 + z^2)
float Magnitude() const;
[[nodiscard]] float Magnitude() const;
static float Magnitude(const Vector3& of);
/// Returns a float value equal to the magnitudes of the two vectors multiplied together and then multiplied by the cosine of the angle between them.
/// For normalized vectors, dot returns 1 if they point in exactly the same direction,
/// -1 if they point in completely opposite directions, and 0 if the vectors are perpendicular.
float Dot(const Vector3& rhs) const;
[[nodiscard]] float Dot(const Vector3& rhs) const;
static float Dot(const Vector3& lhs, const Vector3& rhs);
/// Projects one vector onto another and returns the result. (IDK)
Vector3 Project(const Vector3& rhs) const;
[[nodiscard]] Vector3 Project(const Vector3& rhs) const;
static Vector3 Project(const Vector3& lhs, const Vector3& rhs);
/// The cross product of two vectors results in a third vector which is perpendicular to the two input vectors.
/// The result's magnitude is equal to the magnitudes of the two inputs multiplied together and then multiplied by the sine of the angle between the inputs.
Vector3 Cross(const Vector3& rhs) const;
[[nodiscard]] Vector3 Cross(const Vector3& rhs) const;
static Vector3 Cross(const Vector3& lhs, const Vector3& rhs);
/// Returns a copy of this vector, resized to have a magnitude of 1, while preserving "direction"
/// @note If the vector is zero and cannot be normalized, the vector (1, 0, 0) is returned, and an error message is printed.
/// If you do not want to generate an error message on failure, but want to handle the failure yourself, use the Normalize() function instead.
/// @see Normalize()
Vector3 Normalized() const;
[[nodiscard]] Vector3 Normalized() const;
static Vector3 Normalized(const Vector3& targ);
/// Normalizes this Vector3.
@@ -281,56 +292,56 @@ public:
/// Interpolates between the points and b by the interpolant t.
/// The parameter is (TODO: SHOULD BE!) clamped to the range[0, 1].
/// This is most commonly used to find a point some fraction of the wy along a line between two endpoints (eg. to move an object gradually between those points).
Vector3 Lerp(const Vector3& goal, float alpha) const;
[[nodiscard]] Vector3 Lerp(const Vector3& goal, float alpha) const;
static Vector3 Lerp(const Vector3& lhs, const Vector3& rhs, float alpha);
/// 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 unnormalized, and normalizes the computations.
If you are computing the angle between two normalized vectors, it is better to use AngleBetweenNorm().
@see AngleBetweenNorm(). */
Angle2D AngleBetween(const Vector3& rhs) const;
[[nodiscard]] Angle2D AngleBetween(const Vector3& rhs) const;
static Angle2D AngleBetween(const Vector3& lhs, const Vector3& rhs);
/// Adds two vectors
Vector3 operator+(const Vector3& rhs) const;
Vector3 Add(const Vector3& rhs) const;
[[nodiscard]] Vector3 Add(const Vector3& rhs) const;
static Vector3 Add(const Vector3& lhs, const Vector3& rhs);
/// Adds the vector(s, s, s) to this vector
Vector3 Add(float s) const;
[[nodiscard]] Vector3 Add(float s) const;
/// Subtracts two vectors
Vector3 operator-(const Vector3& rhs) const;
Vector3 Sub(const Vector3& rhs) const;
[[nodiscard]] Vector3 Sub(const Vector3& rhs) const;
static Vector3 Sub(const Vector3& lhs, const Vector3& rhs);
/// Multiplies this vector by a scalar value
Vector3 operator*(float rhs) const;
Vector3 Mul(float scalar) const;
[[nodiscard]] Vector3 Mul(float scalar) const;
static Vector3 Mul(const Vector3& lhs, float rhs);
/// Multiplies this vector by a vector, element-wise
/// @note Mathematically, the multiplication of two vectors is not defined in linear space structures,
/// but this function is provided here for syntactical convenience.
Vector3 Mul(const Vector3& rhs) const;
[[nodiscard]] Vector3 Mul(const Vector3& rhs) const;
/// Divides this vector by a scalar
Vector3 operator/(float rhs) const;
Vector3 Div(float scalar) const;
[[nodiscard]] Vector3 Div(float scalar) const;
static Vector3 Div(const Vector3& lhs, float rhs);
/// Divides this vector by a vector, element-wise
/// @note Mathematically, the multiplication of two vectors is not defined in linear space structures,
/// but this function is provided here for syntactical convenience
Vector3 Div(const Vector3& v) const;
[[nodiscard]] Vector3 Div(const Vector3& v) const;
/// Unary + operator
Vector3 operator+() const; // TODO: Implement
/// Unary - operator (Negation)
Vector3 operator-() const;
bool Equals(const Vector3& rhs, float epsilon = 1e-3f) const;
bool Equals(float _x, float _y, float _z, float epsilon = 1e-3f) const;
[[nodiscard]] bool Equals(const Vector3& rhs, float epsilon = 1e-3f) const;
[[nodiscard]] bool Equals(float _x, float _y, float _z, float epsilon = 1e-3f) const;
Vector3 &operator =(const Vector3& rhs);
Vector3& operator+=(const Vector3& rhs);
@@ -340,8 +351,13 @@ public:
void Set(float d, float d1, float d2);
[[nodiscard]] std::string ToString() const;
};
std::ostream& operator << (std::ostream& o, const Vector3& vector);
static Vector3 operator*(float lhs, const Vector3& rhs)
{
return rhs * lhs;

View File

@@ -335,6 +335,22 @@ namespace J3ML::LinearAlgebra {
return {x, y, z};
}
float Vector3::ScaleToLength(float newLength) {
float length = LengthSquared();
if (length < 1e-6f) {
Set(newLength, 0, 0); // Will always produce a vector of the requested length.
return 0.f;
}
length = Math::Sqrt(length);
float scalar = newLength / length;
x *= scalar;
y *= scalar;
z *= scalar;
return length;
}
Vector3 Vector3::Abs() const {
return {std::abs(x), std::abs(y), std::abs(z)};
}
@@ -501,6 +517,15 @@ namespace J3ML::LinearAlgebra {
z = d2;
}
std::string Vector3::ToString() const {
return std::format("{},{},{}", x, y, z);
}
std::ostream & operator<<(std::ostream &o, const Vector3 &vector) {
o << vector.ToString();
return o;
}
Vector3::Vector3(const Vector2& XY, float Z) {
x = XY.x;
y = XY.y;