diff --git a/Vector3.cpp b/Vector3.cpp index 7ec6a95..8893df4 100644 --- a/Vector3.cpp +++ b/Vector3.cpp @@ -5,6 +5,7 @@ #include "Vector3.h" #include "Angle.h" #include "Spherical.h" +//#include "TypeTraits.h" #include @@ -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 Vector3::Angle(const Vector3& v1, const Vector3& v2) { float dot = Vector3::Dot(v1, v2); float fraction = dot / denominator; if (isnan(fraction)) - return AngleOf::Degrees( - fraction); // short cut to returning NaN universally + return AngleOf::Degrees(fraction); // short cut to returning NaN universally float cdot = clamp(fraction, -1.0, 1.0); float r = ((float)acos(cdot)); return AngleOf::Radians(r); } -AngleOf Vector3::SignedAngle(const Vector3& v1, - const Vector3& v2, - const Vector3& axis) { +AngleOf Vector3::SignedAngle(const Vector3& v1, const Vector3& v2, const Vector3& axis) { // angle in [0,180] AngleOf 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 +Vector3Of::Vector3Of() {} + +template +Vector3Of::Vector3Of(T horizontal, T vertical, T depth) + : horizontal(horizontal), vertical(vertical), depth(depth) {} + +template +Vector3Of::Vector3Of(Vector2Of v) : horizontal(v.horizontal), vertical(v.vertical) {} + +template +Vector3Of::Vector3Of(SphericalOf 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 +Vector3Of::Vector3Of(Vector3 v) : horizontal(v.x), vertical(v.y), depth(v.z) {} + +template +Vector3 Vector3Of::ToVector3() { + return Vector3(this->horizontal, this->vertical, this->depth); +} + +template +Vector3Of::~Vector3Of() {} + +template +const Vector3Of Vector3Of::zero = Vector3Of(T{}, T{}, T{}); + +template <> +const Vector3Of Vector3Of::unit = Vector3Of(1, 1, 1); +template <> +const Vector3Of Vector3Of::unit = Vector3Of(1.0f, 1.0f, 1.0f); +template <> +const Vector3Of Vector3Of::unit = Vector3Of(1.0f, 1.0f, 1.0f); + +// template +// const Vector3Of Vector3Of::unit = +// Vector3Of(TypeTraits::unit(), TypeTraits::unit(), TypeTraits::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 +T Vector3Of::MagnitudeOf(const Vector3Of& v) { + return sqrtf(v.horizontal * v.horizontal + v.vertical * v.vertical + v.depth * v.depth); +} +template +T Vector3Of::Magnitude() const { + return (T)sqrtf(this->horizontal * this->horizontal + this->vertical * this->vertical + + this->depth * this->depth); +} + +template +float Vector3Of::SqrMagnitudeOf(const Vector3Of& v) { + return v.horizontal * v.horizontal + v.vertical * v.vertical + v.depth * v.depth; +} +template +float Vector3Of::SqrMagnitude() const { + return (horizontal * horizontal + vertical * vertical + depth * depth); +} + +template +Vector3Of Vector3Of::Normalize(const Vector3Of& v) { + float num = Vector3Of::MagnitudeOf(v); + Vector3Of result = Vector3Of::zero; + if (num > epsilon) { + result = v / num; + } + return result; +} + +template +Vector3Of Vector3Of::Normalized() const { + float num = this->Magnitude(); + Vector3Of result = Vector3Of::zero; + if (num > epsilon) { + result = ((Vector3Of) * this) / num; + } + return result; +} +template +Vector3Of Vector3Of::operator-(const Vector3Of& v) const { + return Vector3(this->horizontal - v.horizontal, this->vertical - v.vertical, + this->depth - v.depth); +} + +template +Vector3Of Vector3Of::operator-=(const Vector3Of& v) { + this->horizontal -= v.horizontal; + this->vertical -= v.vertical; + this->depth -= v.depth; + return *this; +} + +template +Vector3Of Vector3Of::operator+(const Vector3Of& v) const { + return Vector3(this->horizontal + v.horizontal, this->vertical + v.vertical, + this->depth + v.depth); +} + +template +Vector3Of Vector3Of::operator+=(const Vector3Of& v) { + this->horizontal += v.horizontal; + this->vertical += v.vertical; + this->depth += v.depth; + return *this; +} + +template +Vector3Of Vector3Of::operator*=(float f) { + this->horizontal *= f; + this->vertical *= f; + this->depth *= f; + return *this; +} + +template +Vector3Of Vector3Of::operator/=(float f) { + this->horizontal /= f; + this->vertical /= f; + this->depth /= f; + return *this; +} + +template +float Vector3Of::Dot(const Vector3Of& v1, const Vector3Of& v2) { + return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical + v1.depth * v2.depth; +} + +template +AngleOf Vector3Of::Angle(const Vector3Of& v1, const Vector3Of& v2) { + float denominator = sqrtf(v1.SqrMagnitude() * v2.SqrMagnitude()); + if (denominator < epsilon) + return AngleOf(); + + float dot = Vector3Of::Dot(v1, v2); + float fraction = dot / denominator; + if (isnan(fraction)) + return AngleOf::Degrees(fraction); // short cut to returning NaN universally + + float cdot = clamp(fraction, -1.0, 1.0); + float r = ((float)acos(cdot)); + return AngleOf::Radians(r); +} + +template class Vector3Of; + +} // namespace LinearAlgebra + +#pragma endregion Vector3Of \ No newline at end of file diff --git a/Vector3.h b/Vector3.h index 914d72a..b94fa0d 100644 --- a/Vector3.h +++ b/Vector3.h @@ -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 SignedAngle(const Vector3& v1, - const Vector3& v2, - const Vector3& axis); + static AngleOf 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 +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 v); + Vector3Of(SphericalOf 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 Vector3Of::unit(1, 1, 1); // Hardcoded unit vector for int + // const Vector3Of Vector3Of::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 Normalize(const Vector3Of& v); + /// @brief Convert the vector to a length of 1 + /// @return The vector normalized to a length of 1 + Vector3Of 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 operator-(const Vector3Of& v) const; + Vector3Of 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 operator+(const Vector3Of& v) const; + Vector3Of 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 operator*(const Vector3Of& v, float f) { + return Vector3Of(v.horizontal * f, v.vertical * f, v.depth * f); + } + friend Vector3Of operator*(float f, const Vector3Of& v) { + return Vector3Of(f * v.horizontal, f * v.vertical, f * v.depth); +// return Vector3Of(v.horizontal * f, v.vertical * f, v.depth * f); + } + Vector3Of 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 operator/(const Vector3Of& v, float f) { + return Vector3Of(v.horizontal / f, v.vertical / f, v.depth / f); + } + friend Vector3Of operator/(float f, const Vector3Of& v) { + return Vector3Of(f / v.horizontal, f / v.vertical, f / v.depth); +// return Vector3Of(v.horizontal / f, v.vertical / f, v.depth / f); + } + Vector3Of 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 Angle(const Vector3Of& v1, const Vector3Of& v2); +}; + +using Vector3Int = Vector3Of; +using Vector3Float = Vector3Of; + } // namespace LinearAlgebra -using namespace LinearAlgebra; +// using namespace LinearAlgebra; #include "Spherical.h"