mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 23:13:26 +00:00
Adds less than, greater than, less than or equal, and greater than or equal operators to the Vector2, Vector3 and Vector4 classes. The comparison is based on the lengths of the vectors. Adds corresponding unit tests.
431 lines
12 KiB
C++
431 lines
12 KiB
C++
//
|
|
// Created by Vlad on 01.09.2024.
|
|
//
|
|
|
|
#include <cfloat> // For FLT_MAX, FLT_MIN
|
|
#include <cmath>
|
|
#include <gtest/gtest.h>
|
|
#include <limits> // For std::numeric_limits
|
|
#include <omath/vector3.hpp>
|
|
|
|
using namespace omath;
|
|
|
|
class UnitTestVector3 : public ::testing::Test
|
|
{
|
|
protected:
|
|
Vector3<float> v1;
|
|
Vector3<float> v2;
|
|
|
|
void SetUp() override
|
|
{
|
|
v1 = Vector3(1.0f, 2.0f, 3.0f);
|
|
v2 = Vector3(4.0f, 5.0f, 6.0f);
|
|
}
|
|
};
|
|
|
|
// Test constructor and default values
|
|
TEST_F(UnitTestVector3, Constructor_Default)
|
|
{
|
|
constexpr Vector3<float> v;
|
|
EXPECT_FLOAT_EQ(v.x, 0.0f);
|
|
EXPECT_FLOAT_EQ(v.y, 0.0f);
|
|
EXPECT_FLOAT_EQ(v.z, 0.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Constructor_Values)
|
|
{
|
|
constexpr Vector3<float> v(1.0f, 2.0f, 3.0f);
|
|
EXPECT_FLOAT_EQ(v.x, 1.0f);
|
|
EXPECT_FLOAT_EQ(v.y, 2.0f);
|
|
EXPECT_FLOAT_EQ(v.z, 3.0f);
|
|
}
|
|
|
|
// Test equality operators
|
|
TEST_F(UnitTestVector3, EqualityOperator)
|
|
{
|
|
constexpr Vector3 v3(1.0f, 2.0f, 3.0f);
|
|
EXPECT_TRUE(v1 == v3);
|
|
EXPECT_FALSE(v1 == v2);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, InequalityOperator)
|
|
{
|
|
constexpr Vector3 v3(1.0f, 2.0f, 3.0f);
|
|
EXPECT_FALSE(v1 != v3);
|
|
EXPECT_TRUE(v1 != v2);
|
|
}
|
|
|
|
// Test arithmetic operators
|
|
TEST_F(UnitTestVector3, AdditionOperator)
|
|
{
|
|
constexpr Vector3 v3 = Vector3(1.0f, 2.0f, 3.0f) + Vector3(4.0f, 5.0f, 6.0f);
|
|
EXPECT_FLOAT_EQ(v3.x, 5.0f);
|
|
EXPECT_FLOAT_EQ(v3.y, 7.0f);
|
|
EXPECT_FLOAT_EQ(v3.z, 9.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, SubtractionOperator)
|
|
{
|
|
constexpr Vector3 v3 = Vector3(4.0f, 5.0f, 6.0f) - Vector3(1.0f, 2.0f, 3.0f);
|
|
EXPECT_FLOAT_EQ(v3.x, 3.0f);
|
|
EXPECT_FLOAT_EQ(v3.y, 3.0f);
|
|
EXPECT_FLOAT_EQ(v3.z, 3.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, MultiplicationOperator_Scalar)
|
|
{
|
|
constexpr Vector3 v3 = Vector3(1.0f, 2.0f, 3.0f) * 2.0f;
|
|
EXPECT_FLOAT_EQ(v3.x, 2.0f);
|
|
EXPECT_FLOAT_EQ(v3.y, 4.0f);
|
|
EXPECT_FLOAT_EQ(v3.z, 6.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, MultiplicationOperator_Vector)
|
|
{
|
|
constexpr auto v3 = Vector3(1.0f, 2.0f, 3.0f) * Vector3(4.0f, 5.0f, 6.0f);
|
|
EXPECT_FLOAT_EQ(v3.x, 4.0f);
|
|
EXPECT_FLOAT_EQ(v3.y, 10.0f);
|
|
EXPECT_FLOAT_EQ(v3.z, 18.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, DivisionOperator_Scalar)
|
|
{
|
|
constexpr auto v3 = Vector3(4.0f, 5.0f, 6.0f) / 2.0f;
|
|
EXPECT_FLOAT_EQ(v3.x, 2.0f);
|
|
EXPECT_FLOAT_EQ(v3.y, 2.5f);
|
|
EXPECT_FLOAT_EQ(v3.z, 3.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, DivisionOperator_Vector)
|
|
{
|
|
constexpr auto v3 = Vector3(4.0f, 5.0f, 6.0f) / Vector3(1.0f, 2.0f, 3.0f);
|
|
EXPECT_FLOAT_EQ(v3.x, 4.0f);
|
|
EXPECT_FLOAT_EQ(v3.y, 2.5f);
|
|
EXPECT_FLOAT_EQ(v3.z, 2.0f);
|
|
}
|
|
|
|
// Test compound assignment operators
|
|
TEST_F(UnitTestVector3, AdditionAssignmentOperator)
|
|
{
|
|
v1 += v2;
|
|
EXPECT_FLOAT_EQ(v1.x, 5.0f);
|
|
EXPECT_FLOAT_EQ(v1.y, 7.0f);
|
|
EXPECT_FLOAT_EQ(v1.z, 9.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, SubtractionAssignmentOperator)
|
|
{
|
|
v1 -= v2;
|
|
EXPECT_FLOAT_EQ(v1.x, -3.0f);
|
|
EXPECT_FLOAT_EQ(v1.y, -3.0f);
|
|
EXPECT_FLOAT_EQ(v1.z, -3.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, MultiplicationAssignmentOperator_Scalar)
|
|
{
|
|
v1 *= 2.0f;
|
|
EXPECT_FLOAT_EQ(v1.x, 2.0f);
|
|
EXPECT_FLOAT_EQ(v1.y, 4.0f);
|
|
EXPECT_FLOAT_EQ(v1.z, 6.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, MultiplicationAssignmentOperator_Vector)
|
|
{
|
|
v1 *= v2;
|
|
EXPECT_FLOAT_EQ(v1.x, 4.0f);
|
|
EXPECT_FLOAT_EQ(v1.y, 10.0f);
|
|
EXPECT_FLOAT_EQ(v1.z, 18.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, DivisionAssignmentOperator_Scalar)
|
|
{
|
|
v1 /= 2.0f;
|
|
EXPECT_FLOAT_EQ(v1.x, 0.5f);
|
|
EXPECT_FLOAT_EQ(v1.y, 1.0f);
|
|
EXPECT_FLOAT_EQ(v1.z, 1.5f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, DivisionAssignmentOperator_Vector)
|
|
{
|
|
v1 /= v2;
|
|
EXPECT_FLOAT_EQ(v1.x, 0.25f);
|
|
EXPECT_FLOAT_EQ(v1.y, 0.4f);
|
|
EXPECT_FLOAT_EQ(v1.z, 0.5f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, NegationOperator)
|
|
{
|
|
constexpr auto v3 = -Vector3(1.0f, 2.0f, 3.0f);
|
|
EXPECT_FLOAT_EQ(v3.x, -1.0f);
|
|
EXPECT_FLOAT_EQ(v3.y, -2.0f);
|
|
EXPECT_FLOAT_EQ(v3.z, -3.0f);
|
|
}
|
|
|
|
// Test other member functions
|
|
TEST_F(UnitTestVector3, DistToSqr)
|
|
{
|
|
constexpr auto distSqr = Vector3(1.0f, 2.0f, 3.0f).distance_to_sqr(Vector3(4.0f, 5.0f, 6.0f));
|
|
EXPECT_FLOAT_EQ(distSqr, 27.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, DotProduct)
|
|
{
|
|
constexpr auto dot = Vector3(1.0f, 2.0f, 3.0f).dot(Vector3(4.0f, 5.0f, 6.0f));
|
|
EXPECT_FLOAT_EQ(dot, 32.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, LengthSqr)
|
|
{
|
|
constexpr auto lengthSqr = Vector3(1.0f, 2.0f, 3.0f).length_sqr();
|
|
EXPECT_FLOAT_EQ(lengthSqr, 14.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Abs)
|
|
{
|
|
auto v3 = Vector3(-1.0f, -2.0f, -3.0f);
|
|
v3.abs();
|
|
EXPECT_FLOAT_EQ(v3.x, 1.0f);
|
|
EXPECT_FLOAT_EQ(v3.y, 2.0f);
|
|
EXPECT_FLOAT_EQ(v3.z, 3.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Sum)
|
|
{
|
|
constexpr auto sum = Vector3(1.0f, 2.0f, 3.0f).sum();
|
|
EXPECT_FLOAT_EQ(sum, 6.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Sum2D)
|
|
{
|
|
constexpr auto sum2D = Vector3(1.0f, 2.0f, 3.0f).sum_2d();
|
|
EXPECT_FLOAT_EQ(sum2D, 3.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, CrossProduct)
|
|
{
|
|
constexpr Vector3 v3 = Vector3(1.0f, 2.0f, 3.0f).cross(Vector3(4.0f, 5.0f, 6.0f));
|
|
EXPECT_FLOAT_EQ(v3.x, -3.0f);
|
|
EXPECT_FLOAT_EQ(v3.y, 6.0f);
|
|
EXPECT_FLOAT_EQ(v3.z, -3.0f);
|
|
}
|
|
|
|
// New tests to cover corner cases
|
|
|
|
// Test operations with zero vectors
|
|
TEST_F(UnitTestVector3, Addition_WithZeroVector)
|
|
{
|
|
constexpr Vector3 v_zero(0.0f, 0.0f, 0.0f);
|
|
const Vector3 result = v1 + v_zero;
|
|
EXPECT_FLOAT_EQ(result.x, v1.x);
|
|
EXPECT_FLOAT_EQ(result.y, v1.y);
|
|
EXPECT_FLOAT_EQ(result.z, v1.z);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Subtraction_WithZeroVector)
|
|
{
|
|
constexpr Vector3 v_zero(0.0f, 0.0f, 0.0f);
|
|
const Vector3 result = v1 - v_zero;
|
|
EXPECT_FLOAT_EQ(result.x, v1.x);
|
|
EXPECT_FLOAT_EQ(result.y, v1.y);
|
|
EXPECT_FLOAT_EQ(result.z, v1.z);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Multiplication_WithZeroVector)
|
|
{
|
|
constexpr Vector3 v_zero(0.0f, 0.0f, 0.0f);
|
|
const Vector3 result = v1 * v_zero;
|
|
EXPECT_FLOAT_EQ(result.x, 0.0f);
|
|
EXPECT_FLOAT_EQ(result.y, 0.0f);
|
|
EXPECT_FLOAT_EQ(result.z, 0.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Division_ByZeroVector)
|
|
{
|
|
constexpr Vector3 v_zero(0.0f, 0.0f, 0.0f);
|
|
const Vector3 result = v1 / v_zero;
|
|
EXPECT_TRUE(std::isinf(result.x) || std::isnan(result.x));
|
|
EXPECT_TRUE(std::isinf(result.y) || std::isnan(result.y));
|
|
EXPECT_TRUE(std::isinf(result.z) || std::isnan(result.z));
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Division_ByZeroScalar)
|
|
{
|
|
constexpr float zero = 0.0f;
|
|
const Vector3 result = v1 / zero;
|
|
EXPECT_TRUE(std::isinf(result.x) || std::isnan(result.x));
|
|
EXPECT_TRUE(std::isinf(result.y) || std::isnan(result.y));
|
|
EXPECT_TRUE(std::isinf(result.z) || std::isnan(result.z));
|
|
}
|
|
|
|
// Test operations with infinity
|
|
TEST_F(UnitTestVector3, Addition_WithInfinity)
|
|
{
|
|
constexpr Vector3 v_inf(INFINITY, INFINITY, INFINITY);
|
|
const Vector3 result = v1 + v_inf;
|
|
EXPECT_TRUE(std::isinf(result.x));
|
|
EXPECT_TRUE(std::isinf(result.y));
|
|
EXPECT_TRUE(std::isinf(result.z));
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Subtraction_WithInfinity)
|
|
{
|
|
constexpr Vector3 v_inf(INFINITY, INFINITY, INFINITY);
|
|
const Vector3 result = v1 - v_inf;
|
|
EXPECT_TRUE(std::isinf(result.x));
|
|
EXPECT_TRUE(std::isinf(result.y));
|
|
EXPECT_TRUE(std::isinf(result.z));
|
|
}
|
|
|
|
// Test operations with NaN
|
|
TEST_F(UnitTestVector3, Multiplication_WithNaN)
|
|
{
|
|
constexpr Vector3 v_nan(NAN, NAN, NAN);
|
|
const Vector3 result = v1 * v_nan;
|
|
EXPECT_TRUE(std::isnan(result.x));
|
|
EXPECT_TRUE(std::isnan(result.y));
|
|
EXPECT_TRUE(std::isnan(result.z));
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Division_WithNaN)
|
|
{
|
|
constexpr Vector3 v_nan(NAN, NAN, NAN);
|
|
const Vector3 result = v1 / v_nan;
|
|
EXPECT_TRUE(std::isnan(result.x));
|
|
EXPECT_TRUE(std::isnan(result.y));
|
|
EXPECT_TRUE(std::isnan(result.z));
|
|
}
|
|
|
|
// Test Length, Length2D, and Normalized
|
|
TEST_F(UnitTestVector3, Length)
|
|
{
|
|
const float length = v1.length();
|
|
EXPECT_FLOAT_EQ(length, std::sqrt(14.0f));
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Length_ZeroVector)
|
|
{
|
|
constexpr Vector3 v_zero(0.0f, 0.0f, 0.0f);
|
|
const float length = v_zero.length();
|
|
EXPECT_FLOAT_EQ(length, 0.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Length_LargeValues)
|
|
{
|
|
constexpr Vector3 v_large(FLT_MAX, FLT_MAX, FLT_MAX);
|
|
const float length = v_large.length();
|
|
EXPECT_TRUE(std::isinf(length));
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Length2D)
|
|
{
|
|
const float length2D = v1.length_2d();
|
|
EXPECT_FLOAT_EQ(length2D, std::sqrt(5.0f));
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Normalized)
|
|
{
|
|
const Vector3 v_norm = v1.normalized();
|
|
const float length = v_norm.length();
|
|
EXPECT_NEAR(length, 1.0f, 0.0001f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Normalized_ZeroVector)
|
|
{
|
|
constexpr Vector3 v_zero(0.0f, 0.0f, 0.0f);
|
|
const Vector3 v_norm = v_zero.normalized();
|
|
EXPECT_FLOAT_EQ(v_norm.x, 0.0f);
|
|
EXPECT_FLOAT_EQ(v_norm.y, 0.0f);
|
|
EXPECT_FLOAT_EQ(v_norm.z, 0.0f);
|
|
}
|
|
|
|
// Test Cross Product edge cases
|
|
TEST_F(UnitTestVector3, CrossProduct_ParallelVectors)
|
|
{
|
|
constexpr Vector3 v_a(1.0f, 2.0f, 3.0f);
|
|
constexpr Vector3 v_b = v_a * 2.0f; // Parallel to v_a
|
|
constexpr Vector3 cross = v_a.cross(v_b);
|
|
EXPECT_FLOAT_EQ(cross.x, 0.0f);
|
|
EXPECT_FLOAT_EQ(cross.y, 0.0f);
|
|
EXPECT_FLOAT_EQ(cross.z, 0.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, CrossProduct_OrthogonalVectors)
|
|
{
|
|
constexpr Vector3 v_a(1.0f, 0.0f, 0.0f);
|
|
constexpr Vector3 v_b(0.0f, 1.0f, 0.0f);
|
|
constexpr Vector3 cross = v_a.cross(v_b);
|
|
EXPECT_FLOAT_EQ(cross.x, 0.0f);
|
|
EXPECT_FLOAT_EQ(cross.y, 0.0f);
|
|
EXPECT_FLOAT_EQ(cross.z, 1.0f);
|
|
}
|
|
|
|
// Test negative values
|
|
TEST_F(UnitTestVector3, Addition_NegativeValues)
|
|
{
|
|
constexpr Vector3 v_neg(-1.0f, -2.0f, -3.0f);
|
|
const Vector3 result = v1 + v_neg;
|
|
EXPECT_FLOAT_EQ(result.x, 0.0f);
|
|
EXPECT_FLOAT_EQ(result.y, 0.0f);
|
|
EXPECT_FLOAT_EQ(result.z, 0.0f);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, Subtraction_NegativeValues)
|
|
{
|
|
constexpr Vector3 v_neg(-1.0f, -2.0f, -3.0f);
|
|
const Vector3 result = v1 - v_neg;
|
|
EXPECT_FLOAT_EQ(result.x, 2.0f);
|
|
EXPECT_FLOAT_EQ(result.y, 4.0f);
|
|
EXPECT_FLOAT_EQ(result.z, 6.0f);
|
|
}
|
|
|
|
// Test AsTuple method
|
|
TEST_F(UnitTestVector3, AsTuple)
|
|
{
|
|
const auto tuple = v1.as_tuple();
|
|
EXPECT_FLOAT_EQ(std::get<0>(tuple), v1.x);
|
|
EXPECT_FLOAT_EQ(std::get<1>(tuple), v1.y);
|
|
EXPECT_FLOAT_EQ(std::get<2>(tuple), v1.z);
|
|
}
|
|
|
|
// Test AsTuple method
|
|
TEST_F(UnitTestVector3, AngleBeatween)
|
|
{
|
|
EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).angle_between({1, 0 ,0}).value().as_degrees(), 90.0f);
|
|
EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).angle_between({0.0f, 0.0f, 1.0f}).value().as_degrees(), 0.0f);
|
|
EXPECT_FALSE(Vector3(0.0f, 0.0f, 0.0f).angle_between({0.0f, 0.0f, 1.0f}).has_value());
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, IsPerpendicular)
|
|
{
|
|
EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).is_perpendicular({1, 0 ,0}), true);
|
|
EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).is_perpendicular({0.0f, 0.0f, 1.0f}), false);
|
|
EXPECT_FALSE(Vector3(0.0f, 0.0f, 0.0f).is_perpendicular({0.0f, 0.0f, 1.0f}));
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, LessOperator)
|
|
{
|
|
EXPECT_TRUE(v1 < v2);
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, GreaterOperator)
|
|
{
|
|
EXPECT_TRUE(v2 > v1);
|
|
}
|
|
TEST_F(UnitTestVector3, LessEqualOperator)
|
|
{
|
|
EXPECT_TRUE(omath::Vector3<float>{} <= omath::Vector3<float>{});
|
|
EXPECT_TRUE(omath::Vector3<float>{} <= omath::Vector3(1.f, 1.f, 1.f));
|
|
}
|
|
|
|
TEST_F(UnitTestVector3, GreaterEqualOperator)
|
|
{
|
|
EXPECT_TRUE(omath::Vector3<float>{} >= omath::Vector3<float>{});
|
|
EXPECT_TRUE(omath::Vector3(1.f, 1.f, 1.f) >= omath::Vector3<float>{});
|
|
}
|
|
|
|
// Static assertions (compile-time checks)
|
|
static_assert(Vector3(1.0f, 2.0f, 3.0f).length_sqr() == 14.0f, "LengthSqr should be 14");
|
|
static_assert(Vector3(1.0f, 2.0f, 3.0f).dot(Vector3(4.0f, 5.0f, 6.0f)) == 32.0f, "Dot product should be 32");
|
|
static_assert(Vector3(4.0f, 5.0f, 6.0f).distance_to_sqr(Vector3(1.0f, 2.0f, 3.0f)) == 27.0f, "DistToSqr should be 27");
|
|
static_assert(Vector3(-1.0f, -2.0f, -3.0f).abs() == Vector3(1.0f, 2.0f, 3.0f), "Abs should convert negative values to positive");
|