diff --git a/openVulkanoCpp/Math/CoordinateSystem.hpp b/openVulkanoCpp/Math/CoordinateSystem.hpp new file mode 100644 index 0000000..5ff705b --- /dev/null +++ b/openVulkanoCpp/Math/CoordinateSystem.hpp @@ -0,0 +1,65 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Math.hpp" +#include +#include + +namespace OpenVulkano::Math +{ + class CoordinateSystem final + { + public: + enum System: uint8_t + { + RIGHT_HANDED_Y_UP = 0, + RIGHT_HANDED_Z_UP, + LEFT_HANDED_Y_UP, + LEFT_HANDED_Z_UP + }; + + enum class Handedness: uint8_t { Right = 0, Left }; + + enum class UpAxis: uint8_t { Y, Z }; + + constexpr CoordinateSystem(System system = RIGHT_HANDED_Y_UP): m_system(system) {} + + constexpr CoordinateSystem(Handedness handedness, UpAxis up): m_system(static_cast(static_cast(handedness) << 1 | static_cast(up))) {} + + [[nodiscard]] constexpr std::string_view GetName() const + { + return magic_enum::enum_name(m_system); + } + + [[nodiscard]] constexpr static std::optional GetFromName(std::string_view name) + { + auto result = magic_enum::enum_cast(name); + if (result.has_value()) return CoordinateSystem(result.value()); + return {}; + } + + [[nodiscard]] constexpr Handedness GetHandedness() const { return static_cast(m_system >> 1); } + + [[nodiscard]] constexpr UpAxis GetUpAxis() const { return static_cast(m_system & 1); } + + [[nodiscard]] constexpr operator System() const { return m_system; } + + [[nodiscard]] constexpr operator Handedness() const { return GetHandedness(); } + + [[nodiscard]] constexpr operator UpAxis() const { return GetUpAxis(); } + + [[nodiscard]] constexpr auto operator <=>(const CoordinateSystem& other) const { return m_system <=> other.m_system; } + [[nodiscard]] constexpr auto operator <=>(const System& other) const { return m_system <=> other; } + + [[nodiscard]] constexpr bool operator ==(const CoordinateSystem& other) const { return m_system == other.m_system; } + [[nodiscard]] constexpr bool operator ==(const System& other) const { return m_system == other; } + + private: + System m_system; + }; +} \ No newline at end of file diff --git a/tests/Math/CoordinateSystemTest.cpp b/tests/Math/CoordinateSystemTest.cpp new file mode 100644 index 0000000..ca25b58 --- /dev/null +++ b/tests/Math/CoordinateSystemTest.cpp @@ -0,0 +1,108 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "Math/CoordinateSystem.hpp" +#include + +using namespace OpenVulkano::Math; +using Catch::Approx; + +TEST_CASE("CoordinateSystem - Construction", "[CoordinateSystem]") +{ + SECTION("Default constructor creates RIGHT_HANDED_Y_UP") + { + CoordinateSystem cs; + REQUIRE(cs == CoordinateSystem::RIGHT_HANDED_Y_UP); + REQUIRE(cs.GetHandedness() == CoordinateSystem::Handedness::Right); + REQUIRE(cs.GetUpAxis() == CoordinateSystem::UpAxis::Y); + } + + SECTION("Construct from System enum") + { + CoordinateSystem cs1(CoordinateSystem::RIGHT_HANDED_Y_UP); + REQUIRE(cs1.GetHandedness() == CoordinateSystem::Handedness::Right); + REQUIRE(cs1.GetUpAxis() == CoordinateSystem::UpAxis::Y); + + CoordinateSystem cs2(CoordinateSystem::RIGHT_HANDED_Z_UP); + REQUIRE(cs2.GetHandedness() == CoordinateSystem::Handedness::Right); + REQUIRE(cs2.GetUpAxis() == CoordinateSystem::UpAxis::Z); + + CoordinateSystem cs3(CoordinateSystem::LEFT_HANDED_Y_UP); + REQUIRE(cs3.GetHandedness() == CoordinateSystem::Handedness::Left); + REQUIRE(cs3.GetUpAxis() == CoordinateSystem::UpAxis::Y); + + CoordinateSystem cs4(CoordinateSystem::LEFT_HANDED_Z_UP); + REQUIRE(cs4.GetHandedness() == CoordinateSystem::Handedness::Left); + REQUIRE(cs4.GetUpAxis() == CoordinateSystem::UpAxis::Z); + } + + SECTION("Construct from Handedness and UpAxis") + { + CoordinateSystem cs1(CoordinateSystem::Handedness::Right, CoordinateSystem::UpAxis::Y); + REQUIRE(cs1 == CoordinateSystem::RIGHT_HANDED_Y_UP); + + CoordinateSystem cs2(CoordinateSystem::Handedness::Right, CoordinateSystem::UpAxis::Z); + REQUIRE(cs2 == CoordinateSystem::RIGHT_HANDED_Z_UP); + + CoordinateSystem cs3(CoordinateSystem::Handedness::Left, CoordinateSystem::UpAxis::Y); + REQUIRE(cs3 == CoordinateSystem::LEFT_HANDED_Y_UP); + + CoordinateSystem cs4(CoordinateSystem::Handedness::Left, CoordinateSystem::UpAxis::Z); + REQUIRE(cs4 == CoordinateSystem::LEFT_HANDED_Z_UP); + } +} + +TEST_CASE("CoordinateSystem - Name conversion", "[CoordinateSystem]") +{ + SECTION("GetName returns correct string representation") + { + REQUIRE(CoordinateSystem(CoordinateSystem::RIGHT_HANDED_Y_UP).GetName() == "RIGHT_HANDED_Y_UP"); + REQUIRE(CoordinateSystem(CoordinateSystem::RIGHT_HANDED_Z_UP).GetName() == "RIGHT_HANDED_Z_UP"); + REQUIRE(CoordinateSystem(CoordinateSystem::LEFT_HANDED_Y_UP).GetName() == "LEFT_HANDED_Y_UP"); + REQUIRE(CoordinateSystem(CoordinateSystem::LEFT_HANDED_Z_UP).GetName() == "LEFT_HANDED_Z_UP"); + } + + SECTION("GetFromName parses valid names") + { + auto cs1 = CoordinateSystem::GetFromName("RIGHT_HANDED_Y_UP"); + REQUIRE(cs1.has_value()); + REQUIRE(cs1.value() == CoordinateSystem::RIGHT_HANDED_Y_UP); + + auto cs2 = CoordinateSystem::GetFromName("LEFT_HANDED_Z_UP"); + REQUIRE(cs2.has_value()); + REQUIRE(cs2.value() == CoordinateSystem::LEFT_HANDED_Z_UP); + } + + SECTION("GetFromName returns nullopt for invalid names") + { + REQUIRE_FALSE(CoordinateSystem::GetFromName("INVALID_NAME").has_value()); + REQUIRE_FALSE(CoordinateSystem::GetFromName("").has_value()); + REQUIRE_FALSE(CoordinateSystem::GetFromName("right_handed_y_up").has_value()); + } +} + +TEST_CASE("CoordinateSystem - Conversion operators", "[CoordinateSystem]") +{ + CoordinateSystem cs(CoordinateSystem::LEFT_HANDED_Z_UP); + + SECTION("Convert to System") + { + CoordinateSystem::System sys = cs; + REQUIRE(sys == CoordinateSystem::LEFT_HANDED_Z_UP); + } + + SECTION("Convert to Handedness") + { + CoordinateSystem::Handedness hand = cs; + REQUIRE(hand == CoordinateSystem::Handedness::Left); + } + + SECTION("Convert to UpAxis") + { + CoordinateSystem::UpAxis up = cs; + REQUIRE(up == CoordinateSystem::UpAxis::Z); + } +} \ No newline at end of file