All checks were successful
Build and Run C++ Unit Tests / build-and-test (push) Successful in 2m2s
401 lines
15 KiB
C++
401 lines
15 KiB
C++
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0.If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef VECTOR2_H
|
|
#define VECTOR2_H
|
|
|
|
#include "Angle.h"
|
|
|
|
/*
|
|
extern "C" {
|
|
/// <summary>
|
|
/// 2-dimensional Vector representation (C-style)
|
|
/// </summary>
|
|
/// This is a C-style implementation
|
|
/// This uses the right-handed coordinate system.
|
|
typedef struct Vec2 {
|
|
/// <summary>
|
|
/// The right axis of the vector
|
|
/// </summary>
|
|
float x;
|
|
/// <summary>
|
|
/// The upward/forward axis of the vector
|
|
/// </summary>
|
|
float y;
|
|
|
|
} Vec2;
|
|
}
|
|
*/
|
|
namespace LinearAlgebra {
|
|
|
|
// struct Vector3;
|
|
template <typename T>
|
|
class PolarOf;
|
|
|
|
/*
|
|
/// @brief A 2-dimensional vector
|
|
/// @remark This uses the right=handed carthesian coordinate system.
|
|
/// @note This implementation intentionally avoids the use of x and y
|
|
struct Vector2 : Vec2 {
|
|
friend struct Vec2;
|
|
|
|
public:
|
|
/// @brief A new 2-dimensional zero vector
|
|
Vector2();
|
|
/// @brief A new 2-dimensional vector
|
|
/// @param right The distance in the right direction in meters
|
|
/// @param forward The distance in the forward direction in meters
|
|
Vector2(float right, float forward);
|
|
/// @brief Convert a Vector3 to a Vector2
|
|
/// @param v The 3D vector
|
|
/// @note This will project the vector to the horizontal plane
|
|
Vector2(Vector3 v);
|
|
/// @brief Convert a Polar vector to a 2-dimensional vector
|
|
/// @param v The vector in polar coordinates
|
|
Vector2(PolarOf<float> v);
|
|
|
|
/// @brief Vector2 destructor
|
|
~Vector2();
|
|
|
|
/// @brief A vector with zero for all axis
|
|
const static Vector2 zero;
|
|
/// @brief A vector with one for all axis
|
|
const static Vector2 one;
|
|
/// @brief A normalized forward-oriented vector
|
|
const static Vector2 forward;
|
|
/// @brief A normalized back-oriented vector
|
|
const static Vector2 back;
|
|
/// @brief A normalized right-oriented vector
|
|
const static Vector2 right;
|
|
/// @brief A normalized left-oriented vector
|
|
const static Vector2 left;
|
|
/// @brief A normalized up-oriented vector
|
|
/// @note This is a convenience function which is equal to Vector2::forward
|
|
const static Vector2 up;
|
|
/// @brief A normalized down-oriented vector
|
|
/// @note This is a convenience function which is equal to Vector2::down
|
|
const static Vector2 down;
|
|
|
|
/// @brief Check if this vector to the given vector
|
|
/// @param v The vector to check against
|
|
/// @return true if it is identical to the given vector
|
|
/// @note This uses float comparison to check equality which may have strange
|
|
/// effects. Equality on floats should be avoided.
|
|
bool operator==(const Vector2& v);
|
|
|
|
/// @brief The vector length
|
|
/// @param v The vector for which you need the length
|
|
/// @return The vector length
|
|
static float Magnitude(const Vector2& v);
|
|
/// @brief The vector length
|
|
/// @return The vector length
|
|
float magnitude() const;
|
|
/// @brief The squared vector length
|
|
/// @param v The vector for which you need the squared length
|
|
/// @return The squared vector length
|
|
/// @remark The squared length is computationally simpler than the real
|
|
/// length. Think of Pythagoras A^2 + B^2 = C^2. This prevents the calculation
|
|
/// of the squared root of C.
|
|
static float SqrMagnitude(const Vector2& v);
|
|
/// @brief The squared vector length
|
|
/// @return The squared vector length
|
|
/// @remark The squared length is computationally simpler than the real
|
|
/// length. Think of Pythagoras A^2 + B^2 = C^2. This prevents the calculation
|
|
/// of the squared root of C.
|
|
float sqrMagnitude() const;
|
|
|
|
/// @brief Convert the vector to a length of 1
|
|
/// @param v The vector to convert
|
|
/// @return The vector normalized to a length of 1
|
|
static Vector2 Normalize(const Vector2& v);
|
|
/// @brief Convert the vector to a length 1
|
|
/// @return The vector normalized to a length of 1
|
|
Vector2 normalized() const;
|
|
|
|
/// @brief Negate the vector such that it points in the opposite direction
|
|
/// @return The negated vector
|
|
Vector2 operator-();
|
|
|
|
/// @brief Subtract a vector from this vector
|
|
/// @param v The vector to subtract from this vector
|
|
/// @return The result of the subtraction
|
|
Vector2 operator-(const Vector2& v) const;
|
|
Vector2 operator-=(const Vector2& v);
|
|
/// @brief Add a vector to this vector
|
|
/// @param v The vector to add to this vector
|
|
/// @return The result of the addition
|
|
Vector2 operator+(const Vector2& v) const;
|
|
Vector2 operator+=(const Vector2& v);
|
|
|
|
/// @brief Scale the vector using another vector
|
|
/// @param v1 The vector to scale
|
|
/// @param v2 A vector with the scaling factors
|
|
/// @return The scaled vector
|
|
/// @remark Each component of the vector v1 will be multiplied with the
|
|
/// matching component from the scaling vector v2.
|
|
static Vector2 Scale(const Vector2& v1, const Vector2& v2);
|
|
/// @brief Scale the vector uniformly up
|
|
/// @param f The scaling factor
|
|
/// @return The scaled vector
|
|
/// @remark Each component of the vector will be multipled with the same
|
|
/// factor f.
|
|
friend Vector2 operator*(const Vector2& v, float f) { return Vector2(v.x * f,
|
|
v.y * f); } friend Vector2 operator*(float f, const Vector2& v) { return
|
|
Vector2(v.x * f, v.y * f);
|
|
// return Vector2(f * v.x, f * v.y);
|
|
}
|
|
Vector2 operator*=(float f);
|
|
/// @brief Scale the vector uniformly down
|
|
/// @param f The scaling factor
|
|
/// @return The scaled vector
|
|
/// @remark Each componet of the vector will be divided by the same factor.
|
|
friend Vector2 operator/(const Vector2& v, float f) { return Vector2(v.x / f,
|
|
v.y / f); } friend Vector2 operator/(float f, const Vector2& v) { return
|
|
Vector2(f / v.x, f / v.y); } Vector2 operator/=(float f);
|
|
|
|
/// @brief The dot product of two vectors
|
|
/// @param v1 The first vector
|
|
/// @param v2 The second vector
|
|
/// @return The dot product of the two vectors
|
|
static float Dot(const Vector2& v1, const Vector2& v2);
|
|
|
|
/// @brief The distance between two vectors
|
|
/// @param v1 The first vector
|
|
/// @param v2 The second vector
|
|
/// @return The distance between the two vectors
|
|
static float Distance(const Vector2& v1, const Vector2& v2);
|
|
|
|
/// @brief The angle between two vectors
|
|
/// @param v1 The first vector
|
|
/// @param v2 The second vector
|
|
/// @return The angle between the two vectors
|
|
/// @remark This reterns an unsigned angle which is the shortest distance
|
|
/// between the two vectors. Use Vector2::SignedAngle if a signed angle is
|
|
/// needed.
|
|
static float Angle(const Vector2& v1, const Vector2& v2);
|
|
/// @brief The signed angle between two vectors
|
|
/// @param v1 The starting vector
|
|
/// @param v2 The ending vector
|
|
/// @return The signed angle between the two vectors
|
|
static float SignedAngle(const Vector2& v1, const Vector2& v2);
|
|
|
|
/// @brief Rotate the vector
|
|
/// @param v The vector to rotate
|
|
/// @param a The angle in degrees to rotate
|
|
/// @return The rotated vector
|
|
static Vector2 Rotate(const Vector2& v, AngleSingle a);
|
|
|
|
/// @brief Lerp (linear interpolation) between two vectors
|
|
/// @param v1 The starting vector
|
|
/// @param v2 The end vector
|
|
/// @param f The interpolation distance
|
|
/// @return The lerped vector
|
|
/// @remark The factor f is unclamped. Value 0 matches the vector *v1*, Value
|
|
/// 1 matches vector *v2*. Value -1 is vector *v1* minus the difference
|
|
/// between *v1* and *v2* etc.
|
|
static Vector2 Lerp(const Vector2& v1, const Vector2& v2, float f);
|
|
};
|
|
*/
|
|
template <typename T>
|
|
class Vector2Of {
|
|
public:
|
|
/// @brief The distance in the horizontal direction, left = negative, right =
|
|
/// positive
|
|
T horizontal = T{};
|
|
/// @brief The distance in the vertical direction, down = negative, up =
|
|
/// positive
|
|
T vertical = T{};
|
|
|
|
/// @brief A new 2-dimensional zero vector
|
|
Vector2Of();
|
|
/// @brief A new 2-dimensional vector
|
|
/// @param horizontal The distance in the horizontal direction, left =
|
|
/// negative, right = positive
|
|
/// @param vertical The distance in the vertical direction, down = negative,
|
|
/// up = positive
|
|
Vector2Of(T horizontal, T vertical);
|
|
|
|
/// @brief Converting constructor: allow Vector2Of<U> -> Vector2Of<T>
|
|
/// @tparam U
|
|
/// @param other
|
|
template <typename U>
|
|
constexpr Vector2Of(const Vector2Of<U>& other) noexcept
|
|
: horizontal(static_cast<T>(other.horizontal)),
|
|
vertical(static_cast<T>(other.vertical)) {}
|
|
|
|
static Vector2Of<float> FromPolar(PolarOf<float> v);
|
|
|
|
template <typename U>
|
|
constexpr Vector2Of& operator=(const Vector2Of<U>& other) noexcept {
|
|
this->horizontal = static_cast<T>(other.horizontal);
|
|
this->vertical = static_cast<T>(other.vertical);
|
|
return *this;
|
|
}
|
|
|
|
/// @brief A vector with zero for all axis
|
|
const static Vector2Of zero;
|
|
/// @brief A normalized forward-oriented vector
|
|
const static Vector2Of forward;
|
|
|
|
/// @brief Check if this vector to the given vector
|
|
/// @param v The vector to check against
|
|
/// @return true if it is identical to the given vector
|
|
/// @note This uses float comparison to check equality which may have strange
|
|
/// effects. Equality on floats should be avoided.
|
|
bool operator==(const Vector2Of& v);
|
|
|
|
/// @brief The vector length
|
|
/// @param v The vector for which you need the length
|
|
/// @return The vector length
|
|
static float MagnitudeOf(const Vector2Of& v);
|
|
/// @brief The vector length
|
|
/// @return The vector length
|
|
float Magnitude() const;
|
|
|
|
/// @brief The squared vector length
|
|
/// @param v The vector for which you need the squared length
|
|
/// @return The squared vector length
|
|
/// @remark The squared length is computationally simpler than the real
|
|
/// length. Think of Pythagoras A^2 + B^2 = C^2. This prevents the calculation
|
|
/// of the squared root of C.
|
|
static float SqrMagnitudeOf(const Vector2Of& v);
|
|
/// @brief The squared vector length
|
|
/// @return The squared vector length
|
|
/// @remark The squared length is computationally simpler than the real
|
|
/// length. Think of Pythagoras A^2 + B^2 = C^2. This prevents the calculation
|
|
/// of the squared root of C.
|
|
float SqrMagnitude() const;
|
|
|
|
/// @brief The distance between two vectors
|
|
/// @param v1 The first vector
|
|
/// @param v2 The second vector
|
|
/// @return The distance between the two vectors
|
|
static float Distance(const Vector2Of& v1, const Vector2Of& v2);
|
|
|
|
/// @brief Negate the vector such that it points in the opposite direction
|
|
/// @return The negated vector
|
|
Vector2Of operator-();
|
|
|
|
/// @brief Subtract a vector from this vector
|
|
/// @param v The vector to subtract from this vector
|
|
/// @return The result of the subtraction
|
|
Vector2Of operator-(const Vector2Of& v) const;
|
|
Vector2Of operator-=(const Vector2Of& v);
|
|
|
|
/// @brief Add a vector to this vector
|
|
/// @param v The vector to add to this vector
|
|
/// @return The result of the addition
|
|
Vector2Of operator+(const Vector2Of& v) const;
|
|
Vector2Of operator+=(const Vector2Of& v);
|
|
|
|
/// @brief Scale the vector using another vector
|
|
/// @param v1 The vector to scale
|
|
/// @param v2 A vector with the scaling factors
|
|
/// @return The scaled vector
|
|
/// @remark Each component of the vector v1 will be multiplied with the
|
|
/// matching component from the scaling vector v2.
|
|
static Vector2Of Scale(const Vector2Of& v1, const Vector2Of& v2);
|
|
|
|
/// @brief Scale the vector uniformly up
|
|
/// @param f The scaling factor
|
|
/// @return The scaled vector
|
|
/// @remark Each component of the vector will be multiplied by the same
|
|
/// factor.
|
|
template <typename U>
|
|
friend Vector2Of<U> operator*(const Vector2Of<U>& m, U f);
|
|
template <typename U>
|
|
friend Vector2Of<U> operator*(U f, const Vector2Of<U>& m);
|
|
|
|
/// @brief Scale the vector uniformly down
|
|
/// @param f The scaling factor
|
|
/// @return The scaled vector
|
|
/// @remark Each component of the vector will be divided by the same factor.
|
|
template <typename U>
|
|
friend Vector2Of<U> operator/(const Vector2Of<U>& m, U f);
|
|
template <typename U>
|
|
friend Vector2Of<U> operator/(U f, const Vector2Of<U>& m);
|
|
|
|
/// @brief The dot product of two vectors
|
|
/// @param v1 The first vector
|
|
/// @param v2 The second vector
|
|
/// @return The dot product of the two vectors
|
|
static T Dot(const Vector2Of& v1, const Vector2Of& v2);
|
|
|
|
static Vector2Of<float> Normalize(const Vector2Of& v);
|
|
/// @brief Convert the vector to a length 1
|
|
/// @return The vector normalized to a length of 1
|
|
Vector2Of<float> Normalized() const;
|
|
|
|
/// @brief The angle between two vectors
|
|
/// @param v1 The first vector
|
|
/// @param v2 The second vector
|
|
/// @return The angle between the two vectors
|
|
/// @remark This reterns an unsigned angle which is the shortest distance
|
|
/// between the two vectors. Use Vector2::SignedAngle if a signed angle is
|
|
/// needed.
|
|
static AngleOf<float> UnsignedAngle(const Vector2Of& v1, const Vector2Of& v2);
|
|
/// @brief The signed angle between two vectors
|
|
/// @param v1 The starting vector
|
|
/// @param v2 The ending vector
|
|
/// @return The signed angle between the two vectors
|
|
static AngleOf<float> SignedAngle(const Vector2Of& v1, const Vector2Of& v2);
|
|
|
|
/// @brief Rotate the vector
|
|
/// @param v The vector to rotate
|
|
/// @param a The angle in degrees to rotate
|
|
/// @return The rotated vector
|
|
static Vector2Of<float> Rotate(const Vector2Of& v, AngleOf<float> a);
|
|
|
|
/// @brief Lerp (linear interpolation) between two vectors
|
|
/// @param v1 The starting vector
|
|
/// @param v2 The end vector
|
|
/// @param f The interpolation distance
|
|
/// @return The lerped vector
|
|
/// @remark The factor f is unclamped. Value 0 matches the vector *v1*, Value
|
|
/// 1 matches vector *v2*. Value -1 is vector *v1* minus the difference
|
|
/// between *v1* and *v2* etc.
|
|
static Vector2Of<float> Lerp(const Vector2Of& v1,
|
|
const Vector2Of& v2,
|
|
float f);
|
|
};
|
|
|
|
#pragma region friend functions
|
|
|
|
// For a class template a friend function must also be a template and defined in
|
|
// the header (unless you restrict to a concrete instantiation)...
|
|
|
|
template <typename U>
|
|
Vector2Of<U> operator*(const Vector2Of<U>& v, U f) {
|
|
return Vector2Of<U>(v.horizontal * f, v.vertical * f);
|
|
}
|
|
template <typename U>
|
|
Vector2Of<U> operator*(U f, const Vector2Of<U>& v) {
|
|
return Vector2Of<U>(f * v.horizontal, f * v.vertical);
|
|
}
|
|
|
|
template <typename U>
|
|
Vector2Of<U> operator/(const Vector2Of<U>& v, U f) {
|
|
return Vector2Of<U>(v.horizontal / f, v.vertical / f);
|
|
}
|
|
template <typename U>
|
|
Vector2Of<U> operator/(U f, const Vector2Of<U>& v) {
|
|
return Vector2Of<U>(f / v.horizontal, f / v.vertical);
|
|
}
|
|
|
|
#pragma endregion friend functions
|
|
|
|
// template class Vector2Of<float>;
|
|
|
|
using Vector2Int = Vector2Of<int>;
|
|
using Vector2Float = Vector2Of<float>;
|
|
|
|
// template <typename T>
|
|
// inline Vector2Of operator/(const Vector2Of<T>& v, float f) {
|
|
// return Vector2Of(v.horizontal / f, v.vertical / f);
|
|
// }
|
|
|
|
} // namespace LinearAlgebra
|
|
// using namespace LinearAlgebra;
|
|
|
|
#endif |