Initial implementation Vector3Of

This commit is contained in:
Pascal Serrarens 2025-12-19 12:36:51 +01:00
parent 9886f98f6b
commit 4cf2511a8b
2 changed files with 305 additions and 17 deletions

View File

@ -5,6 +5,7 @@
#include "Vector3.h"
#include "Angle.h"
#include "Spherical.h"
//#include "TypeTraits.h"
#include <math.h>
@ -160,8 +161,7 @@ float Vector3::Distance(const Vector3& v1, const Vector3& v2) {
}
Vector3 Vector3::Cross(const Vector3& v1, const Vector3& v2) {
return Vector3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z,
v1.x * v2.y - v1.y * v2.x);
return Vector3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x);
}
Vector3 Vector3::Project(const Vector3& v, const Vector3& n) {
@ -194,17 +194,14 @@ AngleOf<float> Vector3::Angle(const Vector3& v1, const Vector3& v2) {
float dot = Vector3::Dot(v1, v2);
float fraction = dot / denominator;
if (isnan(fraction))
return AngleOf<float>::Degrees(
fraction); // short cut to returning NaN universally
return AngleOf<float>::Degrees(fraction); // short cut to returning NaN universally
float cdot = clamp(fraction, -1.0, 1.0);
float r = ((float)acos(cdot));
return AngleOf<float>::Radians(r);
}
AngleOf<float> Vector3::SignedAngle(const Vector3& v1,
const Vector3& v2,
const Vector3& axis) {
AngleOf<float> Vector3::SignedAngle(const Vector3& v1, const Vector3& v2, const Vector3& axis) {
// angle in [0,180]
AngleOf<float> angle = Vector3::Angle(v1, v2);
@ -222,3 +219,169 @@ Vector3 Vector3::Lerp(const Vector3& v1, const Vector3& v2, float f) {
Vector3 v = v1 + (v2 - v1) * f;
return v;
}
#pragma region Vector3Of
namespace LinearAlgebra {
template <typename T>
Vector3Of<T>::Vector3Of() {}
template <typename T>
Vector3Of<T>::Vector3Of(T horizontal, T vertical, T depth)
: horizontal(horizontal), vertical(vertical), depth(depth) {}
template <typename T>
Vector3Of<T>::Vector3Of(Vector2Of<T> v) : horizontal(v.horizontal), vertical(v.vertical) {}
template <typename T>
Vector3Of<T>::Vector3Of(SphericalOf<T> v) {
float cosVertical = Angle::Cos(v.direction.vertical);
float sinVertical = Angle::Sin(v.direction.vertical);
float cosHorizontal = Angle::Cos(v.direction.horizontal);
float sinHorizontal = Angle::Sin(v.direction.horizontal);
horizontal = v.distance * sinVertical * sinHorizontal;
vertical = v.distance * cosVertical;
depth = v.distance * sinVertical * cosHorizontal;
}
template <typename T>
Vector3Of<T>::Vector3Of(Vector3 v) : horizontal(v.x), vertical(v.y), depth(v.z) {}
template <typename T>
Vector3 Vector3Of<T>::ToVector3() {
return Vector3(this->horizontal, this->vertical, this->depth);
}
template <typename T>
Vector3Of<T>::~Vector3Of() {}
template <typename T>
const Vector3Of<T> Vector3Of<T>::zero = Vector3Of(T{}, T{}, T{});
template <>
const Vector3Of<int> Vector3Of<int>::unit = Vector3Of<int>(1, 1, 1);
template <>
const Vector3Of<float> Vector3Of<float>::unit = Vector3Of<float>(1.0f, 1.0f, 1.0f);
template <>
const Vector3Of<double> Vector3Of<double>::unit = Vector3Of<double>(1.0f, 1.0f, 1.0f);
// template <typename T>
// const Vector3Of<T> Vector3Of<T>::unit =
// Vector3Of(TypeTraits<T>::unit(), TypeTraits<T>::unit(), TypeTraits<T>::unit());
// const Vector3Of Vector3Of::right = Vector3Of(1, 0, 0);
// const Vector3Of Vector3Of::left = Vector3Of(-1, 0, 0);
// const Vector3Of Vector3Of::up = Vector3Of(0, 1, 0);
// const Vector3Of Vector3Of::down = Vector3Of(0, -1, 0);
// const Vector3Of Vector3Of::forward = Vector3Of(0, 0, 1);
// const Vector3Of Vector3Of::back = Vector3Of(0, 0, -1);
template <typename T>
T Vector3Of<T>::MagnitudeOf(const Vector3Of& v) {
return sqrtf(v.horizontal * v.horizontal + v.vertical * v.vertical + v.depth * v.depth);
}
template <typename T>
T Vector3Of<T>::Magnitude() const {
return (T)sqrtf(this->horizontal * this->horizontal + this->vertical * this->vertical +
this->depth * this->depth);
}
template <typename T>
float Vector3Of<T>::SqrMagnitudeOf(const Vector3Of& v) {
return v.horizontal * v.horizontal + v.vertical * v.vertical + v.depth * v.depth;
}
template <typename T>
float Vector3Of<T>::SqrMagnitude() const {
return (horizontal * horizontal + vertical * vertical + depth * depth);
}
template <typename T>
Vector3Of<T> Vector3Of<T>::Normalize(const Vector3Of& v) {
float num = Vector3Of<T>::MagnitudeOf(v);
Vector3Of<T> result = Vector3Of<T>::zero;
if (num > epsilon) {
result = v / num;
}
return result;
}
template <typename T>
Vector3Of<T> Vector3Of<T>::Normalized() const {
float num = this->Magnitude();
Vector3Of<T> result = Vector3Of<T>::zero;
if (num > epsilon) {
result = ((Vector3Of<T>) * this) / num;
}
return result;
}
template <typename T>
Vector3Of<T> Vector3Of<T>::operator-(const Vector3Of& v) const {
return Vector3(this->horizontal - v.horizontal, this->vertical - v.vertical,
this->depth - v.depth);
}
template <typename T>
Vector3Of<T> Vector3Of<T>::operator-=(const Vector3Of& v) {
this->horizontal -= v.horizontal;
this->vertical -= v.vertical;
this->depth -= v.depth;
return *this;
}
template <typename T>
Vector3Of<T> Vector3Of<T>::operator+(const Vector3Of& v) const {
return Vector3(this->horizontal + v.horizontal, this->vertical + v.vertical,
this->depth + v.depth);
}
template <typename T>
Vector3Of<T> Vector3Of<T>::operator+=(const Vector3Of& v) {
this->horizontal += v.horizontal;
this->vertical += v.vertical;
this->depth += v.depth;
return *this;
}
template <typename T>
Vector3Of<T> Vector3Of<T>::operator*=(float f) {
this->horizontal *= f;
this->vertical *= f;
this->depth *= f;
return *this;
}
template <typename T>
Vector3Of<T> Vector3Of<T>::operator/=(float f) {
this->horizontal /= f;
this->vertical /= f;
this->depth /= f;
return *this;
}
template <typename T>
float Vector3Of<T>::Dot(const Vector3Of& v1, const Vector3Of& v2) {
return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + v1.depth * v2.depth;
}
template <typename T>
AngleOf<float> Vector3Of<T>::Angle(const Vector3Of& v1, const Vector3Of& v2) {
float denominator = sqrtf(v1.SqrMagnitude() * v2.SqrMagnitude());
if (denominator < epsilon)
return AngleOf<float>();
float dot = Vector3Of::Dot(v1, v2);
float fraction = dot / denominator;
if (isnan(fraction))
return AngleOf<float>::Degrees(fraction); // short cut to returning NaN universally
float cdot = clamp(fraction, -1.0, 1.0);
float r = ((float)acos(cdot));
return AngleOf<float>::Radians(r);
}
template class Vector3Of<float>;
} // namespace LinearAlgebra
#pragma endregion Vector3Of

145
Vector3.h
View File

@ -146,9 +146,7 @@ struct Vector3 : Vec3 {
/// @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*(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);
@ -158,9 +156,7 @@ struct Vector3 : Vec3 {
/// @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/(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);
@ -210,9 +206,7 @@ struct Vector3 : Vec3 {
/// @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);
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
@ -225,8 +219,139 @@ struct Vector3 : Vec3 {
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;
// using namespace LinearAlgebra;
#include "Spherical.h"