Resample path vertices for arc-length parameterization.
Uses piecewise linear arc length estimation. Output vertices have constant spacing along curve.
384{
385 if (path_vertices.size() < 2 || num_samples < 2) {
386 return path_vertices;
387 }
388
389 std::vector<float> arc_lengths;
390 arc_lengths.reserve(path_vertices.size());
391 arc_lengths.push_back(0.0F);
392
393 float total_length = 0.0F;
394 for (size_t i = 1; i < path_vertices.size(); ++i) {
395 float segment_length = glm::distance(
396 path_vertices[i].position,
397 path_vertices[i - 1].position);
398 total_length += segment_length;
399 arc_lengths.push_back(total_length);
400 }
401
402 if (total_length < 1e-6F) {
403 return path_vertices;
404 }
405
406 std::vector<Nodes::LineVertex> resampled;
407 resampled.reserve(num_samples);
408
409 for (size_t i = 0; i < num_samples; ++i) {
410 float target_length = (static_cast<float>(i) / static_cast<float>(num_samples - 1)) * total_length;
411
412 auto it = std::ranges::lower_bound(arc_lengths, target_length);
413 size_t idx = std::distance(arc_lengths.begin(), it);
414
415 if (idx == 0) {
416 resampled.push_back(path_vertices[0]);
417 } else if (idx >= path_vertices.size()) {
418 resampled.push_back(path_vertices.back());
419 } else {
420 float s0 = arc_lengths[idx - 1];
421 float s1 = arc_lengths[idx];
422 float t = (target_length - s0) / (s1 - s0);
423
424 glm::vec3 p0 = path_vertices[idx - 1].position;
425 glm::vec3 p1 = path_vertices[idx].position;
426 glm::vec3 position = glm::mix(p0, p1, t);
427
428 glm::vec3 c0 = path_vertices[idx - 1].color;
429 glm::vec3 c1 = path_vertices[idx].color;
430 glm::vec3 color = glm::mix(c0, c1, t);
431
432 resampled.push_back({ .position = position,
433 .color = color,
434 .thickness = 1.0F });
435 }
436 }
437
438 return resampled;
439}