36[[nodiscard]]
inline std::function<float(glm::vec2)>
39 const float extent = horizontal ? bounds.
width() : bounds.
height();
40 const float span = extent - handle_extent;
41 const float origin = horizontal ? bounds.
min.x : bounds.
min.y;
42 const float half = handle_extent * 0.5F;
44 return [origin, half, span, horizontal](glm::vec2 p) ->
float {
47 const float pos = horizontal ? p.x : p.y;
48 return std::clamp((pos - origin - half) / span, 0.F, 1.F);
60[[nodiscard]]
inline std::function<glm::vec2(glm::vec2)>
63 const glm::vec2 origin = bounds.min;
64 const glm::vec2 extent { bounds.width(), bounds.height() };
66 return [origin, extent](glm::vec2 p) -> glm::vec2 {
67 if (extent.x <= 0.F || extent.y <= 0.F)
68 return glm::vec2(0.F);
69 return glm::clamp((p - origin) / extent, glm::vec2(0.F), glm::vec2(1.F));
89[[nodiscard]]
inline std::function<float(glm::vec2)>
92 const float delta = angle_end - angle_start;
94 return [center, angle_start, delta](glm::vec2 p) ->
float {
95 constexpr float k_two_pi = 6.283185307179586F;
97 if (std::abs(delta) < 1e-6F)
100 const glm::vec2 d = p - center;
101 if (glm::dot(d, d) < 1e-12F)
104 float rel = std::fmod(std::atan2(d.y, d.x) - angle_start, k_two_pi);
105 if (delta > 0.F && rel < 0.F) {
107 }
else if (delta < 0.F && rel > 0.F) {
111 return std::clamp(rel / delta, 0.F, 1.F);
121[[nodiscard]]
inline std::function<float(glm::vec2)>
142[[nodiscard]]
inline std::function<float(glm::vec2)>
145 std::vector<glm::vec2> pts(
points.begin(),
points.end());
146 std::vector<float> cumulative(pts.size(), 0.F);
148 for (
size_t i = 1; i < pts.size(); ++i)
149 cumulative[i] = cumulative[i - 1] + glm::length(pts[i] - pts[i - 1]);
151 const float total = pts.empty() ? 0.F : cumulative.back();
153 return [pts = std::move(pts), cumulative = std::move(cumulative), total](
154 glm::vec2 p) ->
float {
155 if (pts.size() < 2 || total <= 0.F)
158 float best_d2 = std::numeric_limits<float>::max();
161 for (
size_t i = 0; i + 1 < pts.size(); ++i) {
162 const glm::vec2
a = pts[i];
163 const glm::vec2 ab = pts[i + 1] -
a;
164 const float len2 = glm::dot(ab, ab);
166 const float t = len2 > 1e-12F
167 ? glm::clamp(glm::dot(p -
a, ab) / len2, 0.F, 1.F)
170 const glm::vec2 diff = p - (
a + t * ab);
171 const float d2 = glm::dot(diff, diff);
175 best_s = cumulative[i] + t * std::sqrt(len2);
179 return std::clamp(best_s / total, 0.F, 1.F);
194[[nodiscard]]
inline std::function<float(glm::vec2)>
195scaled(std::function<
float(glm::vec2)> norm,
float lo,
float hi)
197 return [norm = std::move(norm),
lo,
hi](glm::vec2 p) ->
float {
198 return lo + norm(p) * (
hi -
lo);
std::vector< glm::vec2 > * points
std::function< float(glm::vec2)> scaled(std::function< float(glm::vec2)> norm, float lo, float hi)
Rescale a normalized projection onto an arbitrary range.
std::function< float(glm::vec2)> path_fraction(std::span< const glm::vec2 > points)
Normalized arc-length position of the closest point on a polyline.
std::function< float(glm::vec2)> angle_fraction(glm::vec2 center, float angle_start, float angle_end) noexcept
Fraction along an angular sweep about center.
std::function< glm::vec2(glm::vec2)> unit_square(AABB2D bounds) noexcept
Unit-square coordinates of a point within bounds.
std::function< float(glm::vec2)> axis_fraction(AABB2D bounds, float handle_extent=0.F, bool horizontal=true) noexcept
Fraction along one axis of bounds, inverse to fader placement.
float height() const noexcept
float width() const noexcept
Axis-aligned bounding rectangle in a 2D coordinate space.