Evaluate a curve into a coordinate-major buffer.
622{
623 if (num_samples < 2) {
624 error<std::invalid_argument>(
627 std::source_location::current(),
628 "num_samples must be at least 2, but got {}",
629 num_samples);
630 }
631
632 if (dim == 0) {
633 error<std::invalid_argument>(
636 std::source_location::current(),
637 "dim must be at least 1");
638 }
639
640 const auto control_count = static_cast<Eigen::Index>(control_points.size() / dim);
641
642 if (control_count < 2) {
643 error<std::invalid_argument>(
646 std::source_location::current(),
647 "Need at least 2 control points, but got {}",
648 control_count);
649 }
650
652 error<std::invalid_argument>(
655 std::source_location::current(),
656 "Unsupported interpolation mode: {}",
657 static_cast<int>(
m_mode));
658 }
659
661 error<std::invalid_argument>(
664 std::source_location::current(),
665 "{} interpolation requires exactly {} control points, but got {}",
667 }
668
669 Eigen::Index active_count = 0;
670 const double* active =
extend(control_points, dim, active_count);
671
672 const Eigen::Index num_segments = compute_num_segments(
674
675 if (num_segments < 1) {
676 error<std::invalid_argument>(
679 std::source_location::current(),
680 "Need sufficient control points for multi-segment {} interpolation, but got {}",
681 static_cast<int>(
m_mode), control_count);
682 }
683
684 const auto stride = static_cast<size_t>(num_samples);
685 out.resize(dim * stride);
686
688
691 const double* basis =
m_basis.data();
692 double* out_base = out.data();
693
694 if (
m_chunks.size() > 1 && num_samples >= k_parallel_min_samples) {
696 [&](const CurveChunk& chunk) {
697 const auto count = static_cast<size_t>(chunk.sample_count);
698 std::vector<double> params(count);
699 fill_parameters(params.data(), chunk, num_samples, num_segments);
700
701 double* dst = out_base + static_cast<size_t>(chunk.sample_begin);
702
703 if (trig) {
704 evaluate_chunk_cosine(active, chunk.start_col, params.data(),
705 dim, count, dst, stride);
706 return;
707 }
708
709 std::vector<double> folded(dim * static_cast<size_t>(pps));
710 fold_controls(active, chunk.start_col, dim, pps, basis, folded.data());
711
712 evaluate_chunk_polynomial(folded.data(), params.data(),
713 dim, pps,
count, dst, stride);
714 });
715
716 return;
717 }
718
719 for (
const CurveChunk& chunk :
m_chunks) {
720 const auto count =
static_cast<size_t>(chunk.sample_count);
721
723 fill_parameters(
m_tbuf.data(), chunk, num_samples, num_segments);
724
725 double* dst = out_base + static_cast<size_t>(chunk.sample_begin);
726
727 if (trig) {
728 evaluate_chunk_cosine(active, chunk.start_col,
m_tbuf.data(),
729 dim,
count, dst, stride);
730 continue;
731 }
732
733 m_folded.resize(dim *
static_cast<size_t>(pps));
734 fold_controls(active, chunk.start_col, dim, pps, basis,
m_folded.data());
735
737 dim, pps,
count, dst, stride);
738 }
739}
std::vector< double > m_tbuf
const double * extend(std::span< const double > control_points, size_t dim, Eigen::Index &count)
void build_chunks(Eigen::Index num_samples, Eigen::Index num_segments, Eigen::Index active_count)
std::vector< double > m_basis
std::vector< CurveChunk > m_chunks
std::vector< double > m_folded
Eigen::Index m_points_per_segment
@ Runtime
General runtime operations (default fallback)
@ Kinesis
General mathematical and physics algorithns.