Converted all unit tests to template form
All checks were successful
Build and Run C++ Unit Tests / build-and-test (push) Successful in 2m2s

This commit is contained in:
Pascal Serrarens 2025-12-22 15:01:11 +01:00
parent 679471f748
commit b555fb5d6a
21 changed files with 1285 additions and 1011 deletions

View File

@ -43,24 +43,22 @@ const DirectionOf<T> DirectionOf<T>::right =
DirectionOf<T>(AngleOf<T>::Degrees(90), AngleOf<T>());
template <typename T>
Vector3 DirectionOf<T>::ToVector3() const {
Vector3Of<float> DirectionOf<T>::ToVector3() const {
Quaternion q = Quaternion::Euler(-this->vertical.InDegrees(),
this->horizontal.InDegrees(), 0);
Vector3 v = q * Vector3::forward;
Vector3Of<float> v = q * Vector3Of<float>::forward;
return v;
}
template <typename T>
DirectionOf<T> DirectionOf<T>::FromVector3(Vector3 vector) {
DirectionOf<T> DirectionOf<T>::FromVector3(Vector3Of<float> vector) {
DirectionOf<T> d;
d.horizontal = AngleOf<T>::Atan2(
vector.Right(),
vector
.Forward()); // AngleOf<T>::Radians(atan2f(v.Right(), v.Forward()));
d.vertical =
AngleOf<T>::Degrees(-90) -
AngleOf<T>::Acos(
vector.Up()); // AngleOf<T>::Radians(-(0.5f * pi) - acosf(v.Up()));
vector.horizontal,
vector.depth); // AngleOf<T>::Radians(atan2f(v.Right(), v.Forward()));
d.vertical = AngleOf<T>::Degrees(-90) -
AngleOf<T>::Acos(vector.vertical); // AngleOf<T>::Radians(-(0.5f
// * pi) - acosf(v.Up()));
d.Normalize();
return d;
}
@ -101,4 +99,4 @@ void DirectionOf<T>::Normalize() {
template class LinearAlgebra::DirectionOf<float>;
template class LinearAlgebra::DirectionOf<signed short>;
}
} // namespace LinearAlgebra

View File

@ -9,7 +9,9 @@
namespace LinearAlgebra {
struct Vector3;
//struct Vector3;
template <typename T>
class Vector3Of;
/// @brief A direction using angles in various representations
/// @tparam T The implementation type used for the representation of the angles
@ -38,13 +40,13 @@ class DirectionOf {
/// @brief Convert the direction into a carthesian vector
/// @return The carthesian vector corresponding to this direction.
Vector3 ToVector3() const;
Vector3Of<float> ToVector3() const;
/// @brief Convert a carthesian vector into a direction
/// @param v The carthesian vector
/// @return The direction.
/// @note Information about the length of the carthesian vector is not
/// included in this transformation.
static DirectionOf<T> FromVector3(Vector3 vector);
static DirectionOf<T> FromVector3(Vector3Of<float> vector);
/// @brief Create a direction using angle values in degrees
/// @param horizontal The horizontal angle in degrees

View File

@ -36,11 +36,11 @@ PolarOf<T> PolarOf<T>::Radians(float distance, float radians) {
return PolarOf<T>(distance, AngleOf<T>::Radians(radians));
}
template <typename T>
PolarOf<T> PolarOf<T>::FromVector2(Vector2Of<T> v) {
template <>
PolarOf<float> PolarOf<float>::FromVector2(Vector2Of<float> v) {
float distance = v.Magnitude();
AngleOf<T> angle = Vector2Of<T>::SignedAngle(Vector2Of<T>::forward, v);
PolarOf<T> p = PolarOf(distance, angle);
AngleOf<float> angle = Vector2Of<float>::SignedAngle(Vector2Of<float>::forward, v);
PolarOf<float> p = PolarOf(distance, angle);
return p;
}
template <typename T>
@ -175,4 +175,4 @@ PolarOf<T> PolarOf<T>::Rotate(const PolarOf& v, AngleOf<T> angle) {
}
template class LinearAlgebra::PolarOf<float>;
template class LinearAlgebra::PolarOf<signed short>;
template class LinearAlgebra::PolarOf<signed short>;

View File

@ -56,7 +56,7 @@ class PolarOf {
/// @brief Convert a vector from 2D carthesian coordinates to polar
/// coordinates
/// @param v The vector to convert
static PolarOf<T> FromVector2(Vector2Of<T> v);
static PolarOf<float> FromVector2(Vector2Of<float> v);
/// @brief Convert a vector from spherical coordinates to polar coordinates
/// @param s The vector to convert
/// @note The resulting vector will be projected on the horizontal plane

View File

@ -44,8 +44,8 @@ Quaternion::~Quaternion() {}
const Quaternion Quaternion::identity = Quaternion(0, 0, 0, 1);
Vector3 Quaternion::xyz() const {
return Vector3(x, y, z);
Vector3Of<float> Quaternion::xyz() const {
return Vector3Of<float>(x, y, z);
}
float Quaternion::GetLength() const {
@ -78,18 +78,18 @@ float Quaternion::Dot(Quaternion a, Quaternion b) {
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
Vector3 Quaternion::ToAngles(const Quaternion& q1) {
Vector3Of<float> Quaternion::ToAngles(const Quaternion& q1) {
float test = q1.x * q1.y + q1.z * q1.w;
if (test > 0.499f) { // singularity at north pole
return Vector3(0, 2 * (float)atan2(q1.x, q1.w) * Rad2Deg, 90);
return Vector3Of<float>(0, 2 * (float)atan2(q1.x, q1.w) * Rad2Deg, 90);
} else if (test < -0.499f) { // singularity at south pole
return Vector3(0, -2 * (float)atan2(q1.x, q1.w) * Rad2Deg, -90);
return Vector3Of<float>(0, -2 * (float)atan2(q1.x, q1.w) * Rad2Deg, -90);
} else {
float sqx = q1.x * q1.x;
float sqy = q1.y * q1.y;
float sqz = q1.z * q1.z;
return Vector3(
return Vector3Of<float>(
atan2f(2 * q1.x * q1.w - 2 * q1.y * q1.z, 1 - 2 * sqx - 2 * sqz) *
Rad2Deg,
atan2f(2 * q1.y * q1.w - 2 * q1.x * q1.z, 1 - 2 * sqy - 2 * sqz) *
@ -128,7 +128,7 @@ Quaternion Quaternion::operator*(const Quaternion& r2) const {
-this->x * r2.x - this->y * r2.y - this->z * r2.z + this->w * r2.w);
};
Vector3 Quaternion::operator*(const Vector3& p) const {
Vector3Of<float> Quaternion::operator*(const Vector3Of<float>& p) const {
float num = this->x * 2;
float num2 = this->y * 2;
float num3 = this->z * 2;
@ -142,9 +142,9 @@ Vector3 Quaternion::operator*(const Vector3& p) const {
float num11 = this->w * num2;
float num12 = this->w * num3;
float px = p.Right();
float py = p.Up();
float pz = p.Forward();
float px = p.horizontal;
float py = p.vertical;
float pz = p.depth;
// Vector3 result = Vector3::zero;
// result.x =
float rx =
@ -155,7 +155,7 @@ Vector3 Quaternion::operator*(const Vector3& p) const {
// result.z =
float rz =
(num8 - num11) * px + (num9 + num10) * py + (1 - (num4 + num5)) * pz;
Vector3 result = Vector3(rx, ry, rz);
Vector3Of<float> result = Vector3Of<float>(rx, ry, rz);
return result;
}
@ -168,23 +168,23 @@ Quaternion Quaternion::Inverse(Quaternion r) {
return Quaternion(-r.x / n, -r.y / n, -r.z / n, r.w / n);
}
Quaternion Quaternion::LookRotation(const Vector3& forward) {
Vector3 up = Vector3(0, 1, 0);
Quaternion Quaternion::LookRotation(const Vector3Of<float>& forward) {
Vector3Of<float> up = Vector3Of<float>(0, 1, 0);
return LookRotation(forward, up);
}
Quaternion Quaternion::LookRotation(const Vector3& forward, const Vector3& up) {
Vector3 nForward = Vector3::Normalize(forward);
Vector3 nRight = Vector3::Normalize(Vector3::Cross(up, nForward));
Vector3 nUp = Vector3::Cross(nForward, nRight);
float m00 = nRight.Right(); // x;
float m01 = nRight.Up(); // y;
float m02 = nRight.Forward(); // z;
float m10 = nUp.Right(); // x;
float m11 = nUp.Up(); // y;
float m12 = nUp.Forward(); // z;
float m20 = nForward.Right(); // x;
float m21 = nForward.Up(); // y;
float m22 = nForward.Forward(); // z;
Quaternion Quaternion::LookRotation(const Vector3Of<float>& forward, const Vector3Of<float>& up) {
Vector3Of<float> nForward = Vector3Of<float>::Normalize(forward);
Vector3Of<float> nRight = Vector3Of<float>::Normalize(Vector3Of<float>::Cross(up, nForward));
Vector3Of<float> nUp = Vector3Of<float>::Cross(nForward, nRight);
float m00 = nRight.horizontal; // x;
float m01 = nRight.vertical; // y;
float m02 = nRight.depth; // z;
float m10 = nUp.horizontal; // x;
float m11 = nUp.vertical; // y;
float m12 = nUp.depth; // z;
float m20 = nForward.horizontal; // x;
float m21 = nForward.vertical; // y;
float m22 = nForward.depth; // z;
float num8 = (m00 + m11) + m22;
Quaternion quaternion = Quaternion();
@ -224,11 +224,11 @@ Quaternion Quaternion::LookRotation(const Vector3& forward, const Vector3& up) {
return quaternion;
}
Quaternion Quaternion::FromToRotation(Vector3 fromDirection,
Vector3 toDirection) {
Vector3 axis = Vector3::Cross(fromDirection, toDirection);
axis = Vector3::Normalize(axis);
AngleOf<float> angle = Vector3::SignedAngle(fromDirection, toDirection, axis);
Quaternion Quaternion::FromToRotation(Vector3Of<float> fromDirection,
Vector3Of<float> toDirection) {
Vector3Of<float> axis = Vector3Of<float>::Cross(fromDirection, toDirection);
axis = Vector3Of<float>::Normalize(axis);
AngleOf<float> angle = Vector3Of<float>::SignedAngle(fromDirection, toDirection, axis);
Quaternion rotation = Quaternion::AngleAxis(angle.InDegrees(), axis);
return rotation;
}
@ -244,18 +244,18 @@ Quaternion Quaternion::RotateTowards(const Quaternion& from,
return SlerpUnclamped(from, to, t);
}
Quaternion Quaternion::AngleAxis(float angle, const Vector3& axis) {
if (Vector3::SqrMagnitude(axis) == 0.0f)
Quaternion Quaternion::AngleAxis(float angle, const Vector3Of<float>& axis) {
if (Vector3Of<float>::SqrMagnitudeOf(axis) == 0.0f)
return Quaternion();
Quaternion result = Quaternion();
float radians = angle * Deg2Rad;
radians *= 0.5f;
Vector3 axis2 = axis * (float)sin(radians);
result.x = axis2.Right(); // x;
result.y = axis2.Up(); // y;
result.z = axis2.Forward(); // z;
Vector3Of<float> axis2 = axis * (float)sin(radians);
result.x = axis2.horizontal; // x;
result.y = axis2.vertical; // y;
result.z = axis2.depth; // z;
result.w = (float)cos(radians);
return Quaternion::Normalize(result);
@ -266,23 +266,23 @@ float Quaternion::Angle(Quaternion a, Quaternion b) {
return (float)acos(fmin(fabs(f), 1)) * 2 * Rad2Deg;
}
void Quaternion::ToAngleAxis(float* angle, Vector3* axis) {
void Quaternion::ToAngleAxis(float* angle, Vector3Of<float>* axis) {
Quaternion::ToAxisAngleRad(*this, axis, angle);
*angle *= Rad2Deg;
}
void Quaternion::ToAxisAngleRad(const Quaternion& q,
Vector3* const axis,
Vector3Of<float>* const axis,
float* angle) {
Quaternion q1 = (fabs(q.w) > 1.0f) ? Quaternion::Normalize(q) : q;
*angle = 2.0f * acosf(q1.w); // angle
float den = sqrtf(1.0F - q1.w * q1.w);
if (den > 0.0001f) {
*axis = Vector3::Normalize(q1.xyz() / den);
*axis = Vector3Of<float>::Normalize(q1.xyz() / den);
} else {
// This occurs when the angle is zero.
// Not a problem: just set an arbitrary normalized axis.
*axis = Vector3(1, 0, 0);
*axis = Vector3Of<float>(1, 0, 0);
}
}
Quaternion Quaternion::SlerpUnclamped(const Quaternion& a,
@ -298,9 +298,9 @@ Quaternion Quaternion::SlerpUnclamped(const Quaternion& a,
return a;
}
const Vector3 axyz = a.xyz();
const Vector3 bxyz = b.xyz();
float cosHalfAngle = a.w * b.w + Vector3::Dot(axyz, bxyz);
const Vector3Of<float> axyz = a.xyz();
const Vector3Of<float> bxyz = b.xyz();
float cosHalfAngle = a.w * b.w + Vector3Of<float>::Dot(axyz, bxyz);
Quaternion b2 = b;
if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f) {
@ -328,9 +328,9 @@ Quaternion Quaternion::SlerpUnclamped(const Quaternion& a,
blendA = 1.0f - t;
blendB = t;
}
Vector3 v = axyz * blendA + b2.xyz() * blendB;
Vector3Of<float> v = axyz * blendA + b2.xyz() * blendB;
Quaternion result =
Quaternion(v.Right(), v.Up(), v.Forward(), blendA * a.w + blendB * b2.w);
Quaternion(v.horizontal, v.vertical, v.depth, blendA * a.w + blendB * b2.w);
if (result.GetLengthSquared() > 0.0f)
return Quaternion::Normalize(result);
else
@ -348,16 +348,16 @@ Quaternion Quaternion::Slerp(const Quaternion& a,
}
Quaternion Quaternion::Euler(float x, float y, float z) {
return Quaternion::Euler(Vector3(x, y, z));
return Quaternion::Euler(Vector3Of<float>(x, y, z));
}
Quaternion Quaternion::Euler(Vector3 euler) {
Quaternion Quaternion::Euler(Vector3Of<float> euler) {
return Quaternion::FromEulerRad(euler * Deg2Rad);
}
Quaternion Quaternion::FromEulerRad(Vector3 euler) {
float yaw = euler.Right();
float pitch = euler.Up();
float roll = euler.Forward();
Quaternion Quaternion::FromEulerRad(Vector3Of<float> euler) {
float yaw = euler.horizontal;
float pitch = euler.vertical;
float roll = euler.depth;
float rollOver2 = roll * 0.5f;
float sinRollOver2 = (float)sin((float)rollOver2);
float cosRollOver2 = (float)cos((float)rollOver2);
@ -380,15 +380,15 @@ Quaternion Quaternion::FromEulerRad(Vector3 euler) {
}
Quaternion Quaternion::EulerXYZ(float x, float y, float z) {
return Quaternion::EulerXYZ(Vector3(x, y, z));
return Quaternion::EulerXYZ(Vector3Of<float>(x, y, z));
}
Quaternion Quaternion::EulerXYZ(Vector3 euler) {
Quaternion Quaternion::EulerXYZ(Vector3Of<float> euler) {
return Quaternion::FromEulerRadXYZ(euler * Deg2Rad);
}
Quaternion Quaternion::FromEulerRadXYZ(Vector3 euler) {
float yaw = euler.Right(); // x;
float pitch = euler.Up(); // y;
float roll = euler.Forward(); // z;
Quaternion Quaternion::FromEulerRadXYZ(Vector3Of<float> euler) {
float yaw = euler.horizontal; // x;
float pitch = euler.vertical; // y;
float roll = euler.depth; // z;
float rollOver2 = roll * 0.5f;
float sinRollOver2 = (float)sin((float)rollOver2);
float cosRollOver2 = (float)cos((float)rollOver2);
@ -410,29 +410,29 @@ Quaternion Quaternion::FromEulerRadXYZ(Vector3 euler) {
return result;
}
float Quaternion::GetAngleAround(Vector3 axis, Quaternion rotation) {
float Quaternion::GetAngleAround(Vector3Of<float> axis, Quaternion rotation) {
Quaternion secondaryRotation = GetRotationAround(axis, rotation);
float rotationAngle;
Vector3 rotationAxis;
Vector3Of<float> rotationAxis;
secondaryRotation.ToAngleAxis(&rotationAngle, &rotationAxis);
// Do the axis point in opposite directions?
if (Vector3::Dot(axis, rotationAxis) < 0)
if (Vector3Of<float>::Dot(axis, rotationAxis) < 0)
rotationAngle = -rotationAngle;
return rotationAngle;
}
Quaternion Quaternion::GetRotationAround(Vector3 axis, Quaternion rotation) {
Vector3 ra = Vector3(rotation.x, rotation.y, rotation.z); // rotation axis
Vector3 p = Vector3::Project(
Quaternion Quaternion::GetRotationAround(Vector3Of<float> axis, Quaternion rotation) {
Vector3Of<float> ra = Vector3Of<float>(rotation.x, rotation.y, rotation.z); // rotation axis
Vector3Of<float> p = Vector3Of<float>::Project(
ra, axis); // return projection ra on to axis (parallel component)
Quaternion twist = Quaternion(p.Right(), p.Up(), p.Forward(), rotation.w);
Quaternion twist = Quaternion(p.horizontal, p.vertical, p.depth, rotation.w);
twist = Quaternion::Normalize(twist);
return twist;
}
void Quaternion::GetSwingTwist(Vector3 axis,
void Quaternion::GetSwingTwist(Vector3Of<float> axis,
Quaternion rotation,
Quaternion* swing,
Quaternion* twist) {

View File

@ -89,7 +89,7 @@ struct Quaternion : Quat {
/// <param name="q">The quaternion to convert</param>
/// <returns>A vector containing euler angles</returns>
/// The euler angles performed in the order: Z, X, Y
static Vector3 ToAngles(const Quaternion& q);
static Vector3Of<float> ToAngles(const Quaternion& q);
Matrix2 ToRotationMatrix();
@ -98,7 +98,7 @@ struct Quaternion : Quat {
/// </summary>
/// <param name="vector">The vector to rotate</param>
/// <returns>The rotated vector</returns>
Vector3 operator*(const Vector3& vector) const;
Vector3Of<float> operator*(const Vector3Of<float>& vector) const;
/// <summary>
/// Multiply this quaternion with another quaternion
/// </summary>
@ -132,8 +132,8 @@ struct Quaternion : Quat {
/// <param name="forward">The look direction</param>
/// <param name="upwards">The up direction</param>
/// <returns>The look rotation</returns>
static Quaternion LookRotation(const Vector3& forward,
const Vector3& upwards);
static Quaternion LookRotation(const Vector3Of<float>& forward,
const Vector3Of<float>& upwards);
/// <summary>
/// Creates a quaternion with the given forward direction with up =
/// Vector3::up
@ -143,7 +143,7 @@ struct Quaternion : Quat {
/// For the rotation, Vector::up is used for the up direction.
/// Note: if the forward direction == Vector3::up, the result is
/// Quaternion::identity
static Quaternion LookRotation(const Vector3& forward);
static Quaternion LookRotation(const Vector3Of<float>& forward);
/// <summary>
/// Calculat the rotation from on vector to another
@ -151,7 +151,7 @@ struct Quaternion : Quat {
/// <param name="fromDirection">The from direction</param>
/// <param name="toDirection">The to direction</param>
/// <returns>The rotation from the first to the second vector</returns>
static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection);
static Quaternion FromToRotation(Vector3Of<float> fromDirection, Vector3Of<float> toDirection);
/// <summary>
/// Rotate form one orientation to anther with a maximum amount of degrees
@ -170,13 +170,13 @@ struct Quaternion : Quat {
/// <param name="angle">The angle</param>
/// <param name="axis">The axis</param>
/// <returns>The resulting quaternion</returns>
static Quaternion AngleAxis(float angle, const Vector3& axis);
static Quaternion AngleAxis(float angle, const Vector3Of<float>& axis);
/// <summary>
/// Convert this quaternion to angle/axis representation
/// </summary>
/// <param name="angle">A pointer to the angle for the result</param>
/// <param name="axis">A pointer to the axis for the result</param>
void ToAngleAxis(float* angle, Vector3* axis);
void ToAngleAxis(float* angle, Vector3Of<float>* axis);
/// <summary>
/// Get the angle between two orientations
@ -225,7 +225,7 @@ struct Quaternion : Quat {
/// <param name="eulerAngles">Vector with the euler angles</param>
/// <returns>The resulting quaternion</returns>
/// Rotation are appied in the order Z, X, Y.
static Quaternion Euler(Vector3 eulerAngles);
static Quaternion Euler(Vector3Of<float> eulerAngles);
/// <summary>
/// Create a rotation from euler angles
@ -242,7 +242,7 @@ struct Quaternion : Quat {
/// <param name="eulerAngles">Vector with the euler angles</param>
/// <returns>The resulting quaternion</returns>
/// Rotation are appied in the order X, Y, Z.
static Quaternion EulerXYZ(Vector3 eulerAngles);
static Quaternion EulerXYZ(Vector3Of<float> eulerAngles);
/// <summary>
/// Returns the angle of around the give axis for a rotation
@ -250,14 +250,14 @@ struct Quaternion : Quat {
/// <param name="axis">The axis around which the angle should be
/// computed</param> <param name="rotation">The source rotation</param>
/// <returns>The signed angle around the axis</returns>
static float GetAngleAround(Vector3 axis, Quaternion rotation);
static float GetAngleAround(Vector3Of<float> axis, Quaternion rotation);
/// <summary>
/// Returns the rotation limited around the given axis
/// </summary>
/// <param name="axis">The axis which which the rotation should be
/// limited</param> <param name="rotation">The source rotation</param>
/// <returns>The rotation around the given axis</returns>
static Quaternion GetRotationAround(Vector3 axis, Quaternion rotation);
static Quaternion GetRotationAround(Vector3Of<float> axis, Quaternion rotation);
/// <summary>
/// Swing-twist decomposition of a rotation
/// </summary>
@ -266,7 +266,7 @@ struct Quaternion : Quat {
/// <param name="swing">A pointer to the quaternion for the swing
/// result</param> <param name="twist">A pointer to the quaternion for the
/// twist result</param>
static void GetSwingTwist(Vector3 axis,
static void GetSwingTwist(Vector3Of<float> axis,
Quaternion rotation,
Quaternion* swing,
Quaternion* twist);
@ -284,11 +284,11 @@ struct Quaternion : Quat {
float GetLengthSquared() const;
static float GetLengthSquared(const Quaternion& q);
void ToAxisAngleRad(const Quaternion& q, Vector3* const axis, float* angle);
static Quaternion FromEulerRad(Vector3 euler);
static Quaternion FromEulerRadXYZ(Vector3 euler);
void ToAxisAngleRad(const Quaternion& q, Vector3Of<float>* const axis, float* angle);
static Quaternion FromEulerRad(Vector3Of<float> euler);
static Quaternion FromEulerRadXYZ(Vector3Of<float> euler);
Vector3 xyz() const;
Vector3Of<float> xyz() const;
};
} // namespace LinearAlgebra

View File

@ -64,15 +64,15 @@ SphericalOf<T> SphericalOf<T>::FromPolar(PolarOf<T> polar) {
}
template <typename T>
SphericalOf<T> SphericalOf<T>::FromVector3(Vector3 v) {
float distance = v.magnitude();
SphericalOf<T> SphericalOf<T>::FromVector3(Vector3Of<float> v) {
float distance = v.Magnitude();
if (distance == 0.0f) {
return SphericalOf(distance, AngleOf<T>(), AngleOf<T>());
} else {
AngleOf<T> verticalAngle =
AngleOf<T>::Radians((pi / 2 - acosf(v.Up() / distance)));
AngleOf<T>::Radians((pi / 2 - acosf(v.vertical / distance)));
AngleOf<T> horizontalAngle =
AngleOf<T>::Radians(atan2f(v.Right(), v.Forward()));
AngleOf<T>::Radians(atan2f(v.horizontal, v.depth));
return SphericalOf(distance, horizontalAngle, verticalAngle);
}
}
@ -89,7 +89,7 @@ SphericalOf<T> SphericalOf<T>::FromVector3(Vector3 v) {
* @return Vector3 The 3D vector representation of the spherical coordinates.
*/
template <typename T>
Vector3 SphericalOf<T>::ToVector3() const {
Vector3Of<float> SphericalOf<T>::ToVector3() const {
float verticalRad = (pi / 2) - this->direction.vertical.InRadians();
float horizontalRad = this->direction.horizontal.InRadians();
@ -102,7 +102,7 @@ Vector3 SphericalOf<T>::ToVector3() const {
float y = this->distance * cosVertical;
float z = this->distance * sinVertical * cosHorizontal;
Vector3 v = Vector3(x, y, z);
Vector3Of<float> v = Vector3Of<float>(x, y, z);
return v;
}
@ -145,9 +145,9 @@ SphericalOf<T> SphericalOf<T>::operator-() const {
template <typename T>
SphericalOf<T> SphericalOf<T>::operator-(const SphericalOf<T>& s2) const {
// let's do it the easy way...
Vector3 v1 = this->ToVector3();
Vector3 v2 = s2.ToVector3();
Vector3 v = v1 - v2;
Vector3Of<float> v1 = this->ToVector3();
Vector3Of<float> v2 = s2.ToVector3();
Vector3Of<float> v = v1 - v2;
SphericalOf<T> r = SphericalOf<T>::FromVector3(v);
return r;
}
@ -160,9 +160,9 @@ SphericalOf<T> SphericalOf<T>::operator-=(const SphericalOf<T>& v) {
template <typename T>
SphericalOf<T> SphericalOf<T>::operator+(const SphericalOf<T>& s2) const {
// let's do it the easy way...
Vector3 v1 = this->ToVector3();
Vector3 v2 = s2.ToVector3();
Vector3 v = v1 + v2;
Vector3Of<float> v1 = this->ToVector3();
Vector3Of<float> v2 = s2.ToVector3();
Vector3Of<float> v = v1 + v2;
SphericalOf<T> r = SphericalOf<T>::FromVector3(v);
return r;
/*
@ -240,9 +240,9 @@ float SphericalOf<T>::DistanceBetween(const SphericalOf<T>& v1,
const SphericalOf<T>& v2) {
// SphericalOf<T> difference = v1 - v2;
// return difference.distance;
Vector3 vec1 = v1.ToVector3();
Vector3 vec2 = v2.ToVector3();
float distance = Vector3::Distance(vec1, vec2);
Vector3Of<float> vec1 = v1.ToVector3();
Vector3Of<float> vec2 = v2.ToVector3();
float distance = Vector3Of<float>::Distance(vec1, vec2);
return distance;
}
@ -253,8 +253,8 @@ AngleOf<T> SphericalOf<T>::AngleBetween(const SphericalOf& v1,
// if (denominator < epsilon)
// return 0.0f;
Vector3 v1_3 = v1.ToVector3();
Vector3 v2_3 = v2.ToVector3();
Vector3Of<float> v1_3 = v1.ToVector3();
Vector3Of<float> v2_3 = v2.ToVector3();
// float dot = Vector3::Dot(v1_3, v2_3);
// float fraction = dot / denominator;
// if (isnan(fraction))
@ -262,7 +262,7 @@ AngleOf<T> SphericalOf<T>::AngleBetween(const SphericalOf& v1,
// float cdot = Float::Clamp(fraction, -1.0, 1.0);
// float r = ((float)acos(cdot)) * Rad2Deg;
AngleSingle r = Vector3::Angle(v1_3, v2_3);
AngleSingle r = Vector3Of<float>::UnsignedAngle(v1_3, v2_3);
return AngleOf<T>::Degrees(r.InDegrees());
}
@ -270,10 +270,10 @@ template <typename T>
AngleOf<T> SphericalOf<T>::SignedAngleBetween(const SphericalOf<T>& v1,
const SphericalOf<T>& v2,
const SphericalOf<T>& axis) {
Vector3 v1_vector = v1.ToVector3();
Vector3 v2_vector = v2.ToVector3();
Vector3 axis_vector = axis.ToVector3();
AngleSingle r = Vector3::SignedAngle(v1_vector, v2_vector, axis_vector);
Vector3Of<float> v1_vector = v1.ToVector3();
Vector3Of<float> v2_vector = v2.ToVector3();
Vector3Of<float> axis_vector = axis.ToVector3();
AngleSingle r = Vector3Of<float>::SignedAngle(v1_vector, v2_vector, axis_vector);
return AngleOf<T>::Degrees(r.InDegrees());
}

View File

@ -59,10 +59,10 @@ class SphericalOf {
/// @brief Create a Spherical coordinate from a Vector3 coordinate
/// @param v The vector coordinate
/// @return The spherical coordinate
static SphericalOf<T> FromVector3(Vector3 v);
static SphericalOf<T> FromVector3(Vector3Of<float> v);
/// @brief Convert the spherical coordinate to a Vector3 coordinate
/// @return The vector coordinate
Vector3 ToVector3() const;
Vector3Of<float> ToVector3() const;
/// @brief A spherical vector with zero degree angles and distance
const static SphericalOf<T> zero;

View File

@ -69,9 +69,9 @@ Quaternion SwingTwistOf<T>::ToQuaternion() const {
template <typename T>
SwingTwistOf<T> SwingTwistOf<T>::FromQuaternion(Quaternion q) {
Vector3 angles = Quaternion::ToAngles(q);
Vector3Of<float> angles = Quaternion::ToAngles(q);
SwingTwistOf<T> r =
SwingTwistOf<T>::Degrees(angles.Up(), angles.Right(), angles.Forward());
SwingTwistOf<T>::Degrees(angles.vertical, angles.horizontal, angles.depth);
r.Normalize();
return r;
}
@ -80,7 +80,7 @@ template <typename T>
SphericalOf<T> SwingTwistOf<T>::ToAngleAxis() const {
Quaternion q = this->ToQuaternion();
float angle;
Vector3 axis;
Vector3Of<float> axis;
q.ToAngleAxis(&angle, &axis);
DirectionOf<T> direction = DirectionOf<T>::FromVector3(axis);
@ -90,7 +90,7 @@ SphericalOf<T> SwingTwistOf<T>::ToAngleAxis() const {
template <typename T>
SwingTwistOf<T> SwingTwistOf<T>::FromAngleAxis(SphericalOf<T> aa) {
Vector3 vectorAxis = aa.direction.ToVector3();
Vector3Of<float> vectorAxis = aa.direction.ToVector3();
Quaternion q = Quaternion::AngleAxis(aa.distance, vectorAxis);
return SwingTwistOf<T>();
}
@ -139,7 +139,7 @@ SwingTwistOf<T> SwingTwistOf<T>::Inverse(SwingTwistOf<T> rotation) {
template <typename T>
SwingTwistOf<T> SwingTwistOf<T>::AngleAxis(float angle,
const DirectionOf<T>& axis) {
Vector3 axis_vector = axis.ToVector3();
Vector3Of<float> axis_vector = axis.ToVector3();
Quaternion q = Quaternion::AngleAxis(angle, axis_vector);
SwingTwistOf<T> r = SwingTwistOf<T>::FromQuaternion(q);
return r;

View File

@ -7,181 +7,7 @@
#include "FloatSingle.h"
#include "Vector3.h"
// #if defined(AVR)
// #include <Arduino.h>
// #else
#include <math.h>
// #endif
/*
Vector2::Vector2() {
x = 0;
y = 0;
}
Vector2::Vector2(float _x, float _y) {
x = _x;
y = _y;
}
// Vector2::Vector2(Vec2 v) {
// x = v.x;
// y = v.y;
// }
Vector2::Vector2(Vector3 v) {
x = v.Right(); // x;
y = v.Forward(); // z;
}
Vector2::Vector2(PolarSingle p) {
float horizontalRad = p.angle.InDegrees() * Deg2Rad;
float cosHorizontal = cosf(horizontalRad);
float sinHorizontal = sinf(horizontalRad);
x = p.distance * sinHorizontal;
y = p.distance * cosHorizontal;
}
Vector2::~Vector2() {}
const Vector2 Vector2::zero = Vector2(0, 0);
const Vector2 Vector2::one = Vector2(1, 1);
const Vector2 Vector2::right = Vector2(1, 0);
const Vector2 Vector2::left = Vector2(-1, 0);
const Vector2 Vector2::up = Vector2(0, 1);
const Vector2 Vector2::down = Vector2(0, -1);
const Vector2 Vector2::forward = Vector2(0, 1);
const Vector2 Vector2::back = Vector2(0, -1);
bool Vector2::operator==(const Vector2& v) {
return (this->x == v.x && this->y == v.y);
}
float Vector2::Magnitude(const Vector2& v) {
return sqrtf(v.x * v.x + v.y * v.y);
}
float Vector2::magnitude() const {
return (float)sqrtf(x * x + y * y);
}
float Vector2::SqrMagnitude(const Vector2& v) {
return v.x * v.x + v.y * v.y;
}
float Vector2::sqrMagnitude() const {
return (x * x + y * y);
}
Vector2 Vector2::Normalize(const Vector2& v) {
float num = Vector2::Magnitude(v);
Vector2 result = Vector2::zero;
if (num > Float::epsilon) {
result = v / num;
}
return result;
}
Vector2 Vector2::normalized() const {
float num = this->magnitude();
Vector2 result = Vector2::zero;
if (num > Float::epsilon) {
result = ((Vector2) * this) / num;
}
return result;
}
Vector2 Vector2::operator-() {
return Vector2(-this->x, -this->y);
}
Vector2 Vector2::operator-(const Vector2& v) const {
return Vector2(this->x - v.x, this->y - v.y);
}
Vector2 Vector2::operator-=(const Vector2& v) {
this->x -= v.x;
this->y -= v.y;
return *this;
}
Vector2 Vector2::operator+(const Vector2& v) const {
return Vector2(this->x + v.x, this->y + v.y);
}
Vector2 Vector2::operator+=(const Vector2& v) {
this->x += v.x;
this->y += v.y;
return *this;
}
Vector2 Vector2::Scale(const Vector2& v1, const Vector2& v2) {
return Vector2(v1.x * v2.x, v1.y * v2.y);
}
// Vector2 Passer::LinearAlgebra::operator*(const Vector2 &v, float f) {
// return Vector2(v.x * f, v.y * f);
// }
// Vector2 Passer::LinearAlgebra::operator*(float f, const Vector2 &v) {
// return Vector2(v.x * f, v.y * f);
// }
Vector2 Vector2::operator*=(float f) {
this->x *= f;
this->y *= f;
return *this;
}
// Vector2 Passer::LinearAlgebra::operator/(const Vector2 &v, float f) {
// return Vector2(v.x / f, v.y / f);
// }
// Vector2 Passer::LinearAlgebra::operator/(float f, const Vector2 &v) {
// return Vector2(v.x / f, v.y / f);
// }
Vector2 Vector2::operator/=(float f) {
this->x /= f;
this->y /= f;
return *this;
}
float Vector2::Dot(const Vector2& v1, const Vector2& v2) {
return v1.x * v2.x + v1.y * v2.y;
}
float Vector2::Distance(const Vector2& v1, const Vector2& v2) {
return Magnitude(v1 - v2);
}
float Vector2::Angle(const Vector2& v1, const Vector2& v2) {
return (float)fabs(SignedAngle(v1, v2));
}
float Vector2::SignedAngle(const Vector2& v1, const Vector2& v2) {
float sqrMagFrom = v1.sqrMagnitude();
float sqrMagTo = v2.sqrMagnitude();
if (sqrMagFrom == 0 || sqrMagTo == 0)
return 0;
if (!isfinite(sqrMagFrom) || !isfinite(sqrMagTo))
#if defined(AVR)
return NAN;
#else
return nanf("");
#endif
float angleFrom = atan2f(v1.y, v1.x);
float angleTo = atan2f(v2.y, v2.x);
return -(angleTo - angleFrom) * Rad2Deg;
}
Vector2 Vector2::Rotate(const Vector2& v, AngleSingle a) {
float angleRad = a.InDegrees() * Deg2Rad;
#if defined(AVR)
float sinValue = sin(angleRad);
float cosValue = cos(angleRad); // * Angle::Deg2Rad);
#else
float sinValue = (float)sinf(angleRad);
float cosValue = (float)cosf(angleRad);
#endif
float tx = v.x;
float ty = v.y;
Vector2 r = Vector2((cosValue * tx) - (sinValue * ty),
(sinValue * tx) + (cosValue * ty));
return r;
}
Vector2 Vector2::Lerp(const Vector2& v1, const Vector2& v2, float f) {
Vector2 v = v1 + (v2 - v1) * f;
return v;
}
*/
#pragma region Vector2Of
@ -193,10 +19,9 @@ Vector2Of<T>::Vector2Of(T horizontal, T vertical)
: horizontal(horizontal), vertical(vertical) {}
template <typename T>
Vector2Of<float> Vector2Of<T>::FromPolar(PolarOf<T> p) {
float horizontalRad = p.angle.InDegrees() * Deg2Rad;
float cosHorizontal = cosf(horizontalRad);
float sinHorizontal = sinf(horizontalRad);
Vector2Of<float> Vector2Of<T>::FromPolar(PolarOf<float> p) {
float cosHorizontal = AngleOf<float>::Cos(p.angle);
float sinHorizontal = AngleOf<float>::Sin(p.angle);
Vector2Of<float> v;
v.horizontal = p.distance * sinHorizontal;
@ -226,7 +51,8 @@ template <typename T>
float Vector2Of<T>::Magnitude() const {
T sqr = this->horizontal * this->horizontal + this->vertical * this->vertical;
float sqrFloat = static_cast<float>(sqr);
return sqrtf(sqrFloat);
float r = sqrtf(sqrFloat);
return r;
}
template <typename T>
@ -241,6 +67,13 @@ float Vector2Of<T>::SqrMagnitude() const {
return static_cast<float>(sqr);
}
template <typename T>
float Vector2Of<T>::Distance(const Vector2Of& v1, const Vector2Of& v2) {
Vector2Of<float> delta = v1 - v2;
float r = MagnitudeOf(delta);
return r;
}
template <typename T>
Vector2Of<T> Vector2Of<T>::operator-() {
return Vector2Of<T>(-this->horizontal, -this->vertical);
@ -289,11 +122,6 @@ T Vector2Of<T>::Dot(const Vector2Of& v1, const Vector2Of& v2) {
return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical;
}
template <typename T>
float Vector2Of<T>::Distance(const Vector2Of& v1, const Vector2Of& v2) {
return MagnitudeOf(v1 - v2);
}
template <typename T>
Vector2Of<float> Vector2Of<T>::Normalize(const Vector2Of<T>& v) {
float num = Vector2Of<T>::MagnitudeOf(v);
@ -305,68 +133,50 @@ Vector2Of<float> Vector2Of<T>::Normalize(const Vector2Of<T>& v) {
}
template <typename T>
AngleOf<T> Vector2Of<T>::UnsignedAngle(const Vector2Of& v1,
const Vector2Of& v2) {
return AngleOf<T>::Abs(SignedAngle(v1, v2));
AngleOf<float> Vector2Of<T>::UnsignedAngle(const Vector2Of& v1,
const Vector2Of& v2) {
return AngleOf<float>::Abs(SignedAngle(v1, v2));
}
template <typename T>
AngleOf<T> Vector2Of<T>::SignedAngle(const Vector2Of& v1, const Vector2Of& v2) {
AngleOf<float> Vector2Of<T>::SignedAngle(const Vector2Of& v1,
const Vector2Of& v2) {
float sqrMagFrom = v1.SqrMagnitude();
float sqrMagTo = v2.SqrMagnitude();
if (sqrMagFrom == 0 || sqrMagTo == 0)
return AngleOf<T>::zero;
return AngleOf<float>::zero;
if (!isfinite(sqrMagFrom) || !isfinite(sqrMagTo))
return AngleOf<T>::zero; // Angle does not support NaN...
return AngleOf<float>::zero; // Angle does not support NaN...
AngleOf<T> angleFrom = AngleOf<T>::Atan2(static_cast<float>(v1.vertical),
static_cast<float>(v1.horizontal));
AngleOf<T> angleTo = AngleOf<T>::Atan2(static_cast<float>(v2.vertical),
static_cast<float>(v2.horizontal));
AngleOf<float> angleFrom = AngleOf<float>::Atan2(
static_cast<float>(v1.vertical), static_cast<float>(v1.horizontal));
AngleOf<float> angleTo = AngleOf<float>::Atan2(
static_cast<float>(v2.vertical), static_cast<float>(v2.horizontal));
return -(angleTo - angleFrom);
}
template <typename T>
Vector2Of<float> Vector2Of<T>::Rotate(const Vector2Of& v, AngleOf<T> a) {
float sinValue = AngleOf<T>::Sin(a);
float cosValue = AngleOf<T>::Cos(a);
Vector2Of<float> Vector2Of<T>::Rotate(const Vector2Of& v, AngleOf<float> a) {
float sinValue = AngleOf<float>::Sin(a);
float cosValue = AngleOf<float>::Cos(a);
float tx = static_cast<float>(v.horizontal);
float ty = static_cast<float>(v.vertical);
Vector2Of<float> r = Vector2Of<float>((cosValue * tx) - (sinValue * ty),
(sinValue * tx) + (cosValue * ty));
(sinValue * tx) + (cosValue * ty));
return r;
}
template <typename T>
Vector2Of<float> Vector2Of<T>::Lerp(const Vector2Of& v1,
const Vector2Of& v2,
float f) {
Vector2Of<float> v = v1 + static_cast<Vector2Of<float>>(v2 - v1) * f;
return v;
const Vector2Of& v2,
float f) {
Vector2Of<float> v1f = (Vector2Of<float>)v1;
Vector2Of<float> delta = v2 - v1;
Vector2Of<float> r = v1f + delta * f;
return r;
}
// float Vector2::Angle(const Vector2& v1, const Vector2& v2) {
// return (float)fabs(SignedAngle(v1, v2));
// }
// float Vector2::SignedAngle(const Vector2& v1, const Vector2& v2) {
// float sqrMagFrom = v1.sqrMagnitude();
// float sqrMagTo = v2.sqrMagnitude();
// if (sqrMagFrom == 0 || sqrMagTo == 0)
// return 0;
// if (!isfinite(sqrMagFrom) || !isfinite(sqrMagTo))
// #if defined(AVR)
// return NAN;
// #else
// return nanf("");
// #endif
// float angleFrom = atan2f(v1.y, v1.x);
// float angleTo = atan2f(v2.y, v2.x);
// return -(angleTo - angleFrom) * Rad2Deg;
// }
template <typename T>
Vector2Of<float> Vector2Of<T>::Normalized() const {
float num = Vector2Of<T>::MagnitudeOf(*this);
@ -379,6 +189,7 @@ Vector2Of<float> Vector2Of<T>::Normalized() const {
// Explicit instantiation for int
template class Vector2Of<signed short>;
template class Vector2Of<int>;
template class Vector2Of<float>;
#pragma endregion Vector2Of

View File

@ -216,8 +216,6 @@ class Vector2Of {
/// up = positive
Vector2Of(T horizontal, T vertical);
static Vector2Of<float> FromPolar(PolarOf<T> v);
/// @brief Converting constructor: allow Vector2Of<U> -> Vector2Of<T>
/// @tparam U
/// @param other
@ -226,10 +224,13 @@ class Vector2Of {
: 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);
this->horizontal = static_cast<T>(other.horizontal);
this->vertical = static_cast<T>(other.vertical);
return *this;
}
/// @brief A vector with zero for all axis
@ -266,6 +267,12 @@ class Vector2Of {
/// 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-();
@ -315,12 +322,6 @@ class Vector2Of {
/// @return The dot product of the two vectors
static T Dot(const Vector2Of& v1, const Vector2Of& 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 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
@ -333,18 +334,18 @@ class Vector2Of {
/// @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<T> UnsignedAngle(const Vector2Of& v1, const Vector2Of& v2);
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<T> SignedAngle(const Vector2Of& v1, const Vector2Of& v2);
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<T> a);
static Vector2Of<float> Rotate(const Vector2Of& v, AngleOf<float> a);
/// @brief Lerp (linear interpolation) between two vectors
/// @param v1 The starting vector
@ -354,7 +355,9 @@ class Vector2Of {
/// @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);
static Vector2Of<float> Lerp(const Vector2Of& v1,
const Vector2Of& v2,
float f);
};
#pragma region friend functions

View File

@ -4,8 +4,9 @@
#include "Vector3.h"
#include "Angle.h"
#include "FloatSingle.h"
#include "Spherical.h"
//#include "TypeTraits.h"
// #include "TypeTraits.h"
#include <math.h>
@ -13,6 +14,7 @@ const float Deg2Rad = 0.0174532924F;
const float Rad2Deg = 57.29578F;
const float epsilon = 1E-05f;
/*
Vector3::Vector3() {
this->x = 0;
this->y = 0;
@ -161,7 +163,8 @@ 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,14 +197,16 @@ 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);
@ -219,6 +224,7 @@ Vector3 Vector3::Lerp(const Vector3& v1, const Vector3& v2, float f) {
Vector3 v = v1 + (v2 - v1) * f;
return v;
}
*/
#pragma region Vector3Of
@ -232,44 +238,47 @@ 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 = AngleOf<T>::Cos(v.direction.vertical);
float sinVertical = AngleOf<T>::Sin(v.direction.vertical);
float cosHorizontal = AngleOf<T>::Cos(v.direction.horizontal);
float sinHorizontal = AngleOf<T>::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);
}
Vector3Of<T>::Vector3Of(Vector2Of<T> v)
: horizontal(v.horizontal), vertical(v.vertical) {}
template <typename T>
Vector3Of<T>::~Vector3Of() {}
template <>
Vector3Of<float> Vector3Of<float>::FromSpherical(SphericalOf<float> v) {
AngleOf<float> vertical = AngleOf<float>::Degrees(90) - v.direction.vertical;
AngleOf<float> horizontal = v.direction.horizontal;
float cosVertical = AngleOf<float>::Cos(vertical);
float sinVertical = AngleOf<float>::Sin(vertical);
float cosHorizontal = AngleOf<float>::Cos(horizontal);
float sinHorizontal = AngleOf<float>::Sin(horizontal);
Vector3Of<float> r = Vector3Of<float>();
r.horizontal = v.distance * sinVertical * sinHorizontal;
r.vertical = v.distance * cosVertical;
r.depth = v.distance * sinVertical * cosHorizontal;
return r;
}
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);
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);
const Vector3Of<double> Vector3Of<double>::unit =
Vector3Of<double>(1.0f, 1.0f, 1.0f);
template <typename T>
const Vector3Of<T> Vector3Of<T>::forward = Vector3Of(T{}, T{}, 1);
// template <typename T>
// const Vector3Of<T> Vector3Of<T>::unit =
// Vector3Of(TypeTraits<T>::unit(), TypeTraits<T>::unit(), TypeTraits<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);
@ -278,18 +287,26 @@ const Vector3Of<double> Vector3Of<double>::unit = Vector3Of<double>(1.0f, 1.0f,
// 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);
bool Vector3Of<T>::operator==(const Vector3Of& v) const {
return (this->horizontal == v.horizontal && this->vertical == v.vertical &&
this->depth == v.depth);
}
template <typename T>
float 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);
float Vector3Of<T>::Magnitude() const {
return 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;
return v.horizontal * v.horizontal + v.vertical * v.vertical +
v.depth * v.depth;
}
template <typename T>
float Vector3Of<T>::SqrMagnitude() const {
@ -311,14 +328,18 @@ Vector3Of<T> Vector3Of<T>::Normalized() const {
float num = this->Magnitude();
Vector3Of<T> result = Vector3Of<T>::zero;
if (num > epsilon) {
result = ((Vector3Of<T>) * this) / num;
result = ((Vector3Of<T>)*this) / num;
}
return result;
}
template <typename T>
Vector3Of<T> Vector3Of<T>::operator-() const {
return Vector3Of<T>(-this->horizontal, -this->vertical, -this->depth);
}
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);
return Vector3Of<T>(this->horizontal - v.horizontal,
this->vertical - v.vertical, this->depth - v.depth);
}
template <typename T>
@ -331,8 +352,8 @@ Vector3Of<T> Vector3Of<T>::operator-=(const Vector3Of& v) {
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);
return Vector3Of<T>(this->horizontal + v.horizontal,
this->vertical + v.vertical, this->depth + v.depth);
}
template <typename T>
@ -343,6 +364,12 @@ Vector3Of<T> Vector3Of<T>::operator+=(const Vector3Of& v) {
return *this;
}
template <typename T>
Vector3Of<T> Vector3Of<T>::Scale(const Vector3Of& v1, const Vector3Of& v2) {
return Vector3Of<T>(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical,
v1.depth * v2.depth);
}
template <typename T>
Vector3Of<T> Vector3Of<T>::operator*=(float f) {
this->horizontal *= f;
@ -360,12 +387,64 @@ Vector3Of<T> Vector3Of<T>::operator/=(float f) {
}
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;
float Vector3Of<T>::Distance(const Vector3Of& v1, const Vector3Of& v2) {
return MagnitudeOf(v1 - v2);
}
template <typename T>
AngleOf<float> Vector3Of<T>::UnsignedAngle(const Vector3Of& v1, const Vector3Of& v2) {
T 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>
Vector3Of<T> Vector3Of<T>::Cross(const Vector3Of& v1, const Vector3Of& v2) {
return Vector3Of<T>(
v1.vertical * v2.depth - v1.depth * v2.vertical,
v1.depth * v2.horizontal - v1.horizontal * v2.depth,
v1.horizontal * v2.vertical - v1.vertical * v2.horizontal);
}
template <typename T>
Vector3Of<float> Vector3Of<T>::Project(const Vector3Of& v, const Vector3Of& n) {
T sqrMagnitude = Dot(n, n);
if (sqrMagnitude < epsilon)
return Vector3Of<float>::zero;
else {
T dot = Dot(v, n);
Vector3Of<float> r = n * dot;
r /= sqrMagnitude;
return r;
}
}
template <typename T>
Vector3Of<float> Vector3Of<T>::ProjectOnPlane(const Vector3Of& v,
const Vector3Of& n) {
Vector3Of<float> r = (Vector3Of<float>)v - Project(v, n);
return r;
}
template <typename T>
AngleOf<float> Vector3Of<T>::SignedAngle(const Vector3Of& v1,
const Vector3Of& v2,
const Vector3Of& axis) {
// angle in [0,180]
AngleOf<float> angle = Vector3Of<T>::UnsignedAngle(v1, v2);
Vector3Of<T> cross = Vector3Of<T>::Cross(v1, v2);
float b = Vector3Of<T>::Dot(axis, cross);
float signd = b < 0 ? -1.0F : (b > 0 ? 1.0F : 0.0F);
// angle in [-179,180]
AngleOf<float> signed_angle = angle * signd;
return AngleOf<float>(signed_angle);
}
template <typename T>
AngleOf<float> Vector3Of<T>::UnsignedAngle(const Vector3Of& v1,
const Vector3Of& v2) {
float denominator = sqrtf(v1.SqrMagnitude() * v2.SqrMagnitude());
if (denominator < epsilon)
return AngleOf<float>();
@ -373,14 +452,26 @@ AngleOf<float> Vector3Of<T>::UnsignedAngle(const Vector3Of& v1, const Vector3Of&
float dot = Vector3Of::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 cdot = Float::Clamp(fraction, -1.0, 1.0);
float r = ((float)acos(cdot));
return AngleOf<float>::Radians(r);
}
template <typename T>
Vector3Of<float> Vector3Of<T>::Lerp(const Vector3Of& v1,
const Vector3Of& v2,
float f) {
Vector3Of<float> v1f = v1;
Vector3Of<float> delta = v2 - v1;
Vector3Of<float> r = v1f + delta * f;
return r;
}
template class Vector3Of<float>;
template class Vector3Of<int>;
} // namespace LinearAlgebra

144
Vector3.h
View File

@ -7,7 +7,7 @@
#include "Vector2.h"
/*
extern "C" {
/// <summary>
/// 3-dimensional Vector representation (C-style)
@ -31,12 +31,14 @@ typedef struct Vec3 {
} 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.
@ -147,8 +149,8 @@ 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*(float f, const Vector3& v) {
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);
}
@ -157,8 +159,8 @@ 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/(float f, const Vector3& v) {
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);
}
@ -207,7 +209,8 @@ 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
@ -219,57 +222,86 @@ struct Vector3 : Vec3 {
/// 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
/// @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
/// @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
/// @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
/// @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
/// @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();
// Vector3Of(SphericalOf<T> v);
/// @brief Vector3 destructor
~Vector3Of();
/// @brief Converting constructor: allow Vector2Of<U> -> Vector2Of<T>
/// @tparam U
/// @param other
template <typename U>
constexpr Vector3Of(const Vector3Of<U>& other) noexcept
: horizontal(static_cast<T>(other.horizontal)),
vertical(static_cast<T>(other.vertical)),
depth(static_cast<T>(other.depth)) {}
static Vector3Of<float> FromSpherical(SphericalOf<float> v);
/// @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 A normalized forward-oriented vector
const static Vector3Of forward;
/// @brief A normalized back-oriented vector
const static Vector3Of back;
/// @brief A normalized right-oriented vector
const static Vector3Of right;
/// @brief A normalized left-oriented vector
const static Vector3Of left;
/// @brief A normalized up-oriented vector
const static Vector3Of up;
/// @brief A normalized down-oriented vector
const static Vector3Of 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 Vector3Of& v) const;
/// @brief The vector length
/// @param v The vector for which you need the length
/// @return The vector length
static T MagnitudeOf(const Vector3Of& v);
static float MagnitudeOf(const Vector3Of& v);
/// @brief The vector length
/// @return The vector length
T Magnitude() const;
float Magnitude() const;
/// @brief The squared vector length
/// @param v The vector for which you need the length
@ -293,6 +325,10 @@ class Vector3Of {
/// @return The vector normalized to a length of 1
Vector3Of<T> Normalized() const;
/// @brief Negate te vector such that it points in the opposite direction
/// @return The negated vector
Vector3Of<T> operator-() const;
/// @brief Subtract a vector from this vector
/// @param v The vector to subtract from this vector
/// @return The result of this subtraction
@ -305,6 +341,14 @@ class Vector3Of {
Vector3Of<T> operator+(const Vector3Of& v) const;
Vector3Of<T> operator+=(const Vector3Of& 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 Vector3Of<T> Scale(const Vector3Of& v1, const Vector3Of& v2);
/// @brief Scale the vector uniformly up
/// @param f The scaling factor
/// @return The scaled vector
@ -315,7 +359,7 @@ class Vector3Of {
}
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);
// return Vector3Of<T>(v.horizontal * f, v.vertical * f, v.depth * f);
}
Vector3Of<T> operator*=(float f);
@ -328,15 +372,39 @@ class Vector3Of {
}
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);
// return Vector3Of<T>(v.horizontal / f, v.vertical / f, v.depth / f);
}
Vector3Of<T> 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 Vector3Of& v1, const Vector3Of& 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 Vector3Of& v1, const Vector3Of& v2);
static T Dot(const Vector3Of& v1, const Vector3Of& 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 Vector3Of<T> Cross(const Vector3Of& v1, const Vector3Of& 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 Vector3Of<float> Project(const Vector3Of& v, const Vector3Of& 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 Vector3Of<float> ProjectOnPlane(const Vector3Of& v, const Vector3Of& n);
/// @brief The angle between two vectors
/// @param v1 The first vector
@ -346,6 +414,26 @@ class Vector3Of {
/// between the two vectors. Use Vector3::SignedAngle if a signed angle is
/// needed.
static AngleOf<float> UnsignedAngle(const Vector3Of& v1, const Vector3Of& 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 Vector3Of& v1,
const Vector3Of& v2,
const Vector3Of& 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 Vector3Of<float> Lerp(const Vector3Of& v1,
const Vector3Of& v2,
float f);
};
using Vector3Int = Vector3Of<int>;

View File

@ -10,7 +10,6 @@ using namespace LinearAlgebra;
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
//using AngleTypes = ::testing::Types<AngleOf<float>, AngleOf<signed short>, AngleOf<signed char>>;
using BaseTypes = ::testing::Types<float, signed short, signed char>;
template <typename T>

View File

@ -1,128 +1,151 @@
#if GTEST
#include <gtest/gtest.h>
#include <limits>
#include <math.h>
#include <chrono>
#include <limits>
#include "Polar.h"
#include "Spherical.h"
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
using Vector2 = Vector2Of<float>;
using BaseTypes = ::testing::Types<float, signed short>;
template <typename T>
class PolarTests : public ::testing::Test {};
TYPED_TEST_SUITE(PolarTests, BaseTypes);
TYPED_TEST(PolarTests, FromVector2) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
using Polar = PolarOf<float>;
TEST(Polar, FromVector2) {
Vector2 v = Vector2(0, 1);
PolarSingle p = PolarSingle::FromVector2(v);
Polar p = Polar::FromVector2(v);
EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance 0 1";
EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "s.angle 0 0 1";
v = Vector2(1, 0);
p = PolarSingle::FromVector2(v);
p = Polar::FromVector2(v);
EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance 1 0";
EXPECT_FLOAT_EQ(p.angle.InDegrees(), 90.0F) << "s.angle 1 0";
v = Vector2(-1, 1);
p = PolarSingle::FromVector2(v);
p = Polar::FromVector2(v);
EXPECT_FLOAT_EQ(p.distance, sqrt(2.0F)) << "p.distance -1 1";
EXPECT_NEAR(p.angle.InDegrees(), -45.0F, 1.0e-05) << "s.angle -1 1";
}
TEST(Polar, FromSpherical) {
SphericalSingle s;
PolarSingle p;
TYPED_TEST(PolarTests, FromSpherical) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
using Polar = PolarOf<T>;
using Angle = AngleOf<T>;
s = SphericalSingle(1, DirectionSingle::forward);
p = PolarSingle::FromSpherical(s);
Spherical s;
Polar p;
s = Spherical(1, DirectionOf<T>::forward);
p = Polar::FromSpherical(s);
EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(1 0 0)";
EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "p.angle FromSpherical(1 0 0)";
s = SphericalSingle(1, AngleSingle::Degrees(45), AngleSingle::Degrees(0));
p = PolarSingle::FromSpherical(s);
s = Spherical(1, AngleOf<T>::Degrees(45), AngleOf<T>::Degrees(0));
p = Polar::FromSpherical(s);
EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(1 45 0)";
EXPECT_FLOAT_EQ(p.angle.InDegrees(), 45.0F)
<< "p.angle FromSpherical(1 45 0)";
s = SphericalSingle(1, AngleSingle::Degrees(-45), AngleSingle::Degrees(0));
p = PolarSingle::FromSpherical(s);
s = Spherical(1, Angle::Degrees(-45), Angle::Degrees(0));
p = Polar::FromSpherical(s);
EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(1 -45 0)";
EXPECT_FLOAT_EQ(p.angle.InDegrees(), -45.0F)
<< "p.angle FromSpherical(1 -45 0)";
s = SphericalSingle(0, AngleSingle::Degrees(0), AngleSingle::Degrees(0));
p = PolarSingle::FromSpherical(s);
s = Spherical(0, Angle::Degrees(0), Angle::Degrees(0));
p = Polar::FromSpherical(s);
EXPECT_FLOAT_EQ(p.distance, 0.0F) << "p.distance FromSpherical(0 0 0)";
EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "p.angle FromSpherical(0 0 0)";
s = SphericalSingle(-1, AngleSingle::Degrees(0), AngleSingle::Degrees(0));
p = PolarSingle::FromSpherical(s);
s = Spherical(-1, Angle::Degrees(0), Angle::Degrees(0));
p = Polar::FromSpherical(s);
EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(-1 0 0)";
EXPECT_FLOAT_EQ(p.angle.InDegrees(), -180.0F)
<< "p.angle FromSpherical(-1 0 0)";
s = SphericalSingle(0, AngleSingle::Degrees(0), AngleSingle::Degrees(90));
p = PolarSingle::FromSpherical(s);
s = Spherical(0, Angle::Degrees(0), Angle::Degrees(90));
p = Polar::FromSpherical(s);
EXPECT_FLOAT_EQ(p.distance, 0.0F) << "p.distance FromSpherical(0 0 90)";
EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "p.angle FromSpherical(0 0 90)";
}
TEST(Polar, Negation) {
PolarSingle v = PolarSingle(2, AngleSingle::Degrees(45));
PolarSingle r = PolarSingle::zero;
TYPED_TEST(PolarTests, Negation) {
using T = TypeParam;
using Polar = PolarOf<T>;
using Angle = AngleOf<T>;
Polar v = Polar(2, Angle::Degrees(45));
Polar r = Polar::zero;
r = -v;
EXPECT_FLOAT_EQ(r.distance, 2);
EXPECT_FLOAT_EQ(r.angle.InDegrees(), -135);
EXPECT_TRUE(r == PolarSingle(2, AngleSingle::Degrees(-135)))
<< "Negate(2 45)";
EXPECT_TRUE(r == Polar(2, Angle::Degrees(-135))) << "Negate(2 45)";
v = PolarSingle::Deg(2, -45);
v = Polar::Deg(2, -45);
r = -v;
EXPECT_TRUE(r == PolarSingle(2, AngleSingle::Degrees(135)))
<< "Negate(2 -45)";
EXPECT_TRUE(r == Polar(2, Angle::Degrees(135))) << "Negate(2 -45)";
v = PolarSingle::Degrees(2, 0);
v = Polar::Degrees(2, 0);
r = -v;
EXPECT_TRUE(r == PolarSingle(2, AngleSingle::Degrees(180))) << "Negate(2 0)";
EXPECT_TRUE(r == Polar(2, Angle::Degrees(180))) << "Negate(2 0)";
v = PolarSingle(0, AngleSingle::Degrees(0));
v = Polar(0, Angle::Degrees(0));
r = -v;
EXPECT_FLOAT_EQ(r.distance, 0.0f);
EXPECT_FLOAT_EQ(r.angle.InDegrees(), 0.0f);
EXPECT_TRUE(r == PolarSingle(0, AngleSingle::Degrees(0))) << "Negate(0 0)";
EXPECT_TRUE(r == Polar(0, Angle::Degrees(0))) << "Negate(0 0)";
}
TEST(Polar, Subtraction) {
PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45));
PolarSingle v2 = PolarSingle(1, AngleSingle::Degrees(-90));
PolarSingle r = PolarSingle::zero;
TYPED_TEST(PolarTests, Subtraction) {
using T = TypeParam;
using Polar = PolarOf<T>;
using Angle = AngleOf<T>;
Polar v1 = Polar(4, Angle::Degrees(45));
Polar v2 = Polar(1, Angle::Degrees(-90));
Polar r = Polar::zero;
r = v1 - v2;
// don't know what to expect yet
v2 = PolarSingle::zero;
v2 = Polar::zero;
r = v1 - v2;
EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Subtraction(0 0)";
}
TEST(Polar, Addition) {
PolarSingle v1 = PolarSingle(1, AngleSingle::Degrees(45));
PolarSingle v2 = PolarSingle(1, AngleSingle::Degrees(-90));
PolarSingle r = PolarSingle::zero;
TYPED_TEST(PolarTests, Addition) {
using T = TypeParam;
using Polar = PolarOf<T>;
using Angle = AngleOf<T>;
Polar v1 = Polar(1, Angle::Degrees(45));
Polar v2 = Polar(1, Angle::Degrees(-90));
Polar r = Polar::zero;
r = v1 - v2;
// don't know what to expect yet
v2 = PolarSingle::zero;
v2 = Polar::zero;
r = v1 + v2;
EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0)";
@ -130,15 +153,19 @@ TEST(Polar, Addition) {
r += v2;
EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0)";
v2 = PolarSingle(1, AngleSingle::Degrees(-45));
v2 = Polar(1, Angle::Degrees(-45));
r = v1 + v2;
EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(0 0 0)";
EXPECT_FLOAT_EQ(r.angle.InDegrees(), 0) << "Addition(0 0 0)";
}
TEST(Polar, Scale_Multiply) {
PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45));
PolarSingle r = PolarSingle::zero;
TYPED_TEST(PolarTests, Scale_Multiply) {
using T = TypeParam;
using Polar = PolarOf<T>;
using Angle = AngleOf<T>;
Polar v1 = Polar(4, Angle::Degrees(45));
Polar r = Polar::zero;
r = v1 * 2.0f;
EXPECT_FLOAT_EQ(r.distance, v1.distance * 2) << "ScaleMult(4 45, 2)";
@ -146,9 +173,13 @@ TEST(Polar, Scale_Multiply) {
<< "ScaleMult(4 45, 2)";
}
TEST(Polar, Scale_Divide) {
PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45));
PolarSingle r = PolarSingle::zero;
TYPED_TEST(PolarTests, Scale_Divide) {
using T = TypeParam;
using Polar = PolarOf<T>;
using Angle = AngleOf<T>;
Polar v1 = Polar(4, Angle::Degrees(45));
Polar r = Polar::zero;
r = v1 / 2.0f;
EXPECT_FLOAT_EQ(r.distance, v1.distance / 2) << "ScaleDiv(4 45, 2)";
@ -156,31 +187,39 @@ TEST(Polar, Scale_Divide) {
<< "ScaleDiv(4 45, 2)";
}
TEST(Polar, Distance) {
PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45));
PolarSingle v2 = PolarSingle(1, AngleSingle::Degrees(-90));
TYPED_TEST(PolarTests, Distance) {
using T = TypeParam;
using Polar = PolarOf<T>;
using Angle = AngleOf<T>;
Polar v1 = Polar(4, Angle::Degrees(45));
Polar v2 = Polar(1, Angle::Degrees(-90));
float d = 0;
d = PolarSingle::Distance(v1, v2);
d = Polar::Distance(v1, v2);
// don't know what to expect yet
v2 = PolarSingle::zero;
d = PolarSingle::Distance(v1, v2);
v2 = Polar::zero;
d = Polar::Distance(v1, v2);
EXPECT_FLOAT_EQ(d, v1.distance) << "Distance(4 45, zero)";
}
TEST(Polar, Rotate) {
PolarSingle v = PolarSingle(4, AngleSingle::Degrees(45));
PolarSingle r = PolarSingle::zero;
TYPED_TEST(PolarTests, Rotate) {
using T = TypeParam;
using Polar = PolarOf<T>;
using Angle = AngleOf<T>;
r = PolarSingle::Rotate(v, AngleSingle::Degrees(45));
Polar v = Polar(4, Angle::Degrees(45));
Polar r = Polar::zero;
r = Polar::Rotate(v, Angle::Degrees(45));
EXPECT_FLOAT_EQ(r.distance, v.distance) << "Rotate(4 45, 45)";
EXPECT_FLOAT_EQ(r.angle.InDegrees(), 90.0f) << "Rotate(4 45, 45)";
}
// Performance Test
TEST(PolarOfTest, PerformanceTest) {
const int numIterations = 1000000; // Number of instances to test
TYPED_TEST(PolarTests, PerformanceTest) {
const int numIterations = 1000000; // Number of instances to test
std::vector<PolarOf<float>> polarObjects;
// Measure time for creating a large number of PolarOf objects
@ -188,11 +227,11 @@ TEST(PolarOfTest, PerformanceTest) {
for (int i = 0; i < numIterations; ++i) {
float distance =
static_cast<float>(rand() % 100); // Random distance from 0 to 100
AngleOf<float> angle = AngleOf<float>::Degrees(
static_cast<float>(rand() % 360)); // Random angle from 0 to 360 degrees
static_cast<float>(rand() % 100); // Random distance from 0 to 100
AngleOf<float> angle = AngleOf<float>::Degrees(static_cast<float>(
rand() % 360)); // Random angle from 0 to 360 degrees
PolarOf<float> p = PolarOf<float>(distance, angle);
polarObjects.emplace_back(p); // Create and store the object
polarObjects.emplace_back(p); // Create and store the object
}
auto end = std::chrono::high_resolution_clock::now();
@ -202,7 +241,7 @@ TEST(PolarOfTest, PerformanceTest) {
<< std::endl;
// Test completion with a message
ASSERT_GE(duration.count(), 0); // Ensure duration is non-negative
ASSERT_GE(duration.count(), 0); // Ensure duration is non-negative
// Assert that the duration is less than or equal to 1 second
ASSERT_LE(duration.count(), 1.0)
@ -210,26 +249,27 @@ TEST(PolarOfTest, PerformanceTest) {
}
// Edge Case 1: Testing with distance = 0 and angle = 45
TEST(PolarOfTest, TestDistanceZero) {
TYPED_TEST(PolarTests, TestDistanceZero) {
PolarOf<float> p1(0.0f, AngleOf<float>::Degrees(45.0f));
EXPECT_EQ(p1.distance, 0.0f); // Ensure distance is 0
EXPECT_EQ(p1.angle.InDegrees(), 0.0f); // Ensure angle is 0 when distance is 0
EXPECT_EQ(p1.distance, 0.0f); // Ensure distance is 0
EXPECT_EQ(p1.angle.InDegrees(),
0.0f); // Ensure angle is 0 when distance is 0
}
// Edge Case 2: Testing with negative distance, angle should be adjusted
TEST(PolarOfTest, TestNegativeDistance) {
TYPED_TEST(PolarTests, TestNegativeDistance) {
PolarOf<float> p2(-10.0f, AngleOf<float>::Degrees(90.0f));
EXPECT_EQ(p2.distance, 10.0f); // Ensure distance is positive
EXPECT_EQ(p2.distance, 10.0f); // Ensure distance is positive
EXPECT_NEAR(p2.angle.InDegrees(), -90.0f,
0.0001f); // Ensure angle is normalized to 270 degrees (180 + 90)
0.0001f); // Ensure angle is normalized to 270 degrees (180 + 90)
}
// Edge Case 3: Testing with positive distance and angle = 180
TEST(PolarOfTest, TestPositiveDistance) {
TYPED_TEST(PolarTests, TestPositiveDistance) {
PolarOf<float> p3(100.0f, AngleOf<float>::Degrees(180.0f));
EXPECT_EQ(p3.distance, 100.0f); // Ensure distance is correct
EXPECT_EQ(p3.distance, 100.0f); // Ensure distance is correct
EXPECT_NEAR(p3.angle.InDegrees(), -180.0f,
0.0001f); // Ensure angle is correct
0.0001f); // Ensure angle is correct
}
#endif

View File

@ -27,15 +27,15 @@ TEST(Quaternion, ToAngles) {
bool r = false;
Quaternion q1 = Quaternion(0, 0, 0, 1);
Vector3 v = Vector3::zero;
Vector3Of<float> v = Vector3Of<float>::zero;
v = Quaternion::ToAngles(q1);
r = v == Vector3(0, 0, 0);
r = v == Vector3Of<float>(0, 0, 0);
EXPECT_TRUE(r) << "Quaternion::ToAngles 0 0 0 1";
q1 = Quaternion(1, 0, 0, 0);
v = Quaternion::ToAngles(q1);
r = v == Vector3(180, 0, 0);
r = v == Vector3Of<float>(180, 0, 0);
// EXPECT_TRUE(r) << "Quaternion::ToAngles 1 0 0 0";
// fails on MacOS?
}
@ -56,16 +56,16 @@ TEST(Quaternion, MultiplicationVector) {
bool r = false;
Quaternion q1 = Quaternion(0, 0, 0, 1);
Vector3 v1 = Vector3(0, 1, 0);
Vector3 v = Vector3::zero;
Vector3Of<float> v1 = Vector3Of<float>(0, 1, 0);
Vector3Of<float> v = Vector3Of<float>::zero;
v = q1 * v1;
r = v == Vector3(0, 1, 0);
r = v == Vector3Of<float>(0, 1, 0);
EXPECT_TRUE(r) << "0 0 0 1 * Vector 0 1 0";
q1 = Quaternion(1, 0, 0, 0);
v = q1 * v1;
r = v == Vector3(0, -1, 0);
r = v == Vector3Of<float>(0, -1, 0);
EXPECT_TRUE(r) << "1 0 0 0 * Vector 0 1 0";
}
@ -118,7 +118,7 @@ TEST(Quaternion, SlerpUnclamped) {
TEST(Quaternion, Euler) {
bool r = false;
Vector3 v1 = Vector3(0, 0, 0);
Vector3Of<float> v1 = Vector3Of<float>(0, 0, 0);
Quaternion q = Quaternion::identity;
q = Quaternion::Euler(v1);
@ -129,7 +129,7 @@ TEST(Quaternion, Euler) {
r = q == Quaternion::identity;
EXPECT_TRUE(r) << "Euler 0 0 0";
v1 = Vector3(90, 90, -90);
v1 = Vector3Of<float>(90, 90, -90);
q = Quaternion::Euler(v1);
r = q == Quaternion(0, 0.707106709F, -0.707106709F, 0);
EXPECT_TRUE(r) << "Euler Vector 90 90 -90";
@ -142,7 +142,7 @@ TEST(Quaternion, Euler) {
TEST(Quaternion, GetAngleAround) {
bool r = false;
Vector3 v1 = Vector3(0, 1, 0);
Vector3Of<float> v1 = Vector3Of<float>(0, 1, 0);
Quaternion q1 = Quaternion(0, 0, 0, 1);
float f;
@ -153,7 +153,7 @@ TEST(Quaternion, GetAngleAround) {
f = Quaternion::GetAngleAround(v1, q1);
EXPECT_FLOAT_EQ(f, 180) << "GetAngleAround 0 1 0 , 0 0.7 -0.7 0";
v1 = Vector3(0, 0, 0);
v1 = Vector3Of<float>(0, 0, 0);
f = Quaternion::GetAngleAround(v1, q1);
r = isnan(f);
EXPECT_TRUE(r) << "GetAngleAround 0 0 0 , 0 0.7 -0.7 0";
@ -162,7 +162,7 @@ TEST(Quaternion, GetAngleAround) {
TEST(Quaternion, GetRotationAround) {
bool r = false;
Vector3 v1 = Vector3(0, 1, 0);
Vector3Of<float> v1 = Vector3Of<float>(0, 1, 0);
Quaternion q1 = Quaternion(0, 0, 0, 1);
Quaternion q = Quaternion::identity;
@ -175,7 +175,7 @@ TEST(Quaternion, GetRotationAround) {
r = q == Quaternion(0, 1, 0, 0);
EXPECT_TRUE(r) << "GetRotationAround 0 1 0 , 0 0.7 -0.7 0";
v1 = Vector3(0, 0, 0);
v1 = Vector3Of<float>(0, 0, 0);
q = Quaternion::GetRotationAround(v1, q1);
r = isnan(q.x) && isnan(q.y) && isnan(q.z) && isnan(q.w);
EXPECT_TRUE(r) << "GetRotationAround 0 0 0 , 0 0.7 -0.7 0";

View File

@ -1,214 +0,0 @@
#if GTEST
#include <gtest/gtest.h>
#include <limits>
#include <math.h>
#include <chrono>
#include "Spherical.h"
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
TEST(SphericalSingle, FromVector3) {
Vector3 v = Vector3(0, 0, 1);
SphericalSingle s = SphericalSingle ::FromVector3(v);
EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 0 1";
EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) << "s.hor 0 0 1";
EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) << "s.vert 0 0 1";
v = Vector3(0, 1, 0);
s = SphericalSingle ::FromVector3(v);
EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 1 0";
EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) << "s.hor 0 1 0";
EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 90.0F) << "s.vert 0 1 0";
v = Vector3(1, 0, 0);
s = SphericalSingle ::FromVector3(v);
EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 1 0 0";
EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 90.0F) << "s.hor 1 0 0";
EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) << "s.vert 1 0 0";
}
TEST(SphericalSingle, FromPolar) {
PolarSingle p = PolarSingle(1, AngleSingle::Degrees(0));
SphericalSingle s = SphericalSingle ::FromPolar(p);
EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 0)";
EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F)
<< "s.hor Polar(1 0)";
EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F)
<< "s.vert Polar(1 0)";
p = PolarSingle(1, AngleSingle::Degrees(45));
s = SphericalSingle ::FromPolar(p);
EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 45)";
EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 45.0F)
<< "s.hor Polar(1 45)";
EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F)
<< "s.vert Polar(1 45)";
p = PolarSingle(1, AngleSingle::Degrees(-45));
s = SphericalSingle ::FromPolar(p);
EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 -45)";
EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), -45.0F)
<< "s.hor Polar(1 -45)";
EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F)
<< "s.vert Polar(1 -45)";
p = PolarSingle(0, AngleSingle::Degrees(0));
s = SphericalSingle ::FromPolar(p);
EXPECT_FLOAT_EQ(s.distance, 0.0F) << "s.distance Polar(0 0)";
EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F)
<< "s.hor Polar(0 0)";
EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F)
<< "s.vert Polar(0 0)";
p = PolarSingle(-1, AngleSingle::Degrees(0));
s = SphericalSingle ::FromPolar(p);
EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(-1 0)";
EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), -180.0F)
<< "s.hor Polar(-1 0)";
EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F)
<< "s.vert Polar(-1 0)";
}
TEST(SphericalSingle, Incident1) {
Vector3 v = Vector3(2.242557f, 1.027884f, -0.322347f);
SphericalSingle s = SphericalSingle ::FromVector3(v);
SphericalSingle sr = SphericalSingle(2.49F, AngleSingle::Degrees(98.18f),
AngleSingle::Degrees(24.4F));
EXPECT_NEAR(s.distance, sr.distance, 1.0e-01);
EXPECT_NEAR(s.direction.horizontal.InDegrees(),
sr.direction.horizontal.InDegrees(), 1.0e-02);
EXPECT_NEAR(s.direction.vertical.InDegrees(),
sr.direction.vertical.InDegrees(), 1.0e-02);
Vector3 r = Vector3(sr);
EXPECT_NEAR(r.Right(), v.Right(), 1.0e-02) << "toVector3.x 1 0 0";
EXPECT_NEAR(r.Up(), v.Up(), 1.0e-02) << "toVector3.y 1 0 0";
EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-02) << "toVector3.z 1 0 0";
}
TEST(SphericalSingle, Incident2) {
Vector3 v = Vector3(1.0f, 0.0f, 1.0f);
SphericalSingle s = SphericalSingle ::FromVector3(v);
SphericalSingle sr = SphericalSingle(
1.4142135623F, AngleSingle::Degrees(45.0f), AngleSingle::Degrees(0.0F));
EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
EXPECT_NEAR(s.direction.horizontal.InDegrees(),
sr.direction.horizontal.InDegrees(), 1.0e-05);
EXPECT_NEAR(s.direction.vertical.InDegrees(),
sr.direction.vertical.InDegrees(), 1.0e-05);
Vector3 r = Vector3(sr);
EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
v = Vector3(0.0f, 1.0f, 1.0f);
s = SphericalSingle ::FromVector3(v);
sr = SphericalSingle(1.4142135623F, AngleSingle::Degrees(0.0f),
AngleSingle::Degrees(45.0F));
EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
EXPECT_NEAR(s.direction.horizontal.InDegrees(),
sr.direction.horizontal.InDegrees(), 1.0e-05);
EXPECT_NEAR(s.direction.vertical.InDegrees(),
sr.direction.vertical.InDegrees(), 1.0e-05);
r = Vector3(sr);
EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
v = Vector3(1.0f, 1.0f, 1.0f);
s = SphericalSingle ::FromVector3(v);
r = Vector3(s);
EXPECT_NEAR(s.distance, 1.73205080F, 1.0e-02);
EXPECT_NEAR(s.direction.horizontal.InDegrees(), 45.0F, 1.0e-02);
EXPECT_NEAR(s.direction.vertical.InDegrees(), 35.26F, 1.0e-02);
EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
// s = SphericalSingle(10, 45, 45);
// r = s.ToVector3();
// EXPECT_NEAR(r.x, 5, 1.0e-06);
// EXPECT_NEAR(r.y, 7.07, 1.0e-06);
// EXPECT_NEAR(r.z, 5, 1.0e-06);
}
TEST(SphericalSingle, Addition) {
SphericalSingle v1 =
SphericalSingle(1, AngleSingle::Degrees(45), AngleSingle::Degrees(0));
SphericalSingle v2 = SphericalSingle ::zero;
SphericalSingle r = SphericalSingle ::zero;
r = v1 + v2;
EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";
r = v1;
r += v2;
EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";
v2 = SphericalSingle(1, AngleSingle::Degrees(-45), AngleSingle::Degrees(0));
r = v1 + v2;
EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 -45 0)";
EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 0) << "Addition(1 -45 0)";
EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 0) << "Addition(1 -45 0)";
v2 = SphericalSingle(1, AngleSingle::Degrees(0), AngleSingle::Degrees(90));
r = v1 + v2;
EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 0 90)";
EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 45) << "Addition(1 0 90)";
EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 45) << "Addition(1 0 90)";
}
TEST(SphericalSingle, AdditionPerformance) {
const int numIterations = 1000000; // Number of additions to test
std::vector<SphericalSingle> sphericalObjects;
// Populate the vector with random SphericalOf objects
for (int i = 0; i < numIterations; ++i) {
float distance = (float)(rand() % 100);
float horizontal = (float)(rand() % 180);
float vertical = (float)(rand() % 360);
SphericalSingle s = SphericalSingle::Deg(distance, horizontal, vertical);
sphericalObjects.push_back(s);
}
// Measure the time to perform multiple additions
auto start = std::chrono::high_resolution_clock::now();
SphericalSingle result = SphericalSingle::zero; // Start with a
// zero-initialized object
for (int i = 0; i < numIterations - 1; ++i) {
result = result + sphericalObjects[i]; // Add objects
// together
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = end - start;
std::cout << "Time to perform " << numIterations - 1
<< " additions: " << duration.count() << " seconds." << std::endl;
// Assert that the time taken is less than
// 1 second (or any other performance
// requirement)
ASSERT_LE(duration.count(), 1.0) << "Performance test failed: "
"Additions took longer than 1 "
"second.";
}
#endif

View File

@ -1,17 +1,26 @@
#if GTEST
#include <gtest/gtest.h>
#include <limits>
#include <math.h>
#include <chrono>
#include <limits>
#include "Spherical.h"
#include "Vector3.h"
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
TEST(Spherical16, FromVector3) {
Vector3 v = Vector3(0, 0, 1);
Spherical16 s = Spherical16::FromVector3(v);
using BaseTypes = ::testing::Types<float, signed short>;
template <typename T>
class SphericalTests : public ::testing::Test {};
TYPED_TEST_SUITE(SphericalTests, BaseTypes);
TYPED_TEST(SphericalTests, FromVector3) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
Vector3Of<float> v = Vector3Of<float>(0, 0, 1);
Spherical s = Spherical::FromVector3(v);
EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 0 1";
EXPECT_FLOAT_EQ((float)s.direction.horizontal.InDegrees(), 0.0F)
@ -19,149 +28,167 @@ TEST(Spherical16, FromVector3) {
EXPECT_FLOAT_EQ((float)s.direction.vertical.InDegrees(), 0.0F)
<< "s.vert 0 0 1";
v = Vector3(0, 1, 0);
s = Spherical16::FromVector3(v);
v = Vector3Of<float>(0, 1, 0);
s = Spherical::FromVector3(v);
EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 1 0";
EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) << "s.hor 0 1 0";
EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 90.0F) << "s.vert 0 1 0";
v = Vector3(1, 0, 0);
s = Spherical16::FromVector3(v);
v = Vector3Of<float>(1, 0, 0);
s = Spherical::FromVector3(v);
EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 1 0 0";
EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 90.0F) << "s.hor 1 0 0";
EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) << "s.vert 1 0 0";
}
TEST(Spherical16, Vector3) {
Vector3 v = Vector3(1, 2, 3);
Spherical16 rd = Spherical16::FromVector3(v);
Vector3 rv = rd.ToVector3();
EXPECT_LT(Vector3::Distance(v, rv), 10e-4) << " 1 2 3 <-> spherical";
TYPED_TEST(SphericalTests, Vector3) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
v = Vector3(1, 2, -3);
rd = Spherical16::FromVector3(v);
Vector3Of<float> v = Vector3Of<float>(1, 2, 3);
Spherical rd = Spherical::FromVector3(v);
Vector3Of<float> rv = rd.ToVector3();
EXPECT_LT(Vector3Of<float>::Distance(v, rv), 10e-4) << " 1 2 3 <-> spherical";
v = Vector3Of<float>(1, 2, -3);
rd = Spherical::FromVector3(v);
rv = rd.ToVector3();
EXPECT_LT(Vector3::Distance(v, rv), 10e-4) << " 1 2 3 <-> spherical";
EXPECT_LT(Vector3Of<float>::Distance(v, rv), 10e-4) << " 1 2 3 <-> spherical";
}
// TEST(Spherical16, FromPolar) {
// TYPED_TEST(SphericalTests, FromPolar) {
// using T = TypeParam;
// using Spherical = SphericalOf<T>;
// Polar p = Polar(1, 0);
// Spherical16 s = Spherical16::FromPolar(p);
// Spherical s = Spherical::FromPolar(p);
// EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 0)";
// EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), 0.0F) << "s.hor Polar(1 0)";
// EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(1 0)";
// p = Polar(1, 45);
// s = Spherical16::FromPolar(p);
// s = Spherical::FromPolar(p);
// EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 45)";
// EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), 45.0F) << "s.hor Polar(1 45)";
// EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(1 45)";
// p = Polar(1, -45);
// s = Spherical16::FromPolar(p);
// s = Spherical::FromPolar(p);
// EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 -45)";
// EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), -45.0F) << "s.hor Polar(1 -45)";
// EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(1 -45)";
// p = Polar(0, 0);
// s = Spherical16::FromPolar(p);
// s = Spherical::FromPolar(p);
// EXPECT_FLOAT_EQ(s.distance, 0.0F) << "s.distance Polar(0 0)";
// EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), 0.0F) << "s.hor Polar(0 0)";
// EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(0 0)";
// p = Polar(-1, 0);
// s = Spherical16::FromPolar(p);
// s = Spherical::FromPolar(p);
// EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(-1 0)";
// EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), -180.0F) << "s.hor Polar(-1 0)";
// EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(-1 0)";
// }
TEST(Spherical16, Incident1) {
Vector3 v = Vector3(2.242557f, 1.027884f, -0.322347f);
Spherical16 s = Spherical16::FromVector3(v);
TYPED_TEST(SphericalTests, Incident1) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
using Angle = AngleOf<T>;
Spherical16 sr =
Spherical16(2.49F, Angle16::Degrees(98.18f), Angle16::Degrees(24.4F));
Vector3Of<float> v = Vector3Of<float>(2.242557f, 1.027884f, -0.322347f);
Spherical s = Spherical::FromVector3(v);
Spherical sr =
Spherical(2.49F, Angle::Degrees(98.18f), Angle::Degrees(24.4F));
EXPECT_NEAR(s.distance, sr.distance, 1.0e-01);
EXPECT_NEAR(s.direction.horizontal.InDegrees(),
sr.direction.horizontal.InDegrees(), 1.0e-02);
EXPECT_NEAR(s.direction.vertical.InDegrees(),
sr.direction.vertical.InDegrees(), 1.0e-02);
Vector3 r =
Spherical16(sr.distance, sr.direction.horizontal, sr.direction.vertical)
Vector3Of<float> r =
Spherical(sr.distance, sr.direction.horizontal, sr.direction.vertical)
.ToVector3();
EXPECT_NEAR(r.Right(), v.Right(), 1.0e-02) << "toVector3.x 1 0 0";
EXPECT_NEAR(r.Up(), v.Up(), 1.0e-02) << "toVector3.y 1 0 0";
EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-02) << "toVector3.z 1 0 0";
EXPECT_NEAR(r.horizontal, v.horizontal, 1.0e-02) << "toVector3.x 1 0 0";
EXPECT_NEAR(r.vertical, v.vertical, 1.0e-02) << "toVector3.y 1 0 0";
EXPECT_NEAR(r.depth, v.depth, 1.0e-02) << "toVector3.z 1 0 0";
}
TEST(Spherical16, Incident2) {
Vector3 v = Vector3(1.0f, 0.0f, 1.0f);
Spherical16 s = Spherical16::FromVector3(v);
TYPED_TEST(SphericalTests, Incident2) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
using Angle = AngleOf<T>;
Spherical16 sr = Spherical16(1.4142135623F, Angle16::Degrees(45.0f),
Angle16::Degrees(0.0F));
Vector3Of<float> v = Vector3Of<float>(1.0f, 0.0f, 1.0f);
Spherical s = Spherical::FromVector3(v);
Spherical sr =
Spherical(1.4142135623F, Angle::Degrees(45.0f), Angle::Degrees(0.0F));
EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
EXPECT_NEAR(s.direction.horizontal.InDegrees(),
sr.direction.horizontal.InDegrees(), 1.0e-05);
EXPECT_NEAR(s.direction.vertical.InDegrees(),
sr.direction.vertical.InDegrees(), 1.0e-05);
Vector3Of<float> r =
Spherical(sr.distance, sr.direction.horizontal, sr.direction.vertical)
.ToVector3();
EXPECT_NEAR(r.horizontal, v.horizontal, 1.0e-06);
EXPECT_NEAR(r.vertical, v.vertical, 1.0e-06);
EXPECT_NEAR(r.depth, v.depth, 1.0e-06);
v = Vector3Of<float>(0.0f, 1.0f, 1.0f);
s = Spherical::FromVector3(v);
sr = Spherical(1.4142135623F, Angle::Degrees(0), Angle::Degrees(45));
EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
EXPECT_NEAR(s.direction.horizontal.InDegrees(),
sr.direction.horizontal.InDegrees(), 1.0e-05);
EXPECT_NEAR(s.direction.vertical.InDegrees(),
sr.direction.vertical.InDegrees(), 1.0e-05);
Vector3 r =
Spherical16(sr.distance, sr.direction.horizontal, sr.direction.vertical)
r = Spherical(sr.distance, sr.direction.horizontal, sr.direction.vertical)
.ToVector3();
EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
EXPECT_NEAR(r.horizontal, v.horizontal, 1.0e-06);
EXPECT_NEAR(r.vertical, v.vertical, 1.0e-06);
EXPECT_NEAR(r.depth, v.depth, 1.0e-06);
v = Vector3(0.0f, 1.0f, 1.0f);
s = Spherical16::FromVector3(v);
sr = Spherical16(1.4142135623F, Angle16::Degrees(0), Angle16::Degrees(45));
EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
EXPECT_NEAR(s.direction.horizontal.InDegrees(),
sr.direction.horizontal.InDegrees(), 1.0e-05);
EXPECT_NEAR(s.direction.vertical.InDegrees(),
sr.direction.vertical.InDegrees(), 1.0e-05);
r = Spherical16(sr.distance, sr.direction.horizontal, sr.direction.vertical)
.ToVector3();
EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
v = Vector3(1.0f, 1.0f, 1.0f);
s = Spherical16::FromVector3(v);
r = Spherical16(s.distance, s.direction.horizontal, s.direction.vertical)
v = Vector3Of<float>(1.0f, 1.0f, 1.0f);
s = Spherical::FromVector3(v);
r = Spherical(s.distance, s.direction.horizontal, s.direction.vertical)
.ToVector3();
EXPECT_NEAR(s.distance, 1.73205080F, 1.0e-02);
EXPECT_NEAR(s.direction.horizontal.InDegrees(), 45.0F, 1.0e-02);
EXPECT_NEAR(s.direction.vertical.InDegrees(), 35.26F, 1.0e-02);
EXPECT_NEAR(r.Right(), v.Right(), 1.0e-04);
EXPECT_NEAR(r.Up(), v.Up(), 1.0e-04);
EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-04);
EXPECT_NEAR(r.horizontal, v.horizontal, 1.0e-04);
EXPECT_NEAR(r.vertical, v.vertical, 1.0e-04);
EXPECT_NEAR(r.depth, v.depth, 1.0e-04);
// s = Spherical16(10, 45, 45);
// s = Spherical(10, 45, 45);
// r = s.ToVector3();
// EXPECT_NEAR(r.x, 5, 1.0e-06);
// EXPECT_NEAR(r.y, 7.07, 1.0e-06);
// EXPECT_NEAR(r.z, 5, 1.0e-06);
}
TEST(Spherical16, Addition) {
Spherical16 v1 = Spherical16(1, Angle16::Degrees(45), Angle16::Degrees(0));
Spherical16 v2 = Spherical16::zero;
Spherical16 r = Spherical16::zero;
TYPED_TEST(SphericalTests, Addition) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
using Angle = AngleOf<T>;
Spherical v1 = Spherical(1, Angle::Degrees(45), Angle::Degrees(0));
Spherical v2 = Spherical::zero;
Spherical r = Spherical::zero;
r = v1 + v2;
EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";
@ -170,41 +197,44 @@ TEST(Spherical16, Addition) {
r += v2;
EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";
v2 = Spherical16(1, Angle16::Degrees(-45), Angle16::Degrees(0));
v2 = Spherical(1, Angle::Degrees(-45), Angle::Degrees(0));
r = v1 + v2;
EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 -45 0)";
EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 0) << "Addition(1 -45 0)";
EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 0) << "Addition(1 -45 0)";
v2 = Spherical16(1, Angle16::Degrees(0), Angle16::Degrees(90));
v2 = Spherical(1, Angle::Degrees(0), Angle::Degrees(90));
r = v1 + v2;
EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 0 90)";
EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 45) << "Addition(1 0 90)";
EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 45) << "Addition(1 0 90)";
}
TEST(Spherical16, AdditionPerformance) {
const int numIterations = 1000000; // Number of additions to test
std::vector<Spherical16> sphericalObjects;
TYPED_TEST(SphericalTests, AdditionPerformance) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
const int numIterations = 1000000; // Number of additions to test
std::vector<Spherical> sphericalObjects;
// Populate the vector with random SphericalOf objects
for (int i = 0; i < numIterations; ++i) {
float distance = (float)(rand() % 100);
float horizontal = (float)(rand() % 180);
float vertical = (float)(rand() % 360);
Spherical16 s = Spherical16::Deg(distance, horizontal, vertical);
Spherical s = Spherical::Deg(distance, horizontal, vertical);
sphericalObjects.push_back(s);
}
// Measure the time to perform multiple additions
auto start = std::chrono::high_resolution_clock::now();
Spherical16 result = Spherical16::zero; // Start with a
// zero-initialized object
Spherical result = Spherical::zero; // Start with a
// zero-initialized object
for (int i = 0; i < numIterations - 1; ++i) {
result = result + sphericalObjects[i]; // Add objects
// together
result = result + sphericalObjects[i]; // Add objects
// together
}
auto end = std::chrono::high_resolution_clock::now();

View File

@ -7,125 +7,133 @@
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
TEST(SwingTwistSingle, Quaternion) {
using BaseTypes = ::testing::Types<float, signed short>;
template <typename T>
class SwingTwistTests : public ::testing::Test {};
TYPED_TEST_SUITE(SwingTwistTests, BaseTypes);
TYPED_TEST(SwingTwistTests, Quaternion) {
using T = TypeParam;
using SwingTwist = SwingTwistOf<T>;
Quaternion q;
SwingTwistSingle s;
SwingTwist s;
Quaternion rq;
q = Quaternion::identity;
s = SwingTwistSingle::FromQuaternion(q);
s = SwingTwist::FromQuaternion(q);
rq = s.ToQuaternion();
EXPECT_EQ(q, rq) << " 0 0 0 1 <-> SwingTwist";
q = Quaternion::Euler(90, 0, 0);
s = SwingTwistSingle::FromQuaternion(q);
s = SwingTwist::FromQuaternion(q);
rq = s.ToQuaternion();
EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 90 0 0 <-> SwingTwist";
q = Quaternion::Euler(0, 90, 0);
s = SwingTwistSingle::FromQuaternion(q);
s = SwingTwist::FromQuaternion(q);
rq = s.ToQuaternion();
EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 0 90 0 <-> SwingTwist";
q = Quaternion::Euler(0, 0, 90);
s = SwingTwistSingle::FromQuaternion(q);
s = SwingTwist::FromQuaternion(q);
rq = s.ToQuaternion();
EXPECT_EQ(q, rq) << " Euler 0 0 90 <-> SwingTwist";
q = Quaternion::Euler(0, 180, 0); // ==> spherical S(180 0)T0
s = SwingTwistSingle::FromQuaternion(q);
s = SwingTwist::FromQuaternion(q);
rq = s.ToQuaternion();
EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 0 90 0 <-> SwingTwist";
q = Quaternion::Euler(0, 135, 0); // ==> spherical S(180 45)T0
s = SwingTwistSingle::FromQuaternion(q);
s = SwingTwist::FromQuaternion(q);
rq = s.ToQuaternion();
EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 0 90 0 <-> SwingTwist";
}
TEST(SwingTwistSingle, AngleAxis) {
SwingTwistSingle s;
SwingTwistSingle r;
TYPED_TEST(SwingTwistTests, AngleAxis) {
using T = TypeParam;
using SwingTwist = SwingTwistOf<T>;
using Direction = DirectionOf<T>;
using Angle = AngleOf<T>;
s = SwingTwistSingle::AngleAxis(0, DirectionSingle::up);
EXPECT_EQ(s, SwingTwistSingle::Degrees(0, 0, 0)) << "0 up";
SwingTwist s;
SwingTwist r;
r = SwingTwistSingle::AngleAxis(90, DirectionSingle::up);
s = SwingTwistSingle::Degrees(90, 0, 0);
EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
<< "90 up";
s = SwingTwist::AngleAxis(0, Direction::up);
EXPECT_EQ(s, SwingTwist::Degrees(0, 0, 0)) << "0 up";
r = SwingTwistSingle::AngleAxis(180, DirectionSingle::up);
s = SwingTwistSingle::Degrees(180, 0, 0);
EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
<< "180 up";
r = SwingTwist::AngleAxis(90, Direction::up);
s = SwingTwist::Degrees(90, 0, 0);
EXPECT_LT(SwingTwist::Angle(r, s), Angle::Degrees(10e-2f)) << "90 up";
r = SwingTwistSingle::AngleAxis(270, DirectionSingle::up);
s = SwingTwistSingle::Degrees(-90, 0, 0);
EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
<< "270 up";
r = SwingTwist::AngleAxis(180, Direction::up);
s = SwingTwist::Degrees(180, 0, 0);
EXPECT_LT(SwingTwist::Angle(r, s), Angle::Degrees(10e-2f)) << "180 up";
r = SwingTwistSingle::AngleAxis(90, DirectionSingle::right);
s = SwingTwistSingle::Degrees(0, 90, 0);
EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
r = SwingTwist::AngleAxis(270, Direction::up);
s = SwingTwist::Degrees(-90, 0, 0);
EXPECT_LT(SwingTwist::Angle(r, s), Angle::Degrees(10e-2f)) << "270 up";
r = SwingTwist::AngleAxis(90, Direction::right);
s = SwingTwist::Degrees(0, 90, 0);
EXPECT_LT(SwingTwist::Angle(r, s), Angle::Degrees(10e-2f))
<< "90 right";
r = SwingTwistSingle::AngleAxis(180, DirectionSingle::right);
s = SwingTwistSingle::Degrees(0, 180, 0);
EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
r = SwingTwist::AngleAxis(180, Direction::right);
s = SwingTwist::Degrees(0, 180, 0);
EXPECT_LT(SwingTwist::Angle(r, s), Angle::Degrees(10e-2f))
<< "180 right";
r = SwingTwistSingle::AngleAxis(270, DirectionSingle::right);
s = SwingTwistSingle::Degrees(0, -90, 0);
EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
r = SwingTwist::AngleAxis(270, Direction::right);
s = SwingTwist::Degrees(0, -90, 0);
EXPECT_LT(SwingTwist::Angle(r, s), Angle::Degrees(10e-2f))
<< "270 right";
r = SwingTwistSingle::AngleAxis(90, DirectionSingle::forward);
s = SwingTwistSingle::Degrees(0, 0, 90);
EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
<< "90 up";
r = SwingTwist::AngleAxis(90, Direction::forward);
s = SwingTwist::Degrees(0, 0, 90);
EXPECT_LT(SwingTwist::Angle(r, s), Angle::Degrees(10e-2f)) << "90 up";
r = SwingTwistSingle::AngleAxis(180, DirectionSingle::forward);
s = SwingTwistSingle::Degrees(0, 0, 180);
EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
<< "180 up";
r = SwingTwist::AngleAxis(180, Direction::forward);
s = SwingTwist::Degrees(0, 0, 180);
EXPECT_LT(SwingTwist::Angle(r, s), Angle::Degrees(10e-2f)) << "180 up";
r = SwingTwistSingle::AngleAxis(270, DirectionSingle::forward);
s = SwingTwistSingle::Degrees(0, 0, -90);
EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
<< "270 up";
r = SwingTwist::AngleAxis(270, Direction::forward);
s = SwingTwist::Degrees(0, 0, -90);
EXPECT_LT(SwingTwist::Angle(r, s), Angle::Degrees(10e-2f)) << "270 up";
auto r16 = SwingTwist16::AngleAxis(13, Direction16::down);
auto s16 = SwingTwist16::Degrees(-13, 0, 0);
EXPECT_LT(SwingTwist16::Angle(r16, s16), Angle16::Degrees(10e-2f))
auto r16 = SwingTwist::AngleAxis(13, Direction::down);
auto s16 = SwingTwist::Degrees(-13, 0, 0);
EXPECT_LT(SwingTwist::Angle(r16, s16), Angle::Degrees(10e-2f))
<< "270 up";
}
TEST(SwingTwistSingle, Normalize) {
SwingTwistSingle s;
TYPED_TEST(SwingTwistTests, Normalize) {
using T = TypeParam;
using SwingTwist = SwingTwistOf<T>;
s = SwingTwistSingle::Degrees(0, 0, 0);
EXPECT_EQ(s, SwingTwistSingle::Degrees(0, 0, 0)) << "0 0 0 Normalized";
SwingTwist s;
s = SwingTwistSingle::Degrees(0, 180, 0);
EXPECT_EQ(s, SwingTwistSingle::Degrees(180, 0, 180)) << "0 180 0 Normalized";
s = SwingTwist::Degrees(0, 0, 0);
EXPECT_EQ(s, SwingTwist::Degrees(0, 0, 0)) << "0 0 0 Normalized";
s = SwingTwistSingle::Degrees(0, 180, 180);
EXPECT_EQ(s, SwingTwistSingle::Degrees(180, 0, 0)) << "0 180 180 Normalized";
s = SwingTwist::Degrees(0, 180, 0);
EXPECT_EQ(s, SwingTwist::Degrees(180, 0, 180)) << "0 180 0 Normalized";
s = SwingTwistSingle::Degrees(270, 90, 0);
EXPECT_EQ(s, SwingTwistSingle::Degrees(-90, 90, 0)) << "270 90 0 Normalized";
s = SwingTwist::Degrees(0, 180, 180);
EXPECT_EQ(s, SwingTwist::Degrees(180, 0, 0)) << "0 180 180 Normalized";
s = SwingTwistSingle::Degrees(270, 270, 0);
EXPECT_EQ(s, SwingTwistSingle::Degrees(-90, -90, 0))
<< "270 270 0 Normalized";
s = SwingTwist::Degrees(270, 90, 0);
EXPECT_EQ(s, SwingTwist::Degrees(-90, 90, 0)) << "270 90 0 Normalized";
s = SwingTwistSingle::Degrees(270, 225, 0);
EXPECT_EQ(s, SwingTwistSingle::Degrees(90, -45, -180))
<< "270 225 0 Normalized";
s = SwingTwist::Degrees(270, 270, 0);
EXPECT_EQ(s, SwingTwist::Degrees(-90, -90, 0)) << "270 270 0 Normalized";
s = SwingTwistSingle::Degrees(270, 0, 225);
EXPECT_EQ(s, SwingTwistSingle::Degrees(-90, 0, -135))
<< "270 0 225 Normalized";
s = SwingTwist::Degrees(270, 225, 0);
EXPECT_EQ(s, SwingTwist::Degrees(90, -45, -180)) << "270 225 0 Normalized";
s = SwingTwist::Degrees(270, 0, 225);
EXPECT_EQ(s, SwingTwist::Degrees(-90, 0, -135)) << "270 0 225 Normalized";
}
#endif

View File

@ -8,9 +8,21 @@
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
using Vector2 = Vector2Of<float>;
using BaseTypes = ::testing::Types<float, int>;
using FpTypes = ::testing::Types<float>;
template <typename T>
class Vector2Tests : public ::testing::Test {};
TYPED_TEST_SUITE(Vector2Tests, BaseTypes);
template <typename T>
class Vector2FpTests : public ::testing::Test {};
TYPED_TEST_SUITE(Vector2FpTests, FpTypes);
TYPED_TEST(Vector2Tests, FromPolar) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
TEST(Vector2, FromPolar) {
Vector2 v;
PolarSingle p;
Vector2Float r;
@ -37,7 +49,10 @@ TEST(Vector2, FromPolar) {
EXPECT_FLOAT_EQ(r.vertical, 0.0F) << "FromPolar(0 0)";
}
TEST(Vector2, Magnitude) {
TYPED_TEST(Vector2Tests, Magnitude) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v = Vector2(1, 2);
float m = 0;
@ -54,6 +69,14 @@ TEST(Vector2, Magnitude) {
v = Vector2(0, 0);
m = v.Magnitude();
EXPECT_FLOAT_EQ(m, 0) << "v.magnitude 0 0 ";
}
TYPED_TEST(Vector2FpTests, Magnitude) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v;
float m = 0;
if (std::numeric_limits<float>::is_iec559) {
v = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
@ -66,7 +89,10 @@ TEST(Vector2, Magnitude) {
}
}
TEST(Vector2, SqrMagnitude) {
TYPED_TEST(Vector2Tests, SqrMagnitude) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v = Vector2(1, 2);
float m = 0;
@ -83,6 +109,14 @@ TEST(Vector2, SqrMagnitude) {
v = Vector2(0, 0);
m = v.SqrMagnitude();
EXPECT_FLOAT_EQ(m, 0) << "v.sqrMagnitude 0 0 ";
}
TYPED_TEST(Vector2FpTests, SqrMagnitude) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v;
float m;
if (std::numeric_limits<float>::is_iec559) {
v = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
@ -95,7 +129,10 @@ TEST(Vector2, SqrMagnitude) {
}
}
TEST(Vector2, Normalize) {
TYPED_TEST(Vector2Tests, Normalize) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
bool r = false;
Vector2 v1 = Vector2(0, 2);
@ -114,6 +151,15 @@ TEST(Vector2, Normalize) {
v1 = Vector2(0, 0);
v = v1.Normalized();
EXPECT_TRUE(v == Vector2(0, 0)) << "v.normalized 0 0";
}
TYPED_TEST(Vector2FpTests, Normalize) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v;
Vector2 v1;
float r;
if (std::numeric_limits<float>::is_iec559) {
v1 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
@ -128,7 +174,10 @@ TEST(Vector2, Normalize) {
}
}
TEST(Vector2, Negate) {
TYPED_TEST(Vector2Tests, Negate) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v = Vector2::zero;
@ -142,6 +191,14 @@ TEST(Vector2, Negate) {
v1 = Vector2(0, 0);
v = -v1;
EXPECT_TRUE(v == Vector2(0, 0)) << "- 0 0";
}
TYPED_TEST(Vector2FpTests, Negate) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v;
Vector2 v1;
if (std::numeric_limits<float>::is_iec559) {
v1 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
@ -156,7 +213,10 @@ TEST(Vector2, Negate) {
}
}
TEST(Vector2, Subtract) {
TYPED_TEST(Vector2Tests, Subtract) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2);
Vector2 v = Vector2::zero;
@ -181,6 +241,15 @@ TEST(Vector2, Subtract) {
v -= v2;
EXPECT_TRUE(v == Vector2(4, 5)) << "4 5 - 0 0";
}
TYPED_TEST(Vector2FpTests, Subtract) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v;
Vector2 v1 = Vector2(4, 5);
Vector2 v2;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
@ -195,7 +264,10 @@ TEST(Vector2, Subtract) {
}
}
TEST(Vector2, Addition) {
TYPED_TEST(Vector2Tests, Addition) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2);
Vector2 v = Vector2::zero;
@ -215,6 +287,15 @@ TEST(Vector2, Addition) {
EXPECT_TRUE(v == Vector2(4, 5)) << "4 5 + 0 0";
v += v2;
EXPECT_TRUE(v == Vector2(4, 5)) << "4 5 + 0 0";
}
TYPED_TEST(Vector2FpTests, Addition) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v;
Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(0, 0);
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
@ -229,7 +310,10 @@ TEST(Vector2, Addition) {
}
}
TEST(Vector2, Scale) {
TYPED_TEST(Vector2Tests, Scale) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2);
Vector2 v = Vector2::zero;
@ -244,6 +328,15 @@ TEST(Vector2, Scale) {
v2 = Vector2(0, 0);
v = Vector2::Scale(v1, v2);
EXPECT_TRUE(v == Vector2(0, 0)) << "Scale 4 5 , 0 0";
}
TYPED_TEST(Vector2FpTests, Scale) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v;
Vector2 v1 = Vector2(4, 5);
Vector2 v2;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
@ -258,9 +351,12 @@ TEST(Vector2, Scale) {
}
}
TEST(Vector2, Multiply) {
TYPED_TEST(Vector2Tests, Multiply) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
float f = 3;
T f = 3;
Vector2 v = Vector2::zero;
v = v1 * f;
@ -273,6 +369,15 @@ TEST(Vector2, Multiply) {
f = 0;
v = v1 * f;
EXPECT_TRUE(v == Vector2(0, 0)) << "4 5 * 0";
}
TYPED_TEST(Vector2FpTests, Multiply) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v;
Vector2 v1 = Vector2(4, 5);
T f;
if (std::numeric_limits<float>::is_iec559) {
f = FLOAT_INFINITY;
@ -287,9 +392,12 @@ TEST(Vector2, Multiply) {
}
}
TEST(Vector2, Divide) {
TYPED_TEST(Vector2Tests, Divide) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
float f = 2;
T f = 2;
Vector2 v = Vector2::zero;
v = v1 / f;
@ -298,6 +406,15 @@ TEST(Vector2, Divide) {
f = -2;
v = v1 / f;
EXPECT_TRUE(v == Vector2(-2, -2.5F)) << "4 5 / -3";
}
TYPED_TEST(Vector2FpTests, Divide) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v;
Vector2 v1 = Vector2(4, 5);
T f;
if (std::numeric_limits<float>::is_iec559) {
f = 0;
@ -314,7 +431,10 @@ TEST(Vector2, Divide) {
}
}
TEST(Vector2, Dot) {
TYPED_TEST(Vector2Tests, Dot) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2);
float f = 0;
@ -329,6 +449,15 @@ TEST(Vector2, Dot) {
v2 = Vector2(0, 0);
f = Vector2::Dot(v1, v2);
EXPECT_FLOAT_EQ(f, 0) << "Dot(4 5, 0 0)";
}
TYPED_TEST(Vector2FpTests, Dot) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v2;
Vector2 v1 = Vector2(4, 5);
float f;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
@ -341,7 +470,10 @@ TEST(Vector2, Dot) {
}
}
TEST(Vector2, Equality) {
TYPED_TEST(Vector2Tests, Equality) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2);
bool r = false;
@ -352,6 +484,15 @@ TEST(Vector2, Equality) {
v2 = Vector2(4, 5);
r = v1 == v2;
EXPECT_TRUE(r) << "4 5 == 1 2";
}
TYPED_TEST(Vector2FpTests, Equality) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2;
bool r;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
@ -364,7 +505,10 @@ TEST(Vector2, Equality) {
}
}
TEST(Vector2, Distance) {
TYPED_TEST(Vector2Tests, Distance) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2);
float f = 0;
@ -379,6 +523,15 @@ TEST(Vector2, Distance) {
v2 = Vector2(0, 0);
f = Vector2::Distance(v1, v2);
EXPECT_FLOAT_EQ(f, 6.403124F) << "Distance(4 5, 0 0)";
}
TYPED_TEST(Vector2FpTests, Distance) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2;
float f;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
@ -391,10 +544,14 @@ TEST(Vector2, Distance) {
}
}
TEST(Vector2, Angle) {
TYPED_TEST(Vector2Tests, Angle) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
using Angle = AngleOf<float>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2);
AngleSingle f = AngleSingle::zero;
Angle f = Angle::zero;
bool r = false;
f = Vector2::UnsignedAngle(v1, v2);
@ -407,26 +564,40 @@ TEST(Vector2, Angle) {
v2 = Vector2(0, 0);
f = Vector2::UnsignedAngle(v1, v2);
EXPECT_FLOAT_EQ(f.InDegrees(), 0) << "Angle(4 5, 0 0)";
}
TYPED_TEST(Vector2FpTests, Angle) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2;
AngleOf<float> f;
float r;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
f = Vector2::UnsignedAngle(v1, v2);
//r = isnan(f.InDegrees());
// r = isnan(f.InDegrees());
r = f.InDegrees() == 0;
EXPECT_TRUE(r) << "Angle(4 5, INFINITY INFINITY)";
v2 = Vector2(-FLOAT_INFINITY, -FLOAT_INFINITY);
f = Vector2::UnsignedAngle(v1, v2);
//r = isnan(f.InDegrees());
// r = isnan(f.InDegrees());
r = f.InDegrees() == 0;
EXPECT_TRUE(r) << "Angle(4 5, -INFINITY -INFINITY)";
}
}
TEST(Vector2, SignedAngle) {
TYPED_TEST(Vector2Tests, SignedAngle) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
using Angle = AngleOf<float>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2);
AngleSingle f = AngleSingle::zero;
Angle f = Angle::zero;
bool r = false;
f = Vector2::SignedAngle(v1, v2);
@ -440,20 +611,6 @@ TEST(Vector2, SignedAngle) {
f = Vector2::SignedAngle(v1, v2);
EXPECT_FLOAT_EQ(f.InDegrees(), 0) << "SignedAngle(4 5, 0 0)";
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
f = Vector2::SignedAngle(v1, v2);
//r = isnan(f.InDegrees());
r = f.InDegrees() == 0;
EXPECT_TRUE(r) << "SignedAngle(4 5, INFINITY INFINITY)";
v2 = Vector2(-FLOAT_INFINITY, -FLOAT_INFINITY);
f = Vector2::SignedAngle(v1, v2);
//r = isnan(f.InDegrees());
r = f.InDegrees() == 0;
EXPECT_TRUE(r) << "SignedAngle(4 5, -INFINITY -INFINITY)";
}
v1 = Vector2(0, 1);
v2 = Vector2(1, 0);
f = Vector2::SignedAngle(v1, v2);
@ -465,24 +622,55 @@ TEST(Vector2, SignedAngle) {
EXPECT_FLOAT_EQ(f.InDegrees(), 180.0F) << "SignedAngle(0 1, 1 0)";
}
TEST(Vector2, Rotate) {
Vector2 v1 = Vector2(1, 2);
Vector2 r = Vector2(0, 0);
TYPED_TEST(Vector2FpTests, SignedAngle) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
r = Vector2::Rotate(v1, AngleSingle::Degrees(0));
Vector2 v1 = Vector2(4, 5);
Vector2 v2;
AngleOf<float> f;
float r;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY);
f = Vector2::SignedAngle(v1, v2);
// r = isnan(f.InDegrees());
r = f.InDegrees() == 0;
EXPECT_TRUE(r) << "SignedAngle(4 5, INFINITY INFINITY)";
v2 = Vector2(-FLOAT_INFINITY, -FLOAT_INFINITY);
f = Vector2::SignedAngle(v1, v2);
// r = isnan(f.InDegrees());
r = f.InDegrees() == 0;
EXPECT_TRUE(r) << "SignedAngle(4 5, -INFINITY -INFINITY)";
}
}
TYPED_TEST(Vector2Tests, Rotate) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
using Angle = AngleOf<float>;
Vector2 v1 = Vector2(1, 2);
Vector2Of<float> r = Vector2(0, 0);
r = Vector2::Rotate(v1, Angle::Degrees(0));
EXPECT_FLOAT_EQ(Vector2::Distance(r, v1), 0);
r = Vector2::Rotate(v1, AngleSingle::Degrees(180));
EXPECT_NEAR(Vector2::Distance(r, Vector2(-1, -2)), 0, 1.0e-06);
r = Vector2::Rotate(v1, Angle::Degrees(180));
EXPECT_NEAR(Vector2Of<float>::Distance(r, Vector2(-1, -2)), 0, 1.0e-06);
r = Vector2::Rotate(v1, AngleSingle::Degrees(-90));
r = Vector2::Rotate(v1, Angle::Degrees(-90));
EXPECT_NEAR(Vector2::Distance(r, Vector2(2, -1)), 0, 1.0e-06);
r = Vector2::Rotate(v1, AngleSingle::Degrees(270));
r = Vector2::Rotate(v1, Angle::Degrees(270));
EXPECT_NEAR(Vector2::Distance(r, Vector2(2, -1)), 0, 1.0e-06);
}
TEST(Vector2, Lerp) {
TYPED_TEST(Vector2Tests, Lerp) {
using T = TypeParam;
using Vector2 = Vector2Of<T>;
Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2);
Vector2 r = Vector2(0, 0);

View File

@ -1,134 +1,186 @@
#if GTEST
#include <gtest/gtest.h>
#include <limits>
#include <math.h>
#include <limits>
#include "Vector3.h"
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
TEST(Vector3, FromSpherical) {
using BaseTypes = ::testing::Types<float, int>;
using FpTypes = ::testing::Types<float>;
template <typename T>
class Vector3Tests : public ::testing::Test {};
TYPED_TEST_SUITE(Vector3Tests, BaseTypes);
template <typename T>
class Vector3FpTests : public ::testing::Test {};
TYPED_TEST_SUITE(Vector3FpTests, FpTypes);
TYPED_TEST(Vector3FpTests, FromSpherical) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v = Vector3(0, 0, 1);
SphericalOf<float> s = SphericalOf<float>::FromVector3(v);
Vector3 r = Vector3(s);
Vector3 r = Vector3::FromSpherical(s);
EXPECT_FLOAT_EQ(r.Right(), 0.0F) << "toVector3.x 0 0 1";
EXPECT_NEAR(r.Up(), 0.0F, 1.0e-06) << "toVector3.y 0 0 1";
EXPECT_FLOAT_EQ(r.Forward(), 1.0F) << "toVector3.z 0 0 1";
EXPECT_FLOAT_EQ(r.horizontal, 0.0F) << "toVector3.x 0 0 1";
EXPECT_NEAR(r.vertical, 0.0F, 1.0e-06) << "toVector3.y 0 0 1";
EXPECT_FLOAT_EQ(r.depth, 1.0F) << "toVector3.z 0 0 1";
v = Vector3(0, 1, 0);
s = SphericalOf<float>::FromVector3(v);
r = Vector3(s);
r = Vector3::FromSpherical(s);
EXPECT_FLOAT_EQ(r.Right(), 0.0F) << "toVector3.x 0 1 0";
EXPECT_FLOAT_EQ(r.Up(), 1.0F) << "toVector3.y 0 1 0";
EXPECT_NEAR(r.Forward(), 0.0F, 1.0e-06) << "toVector3.z 0 1 0";
EXPECT_FLOAT_EQ(r.horizontal, 0.0F) << "toVector3.x 0 1 0";
EXPECT_FLOAT_EQ(r.vertical, 1.0F) << "toVector3.y 0 1 0";
EXPECT_NEAR(r.depth, 0.0F, 1.0e-06) << "toVector3.z 0 1 0";
v = Vector3(1, 0, 0);
s = SphericalOf<float>::FromVector3(v);
r = Vector3(s);
r = Vector3::FromSpherical(s);
EXPECT_FLOAT_EQ(r.Right(), 1.0F) << "toVector3.x 1 0 0";
EXPECT_NEAR(r.Up(), 0.0F, 1.0e-06) << "toVector3.y 1 0 0";
EXPECT_NEAR(r.Forward(), 0.0F, 1.0e-06) << "toVector3.z 1 0 0";
EXPECT_FLOAT_EQ(r.horizontal, 1.0F) << "toVector3.x 1 0 0";
EXPECT_NEAR(r.vertical, 0.0F, 1.0e-06) << "toVector3.y 1 0 0";
EXPECT_NEAR(r.depth, 0.0F, 1.0e-06) << "toVector3.z 1 0 0";
}
TEST(Vector3, Magnitude) {
TYPED_TEST(Vector3Tests, Magnitude) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v = Vector3(1, 2, 3);
float m = 0;
m = v.magnitude();
m = v.Magnitude();
EXPECT_FLOAT_EQ(m, 3.741657F) << "v.magnitude 1 2 3";
m = Vector3::Magnitude(v);
m = Vector3::MagnitudeOf(v);
EXPECT_FLOAT_EQ(m, 3.741657F) << "Vector3::Magnitude 1 2 3";
v = Vector3(-1, -2, -3);
m = v.magnitude();
m = v.Magnitude();
EXPECT_FLOAT_EQ(m, 3.741657F) << "v.magnitude -1 -2 -3";
v = Vector3(0, 0, 0);
m = v.magnitude();
m = v.Magnitude();
EXPECT_FLOAT_EQ(m, 0) << "v.magnitude 0 0 0 ";
}
TYPED_TEST(Vector3FpTests, Magnitude) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v;
float m;
if (std::numeric_limits<float>::is_iec559) {
v = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
m = v.magnitude();
m = v.Magnitude();
EXPECT_FLOAT_EQ(m, FLOAT_INFINITY)
<< "v.magnitude INFINITY INFINITY INFINITY ";
v = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY);
m = v.magnitude();
m = v.Magnitude();
EXPECT_FLOAT_EQ(m, FLOAT_INFINITY)
<< "v.magnitude -INFINITY -INFINITY -INFINITY ";
}
}
TEST(Vector3, SqrMagnitude) {
TYPED_TEST(Vector3Tests, SqrMagnitude) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v = Vector3(1, 2, 3);
float m = 0;
m = v.sqrMagnitude();
m = v.SqrMagnitude();
EXPECT_FLOAT_EQ(m, 14) << "v.sqrMagnitude 1 2 3";
m = Vector3::SqrMagnitude(v);
m = Vector3::SqrMagnitudeOf(v);
EXPECT_FLOAT_EQ(m, 14) << "Vector3::SqrMagnitude 1 2 3";
v = Vector3(-1, -2, -3);
m = v.sqrMagnitude();
m = v.SqrMagnitude();
EXPECT_FLOAT_EQ(m, 14) << "v.sqrMagnitude -1 -2 -3";
v = Vector3(0, 0, 0);
m = v.sqrMagnitude();
m = v.SqrMagnitude();
EXPECT_FLOAT_EQ(m, 0) << "v.sqrMagnitude 0 0 0 ";
}
TYPED_TEST(Vector3FpTests, SqrMagnitude) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v;
float m;
if (std::numeric_limits<float>::is_iec559) {
v = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
m = v.sqrMagnitude();
m = v.SqrMagnitude();
EXPECT_FLOAT_EQ(m, FLOAT_INFINITY)
<< "v.sqrMagnitude INFINITY INFINITY INFINITY ";
v = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY);
m = v.sqrMagnitude();
m = v.SqrMagnitude();
EXPECT_FLOAT_EQ(m, FLOAT_INFINITY)
<< "v.sqrMagnitude -INFINITY -INFINITY -INFINITY ";
}
}
TEST(Vector3, Normalize) {
TYPED_TEST(Vector3Tests, Normalize) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
bool r = false;
Vector3 v1 = Vector3(0, 2, 0);
Vector3 v = Vector3::zero;
v = v1.normalized();
v = v1.Normalized();
EXPECT_TRUE(v == Vector3(0, 1, 0)) << "v.normalized 0 2 0";
v = Vector3::Normalize(v1);
EXPECT_TRUE(v == Vector3(0, 1, 0)) << "Vector3::Normalize 0 2 0";
v1 = Vector3(0, -2, 0);
v = v1.normalized();
v = v1.Normalized();
EXPECT_TRUE(v == Vector3(0, -1, 0)) << "v.normalized 0 -2 0";
v1 = Vector3(0, 0, 0);
v = v1.normalized();
v = v1.Normalized();
EXPECT_TRUE(v == Vector3(0, 0, 0)) << "v.normalized 0 0 0";
}
TYPED_TEST(Vector3FpTests, Normalize) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
bool r = false;
Vector3 v1 = Vector3(0, 2, 0);
Vector3 v = Vector3::zero;
if (std::numeric_limits<float>::is_iec559) {
v1 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
v = v1.normalized();
r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward());
v = v1.Normalized();
r = isnan(v.horizontal) && isnan(v.vertical) && isnan(v.depth);
EXPECT_TRUE(r) << "v.normalized INFINITY INFINITY INFINITY";
v1 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY);
v = v1.normalized();
r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward());
v = v1.Normalized();
r = isnan(v.horizontal) && isnan(v.vertical) && isnan(v.depth);
EXPECT_TRUE(r) << "v.normalized -INFINITY -INFINITY -INFINITY";
}
}
TEST(Vector3, Negate) {
TYPED_TEST(Vector3Tests, Negate) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v = Vector3::zero;
@ -142,6 +194,14 @@ TEST(Vector3, Negate) {
v1 = Vector3(0, 0, 0);
v = -v1;
EXPECT_TRUE(v == Vector3(0, 0, 0)) << "- 0 0 0";
}
TYPED_TEST(Vector3FpTests, Negate) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v = Vector3::zero;
if (std::numeric_limits<float>::is_iec559) {
v1 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
@ -156,7 +216,11 @@ TEST(Vector3, Negate) {
}
}
TEST(Vector3, Subtract) {
TYPED_TEST(Vector3Tests, Subtract) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
@ -175,6 +239,15 @@ TEST(Vector3, Subtract) {
v2 = Vector3(0, 0, 0);
v = v1 - v2;
EXPECT_TRUE(v == Vector3(4, 5, 6)) << "4 5 6 - 0 0 0";
}
TYPED_TEST(Vector3FpTests, Subtract) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
@ -189,7 +262,10 @@ TEST(Vector3, Subtract) {
}
}
TEST(Vector3, Addition) {
TYPED_TEST(Vector3Tests, Addition) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
@ -204,6 +280,15 @@ TEST(Vector3, Addition) {
v2 = Vector3(0, 0, 0);
v = v1 + v2;
EXPECT_TRUE(v == Vector3(4, 5, 6)) << "4 5 6 + 0 0 0";
}
TYPED_TEST(Vector3FpTests, Addition) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
@ -218,7 +303,11 @@ TEST(Vector3, Addition) {
}
}
TEST(Vector3, Scale) {
TYPED_TEST(Vector3Tests, Scale) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
@ -233,6 +322,15 @@ TEST(Vector3, Scale) {
v2 = Vector3(0, 0, 0);
v = Vector3::Scale(v1, v2);
EXPECT_TRUE(v == Vector3(0, 0, 0)) << "Scale 4 5 6 , 0 0 0";
}
TYPED_TEST(Vector3FpTests, Scale) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
@ -247,7 +345,10 @@ TEST(Vector3, Scale) {
}
}
TEST(Vector3, Multiply) {
TYPED_TEST(Vector3Tests, Multiply) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
float f = 3;
Vector3 v = Vector3::zero;
@ -262,6 +363,15 @@ TEST(Vector3, Multiply) {
f = 0;
v = v1 * f;
EXPECT_TRUE(v == Vector3(0, 0, 0)) << "4 5 6 * 0";
}
TYPED_TEST(Vector3FpTests, Multiply) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
float f = 3;
Vector3 v = Vector3::zero;
if (std::numeric_limits<float>::is_iec559) {
f = FLOAT_INFINITY;
@ -276,7 +386,10 @@ TEST(Vector3, Multiply) {
}
}
TEST(Vector3, Divide) {
TYPED_TEST(Vector3Tests, Divide) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
float f = 2;
Vector3 v = Vector3::zero;
@ -287,6 +400,16 @@ TEST(Vector3, Divide) {
f = -2;
v = v1 / f;
EXPECT_TRUE(v == Vector3(-2, -2.5F, -3)) << "4 5 6 / -3";
}
TYPED_TEST(Vector3FpTests, Divide) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
float f = 2;
Vector3 v = Vector3::zero;
if (std::numeric_limits<float>::is_iec559) {
f = 0;
@ -304,7 +427,10 @@ TEST(Vector3, Divide) {
}
}
TEST(Vector3, Dot) {
TYPED_TEST(Vector3Tests, Dot) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
float f = 0;
@ -319,6 +445,15 @@ TEST(Vector3, Dot) {
v2 = Vector3(0, 0, 0);
f = Vector3::Dot(v1, v2);
EXPECT_FLOAT_EQ(f, 0) << "Dot(4 5 6, 0 0 0)";
}
TYPED_TEST(Vector3FpTests, Dot) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
float f = 0;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
@ -333,7 +468,10 @@ TEST(Vector3, Dot) {
}
}
TEST(Vector3, Equality) {
TYPED_TEST(Vector3Tests, Equality) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
bool r = false;
@ -344,6 +482,15 @@ TEST(Vector3, Equality) {
v2 = Vector3(4, 5, 6);
r = v1 == v2;
EXPECT_TRUE(r) << "4 5 6 == 1 2 3";
}
TYPED_TEST(Vector3FpTests, Equality) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
bool r = false;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
@ -357,7 +504,10 @@ TEST(Vector3, Equality) {
}
}
TEST(Vector3, Distance) {
TYPED_TEST(Vector3Tests, Distance) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
float f = 0;
@ -372,6 +522,15 @@ TEST(Vector3, Distance) {
v2 = Vector3(0, 0, 0);
f = Vector3::Distance(v1, v2);
EXPECT_FLOAT_EQ(f, 8.77496433F) << "Distance(4 5 6, 0 0 0)";
}
TYPED_TEST(Vector3FpTests, Distance) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
float f = 0;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
@ -386,7 +545,10 @@ TEST(Vector3, Distance) {
}
}
TEST(Vector3, Cross) {
TYPED_TEST(Vector3Tests, Cross) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
@ -405,21 +567,34 @@ TEST(Vector3, Cross) {
v = Vector3::Cross(v1, v2);
r = v == Vector3(0, 0, 0);
EXPECT_TRUE(r) << "Cross(4 5 6, 0 0 0)";
}
TYPED_TEST(Vector3FpTests, Cross) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
bool r = false;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
v = Vector3::Cross(v1, v2);
r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward());
r = isnan(v.horizontal) && isnan(v.vertical) && isnan(v.depth);
EXPECT_TRUE(r) << "Cross(4 5 6, INFINITY INFINITY INFINITY)";
v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY);
v = Vector3::Cross(v1, v2);
r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward());
r = isnan(v.horizontal) && isnan(v.vertical) && isnan(v.depth);
EXPECT_TRUE(r) << "Cross(4 5 6, -INFINITY -INFINITY -INFINITY)";
}
}
TEST(Vector3, Project) {
TYPED_TEST(Vector3Tests, Project) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
@ -438,84 +613,124 @@ TEST(Vector3, Project) {
v = Vector3::Project(v1, v2);
r = v == Vector3(0, 0, 0);
EXPECT_TRUE(r) << "Project(4 5 6, 0 0 0)";
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
v = Vector3::Project(v1, v2);
r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward());
EXPECT_TRUE(r) << "Project(4 5 6, INFINITY INFINITY INFINITY)";
v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY);
v = Vector3::Project(v1, v2);
r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward());
EXPECT_TRUE(r) << "Project(4 5 6, -INFINITY -INFINITY -INFINITY)";
}
}
TEST(Vector3, ProjectOnPlane) {
TYPED_TEST(Vector3FpTests, Project) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
bool r = false;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
v = Vector3::Project(v1, v2);
r = isnan(v.horizontal) && isnan(v.vertical) && isnan(v.depth);
EXPECT_TRUE(r) << "Project(4 5 6, INFINITY INFINITY INFINITY)";
v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY);
v = Vector3::Project(v1, v2);
r = isnan(v.horizontal) && isnan(v.vertical) && isnan(v.depth);
EXPECT_TRUE(r) << "Project(4 5 6, -INFINITY -INFINITY -INFINITY)";
}
}
TYPED_TEST(Vector3Tests, ProjectOnPlane) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3Of<float> v = Vector3Of<float>::zero;
bool r = false;
v = Vector3::ProjectOnPlane(v1, v2);
r = v == Vector3(1.71428561F, 0.428571224F, -0.857142925F);
r = v == Vector3Of<float>(1.71428561F, 0.428571224F, -0.857142925F);
EXPECT_TRUE(r) << "ProjectOnPlane(4 5 6, 1 2 3)";
//EXPECT_EQ(v, Vector3(1.71428561F, 0.428571224F, -0.857142925F));
v2 = Vector3(-1, -2, -3);
v = Vector3::ProjectOnPlane(v1, v2);
r = v == Vector3(1.71428561F, 0.428571224F, -0.857142925F);
r = v == Vector3Of<float>(1.71428561F, 0.428571224F, -0.857142925F);
EXPECT_TRUE(r) << "ProjectOnPlane(4 5 6, -1 -2 -3)";
v2 = Vector3(0, 0, 0);
v = Vector3::ProjectOnPlane(v1, v2);
r = v == Vector3(4, 5, 6);
EXPECT_TRUE(r) << "ProjectOnPlane(4 5 6, 0 0 0)";
}
TYPED_TEST(Vector3FpTests, ProjectOnPlane) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v = Vector3::zero;
bool r = false;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
v = Vector3::ProjectOnPlane(v1, v2);
r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward());
r = isnan(v.horizontal) && isnan(v.vertical) && isnan(v.depth);
EXPECT_TRUE(r) << "ProjectOnPlane(4 5 6, INFINITY INFINITY INFINITY)";
v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY);
v = Vector3::ProjectOnPlane(v1, v2);
r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward());
r = isnan(v.horizontal) && isnan(v.vertical) && isnan(v.depth);
EXPECT_TRUE(r) << "ProjectOnPlane(4 5 6, -INFINITY -INFINITY -INFINITY)";
}
}
TEST(Vector3, Angle) {
TYPED_TEST(Vector3Tests, Angle) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
AngleOf<float> f = AngleOf<float>::Degrees(0);
bool r = false;
f = Vector3::Angle(v1, v2);
f = Vector3::UnsignedAngle(v1, v2);
EXPECT_FLOAT_EQ(f.InDegrees(), 12.9331388F) << "Angle(4 5 6, 1 2 3)";
v2 = Vector3(-1, -2, -3);
f = Vector3::Angle(v1, v2);
f = Vector3::UnsignedAngle(v1, v2);
EXPECT_FLOAT_EQ(f.InDegrees(), 167.066864F) << "Angle(4 5 6, -1 -2 -3)";
v2 = Vector3(0, 0, 0);
f = Vector3::Angle(v1, v2);
f = Vector3::UnsignedAngle(v1, v2);
EXPECT_FLOAT_EQ(f.InDegrees(), 0) << "Angle(4 5 6, 0 0 0)";
}
TYPED_TEST(Vector3FpTests, Angle) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
AngleOf<float> f = AngleOf<float>::Degrees(0);
bool r = false;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
f = Vector3::Angle(v1, v2);
f = Vector3::UnsignedAngle(v1, v2);
r = isnan(f.InDegrees());
EXPECT_TRUE(r) << "Angle(4 5 6, INFINITY INFINITY INFINITY)";
v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY);
f = Vector3::Angle(v1, v2);
f = Vector3::UnsignedAngle(v1, v2);
r = isnan(f.InDegrees());
EXPECT_TRUE(r) << "Angle(4 5 6, -INFINITY -INFINITY -INFINITY)";
}
}
TEST(Vector3, SignedAngle) {
TYPED_TEST(Vector3Tests, SignedAngle) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v3 = Vector3(7, 8, -9);
@ -545,6 +760,17 @@ TEST(Vector3, SignedAngle) {
v3 = Vector3(0, 0, 0);
f = Vector3::SignedAngle(v1, v2, v3);
EXPECT_FLOAT_EQ(f.InDegrees(), 0) << "SignedAngle(4 5 6, 1 2 3, 0 0 0)";
}
TYPED_TEST(Vector3FpTests, SignedAngle) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 v3 = Vector3(7, 8, -9);
AngleOf<float> f = AngleOf<float>::Degrees(0);
bool r = false;
if (std::numeric_limits<float>::is_iec559) {
v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
@ -559,7 +785,11 @@ TEST(Vector3, SignedAngle) {
}
}
TEST(Vector3, Lerp) {
TYPED_TEST(Vector3Tests, Lerp) {
using T = TypeParam;
using Vector3 = Vector3Of<T>;
;
Vector3 v1 = Vector3(4, 5, 6);
Vector3 v2 = Vector3(1, 2, 3);
Vector3 r = Vector3(0, 0, 0);