mirror of
https://github.com/slendidev/smath.git
synced 2025-12-08 03:49:52 +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 <cstddef>
|
||||
#include <format>
|
||||
#include <numbers>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef SMATH_ANGLE_UNIT
|
||||
#define SMATH_ANGLE_UNIT rad
|
||||
#endif // SMATH_ANGLE_UNIT
|
||||
|
||||
namespace smath {
|
||||
|
||||
template <std::size_t N, typename T>
|
||||
@@ -35,6 +41,38 @@ struct Vec;
|
||||
|
||||
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 {
|
||||
char data[N]{};
|
||||
static constexpr std::size_t size = N - 1;
|
||||
@@ -401,6 +439,42 @@ using Vec2d = Vec<2, double>;
|
||||
using Vec3d = Vec<3, 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
|
||||
|
||||
template <std::size_t N, typename T>
|
||||
@@ -435,4 +509,5 @@ struct tuple_element<I, smath::Vec<N, T>> {
|
||||
static_assert(I < N);
|
||||
using type = T;
|
||||
};
|
||||
|
||||
} // 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