From 580f39210ed643b8bd313d3cbb9e75629fd67d9e Mon Sep 17 00:00:00 2001 From: Orange Date: Sun, 26 Apr 2026 02:14:14 +0300 Subject: [PATCH] added typecasting for vectors --- include/omath/linear_algebra/vector2.hpp | 6 ++ include/omath/linear_algebra/vector3.hpp | 7 +++ include/omath/linear_algebra/vector4.hpp | 9 +++ tests/general/unit_test_vector2.cpp | 58 +++++++++++++++++++ tests/general/unit_test_vector3.cpp | 65 +++++++++++++++++++++ tests/general/unit_test_vector4.cpp | 74 ++++++++++++++++++++++++ 6 files changed, 219 insertions(+) diff --git a/include/omath/linear_algebra/vector2.hpp b/include/omath/linear_algebra/vector2.hpp index 51d3079..4462239 100644 --- a/include/omath/linear_algebra/vector2.hpp +++ b/include/omath/linear_algebra/vector2.hpp @@ -26,6 +26,12 @@ namespace omath // Constructors constexpr Vector2() = default; + template + requires std::is_arithmetic_v + [[nodiscard]] constexpr explicit operator Vector2() const noexcept + { + return {static_cast(x), static_cast(y)}; + } constexpr Vector2(const Type& x, const Type& y) noexcept: x(x), y(y) { } diff --git a/include/omath/linear_algebra/vector3.hpp b/include/omath/linear_algebra/vector3.hpp index 2845ff7..18f921b 100644 --- a/include/omath/linear_algebra/vector3.hpp +++ b/include/omath/linear_algebra/vector3.hpp @@ -30,6 +30,13 @@ namespace omath } constexpr Vector3() noexcept: Vector2() {}; + template + requires std::is_arithmetic_v + [[nodiscard]] constexpr explicit operator Vector3() const noexcept + { + return {static_cast(this->x), static_cast(this->y), + static_cast(this->z)}; + } [[nodiscard]] constexpr bool operator==(const Vector3& other) const noexcept { return Vector2::operator==(other) && (other.z == z); diff --git a/include/omath/linear_algebra/vector4.hpp b/include/omath/linear_algebra/vector4.hpp index 14e2067..bc20221 100644 --- a/include/omath/linear_algebra/vector4.hpp +++ b/include/omath/linear_algebra/vector4.hpp @@ -21,6 +21,15 @@ namespace omath } constexpr Vector4() noexcept: Vector3(), w(static_cast(0)) {}; + + template + requires std::is_arithmetic_v + [[nodiscard]] constexpr explicit operator Vector4() const noexcept + { + return {static_cast(this->x), static_cast(this->y), + static_cast(this->z), static_cast(this->w)}; + } + [[nodiscard]] constexpr bool operator==(const Vector4& other) const noexcept { diff --git a/tests/general/unit_test_vector2.cpp b/tests/general/unit_test_vector2.cpp index 1aeb7cd..2ac830a 100644 --- a/tests/general/unit_test_vector2.cpp +++ b/tests/general/unit_test_vector2.cpp @@ -368,6 +368,64 @@ TEST_F(UnitTestVector2, GreaterEqualOperator) } +// ── Cast operator tests ────────────────────────────────────────────────────── + +TEST(Vector2Cast, FloatToDouble) +{ + constexpr Vector2 v{1.5f, -2.5f}; + constexpr auto result = static_cast>(v); + EXPECT_DOUBLE_EQ(result.x, 1.5); + EXPECT_DOUBLE_EQ(result.y, -2.5); +} + +TEST(Vector2Cast, DoubleToFloat) +{ + constexpr Vector2 v{1.25, -3.75}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, 1.25f); + EXPECT_FLOAT_EQ(result.y, -3.75f); +} + +TEST(Vector2Cast, FloatToInt_Truncates) +{ + constexpr Vector2 v{3.9f, -2.1f}; + constexpr auto result = static_cast>(v); + EXPECT_EQ(result.x, 3); + EXPECT_EQ(result.y, -2); +} + +TEST(Vector2Cast, IntToFloat_Exact) +{ + constexpr Vector2 v{7, -4}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, 7.f); + EXPECT_FLOAT_EQ(result.y, -4.f); +} + +TEST(Vector2Cast, ZeroPreserved) +{ + constexpr Vector2 v{0.f, 0.f}; + constexpr auto result = static_cast>(v); + EXPECT_DOUBLE_EQ(result.x, 0.0); + EXPECT_DOUBLE_EQ(result.y, 0.0); +} + +TEST(Vector2Cast, NegativeValues) +{ + constexpr Vector2 v{-100.0, -200.0}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, -100.f); + EXPECT_FLOAT_EQ(result.y, -200.f); +} + +TEST(Vector2Cast, SameTypeRoundtrip) +{ + constexpr Vector2 v{1.f, 2.f}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, v.x); + EXPECT_FLOAT_EQ(result.y, v.y); +} + // Static assertions (compile-time checks) static_assert(Vector2(1.0f, 2.0f).length_sqr() == 5.0f, "LengthSqr should be 5"); static_assert(Vector2(1.0f, 2.0f).dot(Vector2(4.0f, 5.0f)) == 14.0f, "Dot product should be 14"); diff --git a/tests/general/unit_test_vector3.cpp b/tests/general/unit_test_vector3.cpp index 492033b..12f9761 100644 --- a/tests/general/unit_test_vector3.cpp +++ b/tests/general/unit_test_vector3.cpp @@ -480,6 +480,71 @@ TEST_F(UnitTestVector3, GreaterEqualOperator) EXPECT_TRUE(omath::Vector3(1.f, 1.f, 1.f) >= omath::Vector3{}); } +// ── Cast operator tests ────────────────────────────────────────────────────── + +TEST(Vector3Cast, FloatToDouble) +{ + constexpr Vector3 v{1.5f, -2.5f, 3.0f}; + constexpr auto result = static_cast>(v); + EXPECT_DOUBLE_EQ(result.x, 1.5); + EXPECT_DOUBLE_EQ(result.y, -2.5); + EXPECT_DOUBLE_EQ(result.z, 3.0); +} + +TEST(Vector3Cast, DoubleToFloat) +{ + constexpr Vector3 v{1.25, -3.75, 0.5}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, 1.25f); + EXPECT_FLOAT_EQ(result.y, -3.75f); + EXPECT_FLOAT_EQ(result.z, 0.5f); +} + +TEST(Vector3Cast, FloatToInt_Truncates) +{ + constexpr Vector3 v{3.9f, -2.1f, 7.7f}; + constexpr auto result = static_cast>(v); + EXPECT_EQ(result.x, 3); + EXPECT_EQ(result.y, -2); + EXPECT_EQ(result.z, 7); +} + +TEST(Vector3Cast, IntToFloat_Exact) +{ + constexpr Vector3 v{7, -4, 0}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, 7.f); + EXPECT_FLOAT_EQ(result.y, -4.f); + EXPECT_FLOAT_EQ(result.z, 0.f); +} + +TEST(Vector3Cast, ZeroPreserved) +{ + constexpr Vector3 v{0.f, 0.f, 0.f}; + constexpr auto result = static_cast>(v); + EXPECT_DOUBLE_EQ(result.x, 0.0); + EXPECT_DOUBLE_EQ(result.y, 0.0); + EXPECT_DOUBLE_EQ(result.z, 0.0); +} + +TEST(Vector3Cast, NegativeValues) +{ + constexpr Vector3 v{-100.0, -200.0, -300.0}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, -100.f); + EXPECT_FLOAT_EQ(result.y, -200.f); + EXPECT_FLOAT_EQ(result.z, -300.f); +} + +TEST(Vector3Cast, SameTypeRoundtrip) +{ + constexpr Vector3 v{1.f, 2.f, 3.f}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, v.x); + EXPECT_FLOAT_EQ(result.y, v.y); + EXPECT_FLOAT_EQ(result.z, v.z); +} + // 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"); diff --git a/tests/general/unit_test_vector4.cpp b/tests/general/unit_test_vector4.cpp index ad777a7..69e4ea6 100644 --- a/tests/general/unit_test_vector4.cpp +++ b/tests/general/unit_test_vector4.cpp @@ -260,4 +260,78 @@ TEST_F(UnitTestVector4, GreaterEqualOperator) { EXPECT_TRUE(omath::Vector4{} >= omath::Vector4{}); EXPECT_TRUE(omath::Vector4(1.f, 1.f, 1.f, 1.f) >= omath::Vector4{}); +} + +// ── Cast operator tests ────────────────────────────────────────────────────── + +using namespace omath; + +TEST(Vector4Cast, FloatToDouble) +{ + constexpr Vector4 v{1.5f, -2.5f, 3.0f, 4.25f}; + constexpr auto result = static_cast>(v); + EXPECT_DOUBLE_EQ(result.x, 1.5); + EXPECT_DOUBLE_EQ(result.y, -2.5); + EXPECT_DOUBLE_EQ(result.z, 3.0); + EXPECT_DOUBLE_EQ(result.w, 4.25); +} + +TEST(Vector4Cast, DoubleToFloat) +{ + constexpr Vector4 v{1.25, -3.75, 0.5, -0.125}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, 1.25f); + EXPECT_FLOAT_EQ(result.y, -3.75f); + EXPECT_FLOAT_EQ(result.z, 0.5f); + EXPECT_FLOAT_EQ(result.w, -0.125f); +} + +TEST(Vector4Cast, FloatToInt_Truncates) +{ + constexpr Vector4 v{3.9f, -2.1f, 7.7f, -0.9f}; + constexpr auto result = static_cast>(v); + EXPECT_EQ(result.x, 3); + EXPECT_EQ(result.y, -2); + EXPECT_EQ(result.z, 7); + EXPECT_EQ(result.w, 0); +} + +TEST(Vector4Cast, IntToFloat_Exact) +{ + constexpr Vector4 v{7, -4, 0, 1}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, 7.f); + EXPECT_FLOAT_EQ(result.y, -4.f); + EXPECT_FLOAT_EQ(result.z, 0.f); + EXPECT_FLOAT_EQ(result.w, 1.f); +} + +TEST(Vector4Cast, ZeroPreserved) +{ + constexpr Vector4 v{0.f, 0.f, 0.f, 0.f}; + constexpr auto result = static_cast>(v); + EXPECT_DOUBLE_EQ(result.x, 0.0); + EXPECT_DOUBLE_EQ(result.y, 0.0); + EXPECT_DOUBLE_EQ(result.z, 0.0); + EXPECT_DOUBLE_EQ(result.w, 0.0); +} + +TEST(Vector4Cast, NegativeValues) +{ + constexpr Vector4 v{-100.0, -200.0, -300.0, -400.0}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, -100.f); + EXPECT_FLOAT_EQ(result.y, -200.f); + EXPECT_FLOAT_EQ(result.z, -300.f); + EXPECT_FLOAT_EQ(result.w, -400.f); +} + +TEST(Vector4Cast, SameTypeRoundtrip) +{ + constexpr Vector4 v{1.f, 2.f, 3.f, 4.f}; + constexpr auto result = static_cast>(v); + EXPECT_FLOAT_EQ(result.x, v.x); + EXPECT_FLOAT_EQ(result.y, v.y); + EXPECT_FLOAT_EQ(result.z, v.z); + EXPECT_FLOAT_EQ(result.w, v.w); } \ No newline at end of file