Finalized Vector2
This commit is contained in:
@@ -8,12 +8,45 @@ namespace J3ML::LinearAlgebra {
|
||||
/// A 2D (x, y) ordered pair.
|
||||
class Vector2 {
|
||||
public:
|
||||
/// The x component.
|
||||
/// A Vector2 is 8 bytes in size. This element lies in the memory offsets 0-3 of this class
|
||||
float x = 0;
|
||||
/// The y component.
|
||||
/// This element is packed to the memory offsets 4-7 of this class.
|
||||
float y = 0;
|
||||
public:
|
||||
/// Specifies the number of elements in this vector.
|
||||
enum {Dimensions = 2};
|
||||
public:
|
||||
/// Default Constructor - Initializes values to zero
|
||||
|
||||
/// @note Due to static data initialization order being undefined in C++,
|
||||
/// do NOT use these members to initialize other static data in other compilation units!
|
||||
|
||||
/// Specifies a compile-time constant Vector2 with value (0,0).
|
||||
static const Vector2 Zero;
|
||||
/// Specifies a compile-time constant Vector2 with value (1,1)
|
||||
static const Vector2 One;
|
||||
/// Specifies a compile-time constant Vector2 with value (1,0).
|
||||
static const Vector2 UnitX;
|
||||
/// Specifies a compile-time constant Vector2 with value (0,1).
|
||||
static const Vector2 UnitY;
|
||||
/// Specifies a compile-time constant Vector2 with value (0,-1).
|
||||
static const Vector2 Up;
|
||||
/// Specifies a compile-time constant Vector2 with value (-1,0).
|
||||
static const Vector2 Left;
|
||||
/// Specifies a compile-time constant Vector2 with value (0,1).
|
||||
static const Vector2 Down;
|
||||
/// Specifies a compile-time constant Vector2 with value (1,0).
|
||||
static const Vector2 Right;
|
||||
/// Specifies a compile-time constant Vector2 with value (NaN, NaN).
|
||||
/// For this constant, each element has the value of quiet NaN, or Not-A-Number.
|
||||
/// @note Never compare a Vector2 to this value! Due to how IEEE floats work, "nan == nan" returns false!
|
||||
/// That is, nothing is equal to NaN, not even NaN itself!
|
||||
static const Vector2 NaN;
|
||||
/// Specifies a compile-time constant Vector2 with value (+infinity, +infinity).
|
||||
static const Vector2 Infinity;
|
||||
public:
|
||||
/// Default Constructor does not initialize any members of this class.
|
||||
Vector2();
|
||||
/// Constructs a new Vector2 with the value (X, Y)
|
||||
Vector2(float X, float Y);
|
||||
@@ -24,19 +57,15 @@ namespace J3ML::LinearAlgebra {
|
||||
Vector2(const Vector2& rhs); // Copy Constructor
|
||||
//Vector2(Vector2&&) = default; // Move Constructor
|
||||
|
||||
static const Vector2 Zero;
|
||||
static const Vector2 Up;
|
||||
static const Vector2 Left;
|
||||
static const Vector2 Down;
|
||||
static const Vector2 Right;
|
||||
static const Vector2 NaN;
|
||||
static const Vector2 Infinity;
|
||||
|
||||
float GetX() const;
|
||||
float GetY() const;
|
||||
[[nodiscard]] float GetX() const;
|
||||
[[nodiscard]] float GetY() const;
|
||||
void SetX(float newX);
|
||||
void SetY(float newY);
|
||||
|
||||
/// Sets all elements of this vector.
|
||||
void Set(float newX, float newY);
|
||||
|
||||
/// Casts this float2 to a C array.
|
||||
/** This function does not allocate new memory or make a copy of this float2. This function simply
|
||||
returns a C pointer view to this data structure. Use ptr()[0] to access the x component of this float2
|
||||
@@ -49,144 +78,297 @@ namespace J3ML::LinearAlgebra {
|
||||
@return A pointer to the first float element of this class. The data is contiguous in memory.
|
||||
@see operator [](), At(). */
|
||||
float* ptr();
|
||||
const float *ptr() const;
|
||||
[[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 and 1 for y.
|
||||
@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);
|
||||
|
||||
const float At(std::size_t index) const;
|
||||
/// Accesses an element of this vector using array notation.
|
||||
/** @param index The element to get. Pass in 0 for x and 1 for y.
|
||||
@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(), operator [](). */
|
||||
[[nodiscard]] const float At(std::size_t index) const;
|
||||
|
||||
float &At(std::size_t index);
|
||||
|
||||
Vector2 Abs() const;
|
||||
[[nodiscard]] Vector2 Abs() const;
|
||||
|
||||
bool IsWithinMarginOfError(const Vector2& rhs, float margin=0.001f) const;
|
||||
[[nodiscard]] bool IsWithinMarginOfError(const Vector2& rhs, float margin=0.001f) const;
|
||||
|
||||
bool IsNormalized(float epsilonSq = 1e-5f) const;
|
||||
bool IsZero(float epsilonSq = 1e-6f) const;
|
||||
bool IsPerpendicular(const Vector2& other, float epsilonSq=1e-5f) const;
|
||||
[[nodiscard]] bool IsNormalized(float epsilonSq = 1e-5f) const;
|
||||
[[nodiscard]] bool IsZero(float epsilonSq = 1e-6f) const;
|
||||
[[nodiscard]] bool IsPerpendicular(const Vector2& other, float epsilonSq=1e-5f) const;
|
||||
|
||||
|
||||
bool operator == (const Vector2& rhs) const;
|
||||
bool operator != (const Vector2& rhs) const;
|
||||
|
||||
Vector2 Min(const Vector2& min) const;
|
||||
/// Returns an element-wise minimum between two vectors.
|
||||
[[nodiscard]] Vector2 Min(const Vector2& min) const;
|
||||
static Vector2 Min(const Vector2& value, const Vector2& minimum);
|
||||
|
||||
Vector2 Max(const Vector2& max) const;
|
||||
/// Returns an element-wise maximum between two vectors.
|
||||
[[nodiscard]] Vector2 Max(const Vector2& max) const;
|
||||
static Vector2 Max(const Vector2& value, const Vector2& maximum);
|
||||
|
||||
Vector2 Clamp(const Vector2& min, const Vector2& max) const;
|
||||
/// Returns a Vector2 that has floor <= this[i] <= ceil for each element.
|
||||
[[nodiscard]] Vector2 Clamp(float floor, float ceil) const;
|
||||
static Vector2 Clamp(const Vector2& value, float floor, float ceil);
|
||||
|
||||
/// Limits each element of this vector between the corresponding elements in floor and ceil.
|
||||
[[nodiscard]] Vector2 Clamp(const Vector2& min, const Vector2& max) const;
|
||||
static Vector2 Clamp(const Vector2& min, const Vector2& middle, const Vector2& max);
|
||||
|
||||
/// Limits each element of this vector in the range [0, 1].
|
||||
[[nodiscard]] Vector2 Clamp01() const;
|
||||
static Vector2 Clamp01(const Vector2& value);
|
||||
|
||||
/// Returns the magnitude between the two vectors.
|
||||
float Distance(const Vector2& to) const;
|
||||
/// @see DistanceSq(), Length(), LengthSquared()
|
||||
[[nodiscard]] float Distance(const Vector2& to) const;
|
||||
static float Distance(const Vector2& from, const Vector2& to);
|
||||
|
||||
float DistanceSq(const Vector2& to) const;
|
||||
[[nodiscard]] float DistanceSq(const Vector2& to) const;
|
||||
static float DistanceSq(const Vector2& from, const Vector2& to);
|
||||
|
||||
float MinElement() const;
|
||||
/// Returns the smaller element of the vector.
|
||||
[[nodiscard]] float MinElement() const;
|
||||
|
||||
float MaxElement() const;
|
||||
/// Returns the larger element of the vector.
|
||||
[[nodiscard]] float MaxElement() const;
|
||||
|
||||
float Length() const;
|
||||
/// Computes the length of this vector
|
||||
/// @return sqrt(x*x + y*y)
|
||||
/// @see LengthSquared(), Distance(), DistanceSq()
|
||||
[[nodiscard]] float Length() const;
|
||||
static float Length(const Vector2& of);
|
||||
|
||||
float LengthSquared() const;
|
||||
/// Computes the squared length of this vector.
|
||||
/** Calling this function is faster than using Length(), 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 LengthSquared(), instead of Length(), since Sqrt() is an order-preserving
|
||||
(monotonous and non-decreasing) function.
|
||||
@return x*x + y*y
|
||||
@see LengthSquared(), Distance(), DistanceSq() */
|
||||
[[nodiscard]] float LengthSquared() const;
|
||||
static float LengthSquared(const Vector2& of);
|
||||
|
||||
/// Returns the length of the vector, which is sqrt(x^2 + y^2)
|
||||
float Magnitude() const;
|
||||
[[nodiscard]] float Magnitude() const;
|
||||
static float Magnitude(const Vector2& of);
|
||||
|
||||
|
||||
bool IsFinite() const;
|
||||
[[nodiscard]] bool IsFinite() const;
|
||||
static bool IsFinite(const Vector2& v);
|
||||
|
||||
/// @return x+y;
|
||||
[[nodiscard]] float SumOfElements() const;
|
||||
/// @return x*y;
|
||||
[[nodiscard]] float ProductOfElements() const;
|
||||
/// @return (x+y)/2
|
||||
[[nodiscard]] float AverageOfElements() const;
|
||||
|
||||
/// Returns a copy of this vector with each element negated.
|
||||
/** This function returns a new vector where each element x of the original vector is replaced by the value -x.
|
||||
@return Vector2(-x, -y)
|
||||
@see Abs(); */
|
||||
[[nodiscard]] Vector2 Neg() const;
|
||||
|
||||
/// Computes the element-wise reciprocal of this vector.
|
||||
/** This function returns a new vector where each element x of the original vector is replaced by the value 1/x.
|
||||
@return Vector2(1/x, 1/y). */
|
||||
[[nodiscard]] Vector2 Recip() const;
|
||||
|
||||
/// Returns the aimed angle direction of this vector, in radians.
|
||||
/** The aimed angle of a 2D vector corresponds to the theta part (or azimuth) of the polar coordinate representation of this vector. Essentially,
|
||||
describes the direction this vector is pointing at. A vector pointing towards +X returns 0, vector pointing towards +Y returns pi/2, vector
|
||||
pointing towards -X returns pi, and a vector pointing towards -Y returns -pi/2 (equal to 3pi/2).
|
||||
@note This vector does not need to be normalized for this function to work, but it DOES need to be non-zero (unlike the function ToPolarCoordinates).
|
||||
@return The aimed angle in the range ]-pi/2, pi/2].
|
||||
@see ToPolarCoordinates, FromPolarCoordinates, SetFromPolarCoordinates */
|
||||
[[nodiscard]] float AimedAngle() const;
|
||||
|
||||
/// Converts this euclidian (x,y) Vector2 to polar coordinates representation in the form (theta, lenght).
|
||||
/** @note It is valid for the magnitude of this vector to be (very close to) zero, in which case the return value is the zero vector.
|
||||
@return A vector2 that has the first component (x) representing the aimed angle (azimuth) of this direction vector, in radians,
|
||||
and is equal to atan2(y, x). The x component has a range of ]-pi/2, pi/2]. The second component (y) of the returned vector
|
||||
stores the length (radius) of this vector.
|
||||
@see SetFromPolarCoordinates, FromPolarCoordinates, AimedAngle */
|
||||
[[nodiscard]] Vector2 ToPolarCoordinates() const;
|
||||
|
||||
/// 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 Vector2& rhs) const;
|
||||
[[nodiscard]] float Dot(const Vector2& rhs) const;
|
||||
static float Dot(const Vector2& lhs, const Vector2& rhs);
|
||||
|
||||
/// Projects one vector onto another and returns the result. (IDK)
|
||||
Vector2 Project(const Vector2& rhs) const;
|
||||
[[nodiscard]] Vector2 Project(const Vector2& rhs) const;
|
||||
/// @see Project
|
||||
static Vector2 Project(const Vector2& lhs, const Vector2& rhs);
|
||||
|
||||
/// Returns a copy of this vector, resized to have a magnitude of 1, while preserving "direction"
|
||||
Vector2 Normalize() const;
|
||||
static Vector2 Normalize(const Vector2& of);
|
||||
/// Normalizes this Vector2
|
||||
/** In the case of failure, this vector is set to (1, 0), so calling this function will never result in an un-normalized vector.
|
||||
@note If this function fials to normalize the vector, no error message is printed, the vector is set to (1, 0) and
|
||||
an error code of 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 Normalize();
|
||||
|
||||
|
||||
/// Returns a normalized copy of this vector.
|
||||
/** @note If the vector is zero and cannot be normalized, the vector (1, 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() */
|
||||
[[nodiscard]] Vector2 Normalized() const;
|
||||
|
||||
/// 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).
|
||||
Vector2 Lerp(const Vector2& rhs, float alpha) const;
|
||||
[[nodiscard]] Vector2 Lerp(const Vector2& rhs, float alpha) const;
|
||||
/// @see Lerp
|
||||
static Vector2 Lerp(const Vector2& lhs, const Vector2& rhs, float alpha);
|
||||
/// Note: Input vectors MUST be normalized first!
|
||||
float AngleBetween(const Vector2& rhs) const;
|
||||
[[nodiscard]] float AngleBetween(const Vector2& rhs) const;
|
||||
static float AngleBetween(const Vector2& lhs, const Vector2& rhs);
|
||||
|
||||
/// Adds two vectors.
|
||||
Vector2 operator +(const Vector2& rhs) const;
|
||||
Vector2 Add(const Vector2& rhs) const;
|
||||
[[nodiscard]] Vector2 Add(const Vector2& rhs) const;
|
||||
static Vector2 Add(const Vector2& lhs, const Vector2& rhs);
|
||||
|
||||
/// Subtracts two vectors.
|
||||
Vector2 operator -(const Vector2& rhs) const;
|
||||
Vector2 Sub(const Vector2& rhs) const;
|
||||
[[nodiscard]] Vector2 Sub(const Vector2& rhs) const;
|
||||
static Vector2 Sub(const Vector2& lhs, const Vector2& rhs);
|
||||
|
||||
/// Multiplies this vector by a scalar value.
|
||||
Vector2 operator *(float rhs) const;
|
||||
Vector2 Mul(float scalar) const;
|
||||
[[nodiscard]] Vector2 Mul(float scalar) const;
|
||||
static Vector2 Mul(const Vector2& 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.
|
||||
Vector2 operator *(const Vector2& rhs) const
|
||||
{
|
||||
|
||||
}
|
||||
Vector2 Mul(const Vector2& v) const;
|
||||
Vector2 operator *(const Vector2& rhs) const;
|
||||
[[nodiscard]] Vector2 Mul(const Vector2& v) const;
|
||||
|
||||
/// Divides this vector by a scalar.
|
||||
Vector2 operator /(float rhs) const;
|
||||
Vector2 Div(float scalar) const;
|
||||
[[nodiscard]] Vector2 Div(float scalar) const;
|
||||
static Vector2 Div(const Vector2& 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
|
||||
Vector2 Div(const Vector2& v) const;
|
||||
Vector2 operator / (const Vector2& rhs) const;
|
||||
[[nodiscard]] Vector2 Div(const Vector2& v) const;
|
||||
|
||||
/// Unary operator +
|
||||
Vector2 operator +() const; // TODO: Implement
|
||||
Vector2 operator +() const { return *this;}
|
||||
Vector2 operator -() const;
|
||||
/// Assigns a vector to another
|
||||
/// Assigns a vector to another.
|
||||
Vector2 &operator =(const Vector2 &rhs);
|
||||
|
||||
/// Adds a vector to this vector, in-place.
|
||||
Vector2& operator+=(const Vector2& rhs);
|
||||
/// Subtracts a vector from this vector, in-place.
|
||||
Vector2& operator-=(const Vector2& rhs);
|
||||
/// Multiplies this vector by a scalar, in-place.
|
||||
Vector2& operator*=(float scalar);
|
||||
/// Divides this vector by a scalar, in-place
|
||||
Vector2& operator/=(float scalar);
|
||||
|
||||
/// Returns this vector with the "perp" operator applied to it.
|
||||
/** The perp operator rotates a vector 90 degrees ccw (around the "z axis"), i.e.
|
||||
for a 2D vector (x,y), this function returns the vector (-y, x).
|
||||
@note This function is identical to Rotate90CCW().
|
||||
@return (-y, x). The returned vector is perpendicular to this vector.
|
||||
@see PerpDot(), Rotated90CCW() */
|
||||
[[nodiscard]] Vector2 Perp() const;
|
||||
|
||||
/// Computes the perp-dot product of this and the given Vector2 in the order this^perp (dot) rhs.
|
||||
/// @see Dot(), Perp()
|
||||
[[nodiscard]] float PerpDot(const Vector2& rhs) const;
|
||||
|
||||
/// Rotates this vector 90 degrees clock-wise
|
||||
/// This rotation is interpreted in a coordinate system on a plane where +x extends to the right, and +y extends upwards.
|
||||
/// @see Perp(), Rotated90CW(), Rotate90CCW(), Rotated90CCW();
|
||||
void Rotate90CW();
|
||||
|
||||
/// Returns a vector that is perpendicular to this vector (rotated 90 degrees clock-wise).
|
||||
/// @note This function is identical to Perp().
|
||||
/// @see Perp(), Rotate90CW(), Rotate90CCW(), Rotated90CCW()
|
||||
[[nodiscard]] Vector2 Rotated90CW() const;
|
||||
|
||||
/// Rotates this vector 90 degrees counterclock-wise.
|
||||
/// This is a coordinate system on a plane +x extends to the right, and +y extends upwards.
|
||||
/// @see Perp(), Rotate90CW(), Rotated90CW(), Rotated90CCW();
|
||||
void Rotate90CCW();
|
||||
|
||||
/// Returns a vector that is perpendicular to this vector (rotated 90 degrees counter-clock-wise)
|
||||
/// @see Perp(), Rotate90CW(), Rotated90CW(), Rotate90CCW()
|
||||
[[nodiscard]] Vector2 Rotated90CCW() const;
|
||||
|
||||
/// Returns this vector reflected about a plane with the given normal.
|
||||
/// By convention, both this and the reflected vector
|
||||
[[nodiscard]] Vector2 Reflect(const Vector2& normal) const;
|
||||
|
||||
/// Refracts this vector about a plane with the given normal.
|
||||
/** By convention, the this vector points towards the plane, and the returned vector points away from the plane.
|
||||
When the ray is going from a denser material to a lighter one, total internal reflection can occur.
|
||||
In this case, this function will just return a reflected vector from a call to Reflect().
|
||||
@param normal Specifies the plane normal direction
|
||||
@param negativeSideRefractionIndex The refraction index of the material we are exiting.
|
||||
@param positiveSideRefractionIndex The refraction index of the material we are entering.
|
||||
@see Reflect(). */
|
||||
[[nodiscard]] Vector2 Refract(const Vector2& normal, float negativeSideRefractionIndex, float positiveSideRefractionIndex) const;
|
||||
|
||||
/// Projects this vector onto the given un-normalized direction vector.
|
||||
/// @param direction The direction vector to project this vector onto.
|
||||
/// This function will normalize the vector, so you can pass in an un-normalized vector.
|
||||
/// @see ProjectToNorm
|
||||
[[nodiscard]] Vector2 ProjectTo(const Vector2& direction) const;
|
||||
/// Projects this vector onto the given normalized direction vector.
|
||||
/// @param direction The vector to project onto.
|
||||
[[nodiscard]] Vector2 ProjectToNorm(const Vector2& direction) const;
|
||||
|
||||
/// Tests if the triangle a->b->c is oriented counter-clockwise.
|
||||
/** Returns true if the triangle a->b->c is oriented counter-clockwise, when viewed in the XY-plane
|
||||
where x spans to the right and y spans up.
|
||||
Another way to think of this is that this function returns true, if the point C lies to the left
|
||||
of the directed line AB. */
|
||||
static bool OrientedCCW(const Vector2 &, const Vector2 &, const Vector2 &);
|
||||
static bool OrientedCCW(const Vector2&, const Vector2&, const Vector2&);
|
||||
|
||||
/// Makes the given vectors linearly independent.
|
||||
/** This function directly follows the Gram-Schmidt procedure on the input vectors.
|
||||
The vector a is kept unmodified, and vector B is modified to be perpendicular to a.
|
||||
@note If any of the input vectors is zero, then the resulting set of vectors cannot be made orthogonal.
|
||||
@see AreOrthogonal(), Orthonormalize(), AreOrthonormal() */
|
||||
static void Orthogonalize(const Vector2& a, Vector2& b);
|
||||
|
||||
/// Returns true if the given vectors are orthogonal to each other.
|
||||
/// @see Orthogonalize(), Orthonormalize(), AreOrthonormal()
|
||||
static bool AreOrthogonal(const Vector2& a, const Vector2& b, float epsilon = 1e-3f);
|
||||
|
||||
/// 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.
|
||||
@note If either of the input vectors is zero, then the resulting set of vectors cannot be made orthonormal.
|
||||
@see Orthogonalize(), AreOrthogonal(), AreOrthonormal() */
|
||||
static void Orthonormalize(Vector2& a, Vector2& b);
|
||||
|
||||
};
|
||||
|
||||
static Vector2 operator*(float lhs, const Vector2 &rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
Vector2 operator*(float lhs, const Vector2 &rhs);
|
||||
}
|
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
Vector2::Vector2(): x(0), y(0)
|
||||
Vector2::Vector2()
|
||||
{}
|
||||
|
||||
Vector2::Vector2(float X, float Y): x(X), y(Y)
|
||||
@@ -95,15 +95,12 @@ namespace J3ML::LinearAlgebra {
|
||||
return rhs * scalar;
|
||||
}
|
||||
|
||||
Vector2 Vector2::Normalize() const
|
||||
Vector2 Vector2::Normalized() const
|
||||
{
|
||||
if (Length() > 0)
|
||||
return {
|
||||
x / Length(),
|
||||
y / Length()
|
||||
};
|
||||
else
|
||||
return {0,0};
|
||||
Vector2 copy = *this;
|
||||
float oldLength = copy.Normalize();
|
||||
assert(oldLength > 0.f && "Vector2::Normalized() failed!");
|
||||
return copy;
|
||||
}
|
||||
|
||||
Vector2 Vector2::Lerp(const Vector2& rhs, float alpha) const
|
||||
@@ -153,6 +150,9 @@ namespace J3ML::LinearAlgebra {
|
||||
}
|
||||
|
||||
const Vector2 Vector2::Zero = {0, 0};
|
||||
const Vector2 Vector2::One = {1, 1};
|
||||
const Vector2 Vector2::UnitX = {1, 0};
|
||||
const Vector2 Vector2::UnitY = {0, 1};
|
||||
const Vector2 Vector2::Up = {0, -1};
|
||||
const Vector2 Vector2::Down = {0, 1};
|
||||
const Vector2 Vector2::Left = {-1, 0};
|
||||
@@ -189,7 +189,7 @@ namespace J3ML::LinearAlgebra {
|
||||
return dot*dot <= epsilonSq * LengthSquared() * other.LengthSquared();
|
||||
}
|
||||
|
||||
Vector2 Vector2::Normalize(const Vector2 &of) { return of.Normalize(); }
|
||||
|
||||
|
||||
Vector2 Vector2::Project(const Vector2 &lhs, const Vector2 &rhs) { return lhs.Project(rhs); }
|
||||
|
||||
@@ -341,4 +341,150 @@ namespace J3ML::LinearAlgebra {
|
||||
return (a.x-c.x)*(b.y-c.y) - (a.y-c.y)*(b.x-c.x) >= 0.f;
|
||||
}
|
||||
|
||||
Vector2 Vector2::operator*(const Vector2 &rhs) const {
|
||||
return this->Mul(rhs);
|
||||
}
|
||||
|
||||
Vector2 Vector2::operator/(const Vector2 &rhs) const { return this->Div(rhs);}
|
||||
|
||||
Vector2 Vector2::Clamp(float floor, float ceil) const {
|
||||
return {std::clamp(this->x, floor, ceil),
|
||||
std::clamp(this->y, floor, ceil)};
|
||||
}
|
||||
|
||||
Vector2 Vector2::Clamp(const Vector2 &value, float floor, float ceil) {
|
||||
return value.Clamp(floor, ceil);
|
||||
}
|
||||
|
||||
Vector2 Vector2::Clamp01() const {
|
||||
return Clamp(0, 1);
|
||||
}
|
||||
|
||||
Vector2 Vector2::Clamp01(const Vector2 &value) {
|
||||
return value.Clamp01();
|
||||
}
|
||||
|
||||
Vector2 Vector2::Clamp(const Vector2 &min, const Vector2 &middle, const Vector2 &max) {
|
||||
return middle.Clamp(min, max);
|
||||
}
|
||||
|
||||
float Vector2::Distance(const Vector2 &from, const Vector2 &to) {
|
||||
return from.Distance(to);
|
||||
}
|
||||
|
||||
float Vector2::SumOfElements() const { return x+y;}
|
||||
|
||||
float Vector2::ProductOfElements() const { return x*y;}
|
||||
|
||||
float Vector2::AverageOfElements() const { return (x+y)/2; }
|
||||
|
||||
Vector2 Vector2::Neg() const { return {-x, -y};}
|
||||
|
||||
Vector2 Vector2::Recip() const { return {1.f/x, 1.f/y}; }
|
||||
|
||||
float Vector2::AimedAngle() const {
|
||||
assert(!IsZero());
|
||||
return std::atan2(y, x);
|
||||
}
|
||||
|
||||
Vector2 Vector2::ToPolarCoordinates() const {
|
||||
float radius = Length();
|
||||
if (radius > 1e-4f)
|
||||
return {std::atan2(y, x), radius};
|
||||
else
|
||||
return Vector2::Zero;
|
||||
}
|
||||
|
||||
Vector2 Vector2::Perp() const {
|
||||
return {-y, x};
|
||||
}
|
||||
|
||||
float Vector2::PerpDot(const Vector2 &rhs) const {
|
||||
return x * rhs.y - y * rhs.x;
|
||||
}
|
||||
|
||||
void Vector2::Rotate90CW() {
|
||||
float oldX = x;
|
||||
x = y;
|
||||
y = -oldX;
|
||||
}
|
||||
|
||||
Vector2 Vector2::Rotated90CW() const {
|
||||
return {y, -x};
|
||||
}
|
||||
|
||||
void Vector2::Rotate90CCW() {
|
||||
float oldX = x;
|
||||
x = -y;
|
||||
y = oldX;
|
||||
}
|
||||
|
||||
Vector2 Vector2::Rotated90CCW() const {
|
||||
return {-y, x};
|
||||
}
|
||||
|
||||
Vector2 Vector2::Reflect(const Vector2 &normal) const {
|
||||
assert(normal.IsNormalized());
|
||||
return 2.f * this->ProjectToNorm(normal) - *this;
|
||||
}
|
||||
|
||||
Vector2
|
||||
Vector2::Refract(const Vector2 &normal, float negativeSideRefractionIndex, float positiveSideRefractionIndex) const {
|
||||
// Implementation from https://www.flipcode.com/archives/reflection_transmission.pdf.
|
||||
// This code is duplicated in Vector3::Refract
|
||||
float n = negativeSideRefractionIndex / positiveSideRefractionIndex;
|
||||
float cosI = this->Dot(normal);
|
||||
float sinT2 = n*n*(1.f - cosI*cosI);
|
||||
if (sinT2 > 1.f) // Total internal reflection occurs?
|
||||
return (-*this).Reflect(normal);
|
||||
return n * *this - (n + std::sqrt(1.f - sinT2)) * normal;
|
||||
}
|
||||
|
||||
Vector2 Vector2::ProjectTo(const Vector2 &direction) const {
|
||||
assert(!direction.IsZero());
|
||||
return direction * this->Dot(direction) / direction.LengthSquared();
|
||||
}
|
||||
|
||||
Vector2 Vector2::ProjectToNorm(const Vector2 &direction) const {
|
||||
assert(direction.IsNormalized());
|
||||
return direction * this->Dot(direction);
|
||||
}
|
||||
|
||||
void Vector2::Orthogonalize(const Vector2 &a, Vector2 &b) {
|
||||
assert(!a.IsZero());
|
||||
b -= a.Dot(b) / a.Length() * a;
|
||||
}
|
||||
|
||||
void Vector2::Orthonormalize(Vector2 &a, Vector2 &b) {
|
||||
assert(!a.IsZero());
|
||||
a.Normalize();
|
||||
b -= a.Dot(b) * a;
|
||||
}
|
||||
|
||||
bool Vector2::AreOrthogonal(const Vector2 &a, const Vector2 &b, float epsilon) {
|
||||
return a.IsPerpendicular(b, epsilon);
|
||||
}
|
||||
|
||||
void Vector2::Set(float newX, float newY) {
|
||||
x = newX;
|
||||
y = newY;
|
||||
}
|
||||
|
||||
float Vector2::Normalize() {
|
||||
assert(IsFinite());
|
||||
float lengthSq = LengthSquared();
|
||||
if (lengthSq > 1e-6f)
|
||||
{
|
||||
float length = std::sqrt(lengthSq);
|
||||
*this *= 1.f / length;
|
||||
return length;
|
||||
} else {
|
||||
Set(1.f, 0.f); // We will always produce a normalized vector.
|
||||
return 0; // But signal failure, so user knows we have generated an arbitrary normalization.
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 operator*(float lhs, const Vector2 &rhs) {
|
||||
return {lhs * rhs.x, lhs * rhs.y};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user