LinearAlgebra-cpp/Vector3.h

358 lines
13 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 VECTOR3_H
#define VECTOR3_H
#include "Vector2.h"
extern "C" {
/// <summary>
/// 3-dimensional Vector representation (C-style)
/// </summary>
/// This is a C-style implementation
/// This uses the right-handed coordinate system.
typedef struct Vec3 {
public:
/// <summary>
/// The right axis of the vector
/// </summary>
float x;
/// <summary>
/// The upward axis of the vector
/// </summary>
float y;
/// <summary>
/// The forward axis of the vector
/// </summary>
float z;
} Vec3;
}
namespace LinearAlgebra {
template <typename T>
class SphericalOf;
/// @brief A 3-dimensional vector
/// @remark This uses a right-handed carthesian coordinate system.
/// @note This implementation intentionally avoids the use of x, y and z values.
struct Vector3 : Vec3 {
friend struct Vec3;
public:
/// @brief A new 3-dimensional zero vector
Vector3();
/// @brief A new 3-dimensional vector
/// @param right The distance in the right direction in meters
/// @param up The distance in the upward direction in meters
/// @param forward The distance in the forward direction in meters
Vector3(float right, float up, float forward);
/// @brief Convert a 2-dimenstional vector to a 3-dimensional vector
/// @param v The vector to convert
Vector3(Vector2 v);
/// @brief Convert vector in spherical coordinates to 3d carthesian
/// coordinates
/// @param v The vector to convert
Vector3(SphericalOf<float> v);
/// @brief Vector3 destructor
~Vector3();
/// @brief A vector with zero for all axis
const static Vector3 zero;
/// @brief A vector with one for all axis
const static Vector3 one;
/// @brief A normalized forward-oriented vector
const static Vector3 forward;
/// @brief A normalized back-oriented vector
const static Vector3 back;
/// @brief A normalized right-oriented vector
const static Vector3 right;
/// @brief A normalized left-oriented vector
const static Vector3 left;
/// @brief A normalized up-oriented vector
const static Vector3 up;
/// @brief A normalized down-oriented vector
const static Vector3 down;
// Access functions which are intended to replace the use of XYZ
inline float Forward() const { return z; };
inline float Up() const { return y; };
inline float Right() const { return x; };
/// @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 Vector3& v) const;
/// @brief The vector length
/// @param v The vector for which you need the length
/// @return The vector length
static float Magnitude(const Vector3& 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 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 leaves out the
/// calculation of the squared root of C.
static float SqrMagnitude(const Vector3& 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 leaves out 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 Vector3 Normalize(const Vector3& v);
/// @brief Convert the vector to a length of 1
/// @return The vector normalized to a length of 1
Vector3 normalized() const;
/// @brief Negate te vector such that it points in the opposite direction
/// @return The negated vector
Vector3 operator-() const;
/// @brief Subtract a vector from this vector
/// @param v The vector to subtract from this vector
/// @return The result of this subtraction
Vector3 operator-(const Vector3& v) const;
Vector3 operator-=(const Vector3& v);
/// @brief Add a vector to this vector
/// @param v The vector to add to this vector
/// @return The result of the addition
Vector3 operator+(const Vector3& v) const;
Vector3 operator+=(const Vector3& 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 Vector3 Scale(const Vector3& v1, const Vector3& 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 Vector3 operator*(const Vector3& v, float f) { return Vector3(v.x * f, v.y * f, v.z * f); }
friend Vector3 operator*(float f, const Vector3& v) {
// return Vector3(f * v.x, f * v.y, f * v.z);
return Vector3(v.x * f, v.y * f, v.z * f);
}
Vector3 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 Vector3 operator/(const Vector3& v, float f) { return Vector3(v.x / f, v.y / f, v.z / f); }
friend Vector3 operator/(float f, const Vector3& v) {
// return Vector3(f / v.x, f / v.y, f / v.z);
return Vector3(v.x / f, v.y / f, v.z / f);
}
Vector3 operator/=(float f);
/// @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 Vector3& v1, const Vector3& v2);
/// @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 Vector3& v1, const Vector3& v2);
/// @brief The cross product of two vectors
/// @param v1 The first vector
/// @param v2 The second vector
/// @return The cross product of the two vectors
static Vector3 Cross(const Vector3& v1, const Vector3& v2);
/// @brief Project the vector on another vector
/// @param v The vector to project
/// @param n The normal vecto to project on
/// @return The projected vector
static Vector3 Project(const Vector3& v, const Vector3& n);
/// @brief Project the vector on a plane defined by a normal orthogonal to the
/// plane.
/// @param v The vector to project
/// @param n The normal of the plane to project on
/// @return Teh projected vector
static Vector3 ProjectOnPlane(const Vector3& v, const Vector3& n);
/// @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 Vector3::SignedAngle if a signed angle is
/// needed.
static AngleOf<float> Angle(const Vector3& v1, const Vector3& v2);
/// @brief The signed angle between two vectors
/// @param v1 The starting vector
/// @param v2 The ending vector
/// @param axis The axis to rotate around
/// @return The signed angle between the two vectors
static AngleOf<float> SignedAngle(const Vector3& v1, const Vector3& v2, const Vector3& axis);
/// @brief Lerp (linear interpolation) between two vectors
/// @param v1 The starting vector
/// @param v2 The ending 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 Vector3 Lerp(const Vector3& v1, const Vector3& v2, float f);
};
/// @brief A 3-dimensional vector
/// @remark This uses a right-handed carthesian coordinate system.
/// @remark No default unit (for instance, meters) is specified
/// @note This implementation intentionally avoids the use of x, y and z values.
/// @tparam T The type of the paramters used to measure distance. Typical values are float and int
template <typename T>
class Vector3Of {
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 The distance in the depth direction, backward = negative, forward = positive
T depth = T{};
/// @brief A new 3-dimensional zero vector
Vector3Of();
/// @brief A new 3-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
/// @param depth The distance in the depth direction, backward = negative, forward =
/// positive
Vector3Of(T horizontal, T vertical, T depth);
Vector3Of(Vector2Of<T> v);
Vector3Of(SphericalOf<T> v);
Vector3Of(Vector3 v);
Vector3 ToVector3();
/// @brief Vector3 destructor
~Vector3Of();
/// @brief A vector with zero for all axis
const static Vector3Of zero;
/// @brief A vector with unit for all axis
const static Vector3Of unit;
// const Vector3Of<int> Vector3Of<int>::unit(1, 1, 1); // Hardcoded unit vector for int
// const Vector3Of<float> Vector3Of<float>::unit(1.0f, 1.0f, 1.0f); // Hardcoded unit vector for
// float
/// @brief The vector length
/// @param v The vector for which you need the length
/// @return The vector length
static T MagnitudeOf(const Vector3Of& v);
/// @brief The vector length
/// @return The vector length
T Magnitude() const;
/// @brief The squared vector length
/// @param v The vector for which you need the 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 leaves out the
/// calculation of the squared root of C.
static float SqrMagnitudeOf(const Vector3Of& 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 leaves out 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 Vector3Of<T> Normalize(const Vector3Of& v);
/// @brief Convert the vector to a length of 1
/// @return The vector normalized to a length of 1
Vector3Of<T> Normalized() const;
/// @brief Subtract a vector from this vector
/// @param v The vector to subtract from this vector
/// @return The result of this subtraction
Vector3Of<T> operator-(const Vector3Of& v) const;
Vector3Of<T> operator-=(const Vector3Of& v);
/// @brief Add a vector to this vector
/// @param v The vector to add to this vector
/// @return The result of the addition
Vector3Of<T> operator+(const Vector3Of& v) const;
Vector3Of<T> operator+=(const Vector3Of& v);
/// @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 Vector3Of<T> operator*(const Vector3Of& v, float f) {
return Vector3Of<T>(v.horizontal * f, v.vertical * f, v.depth * f);
}
friend Vector3Of<T> operator*(float f, const Vector3Of& v) {
return Vector3Of<T>(f * v.horizontal, f * v.vertical, f * v.depth);
// return Vector3Of<T>(v.horizontal * f, v.vertical * f, v.depth * f);
}
Vector3Of<T> 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 Vector3Of<T> operator/(const Vector3Of& v, float f) {
return Vector3Of<T>(v.horizontal / f, v.vertical / f, v.depth / f);
}
friend Vector3Of<T> operator/(float f, const Vector3Of& v) {
return Vector3Of<T>(f / v.horizontal, f / v.vertical, f / v.depth);
// return Vector3Of<T>(v.horizontal / f, v.vertical / f, v.depth / f);
}
Vector3Of<T> 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 Vector3Of& v1, const Vector3Of& 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 Vector3::SignedAngle if a signed angle is
/// needed.
static AngleOf<float> Angle(const Vector3Of& v1, const Vector3Of& v2);
};
using Vector3Int = Vector3Of<int>;
using Vector3Float = Vector3Of<float>;
} // namespace LinearAlgebra
// using namespace LinearAlgebra;
#include "Spherical.h"
#endif