110T arc_length(
const parametric_curve<CurveT<fvec<T, N>>>& curve, T t = T(1),
int num_segments = 128) {
139 num_samples = std::max(num_samples, 2);
143 T step = T(1) /
static_cast<T
>(num_samples - 1);
146 for(
int i = 1; i < num_samples; ++i) {
147 T t_ =
static_cast<T
>(i) * step;
150 prev_point = next_point;
153 _lengths.
domain = { T(0), T(1) };
156 T evaluate(T t)
const {
160 T total_length()
const {
164 const std::vector<T>& lengths()
const {
179 num_segments = std::max(num_segments, 1);
180 num_segment_subdivisions = std::max(num_segment_subdivisions, 1);
181 int num_samples = 3 * num_segments * num_segment_subdivisions;
183 std::vector<T> arc_lengths;
184 T t_step = T(1) /
static_cast<T
>(num_samples);
185 int next_save_index = num_segment_subdivisions - 1;
188 for(
int i = 0; i < num_samples; ++i) {
189 T t =
static_cast<T
>(i + 1) * t_step;
191 _total_length += length(next_point - prev_point);
193 if(i == next_save_index) {
194 arc_lengths.push_back(_total_length);
195 next_save_index += num_segment_subdivisions;
198 prev_point = next_point;
201 _lengths.push_back(T(0));
203 for(
int i = 0; i < num_segments; ++i) {
204 auto d_prev = _lengths.back();
205 auto d_curr = arc_lengths[3 * i + 2];
206 auto d_diff = d_curr - d_prev;
208 if(std::abs(d_diff) < std::numeric_limits<T>::epsilon()) {
212 auto s1_over_3 = arc_lengths[3 * i];
213 auto s1_over_3_scaled = (s1_over_3 - d_prev) / d_diff;
215 auto s2_over_3 = arc_lengths[3 * i + 1];
216 auto s2_over_3_scaled = (s2_over_3 - d_prev) / d_diff;
218 auto y1 = (T(18) * s1_over_3_scaled - T(9) * s2_over_3_scaled + T(2)) / T(6);
219 auto y2 = (T(-9) * s1_over_3_scaled + T(18) * s2_over_3_scaled - T(5)) / T(6);
224 _lengths.push_back(d_curr);
228 T evaluate(T t)
const {
233 return _total_length;
235 T num_segments =
static_cast<T
>(_y1.size());
236 size_t index =
static_cast<size_t>(t * num_segments);
237 auto t_step = T(1) / num_segments;
238 auto t_prev =
static_cast<T
>(index) * t_step;
239 auto t_curr =
static_cast<T
>(index + 1) * t_step;
240 auto t_diff = t_curr - t_prev;
242 auto x = (t - t_prev) / t_diff;
243 auto y = interpolate_cubic_bezier(T(0), _y1[index], _y2[index], T(1), x);
245 auto d_prev = _lengths[index];
246 auto d_curr = _lengths[index + 1];
247 auto d_diff = d_curr - d_prev;
249 return static_cast<T
>(y * d_diff + d_prev);
252 T total_length()
const {
253 return _total_length;
259 std::vector<T> _lengths;
260 T _total_length = T(0);
270 T evaluate(T d)
const {
274 auto it = std::lower_bound(_lengths.begin(), _lengths.end(), d);
275 if(it == _lengths.end())
279 T d_prev = *(it - 1);
281 T x = (d - d_prev) / (d_curr - d_prev);
283 T num_segments =
static_cast<T
>(_lengths.size() - 1);
284 size_t index = std::distance(_lengths.begin(), it);
285 T t_step = T(1) / num_segments;
286 T t_prev =
static_cast<T
>(index - 1) * t_step;
287 T t_curr =
static_cast<T
>(index) * t_step;
288 return interpolate_linear(t_prev, t_curr, x);
291 T total_length()
const {
292 return _lengths.back();
296 std::vector<T> _lengths;
305 num_samples = std::max(num_samples, 2);
308 int num_segments = num_samples - 1;
311 sequence_transform(std::back_inserter(_ts.
breakpoints), [¶m](T x) {
312 T d = param.total_length() * x;
313 return param.evaluate(d);
314 }, num_segments + 1);
316 _ts.
domain = { T(0), param.total_length() };
319 T evaluate(T d)
const {
323 T total_length()
const {
324 return _ts.
domain.upper_bound;
338 T evaluate(T d)
const {
341 for(
int i = 0; i < _depth; ++i) {
342 T t = (t0 + t1) / T(2);
343 auto l = _arc_length.evaluate(t);
352 T l0 = _arc_length.evaluate(t0);
353 T l1 = _arc_length.evaluate(t1);
354 T x = (d - l0) / (l1 - l0);
356 return interpolate_linear(t0, t1, x);
359 T total_length()
const {
360 return _arc_length.total_length();