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