mirror of
https://github.com/slendidev/smath.git
synced 2025-12-10 12:59:51 +02:00
Add angle conversion functions
Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
@@ -25,8 +25,14 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <numbers>
|
||||||
|
#include <optional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#ifndef SMATH_ANGLE_UNIT
|
||||||
|
#define SMATH_ANGLE_UNIT rad
|
||||||
|
#endif // SMATH_ANGLE_UNIT
|
||||||
|
|
||||||
namespace smath {
|
namespace smath {
|
||||||
|
|
||||||
template <std::size_t N, typename T>
|
template <std::size_t N, typename T>
|
||||||
@@ -35,6 +41,38 @@ struct Vec;
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
#define SMATH_STR(x) #x
|
||||||
|
#define SMATH_XSTR(x) SMATH_STR(x)
|
||||||
|
|
||||||
|
consteval bool streq(const char *a, const char *b) {
|
||||||
|
for (;; ++a, ++b) {
|
||||||
|
if (*a != *b)
|
||||||
|
return false;
|
||||||
|
if (*a == '\0')
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class AngularUnit {
|
||||||
|
Radians,
|
||||||
|
Degrees,
|
||||||
|
Turns,
|
||||||
|
};
|
||||||
|
|
||||||
|
consteval std::optional<AngularUnit> parse_unit(const char *s) {
|
||||||
|
if (streq(s, "rad"))
|
||||||
|
return AngularUnit::Radians;
|
||||||
|
if (streq(s, "deg"))
|
||||||
|
return AngularUnit::Degrees;
|
||||||
|
if (streq(s, "turns"))
|
||||||
|
return AngularUnit::Turns;
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto SMATH_ANGLE_UNIT_ID = parse_unit(SMATH_XSTR(SMATH_ANGLE_UNIT));
|
||||||
|
static_assert(SMATH_ANGLE_UNIT_ID != std::nullopt,
|
||||||
|
"Invalid SMATH_ANGLE_UNIT. Should be rad, deg, or turns.");
|
||||||
|
|
||||||
template <std::size_t N> struct FixedString {
|
template <std::size_t N> struct FixedString {
|
||||||
char data[N]{};
|
char data[N]{};
|
||||||
static constexpr std::size_t size = N - 1;
|
static constexpr std::size_t size = N - 1;
|
||||||
@@ -401,6 +439,42 @@ using Vec2d = Vec<2, double>;
|
|||||||
using Vec3d = Vec<3, double>;
|
using Vec3d = Vec<3, double>;
|
||||||
using Vec4d = Vec<4, double>;
|
using Vec4d = Vec<4, double>;
|
||||||
|
|
||||||
|
template <class T> constexpr auto deg(T const value) -> T {
|
||||||
|
if constexpr (detail::SMATH_ANGLE_UNIT_ID == detail::AngularUnit::Degrees) {
|
||||||
|
return value;
|
||||||
|
} else if constexpr (detail::SMATH_ANGLE_UNIT_ID ==
|
||||||
|
detail::AngularUnit::Radians) {
|
||||||
|
return value * static_cast<T>(std::numbers::pi / 180.0);
|
||||||
|
} else if constexpr (detail::SMATH_ANGLE_UNIT_ID ==
|
||||||
|
detail::AngularUnit::Turns) {
|
||||||
|
return value / static_cast<T>(360.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> constexpr auto rad(T const value) -> T {
|
||||||
|
if constexpr (detail::SMATH_ANGLE_UNIT_ID == detail::AngularUnit::Degrees) {
|
||||||
|
return value * static_cast<T>(180.0 / std::numbers::pi);
|
||||||
|
} else if constexpr (detail::SMATH_ANGLE_UNIT_ID ==
|
||||||
|
detail::AngularUnit::Radians) {
|
||||||
|
return value;
|
||||||
|
} else if constexpr (detail::SMATH_ANGLE_UNIT_ID ==
|
||||||
|
detail::AngularUnit::Turns) {
|
||||||
|
return value / (static_cast<T>(2.0) * static_cast<T>(std::numbers::pi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> constexpr auto turns(T const value) -> T {
|
||||||
|
if constexpr (detail::SMATH_ANGLE_UNIT_ID == detail::AngularUnit::Degrees) {
|
||||||
|
return value * static_cast<T>(360.0);
|
||||||
|
} else if constexpr (detail::SMATH_ANGLE_UNIT_ID ==
|
||||||
|
detail::AngularUnit::Radians) {
|
||||||
|
return value * (static_cast<T>(2.0) * static_cast<T>(std::numbers::pi));
|
||||||
|
} else if constexpr (detail::SMATH_ANGLE_UNIT_ID ==
|
||||||
|
detail::AngularUnit::Turns) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace smath
|
} // namespace smath
|
||||||
|
|
||||||
template <std::size_t N, typename T>
|
template <std::size_t N, typename T>
|
||||||
@@ -435,4 +509,5 @@ struct tuple_element<I, smath::Vec<N, T>> {
|
|||||||
static_assert(I < N);
|
static_assert(I < N);
|
||||||
using type = T;
|
using type = T;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|||||||
15
tests/angles.cpp
Normal file
15
tests/angles.cpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <smath.hpp>
|
||||||
|
|
||||||
|
TEST(AngleReturnRadians, DegInput) {
|
||||||
|
EXPECT_NEAR(smath::deg(180.0), std::numbers::pi, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AngleReturnRadians, RadInput) {
|
||||||
|
EXPECT_DOUBLE_EQ(smath::rad(std::numbers::pi), std::numbers::pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AngleReturnRadians, TurnsInput) {
|
||||||
|
EXPECT_NEAR(smath::turns(0.5), std::numbers::pi, 1e-12);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user