111T arc_length(
const parametric_curve<CurveT<fvec<T, N>>>& curve, T t = T(1),
int num_segments = 128) {
141 num_samples = std::max(num_samples, 2);
142 _lengths.values.reserve(num_samples);
143 _lengths.values.push_back(T(0));
145 T step = T(1) /
static_cast<T
>(num_samples - 1);
148 for(
int i = 1; i < num_samples; ++i) {
149 T t_ =
static_cast<T
>(i) * step;
151 _lengths.values.push_back(_lengths.values.back() + length(next_point - prev_point));
152 prev_point = next_point;
155 _lengths.domain = { T(0), T(1) };
158 T evaluate(T t)
const {
159 return _lengths.evaluate(t);
162 T total_length()
const {
163 return _lengths.values.back();
166 const std::vector<T>& lengths()
const {
167 return _lengths.values;
181 num_segments = std::max(num_segments, 1);
182 num_segment_subdivisions = std::max(num_segment_subdivisions, 1);
183 int num_samples = 3 * num_segments * num_segment_subdivisions;
185 std::vector<T> arc_lengths;
186 T t_step = T(1) /
static_cast<T
>(num_samples);
187 int next_save_index = num_segment_subdivisions - 1;
190 for(
int i = 0; i < num_samples; ++i) {
191 T t =
static_cast<T
>(i + 1) * t_step;
193 _total_length += length(next_point - prev_point);
195 if(i == next_save_index) {
196 arc_lengths.push_back(_total_length);
197 next_save_index += num_segment_subdivisions;
200 prev_point = next_point;
203 _lengths.push_back(T(0));
205 for(
int i = 0; i < num_segments; ++i) {
206 auto d_prev = _lengths.back();
207 auto d_curr = arc_lengths[3 * i + 2];
208 auto d_diff = d_curr - d_prev;
210 if(std::abs(d_diff) < std::numeric_limits<T>::epsilon()) {
214 auto s1_over_3 = arc_lengths[3 * i];
215 auto s1_over_3_scaled = (s1_over_3 - d_prev) / d_diff;
217 auto s2_over_3 = arc_lengths[3 * i + 1];
218 auto s2_over_3_scaled = (s2_over_3 - d_prev) / d_diff;
220 auto y1 = (T(18) * s1_over_3_scaled - T(9) * s2_over_3_scaled + T(2)) / T(6);
221 auto y2 = (T(-9) * s1_over_3_scaled + T(18) * s2_over_3_scaled - T(5)) / T(6);
226 _lengths.push_back(d_curr);
230 T evaluate(T t)
const {
235 return _total_length;
237 T num_segments =
static_cast<T
>(_y1.size());
238 size_t index =
static_cast<size_t>(t * num_segments);
239 auto t_step = T(1) / num_segments;
240 auto t_prev =
static_cast<T
>(index) * t_step;
241 auto t_curr =
static_cast<T
>(index + 1) * t_step;
242 auto t_diff = t_curr - t_prev;
244 auto x = (t - t_prev) / t_diff;
245 auto y = interpolate_cubic_bezier(T(0), _y1[index], _y2[index], T(1), x);
247 auto d_prev = _lengths[index];
248 auto d_curr = _lengths[index + 1];
249 auto d_diff = d_curr - d_prev;
251 return static_cast<T
>(y * d_diff + d_prev);
254 T total_length()
const {
255 return _total_length;
261 std::vector<T> _lengths;
262 T _total_length = T(0);
272 T evaluate(T d)
const {
276 auto it = std::lower_bound(_lengths.begin(), _lengths.end(), d);
277 if(it == _lengths.end())
281 T d_prev = *(it - 1);
283 T x = (d - d_prev) / (d_curr - d_prev);
285 T num_segments =
static_cast<T
>(_lengths.size() - 1);
286 size_t index = std::distance(_lengths.begin(), it);
287 T t_step = T(1) / num_segments;
288 T t_prev =
static_cast<T
>(index - 1) * t_step;
289 T t_curr =
static_cast<T
>(index) * t_step;
290 return interpolate_linear(t_prev, t_curr, x);
293 T total_length()
const {
294 return _lengths.back();
298 std::vector<T> _lengths;
307 num_samples = std::max(num_samples, 2);
308 _ts.values.reserve(num_samples);
310 int num_segments = num_samples - 1;
313 sample_steps_transform(std::back_inserter(_ts.values), [¶m](T x) {
314 T d = param.total_length() * x;
315 return param.evaluate(d);
318 _ts.domain = { T(0), param.total_length() };
321 T evaluate(T d)
const {
322 return _ts.evaluate(d);
325 T total_length()
const {
326 return _ts.domain.upper_bound;
340 T evaluate(T d)
const {
343 for(
int i = 0; i < _depth; ++i) {
344 T t = (t0 + t1) / T(2);
345 auto l = _arc_length.evaluate(t);
354 T l0 = _arc_length.evaluate(t0);
355 T l1 = _arc_length.evaluate(t1);
356 T x = (d - l0) / (l1 - l0);
358 return interpolate_linear(t0, t1, x);
361 T total_length()
const {
362 return _arc_length.total_length();