diff options
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_spline.hh | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.cc | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/spline_base.cc | 61 |
4 files changed, 70 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 9b8eca77e6b..39024445808 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1465,6 +1465,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_CURVE_ENDPOINTS 1069 #define GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL 1070 #define GEO_NODE_CURVE_TRIM 1071 +#define GEO_NODE_CURVE_SAMPLE 1072 /** \} */ diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index f85e62768f7..176e44b3245 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -56,6 +56,8 @@ using SplinePtr = std::unique_ptr<Spline>; * along the length of a curve. * 3. #sample_uniform_index_factors returns an array that stores uniform-length samples * along the spline which can be used to interpolate data from method 1. + * 4. #sample_lengths_to_index_factors does the same, but uses arbitrary parameter + * inputs, instead of sampling uniformly. * * Commonly used evaluated data is stored in caches on the spline itself so that operations on * splines don't need to worry about taking ownership of evaluated data when they don't need to. @@ -170,11 +172,16 @@ class Spline { LookupResult lookup_evaluated_length(const float length) const; blender::Array<float> sample_uniform_index_factors(const int samples_size) const; + blender::Array<float> sample_lengths_to_index_factors(blender::Span<float> parameters) const; + LookupResult lookup_data_from_index_factor(const float index_factor) const; void sample_with_index_factors(const blender::fn::GVArray &src, blender::Span<float> index_factors, blender::fn::GMutableSpan dst) const; + void sample_with_index_factors(blender::fn::GSpan src, + blender::Span<float> index_factors, + blender::fn::GMutableSpan dst) const; template<typename T> void sample_with_index_factors(const blender::VArray<T> &src, blender::Span<float> index_factors, diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 3d5973b1d5e..dbea83ae0ca 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -5115,6 +5115,7 @@ static void registerGeometryNodes() register_node_type_geo_curve_primitive_quadrilateral(); register_node_type_geo_curve_primitive_spiral(); register_node_type_geo_curve_primitive_star(); + register_node_type_geo_curve_sample(); register_node_type_geo_curve_resample(); register_node_type_geo_curve_reverse(); register_node_type_geo_curve_subdivide(); diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index a7caae967f6..9652622d4a1 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -463,6 +463,60 @@ Array<float> Spline::sample_uniform_index_factors(const int samples_size) const return samples; } +#ifdef DEBUG +static void assert_sorted_array_in_range(Span<float> data, const float min, const float max) +{ + BLI_assert(data.first() >= min); + for (const int i : IndexRange(1, data.size() - 1)) { + BLI_assert(data[i] >= data[i - 1]); + } + BLI_assert(data.last() <= max); +} +#endif + +/** + * Transform an array of sorted length parameters into index factors. The result is indices + * and factors to the next index, encoded in floats. The logic for converting from the float + * values to interpolation data is in #lookup_data_from_index_factor. + * + * \param parameters: Lengths along the spline to be transformed into index factors + * (to save another allocation). Must be between zero and the total length of the spline. + * + * \note The implementation is similar to #sample_uniform_index_factors(), though + * the two loops are inverted, and obviously custom parameters are provided. + * + * \note This could have a result data argument instead of returning a span in the future. + */ +Array<float> Spline::sample_lengths_to_index_factors(const Span<float> parameters) const +{ + const Span<float> lengths = this->evaluated_lengths(); + const float total_length = this->length(); +#ifdef DEBUG + // assert_sorted_array_in_range(parameters, 0.0f, this->length()); +#endif + + Array<float> index_factors(parameters.size()); + + /* Store the length at the previous evaluated point in a variable so it can + * start out at zero (the lengths array doesn't contain 0 for the first point). */ + float prev_length = 0.0f; + int i_evaluated = 0; + for (const int i_sample : parameters.index_range()) { + const float sample_length = parameters[i_sample]; + + /* Skip over every evaluated point that fits before this sample. */ + while (lengths[i_evaluated] < sample_length) { + prev_length = lengths[i_evaluated]; + i_evaluated++; + } + + const float factor = (sample_length - prev_length) / (lengths[i_evaluated] - prev_length); + index_factors[i_sample] = i_evaluated + factor; + } + + return index_factors; +} + Spline::LookupResult Spline::lookup_data_from_index_factor(const float index_factor) const { const int eval_size = this->evaluated_points_size(); @@ -497,6 +551,13 @@ GVArrayPtr Spline::interpolate_to_evaluated(GSpan data) const return this->interpolate_to_evaluated(GVArray_For_GSpan(data)); } +void Spline::sample_with_index_factors(GSpan src, + Span<float> index_factors, + GMutableSpan dst) const +{ + return this->sample_with_index_factors(GVArray_For_GSpan(src), index_factors, dst); +} + /** * Sample any input data with a value for each evaluated point (already interpolated to evaluated * points) to arbitrary parameters in between the evaluated points. The interpolation is quite |