Evaluate a curve into coordinate-major position and tangent buffers.
A sample's state is its position and its direction, so both are produced together: the basis fold already yields the polynomial coefficients, and differentiating them is a scale by power feeding the same Horner kernel one degree lower. Callers that ignore tangents pay one extra pass over the parameter buffer already in cache.
740{
741 if (num_samples < 2) {
742 error<std::invalid_argument>(
745 std::source_location::current(),
746 "num_samples must be at least 2, but got {}",
747 num_samples);
748 }
749
750 if (dim == 0) {
751 error<std::invalid_argument>(
754 std::source_location::current(),
755 "dim must be at least 1");
756 }
757
758 const auto control_count = static_cast<Eigen::Index>(control_points.size() / dim);
759
760 if (control_count < 2) {
761 error<std::invalid_argument>(
764 std::source_location::current(),
765 "Need at least 2 control points, but got {}",
766 control_count);
767 }
768
770 error<std::invalid_argument>(
773 std::source_location::current(),
774 "Unsupported interpolation mode: {}",
775 static_cast<int>(
m_mode));
776 }
777
779 error<std::invalid_argument>(
782 std::source_location::current(),
783 "{} interpolation requires exactly {} control points, but got {}",
785 }
786
787 Eigen::Index active_count = 0;
788 const double* active =
extend(control_points, dim, active_count);
789
790 const Eigen::Index num_segments = compute_num_segments(
792
793 if (num_segments < 1) {
794 error<std::invalid_argument>(
797 std::source_location::current(),
798 "Need sufficient control points for multi-segment {} interpolation, but got {}",
799 static_cast<int>(
m_mode), control_count);
800 }
801
802 const auto stride = static_cast<size_t>(num_samples);
803 out.resize(dim * stride);
804 tangents.resize(dim * stride);
805
807
810 const double* basis =
m_basis.data();
811 double* out_base =
out.data();
812 double* tan_base = tangents.data();
813
814 if (
m_chunks.size() > 1 && num_samples >= k_parallel_min_samples) {
816 [&](const CurveChunk& chunk) {
817 const auto count = static_cast<size_t>(chunk.sample_count);
818 std::vector<double> params(count);
819 fill_parameters(params.data(), chunk, num_samples, num_segments);
820
821 const auto offset = static_cast<size_t>(chunk.sample_begin);
822 double* dst = out_base + offset;
823 double* tan = tan_base + offset;
824
825 if (trig) {
826 evaluate_chunk_cosine(active, chunk.start_col, params.data(),
827 dim, count, dst, stride);
828 evaluate_chunk_cosine_derivative(active, chunk.start_col, params.data(),
829 dim, count, tan, stride);
830 return;
831 }
832
833 std::vector<double> folded(dim * static_cast<size_t>(pps));
834 fold_controls(active, chunk.start_col, dim, pps, basis, folded.data());
835
836 evaluate_chunk_polynomial(folded.data(), params.data(),
838
839 std::vector<double> dfolded(dim * static_cast<size_t>(pps - 1));
840 fold_derivative(folded.data(), dim, pps, dfolded.data());
841
842 evaluate_chunk_polynomial(dfolded.data(), params.data(),
843 dim, pps - 1,
count, tan, stride);
844 });
845
846 return;
847 }
848
849 for (
const CurveChunk& chunk :
m_chunks) {
850 const auto count =
static_cast<size_t>(chunk.sample_count);
851
853 fill_parameters(
m_tbuf.data(), chunk, num_samples, num_segments);
854
855 const auto offset =
static_cast<size_t>(chunk.sample_begin);
857 double* tan = tan_base +
offset;
858
859 if (trig) {
860 evaluate_chunk_cosine(active, chunk.start_col,
m_tbuf.data(),
862 evaluate_chunk_cosine_derivative(active, chunk.start_col,
m_tbuf.data(),
863 dim,
count, tan, stride);
864 continue;
865 }
866
867 m_folded.resize(dim *
static_cast<size_t>(pps));
868 fold_controls(active, chunk.start_col, dim, pps, basis,
m_folded.data());
869
872
873 m_dfolded.resize(dim *
static_cast<size_t>(pps - 1));
875
877 dim, pps - 1,
count, tan, stride);
878 }
879}
std::vector< float > * out
std::vector< double > m_dfolded
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.