From f2948faf97ae965e24f30d1175530d82d62b3a06 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 22 Apr 2021 16:14:23 -0500 Subject: Splines: Reorganize class inheritence, evaluation --- source/blender/blenkernel/BKE_spline.hh | 161 ++++++++++----------- source/blender/blenkernel/intern/derived_curve.cc | 3 - source/blender/blenkernel/intern/spline_base.cc | 28 +--- source/blender/blenkernel/intern/spline_bezier.cc | 92 ++++++++++-- source/blender/blenkernel/intern/spline_nurbs.cc | 43 +++--- source/blender/blenkernel/intern/spline_poly.cc | 45 +++--- .../blender/functions/FN_generic_virtual_array.hh | 8 +- .../nodes/geometry/nodes/node_geo_curve_to_mesh.cc | 8 +- .../nodes/geometry/nodes/node_geo_curve_trim.cc | 99 +++++++------ 9 files changed, 265 insertions(+), 222 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index 8a707bda92c..0d84a032af4 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -49,6 +49,9 @@ struct PointMapping { float factor; }; +class Spline; +using SplinePtr = std::unique_ptr; + /** * A spline is an abstraction of a curve section, its evaluation methods, and data. * The spline data itself is just control points and a set of attributes. @@ -58,14 +61,16 @@ struct PointMapping { */ class Spline { public: - using SplinePtr = std::unique_ptr; - enum Type { Bezier, NURBS, Poly, }; - Type type; + + private: + Type type_; + + public: bool is_cyclic = false; enum NormalCalculationMode { @@ -76,11 +81,6 @@ class Spline { NormalCalculationMode normal_mode; protected: - mutable bool base_cache_dirty_ = true; - mutable std::mutex base_cache_mutex_; - mutable blender::Vector evaluated_positions_cache_; - mutable blender::Vector evaluated_mapping_cache_; - mutable bool tangent_cache_dirty_ = true; mutable std::mutex tangent_cache_mutex_; mutable blender::Vector evaluated_tangents_cache_; @@ -95,15 +95,10 @@ class Spline { public: virtual ~Spline() = default; - Spline() = default; + Spline(const Type type) : type_(type){}; Spline(Spline &other) - : type(other.type), is_cyclic(other.is_cyclic), normal_mode(other.normal_mode) + : type_(other.type_), is_cyclic(other.is_cyclic), normal_mode(other.normal_mode) { - if (!other.base_cache_dirty_) { - evaluated_positions_cache_ = other.evaluated_positions_cache_; - evaluated_mapping_cache_ = other.evaluated_mapping_cache_; - base_cache_dirty_ = false; - } if (!other.tangent_cache_dirty_) { evaluated_tangents_cache_ = other.evaluated_tangents_cache_; tangent_cache_dirty_ = false; @@ -120,6 +115,8 @@ class Spline { virtual SplinePtr copy() const = 0; + Spline::Type type() const; + virtual int size() const = 0; int segments_size() const; virtual int resolution() const = 0; @@ -141,8 +138,7 @@ class Spline { float length() const; - blender::Span evaluated_positions() const; - blender::Span evaluated_mappings() const; + virtual blender::Span evaluated_positions() const = 0; blender::Span evaluated_lengths() const; blender::Span evaluated_tangents() const; blender::Span evaluated_normals() const; @@ -161,47 +157,13 @@ class Spline { LookupResult lookup_evaluated_factor(const float factor) const; LookupResult lookup_evaluated_length(const float length) const; - /** - * Interpolate data from the original control points to the corresponding ealuated points. - * \param source_data: Should have the same size as the number of control points. - * \param result_data: ... - */ - template - void interpolate_data_to_evaluated_points(blender::Span source_data, - blender::MutableSpan result_data, - const int offset = 0) const - { - /* TODO: Onstead of "offset", it may be better to split a function that returns a single value. - * TODO: Check for null default mixer, possibly using std::enable_if? */ - const int control_points_len = this->size(); - blender::Span mappings = this->evaluated_mappings(); - - blender::attribute_math::DefaultMixer mixer(result_data); - - for (const int i : result_data.index_range()) { - const int evaluated_point_index = offset + i; - const PointMapping &mapping = mappings[evaluated_point_index]; - const int index = mapping.control_point_index; - const int next_index = (index + 1) % control_points_len; - const float factor = mapping.factor; - - const T &value = source_data[index]; - const T &next_value = source_data[next_index]; - - mixer.mix_in(i, value, 1.0f - factor); - mixer.mix_in(i, next_value, factor); - } - - mixer.finalize(); - } + virtual blender::fn::GVArrayPtr interpolate_to_evaluated_points( + const blender::fn::GVArray &source_data) const = 0; protected: virtual void correct_end_tangents() const = 0; - virtual void ensure_base_cache() const = 0; }; -using SplinePtr = std::unique_ptr; - class BezierSpline final : public Spline { public: enum HandleType { @@ -221,9 +183,14 @@ class BezierSpline final : public Spline { blender::Vector tilts_; int resolution_u_; + mutable bool base_cache_dirty_ = true; + mutable std::mutex base_cache_mutex_; + mutable blender::Vector evaluated_positions_cache_; + mutable blender::Vector evaluated_mappings_cache_; + public: virtual SplinePtr copy() const final; - BezierSpline() = default; + BezierSpline() : Spline(Type::Bezier){}; BezierSpline(const BezierSpline &other) : Spline((Spline &)other), handle_types_start_(other.handle_types_start_), @@ -235,12 +202,28 @@ class BezierSpline final : public Spline { tilts_(other.tilts_), resolution_u_(other.resolution_u_) { + if (!other.base_cache_dirty_) { + evaluated_positions_cache_ = other.evaluated_positions_cache_; + evaluated_mappings_cache_ = other.evaluated_mappings_cache_; + base_cache_dirty_ = false; + } } int size() const final; int resolution() const final; void set_resolution(const int value) final; + void add_point(const blender::float3 position, + const HandleType handle_type_start, + const blender::float3 handle_position_start, + const HandleType handle_type_end, + const blender::float3 handle_position_end, + const float radius, + const float tilt); + + void drop_front(const int count) final; + void drop_back(const int count) final; + blender::MutableSpan positions() final; blender::Span positions() const final; blender::MutableSpan radii() final; @@ -257,39 +240,32 @@ class BezierSpline final : public Spline { blender::Span handle_positions_end() const; blender::MutableSpan handle_positions_end(); - void add_point(const blender::float3 position, - const HandleType handle_type_start, - const blender::float3 handle_position_start, - const HandleType handle_type_end, - const blender::float3 handle_position_end, - const float radius, - const float tilt); - - void drop_front(const int count) final; - void drop_back(const int count) final; - - int evaluated_points_size() const final; - bool point_is_sharp(const int index) const; bool handle_start_is_automatic(const int index) const; bool handle_end_is_automatic(const int index) const; void move_control_point(const int index, const blender::float3 new_position); + int evaluated_points_size() const final; + + blender::Span evaluated_mappings() const; + blender::Span evaluated_positions() const final; + + virtual blender::fn::GVArrayPtr interpolate_to_evaluated_points( + const blender::fn::GVArray &source_data) const; + protected: void correct_final_tangents() const; private: void correct_end_tangents() const final; - void ensure_base_cache() const final; bool segment_is_vector(const int start_index) const; void evaluate_bezier_segment(const int index, const int next_index, int &offset, blender::MutableSpan positions, blender::MutableSpan mappings) const; - void evaluate_bezier_position_and_mapping(blender::MutableSpan positions, - blender::MutableSpan mappings) const; + void evaluate_bezier_position_and_mapping() const; }; class NURBSpline final : public Spline { @@ -318,13 +294,17 @@ class NURBSpline final : public Spline { mutable std::mutex knots_mutex_; mutable blender::Vector knots_; + mutable bool position_cache_dirty_ = true; + mutable std::mutex position_cache_mutex_; + mutable blender::Vector evaluated_positions_cache_; + mutable bool basis_cache_dirty_ = true; mutable std::mutex basis_cache_mutex_; - mutable blender::Vector weight_cache_; + mutable blender::Vector basis_cache_; public: SplinePtr copy() const final; - NURBSpline() = default; + NURBSpline() : Spline(Type::NURBS){}; NURBSpline(const NURBSpline &other) : Spline((Spline &)other), positions_(other.positions_), @@ -342,6 +322,14 @@ class NURBSpline final : public Spline { uint8_t order() const; void set_order(const uint8_t value); + void add_point(const blender::float3 position, + const float radius, + const float tilt, + const float weight); + + void drop_front(const int count) final; + void drop_back(const int count) final; + bool check_valid_size_and_order() const; int knots_size() const; @@ -357,22 +345,15 @@ class NURBSpline final : public Spline { blender::MutableSpan weights(); blender::Span weights() const; - void add_point(const blender::float3 position, - const float radius, - const float tilt, - const float weight); - - void drop_front(const int count) final; - void drop_back(const int count) final; - int evaluated_points_size() const final; + blender::Span evaluated_positions() const final; + blender::fn::GVArrayPtr interpolate_to_evaluated_points( - const blender::fn::GVArray &source_data) const; + const blender::fn::GVArray &source_data) const final; protected: void correct_end_tangents() const final; - void ensure_base_cache() const final; void calculate_knots() const; void calculate_basis_cache() const; }; @@ -386,7 +367,7 @@ class PolySpline final : public Spline { private: public: SplinePtr copy() const final; - PolySpline() = default; + PolySpline() : Spline(Type::Bezier){}; PolySpline(const PolySpline &other) : Spline((Spline &)other), positions_(other.positions_), @@ -399,6 +380,11 @@ class PolySpline final : public Spline { int resolution() const final; void set_resolution(const int value) final; + void add_point(const blender::float3 position, const float radius, const float tilt); + + void drop_front(const int count) final; + void drop_back(const int count) final; + blender::MutableSpan positions() final; blender::Span positions() const final; blender::MutableSpan radii() final; @@ -406,16 +392,15 @@ class PolySpline final : public Spline { blender::MutableSpan tilts() final; blender::Span tilts() const final; - void add_point(const blender::float3 position, const float radius, const float tilt); + int evaluated_points_size() const final; - void drop_front(const int count) final; - void drop_back(const int count) final; + blender::Span evaluated_positions() const final; - int evaluated_points_size() const final; + blender::fn::GVArrayPtr interpolate_to_evaluated_points( + const blender::fn::GVArray &source_data) const final; protected: void correct_end_tangents() const final; - void ensure_base_cache() const final; }; /* Proposed name to be different from DNA type. */ diff --git a/source/blender/blenkernel/intern/derived_curve.cc b/source/blender/blenkernel/intern/derived_curve.cc index 9f5f9143641..7d2fc201742 100644 --- a/source/blender/blenkernel/intern/derived_curve.cc +++ b/source/blender/blenkernel/intern/derived_curve.cc @@ -150,7 +150,6 @@ DCurve *dcurve_from_dna_curve(const Curve &dna_curve) case CU_BEZIER: { std::unique_ptr spline = std::make_unique(); spline->set_resolution(nurb->resolu); - spline->type = Spline::Type::Bezier; spline->is_cyclic = nurb->flagu & CU_NURB_CYCLIC; /* TODO: Optimize by reserving the correct size. */ @@ -170,7 +169,6 @@ DCurve *dcurve_from_dna_curve(const Curve &dna_curve) case CU_NURBS: { std::unique_ptr spline = std::make_unique(); spline->set_resolution(nurb->resolu); - spline->type = Spline::Type::NURBS; spline->is_cyclic = nurb->flagu & CU_NURB_CYCLIC; spline->set_order(nurb->orderu); spline->knots_mode = knots_mode_from_dna_nurb(nurb->flagu); @@ -184,7 +182,6 @@ DCurve *dcurve_from_dna_curve(const Curve &dna_curve) } case CU_POLY: { std::unique_ptr spline = std::make_unique(); - spline->type = Spline::Type::Poly; spline->is_cyclic = nurb->flagu & CU_NURB_CYCLIC; for (const BPoint &bp : Span(nurb->bp, nurb->pntsu)) { diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index 88ac8aa1a30..efc53442ec1 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -36,12 +36,16 @@ using blender::Vector; */ void Spline::mark_cache_invalid() { - base_cache_dirty_ = true; tangent_cache_dirty_ = true; normal_cache_dirty_ = true; length_cache_dirty_ = true; } +Spline::Type Spline::type() const +{ + return this->type_; +} + int Spline::evaluated_edges_size() const { const int points_len = this->evaluated_points_size(); @@ -54,12 +58,6 @@ float Spline::length() const return this->evaluated_lengths().last(); } -Span Spline::evaluated_positions() const -{ - this->ensure_base_cache(); - return evaluated_positions_cache_; -} - int Spline::segments_size() const { const int points_len = this->size(); @@ -67,22 +65,6 @@ int Spline::segments_size() const return this->is_cyclic ? points_len : points_len - 1; } -/** - * Returns non-owning access to the cache of mappings from the evaluated points to - * the corresponing control points. Unless the spline is cyclic, the last control point - * index will never be included as an index. - */ -Span Spline::evaluated_mappings() const -{ - this->ensure_base_cache(); -#ifdef DEBUG - if (evaluated_mapping_cache_.last().control_point_index == this->size() - 1) { - BLI_assert(this->is_cyclic); - } -#endif - return evaluated_mapping_cache_; -} - static void accumulate_lengths(Span positions, const bool is_cyclic, MutableSpan lengths) diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc index b8f3717c464..ec86c81d7c3 100644 --- a/source/blender/blenkernel/intern/spline_bezier.cc +++ b/source/blender/blenkernel/intern/spline_bezier.cc @@ -331,9 +331,24 @@ void BezierSpline::evaluate_bezier_segment(const int index, } } -void BezierSpline::evaluate_bezier_position_and_mapping(MutableSpan positions, - MutableSpan mappings) const +void BezierSpline::evaluate_bezier_position_and_mapping() const { + if (!this->base_cache_dirty_) { + return; + } + + std::lock_guard lock{this->base_cache_mutex_}; + if (!this->base_cache_dirty_) { + return; + } + + const int total = this->evaluated_points_size(); + this->evaluated_positions_cache_.resize(total); + this->evaluated_mappings_cache_.resize(total); + + MutableSpan positions = this->evaluated_positions_cache_; + MutableSpan mappings = this->evaluated_mappings_cache_; + /* TODO: It would also be possible to store an array of offsets to facilitate parallelism here, * maybe it is worth it? */ int offset = 0; @@ -354,25 +369,72 @@ void BezierSpline::evaluate_bezier_position_and_mapping(MutableSpan posi } BLI_assert(offset == positions.size()); + + this->base_cache_dirty_ = false; } -void BezierSpline::ensure_base_cache() const +/** + * Returns non-owning access to the cache of mappings from the evaluated points to + * the corresponing control points. Unless the spline is cyclic, the last control point + * index will never be included as an index. + */ +Span BezierSpline::evaluated_mappings() const { - if (!this->base_cache_dirty_) { - return; + this->evaluate_bezier_position_and_mapping(); +#ifdef DEBUG + if (evaluated_mappings_cache_.last().control_point_index == this->size() - 1) { + BLI_assert(this->is_cyclic); } +#endif + return this->evaluated_mappings_cache_; +} - std::lock_guard lock{this->base_cache_mutex_}; - if (!this->base_cache_dirty_) { - return; +Span BezierSpline::evaluated_positions() const +{ + this->evaluate_bezier_position_and_mapping(); + + return this->evaluated_positions_cache_; +} + +template +static void interpolate_to_evaluated_points_impl(Span mappings, + const blender::VArray &source_data, + MutableSpan result_data) +{ + blender::attribute_math::DefaultMixer mixer(result_data); + + for (const int i : result_data.index_range()) { + const PointMapping &mapping = mappings[i]; + const int index = mapping.control_point_index; + const int next_index = (index + 1) % source_data.size(); + const float factor = mapping.factor; + + const T &value = source_data[index]; + const T &next_value = source_data[next_index]; + + mixer.mix_in(i, value, 1.0f - factor); + mixer.mix_in(i, next_value, factor); } - const int total = this->evaluated_points_size(); - this->evaluated_positions_cache_.resize(total); - this->evaluated_mapping_cache_.resize(total); + mixer.finalize(); +} - this->evaluate_bezier_position_and_mapping(this->evaluated_positions_cache_, - this->evaluated_mapping_cache_); +blender::fn::GVArrayPtr BezierSpline::interpolate_to_evaluated_points( + const blender::fn::GVArray &source_data) const +{ + BLI_assert(source_data.size() == this->size()); + Span mappings = this->evaluated_mappings(); - this->base_cache_dirty_ = false; -} \ No newline at end of file + blender::fn::GVArrayPtr new_varray; + blender::attribute_math::convert_to_static_type(source_data.type(), [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v>) { + Array values(this->evaluated_points_size()); + interpolate_to_evaluated_points_impl(mappings, source_data.typed(), values); + new_varray = std::make_unique>>( + std::move(values)); + } + }); + + return new_varray; +} diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc index f81dec2d8f3..0176c36582f 100644 --- a/source/blender/blenkernel/intern/spline_nurbs.cc +++ b/source/blender/blenkernel/intern/spline_nurbs.cc @@ -250,7 +250,7 @@ Span NURBSpline::knots() const this->calculate_knots(); - this->base_cache_dirty_ = false; + this->knots_dirty_ = false; return this->knots_; } @@ -327,13 +327,13 @@ void NURBSpline::calculate_basis_cache() const const int points_len = this->size(); const int evaluated_len = this->evaluated_points_size(); - this->weight_cache_.resize(evaluated_len); + this->basis_cache_.resize(evaluated_len); const int order = this->order(); Span control_weights = this->weights(); Span knots = this->knots(); - MutableSpan basis_cache = this->weight_cache_; + MutableSpan basis_cache(this->basis_cache_); /* This buffer is reused by each basis calculation to store temporary values. * Theoretically it could likely be optimized away in the future. */ @@ -366,20 +366,20 @@ void NURBSpline::calculate_basis_cache() const template void interpolate_to_evaluated_points_impl(Span weights, - const blender::VArray &old_values, - MutableSpan r_values) + const blender::VArray &source_data, + MutableSpan result_data) { - const int points_len = old_values.size(); - BLI_assert(r_values.size() == weights.size()); - blender::attribute_math::DefaultMixer mixer(r_values); + const int points_len = source_data.size(); + BLI_assert(result_data.size() == weights.size()); + blender::attribute_math::DefaultMixer mixer(result_data); - for (const int i : r_values.index_range()) { + for (const int i : result_data.index_range()) { Span point_weights = weights[i].weights; const int start_index = weights[i].start_index; for (const int j : point_weights.index_range()) { const int point_index = (start_index + j) % points_len; - mixer.mix_in(i, old_values[point_index], point_weights[j]); + mixer.mix_in(i, source_data[point_index], point_weights[j]); } } @@ -389,8 +389,10 @@ void interpolate_to_evaluated_points_impl(Span weights, blender::fn::GVArrayPtr NURBSpline::interpolate_to_evaluated_points( const blender::fn::GVArray &source_data) const { + BLI_assert(source_data.size() == this->size()); + this->calculate_basis_cache(); - Span weights = this->weight_cache_; + Span weights(this->basis_cache_); blender::fn::GVArrayPtr new_varray; blender::attribute_math::convert_to_static_type(source_data.type(), [&](auto dummy) { @@ -406,31 +408,32 @@ blender::fn::GVArrayPtr NURBSpline::interpolate_to_evaluated_points( return new_varray; } -void NURBSpline::ensure_base_cache() const +Span NURBSpline::evaluated_positions() const { - if (!this->base_cache_dirty_) { - return; + if (!this->position_cache_dirty_) { + return this->evaluated_positions_cache_; } - std::lock_guard lock{this->base_cache_mutex_}; - if (!this->base_cache_dirty_) { - return; + std::lock_guard lock{this->position_cache_mutex_}; + if (!this->position_cache_dirty_) { + return this->evaluated_positions_cache_; } const int total = this->evaluated_points_size(); this->evaluated_positions_cache_.resize(total); - this->evaluated_mapping_cache_.resize(total); blender::fn::GVArray_For_Span positions_varray(this->positions_.as_span()); blender::fn::GVArrayPtr evaluated_positions_varray = this->interpolate_to_evaluated_points( positions_varray); + /* TODO: Avoid copying. */ Span evaluated_positions = evaluated_positions_varray->typed()->get_internal_span(); - for (const int i : IndexRange(total)) { this->evaluated_positions_cache_[i] = evaluated_positions[i]; } - this->base_cache_dirty_ = false; + this->position_cache_dirty_ = false; + + return this->evaluated_positions_cache_; } diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc index aa9935cb055..ebd4bb1ccb0 100644 --- a/source/blender/blenkernel/intern/spline_poly.cc +++ b/source/blender/blenkernel/intern/spline_poly.cc @@ -17,6 +17,7 @@ #include "BLI_array.hh" #include "BLI_listbase.h" #include "BLI_span.hh" +#include "BLI_virtual_array.hh" #include "BKE_curve.h" #include "BKE_spline.hh" @@ -114,30 +115,30 @@ void PolySpline::correct_end_tangents() const { } -/* TODO: Consider refactoring to avoid copying and "mapping" for poly splines. */ -void PolySpline::ensure_base_cache() const +Span PolySpline::evaluated_positions() const { - if (!this->base_cache_dirty_) { - return; - } - - std::lock_guard lock{this->base_cache_mutex_}; - if (!this->base_cache_dirty_) { - return; - } + return this->positions(); +} - const int total = this->evaluated_points_size(); - this->evaluated_positions_cache_.resize(total); - this->evaluated_mapping_cache_.resize(total); +// static blender::fn::GVArrayPtr bad_hack_copy_varray(const blender::fn::GVArray &source_data) +// { +// } - MutableSpan positions = this->evaluated_positions_cache_.as_mutable_span(); - MutableSpan mappings = this->evaluated_mapping_cache_.as_mutable_span(); +/* TODO: This function is hacky.. how to deal with poly spline interpolation? */ +blender::fn::GVArrayPtr PolySpline::interpolate_to_evaluated_points( + const blender::fn::GVArray &source_data) const +{ + BLI_assert(source_data.size() == this->size()); - for (const int i : positions.index_range()) { - positions[i] = this->positions_[i]; - mappings[i].control_point_index = i; - mappings[i].factor = 0.0f; + if (source_data.is_span()) { + return std::make_unique(source_data.get_internal_span()); } - - this->base_cache_dirty_ = false; -} + // if (source_data.is_single()) { + // BUFFER_FOR_CPP_TYPE_VALUE(source_data.type(), value); + // source_data.get_internal_single(value); + // return std::make_unique( + // source_data.type(), source_data.size(), value); + // } + + return {}; +} \ No newline at end of file diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh index c1af00fd4cd..a7a13c02461 100644 --- a/source/blender/functions/FN_generic_virtual_array.hh +++ b/source/blender/functions/FN_generic_virtual_array.hh @@ -642,7 +642,7 @@ class GVArray_For_EmbeddedVArray : public GVArray_For_VArray { public: template - GVArray_For_EmbeddedVArray(const int64_t size, Args &&... args) + GVArray_For_EmbeddedVArray(const int64_t size, Args &&...args) : GVArray_For_VArray(size), embedded_varray_(std::forward(args)...) { this->varray_ = &embedded_varray_; @@ -657,7 +657,7 @@ class GVMutableArray_For_EmbeddedVMutableArray : public GVMutableArray_For_VMuta public: template - GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&... args) + GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&...args) : GVMutableArray_For_VMutableArray(size), embedded_varray_(std::forward(args)...) { this->varray_ = &embedded_varray_; @@ -714,6 +714,10 @@ class GVArray_For_Span : public GVArray_For_EmbeddedVArray : GVArray_For_EmbeddedVArray>(data.size(), data) { } + GVArray_For_Span(const MutableSpan data) + : GVArray_For_EmbeddedVArray>(data.size(), data.as_span()) + { + } }; /* Same as VMutableArray_For_MutableSpan, but for a generic virtual array. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc index 619ee71e387..dad5c579a3b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc @@ -183,8 +183,10 @@ static void spline_extrude_to_mesh_data(const Spline &spline, Span tangents = spline.evaluated_tangents(); Span normals = spline.evaluated_normals(); Span profile_positions = profile_spline.evaluated_positions(); - Array radii(spline_vert_len); - spline.interpolate_data_to_evaluated_points(spline.radii(), radii); + + GVArrayPtr radii_varray = spline.interpolate_to_evaluated_points( + blender::fn::GVArray_For_Span(spline.radii())); + GVArray_Typed radii = radii_varray->typed(); for (const int i_ring : IndexRange(spline_vert_len)) { float4x4 point_matrix = float4x4::from_normalized_axis_data( positions[i_ring], tangents[i_ring], normals[i_ring]); @@ -198,7 +200,7 @@ static void spline_extrude_to_mesh_data(const Spline &spline, } /* Mark edge loops from sharp vector control points sharp. */ - if (profile_spline.type == Spline::Bezier) { + if (profile_spline.type() == Spline::Bezier) { const BezierSpline &bezier_spline = static_cast(profile_spline); Span mappings = bezier_spline.evaluated_mappings(); for (const int i_profile : mappings.index_range()) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc index 60b0e648e01..5e13210663f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -67,65 +67,66 @@ static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node) namespace blender::nodes { -static void interpolate_control_point(Spline &spline, +static void interpolate_control_point(BezierSpline &spline, const bool adjust_next, const Spline::LookupResult lookup) { - const int evaluated_index = lookup.evaluated_index; + using namespace ::blender::fn; + + const int eval_index = lookup.evaluated_index; Span mappings = spline.evaluated_mappings(); - const PointMapping &mapping = mappings[evaluated_index]; + const PointMapping &mapping = mappings[eval_index]; const int index = mapping.control_point_index + (adjust_next ? 1 : 0); Span evaluated_positions = spline.evaluated_positions(); - spline.positions()[index] = float3::interpolate(evaluated_positions[evaluated_index], - evaluated_positions[evaluated_index + 1], - lookup.factor); + spline.positions()[index] = float3::interpolate( + evaluated_positions[eval_index], evaluated_positions[eval_index + 1], lookup.factor); /* TODO: Do this interpolation with attributes instead. */ - MutableSpan radii = spline.radii(); - Array neighboring_radii(2); - spline.interpolate_data_to_evaluated_points( - radii.as_span(), neighboring_radii.as_mutable_span(), evaluated_index); - radii[index] = interpf(neighboring_radii[1], neighboring_radii[0], lookup.factor); - - MutableSpan tilts = spline.tilts(); - Array neighboring_tilts(2); - spline.interpolate_data_to_evaluated_points( - tilts.as_span(), neighboring_tilts.as_mutable_span(), evaluated_index); - tilts[index] = interpf(neighboring_tilts[1], neighboring_tilts[0], lookup.factor); - - /* Interpolate information specific to different spline types. */ - if (NURBSpline *poly_spline = dynamic_cast(&spline)) { - MutableSpan weights = poly_spline->weights(); - Array neighboring_weights(2); - spline.interpolate_data_to_evaluated_points( - weights.as_span(), neighboring_weights.as_mutable_span(), evaluated_index); - weights[index] = interpf(neighboring_weights[1], neighboring_weights[0], lookup.factor); + { + MutableSpan radii = spline.radii(); + GVArrayPtr radii_varray = spline.interpolate_to_evaluated_points(GVArray_For_Span(radii)); + GVArray_Typed radii_eval = radii_varray->typed(); + + radii[index] = interpf(radii_eval[eval_index + 1], radii_eval[eval_index], lookup.factor); } - else if (BezierSpline *bezier_spline = dynamic_cast(&spline)) { - MutableSpan handle_positions_start = bezier_spline->handle_positions_start(); - Array neighboring_handle_positions_start(2); - spline.interpolate_data_to_evaluated_points( - handle_positions_start.as_span(), - neighboring_handle_positions_start.as_mutable_span(), - evaluated_index); - handle_positions_start[index] = float3::interpolate(neighboring_handle_positions_start[0], - neighboring_handle_positions_start[1], - lookup.factor); - - MutableSpan handle_positions_end = bezier_spline->handle_positions_end(); - Array neighboring_handle_positions_end(2); - spline.interpolate_data_to_evaluated_points(handle_positions_end.as_span(), - neighboring_handle_positions_end.as_mutable_span(), - evaluated_index); - handle_positions_end[index] = float3::interpolate( - neighboring_handle_positions_end[0], neighboring_handle_positions_end[1], lookup.factor); + + { + MutableSpan tilts = spline.radii(); + GVArrayPtr tilt_varray = spline.interpolate_to_evaluated_points(GVArray_For_Span(tilts)); + GVArray_Typed tilts_eval = tilt_varray->typed(); + + tilts[index] = interpf(tilts_eval[eval_index + 1], tilts_eval[eval_index], lookup.factor); + } + + { + MutableSpan handle_positions_start = spline.handle_positions_start(); + GVArrayPtr handle_positions_start_varray = spline.interpolate_to_evaluated_points( + GVArray_For_Span(handle_positions_start)); + GVArray_Typed handle_positions_start_eval = + handle_positions_start_varray->typed(); + + handle_positions_start[index] = float3::interpolate( + handle_positions_start_eval[eval_index], + handle_positions_start_eval[eval_index + 1], + lookup.factor); + } + + { + MutableSpan handle_positions_end = spline.handle_positions_end(); + GVArrayPtr handle_positions_end_varray = spline.interpolate_to_evaluated_points( + GVArray_For_Span(handle_positions_end)); + GVArray_Typed handle_positions_end_eval = handle_positions_end_varray->typed(); + + handle_positions_end[index] = float3::interpolate(handle_positions_end_eval[eval_index], + handle_positions_end_eval[eval_index + 1], + lookup.factor); } } -static void trim_spline(Spline &spline, +static void trim_spline(BezierSpline &spline, const Spline::LookupResult start, const Spline::LookupResult end) { @@ -170,10 +171,13 @@ static void geo_node_curve_trim_exec(GeoNodeExecParams params) const float factor_start = params.extract_input("Start"); const float factor_end = params.extract_input("End"); for (SplinePtr &spline : curve.splines) { + if (spline->type() != Spline::Type::Bezier) { + continue; + } if (spline->is_cyclic) { continue; } - trim_spline(*spline, + trim_spline(static_cast(*spline), spline->lookup_evaluated_factor(std::min(factor_start, factor_end)), spline->lookup_evaluated_factor(std::max(factor_start, factor_end))); } @@ -183,11 +187,14 @@ static void geo_node_curve_trim_exec(GeoNodeExecParams params) const float length_start = params.extract_input("Start_001"); const float length_from_end = params.extract_input("End_001"); for (SplinePtr &spline : curve.splines) { + if (spline->type() != Spline::Type::Bezier) { + continue; + } if (spline->is_cyclic) { continue; } const float length_end = spline->length() - length_from_end; - trim_spline(*spline, + trim_spline(static_cast(*spline), spline->lookup_evaluated_length(std::min(length_start, length_end)), spline->lookup_evaluated_length(std::max(length_start, length_end))); } -- cgit v1.2.3