diff --git a/headers/enduro2d/math/_math.hpp b/headers/enduro2d/math/_math.hpp index 8ba7987c..8c6fe919 100644 --- a/headers/enduro2d/math/_math.hpp +++ b/headers/enduro2d/math/_math.hpp @@ -495,4 +495,21 @@ namespace e2d { namespace math constexpr std::underlying_type_t enum_to_number(E e) noexcept { return static_cast>(e); } + + // + // lerp/inverse_lerp + // + + template < typename T > + std::enable_if_t::value, T> + lerp(T l, T r, T v) noexcept { + return l + (r - l) * v; + } + + template < typename T > + std::enable_if_t::value, T> + inverse_lerp(T l, T r, T v) noexcept { + E2D_ASSERT(!is_near_zero(r - l, T(0))); + return (v - l) / (r - l); + } }} diff --git a/headers/enduro2d/math/rect.hpp b/headers/enduro2d/math/rect.hpp index 66343cbd..6378327d 100644 --- a/headers/enduro2d/math/rect.hpp +++ b/headers/enduro2d/math/rect.hpp @@ -233,6 +233,32 @@ namespace e2d { namespace math && min_l.y < max_r.y; } + // + // normalized_to_point/point_to_normalized + // + + template < typename T > + std::enable_if_t::value, vec2> + normalized_to_point(const rect& r, const vec2& p) noexcept { + const vec2 min = minimum(r); + const vec2 max = maximum(r); + return { + math::lerp(min.x, max.x, p.x), + math::lerp(min.y, max.y, p.y)}; + } + + template < typename T > + std::enable_if_t::value, vec2> + point_to_normalized(const rect& r, const vec2& p) noexcept { + E2D_ASSERT(!math::is_near_zero(r.size.x, T(0))); + E2D_ASSERT(!math::is_near_zero(r.size.y, T(0))); + const vec2 min = minimum(r); + const vec2 max = maximum(r); + return { + math::inverse_lerp(min.x, max.x, p.x), + math::inverse_lerp(min.y, max.y, p.y)}; + } + // // contains_nan // diff --git a/untests/sources/untests_math/rect.cpp b/untests/sources/untests_math/rect.cpp index fd343c47..9611846e 100644 --- a/untests/sources/untests_math/rect.cpp +++ b/untests/sources/untests_math/rect.cpp @@ -125,4 +125,39 @@ TEST_CASE("rect") { REQUIRE(math::contains_nan(r4f(1.f,std::numeric_limits::quiet_NaN()))); REQUIRE(math::contains_nan(r4f(std::numeric_limits::infinity(), 1.f))); } + { + REQUIRE(math::normalized_to_point(r4f(10.f, 20.f), v2f(0.f, 0.f)) == v2f(0.f, 0.f)); + REQUIRE(math::normalized_to_point(r4f(10.f, 20.f), v2f(0.5f, 0.5f)) == v2f(5.f, 10.f)); + REQUIRE(math::normalized_to_point(r4f(10.f, 20.f), v2f(0.25f, 0.75f)) == v2f(2.5f, 15.f)); + REQUIRE(math::normalized_to_point(r4f(10.f, 20.f), v2f(1.f, 1.f)) == v2f(10.f, 20.f)); + + REQUIRE(math::normalized_to_point(r4f(1.f, 2.f, 10.f, 20.f), v2f(0.f, 0.f)) == v2f(1.f, 2.f)); + REQUIRE(math::normalized_to_point(r4f(1.f, 2.f, 10.f, 20.f), v2f(0.5f, 0.5f)) == v2f(6.f, 12.f)); + REQUIRE(math::normalized_to_point(r4f(1.f, 2.f, 10.f, 20.f), v2f(0.25f, 0.75f)) == v2f(3.5f, 17.f)); + REQUIRE(math::normalized_to_point(r4f(1.f, 2.f, 10.f, 20.f), v2f(1.f, 1.f)) == v2f(11.f, 22.f)); + + REQUIRE(math::normalized_to_point(r4f(1.f, 2.f, -11.f, -22.f), v2f(0.f, 0.f)) == v2f(-10.f, -20.f)); + REQUIRE(math::normalized_to_point(r4f(1.f, 2.f, -11.f, -22.f), v2f(0.5f, 0.5f)) == v2f(-4.5f, -9.f)); + REQUIRE(math::normalized_to_point(r4f(1.f, 2.f, -11.f, -22.f), v2f(1.f, 1.f)) == v2f(1.f, 2.f)); + + REQUIRE(math::normalized_to_point(r4f(0.f,0.f), v2f(0.f,0.f)) == v2f(0.f,0.f)); + REQUIRE(math::normalized_to_point(r4f(0.f,0.f), v2f(1.f,1.f)) == v2f(0.f,0.f)); + REQUIRE(math::normalized_to_point(r4f(1.f,2.f,0.f,0.f), v2f(0.f,0.f)) == v2f(1.f,2.f)); + REQUIRE(math::normalized_to_point(r4f(1.f,2.f,0.f,0.f), v2f(1.f,1.f)) == v2f(1.f,2.f)); + } + { + REQUIRE(math::point_to_normalized(r4f(10.f, 20.f), v2f(0.f, 0.f)) == v2f(0.f, 0.f)); + REQUIRE(math::point_to_normalized(r4f(10.f, 20.f), v2f(5.f, 10.f)) == v2f(0.5f,0.5f)); + REQUIRE(math::point_to_normalized(r4f(10.f, 20.f), v2f(2.5f, 15.f)) == v2f(0.25f, 0.75f)); + REQUIRE(math::point_to_normalized(r4f(10.f, 20.f), v2f(10.f, 20.f)) == v2f(1.f, 1.f)); + + REQUIRE(math::point_to_normalized(r4f(1.f, 2.f, 10.f, 20.f), v2f(1.f, 2.f)) == v2f(0.f, 0.f)); + REQUIRE(math::point_to_normalized(r4f(1.f, 2.f, 10.f, 20.f), v2f(6.f, 12.f)) == v2f(0.5f, 0.5f)); + REQUIRE(math::point_to_normalized(r4f(1.f, 2.f, 10.f, 20.f), v2f(3.5f, 17.f)) == v2f(0.25f, 0.75f)); + REQUIRE(math::point_to_normalized(r4f(1.f, 2.f, 10.f, 20.f), v2f(11.f, 22.f)) == v2f(1.f, 1.f)); + + REQUIRE(math::point_to_normalized(r4f(1.f, 2.f, -11.f, -22.f), v2f(-10.f, -20.f)) == v2f(0.f, 0.f)); + REQUIRE(math::point_to_normalized(r4f(1.f, 2.f, -11.f, -22.f), v2f(-4.5f, -9.f)) == v2f(0.5f, 0.5f)); + REQUIRE(math::point_to_normalized(r4f(1.f, 2.f, -11.f, -22.f), v2f(1.f, 2.f)) == v2f(1.f, 1.f)); + } }