48[[nodiscard]]
inline std::function<float(glm::vec2)>
50 const std::function<glm::vec2()>& live_offset = {})
noexcept
52 const float extent = horizontal ? bounds.
width() : bounds.
height();
53 const float span = extent - handle_extent;
54 const float origin = horizontal ? bounds.
min.x : bounds.
min.y;
55 const float half = handle_extent * 0.5F;
57 return [origin, half, span, horizontal, live_offset](glm::vec2 p) ->
float {
60 const float shift = live_offset ? (horizontal ? live_offset().x : live_offset().y) : 0.F;
61 const float pos = (horizontal ? p.x : p.y) - shift;
62 return std::clamp((pos - origin - half) / span, 0.F, 1.F);
75[[nodiscard]]
inline std::function<glm::vec2(glm::vec2)>
78 const glm::vec2 origin = bounds.
min;
79 const glm::vec2 extent { bounds.
width(), bounds.
height() };
81 return [origin, extent, live_offset](glm::vec2 p) -> glm::vec2 {
82 if (extent.x <= 0.F || extent.y <= 0.F)
83 return glm::vec2(0.F);
84 const glm::vec2 shift = live_offset ? live_offset() : glm::vec2(0.F);
85 return glm::clamp((p - shift - origin) / extent, glm::vec2(0.F), glm::vec2(1.F));
110[[nodiscard]]
inline std::function<float(glm::vec2)>
112 const std::function<glm::vec2()>& live_offset = {})
noexcept
114 const float delta = angle_end - angle_start;
116 return [center, angle_start, delta, live_offset](glm::vec2 p) ->
float {
117 constexpr float k_two_pi = 6.283185307179586F;
119 if (std::abs(delta) < 1e-6F)
122 const glm::vec2 shift = live_offset ? live_offset() : glm::vec2(0.F);
123 const glm::vec2 d = (p - shift) - center;
124 if (glm::dot(d, d) < 1e-12F)
127 float rel = std::fmod(std::atan2(d.y, d.x) - angle_start, k_two_pi);
128 if (delta > 0.F && rel < 0.F) {
130 }
else if (delta < 0.F && rel > 0.F) {
134 const float travelled = std::abs(rel);
135 const float sweep = std::abs(delta);
136 const float gap = k_two_pi - sweep;
137 if (travelled <= sweep || gap <= 0.F)
138 return std::clamp(travelled / sweep, 0.F, 1.F);
140 return (travelled - sweep) < gap * 0.5F ? 1.F : 0.F;
150[[nodiscard]]
inline std::function<float(glm::vec2)>
152 const std::function<glm::vec2()>& live_offset = {})
noexcept
175[[nodiscard]]
inline std::function<float(glm::vec2)>
178 std::vector<glm::vec2> pts(
points.begin(),
points.end());
179 std::vector<float> cumulative(pts.size(), 0.F);
181 for (
size_t i = 1; i < pts.size(); ++i)
182 cumulative[i] = cumulative[i - 1] + glm::length(pts[i] - pts[i - 1]);
184 const float total = pts.empty() ? 0.F : cumulative.back();
186 return [pts = std::move(pts), cumulative = std::move(cumulative),
total, live_offset](
187 glm::vec2 p) ->
float {
188 if (pts.size() < 2 ||
total <= 0.F)
191 const glm::vec2 shift = live_offset ? live_offset() : glm::vec2(0.F);
192 const glm::vec2
q = p - shift;
194 float best_d2 = std::numeric_limits<float>::max();
197 for (
size_t i = 0; i + 1 < pts.size(); ++i) {
198 const glm::vec2
a = pts[i];
199 const glm::vec2 ab = pts[i + 1] -
a;
200 const float len2 = glm::dot(ab, ab);
202 const float t = len2 > 1e-12F
203 ? glm::clamp(glm::dot(
q -
a, ab) / len2, 0.F, 1.F)
206 const glm::vec2 diff =
q - (
a + t * ab);
207 const float d2 = glm::dot(diff, diff);
211 best_s = cumulative[i] + t * std::sqrt(len2);
215 return std::clamp(best_s /
total, 0.F, 1.F);
230[[nodiscard]]
inline std::function<float(glm::vec2)>
231scaled(std::function<
float(glm::vec2)> norm,
float lo,
float hi)
233 return [norm = std::move(norm), lo, hi](glm::vec2 p) ->
float {
234 return lo + norm(p) * (hi - lo);
std::vector< glm::vec2 > * points
std::function< glm::vec2(glm::vec2)> unit_square(AABB2D bounds, const std::function< glm::vec2()> &live_offset={}) noexcept
Unit-square coordinates of a point within bounds.
std::function< float(glm::vec2)> path_fraction(std::span< const glm::vec2 > points, const std::function< glm::vec2()> &live_offset={})
Normalized arc-length position of the closest point on a polyline.
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)> angle_fraction(glm::vec2 center, float angle_start, float angle_end, const std::function< glm::vec2()> &live_offset={}) noexcept
Fraction along an angular sweep about center.
std::function< float(glm::vec2)> axis_fraction(AABB2D bounds, float handle_extent=0.F, bool horizontal=true, const std::function< glm::vec2()> &live_offset={}) noexcept
Fraction along one axis of bounds, inverse to fader placement.
float height() const noexcept
glm::vec2 center() const noexcept
float width() const noexcept
Axis-aligned bounding rectangle in a 2D coordinate space.