387 lines
20 KiB
C++
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;
|
|
}
|
|
} |