Files
j3ml/include/J3ML/LinearAlgebra/Vector3.hpp
Redacted 3fc9ca3954
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m36s
Build Docs With Doxygen / Explore-Gitea-Actions (push) Successful in 27s
Update Vector3.hpp
fixed a documentation copy paste mistake
2024-10-31 02:02:03 -04:00

387 lines
20 KiB
C++

#pragma once
#include <J3ML/LinearAlgebra/Vector2.hpp>
#include <J3ML/LinearAlgebra/Vector3.hpp>
#include <cstddef>
#include <cstdlib>
#include <J3ML/LinearAlgebra/Angle2D.hpp>
#include <J3ML/Algorithm/RNG.hpp>
using namespace J3ML::Algorithm;
namespace J3ML::LinearAlgebra {
/// A 3D (x, y, z) ordered pair.
class Vector3 {
public:
float x = 0;
float y = 0;
float z = 0;
public:
enum {Dimensions = 3};
public:
/// Specifies a compile-time constant Vector3 with value (0,0,0).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 Zero;
/// Specifies a compile-time constant Vector3 with value (1,1,1).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 One;
/// Specifies a compile-time constant Vector3 with value (0,1,0).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 Up;
/// Specifies a compile-time constant Vector3 with value (0,-1,0).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 Down;
/// Specifies a compile-time constant Vector3 with value (-1,0,0).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 Left;
/// Specifies a compile-time constant Vector3 with value (1,0,0).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 Right;
/// Specifies a compile-time constant Vector3 with value (0,0,-1).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 Forward;
/// Specifies a compile-time constant Vector3 with value (0,0,1).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 Backward;
/// Specifies a compile-time constant Vector3 with value (NAN, NAN, NAN).
/** For this constant, each element has the value of quiet NaN, or Not-A-Number.
@note Never compare a Vector3 to this value! Due to how IEEE floats work, "nan == nan" returns false!
That is, nothing is equal to NaN, not even NaN itself!
@note Due to static data initialization order being undefined in C++, do NOT use this
member data to initalize other static data in other compilation units! */
static const Vector3 NaN;
/// Specifies a compile-time constant Vector3 with value (+infinity, +infinity, +infinity).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 Infinity;
/// Specifies a compile-time constant Vector3 with value (-infinity, -infinity, -infinity).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 NegativeInfinity;
/// Specifies a compile-time constant Vector3 with value (1,0,0).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 UnitX;
/// Specifies a compile-time constant Vector3 with value (0,1,0).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 UnitY;
/// Specifies a compile-time constant Vector3 with value (0,0,1).
/** @note Due to static data initialization order being undefined in C++, do NOT use this
member to initialize other static data in other compilation units! */
static const Vector3 UnitZ;
public:
/// The default constructor does not initialize any members of this class.
/** This means that the values of the members x, y and z are all undefined after creating a new Vector3 using
this default constructor. Remember to assign to them before use.
@see x, y, z. */
Vector3();
// Constructs a new Vector3 with the value (X, Y, Z)
Vector3(float X, float Y, float Z);
Vector3(const Vector2& XY, float Z);
Vector3(const Vector3& rhs) = default; // Copy Constructor
Vector3(Vector3&&) = default; // Move Constructor
/// Constructs this float3 from a C array, to the value (data[0], data[1], data[2]).
/** @param data An array containing three elements for x, y and z. This pointer may not be null. */
explicit Vector3(const float* data);
/// Constructs a new Vector3 with the value (scalar, scalar, scalar).
explicit Vector3(float scalar);
/// Generates a new Vector3 by fillings its entries by the given scalar.
/// @see Vector3::Vector3(float scalar), SetFromScalar()
static Vector3 FromScalar(float scalar);
/// Generates a direction vector of the given length.
/** The returned vector points at a uniformly random direction.
@see RandomSphere(), RandomBox() */
static Vector3 RandomDir(RNG& rng, float length = 1.f);
static Vector3 RandomSphere(RNG& rng, const Vector3& center, float radius);
static Vector3 RandomBox(RNG& rng, float xmin, float xmax, float ymin, float ymax, float zmin, float zmax);
static Vector3 RandomBox(RNG& rng, const Vector3& min, const Vector3 &max);
static Vector3 RandomBox(RNG& rng, float min, float max);
static Vector3 RotateAroundAxis(const Vector3& vec, const Vector3& axis, const float radians);
static inline Vector3 RandomGeneral(RNG& rng, float minElem, float maxElem) { return RandomBox(rng, minElem, maxElem); }
public:
/// Casts this float3 to a C array.
/** This function does not allocate new memory or make a copy of this Vector3. This function simply
returns a C pointer view to this data structure. Use ptr()[0] to access the x component of this float3,
ptr()[1] to access y, and ptr()[2] to access the z component of this Vector3.
@note Since the returned pointer points to this class, do not dereference the pointer after this
float3 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 [] or
the At() function to access the elements of this vector by index.
@return A pointer to the first float element of this class. The data is contiguous in memory.
@see operator [](), At(). */
float* ptr();
[[nodiscard]] const float *ptr() const { return &x;}
/// Accesses an element of this vector using array notation.
/** @param index The element to get. Pass in 0 for x, 1 for y and 2 for z.
@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.
@see ptr(), At(). */
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, and 2 for z.
@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 [](). */
[[nodiscard]] float At(int index) const;
float &At(int index);
/// Makes the given vectors linearly independent and normalized in length.
/** This function directly follows the Gram-Schmidt procedure on the input vectors.
The vector a is first normalized, and vector b is modified to be perpendicular to a, and also normalized.
Finally, if specified, the vector c is adjusted to be perpendicular to a and b, and normalized.
@note If any of the input vectors is zero, then the resulting set of vectors cannot be made orthonormal.
@see Orthogonalize(), AreOrthogonal(), AreOrthonormal(). */
static void Orthonormalize(Vector3& a, Vector3& b);
static void Orthonormalize(Vector3& a, Vector3& b, Vector3& c);
/// Returns true if the given vectors are orthogonal to each other and all of length 1.
/** @see Orthogonalize(), AreOrthogonal(), Orthonormalize(), AreCollinear(). */
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);
[[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);
/// Returns a scaled copy of this vector which has its new length as given.
/** This function assumes the length of this vector is not zero. In the case of failure, an error message is printed,
and the vector (newLength, 0, 0) is returned.
@see ScaleToLength(). */
[[nodiscard]] Vector3 ScaledToLength(float newLength) const;
[[nodiscard]] Vector3 ProjectToNorm(const Vector3& direction) 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);
[[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;
[[nodiscard]] bool IsFinite() const;
[[nodiscard]] float MinElement() const;
static float MinElement(const Vector3& of);
/// Normalizes this Vector3.
/** In the case of failure, this vector is set to (1, 0, 0), so calling this function will never result in an
unnormalized vector.
@note If this function fails to normalize the vector, no error message is printed, the vector is set to (1,0,0) and
an error code 0 is returned. This is different than the behavior of the Normalized() function, which prints an
error if normalization fails.
@note This function operates in-place.
@return The old length of this vector, or 0 if normalization failed.
@see Normalized(). */
float TryNormalize();
/// 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(). */
[[nodiscard]] Vector3 Perpendicular(const Vector3 &hint = Vector3(0,1,0), const Vector3 &hint2 = Vector3(0,0,1)) const;
/// Returns another vector that is perpendicular to this vector and the vector returned by Perpendicular().
/** The set (this, Perpendicular(), AnotherPerpendicular()) forms a right-handed normalized 3D basis.
@see Perpendicular(), Cross(). */
Vector3 AnotherPerpendicular(const Vector3& hint = Vector3(0,1,0), const Vector3& hint2 = Vector3(0,0,1)) const;
/// Completes this vector to generate a perpendicular basis.
/** This function computes two new vectors b and c which are both orthogonal to this vector and to each other.
That is, the set { this, b, c} is an orthogonal set. The vectors b and c that are outputted are also normalized.
@param outB [out] Receives vector b.
@param outC [out] Receives vector c.
@note When calling this function, this vector should not be zero! */
void PerpendicularBasis(Vector3& outB, Vector3& outC) 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);
[[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);
[[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.
[[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;
[[nodiscard]] float DistanceSquared(const Vector3& to) const;
// Function Alias for DistanceSquared
[[nodiscard]] float DistanceSq(const Vector3& to) const { return DistanceSquared(to); }
static float DistanceSquared(const Vector3& from, const Vector3& to);
[[nodiscard]] float Length() const;
static float Length(const Vector3& of);
[[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)
[[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.
[[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)
[[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.
[[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 Normalized() function instead.
/// @see Normalized()
[[nodiscard]] Vector3 Normalized() const;
static Vector3 Normalized(const Vector3& targ);
/// Normalizes this Vector3.
/** In the case of failure, this vector is set to (1, 0, 0), so calling this function will never result in an
un-normalized vector.
@note If this function fails to normalize the vector, no error message is printed, the vector is set to (1,0,0) and
an error code 0 is returned. This is different than the behavior of the Normalized() function, which prints an
error if normalization fails.
@note This function operates in-place.
@return The old length of this vector, or 0 if normalization fails.
@see Normalized(). */
float Normalize();
/// Linearly interpolates between two points.
/// 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).
[[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(). */
[[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;
[[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
[[nodiscard]] Vector3 Add(float s) const;
/// Subtracts two vectors
Vector3 operator-(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;
[[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.
[[nodiscard]] Vector3 Mul(const Vector3& rhs) const;
/// Divides this vector by a scalar
Vector3 operator/(float rhs) 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
[[nodiscard]] Vector3 Div(const Vector3& v) const;
/// Unary + operator
Vector3 operator+() const; // TODO: Implement
/// Unary - operator (Negation)
Vector3 operator-() 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);
Vector3& operator-=(const Vector3& rhs);
Vector3& operator*=(float scalar);
Vector3& operator/=(float scalar);
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;
}
}