37 const float sample_length,
40 const int num_curve_points)
43 const int last_index = num_curve_points - 1;
44 if (sample_length <= 0.0f) {
45 return {{0, 1}, 0.0f};
47 if (sample_length >= lengths.
last()) {
55 const int index = eval_index / resolution;
56 const int next_index = (index == last_index) ? 0 : index + 1;
57 const float parameter = (eval_factor + eval_index) / resolution - index;
66 const float sample_length,
68 const int evaluated_size)
70 const int last_index = evaluated_size - 1;
71 if (sample_length <= 0.0f) {
72 return {{0, 1}, 0.0f};
74 if (sample_length >= lengths.
last()) {
83 const int next_eval_index = (eval_index == last_index) ? 0 : eval_index + 1;
92 const float sample_length,
94 const int num_curve_points)
96 const int last_index = num_curve_points - 1;
97 if (sample_length <= 0.0f) {
98 return {{0, 1}, 0.0f};
100 if (sample_length >= lengths.
last()) {
109 const int *offset = std::upper_bound(bezier_offsets.
begin(), bezier_offsets.
end(), eval_index);
110 const int left = offset - bezier_offsets.
begin() - 1;
111 const int right =
left == last_index ? 0 :
left + 1;
113 const int prev_offset = bezier_offsets[
left];
114 const float offset_in_segment = eval_factor + (eval_index - prev_offset);
115 const int segment_resolution = bezier_offsets[
left + 1] - prev_offset;
116 const float parameter = std::clamp(offset_in_segment / segment_resolution, 0.0f, 1.0f);
118 return {{
left, right}, parameter};
126 const float sample_length,
128 const int resolution,
129 const int num_curve_points)
132 num_curve_points, evaluated_points_by_curve[curve_index].
size(), cyclic, resolution))
136 bezier_offsets, accumulated_lengths, sample_length, cyclic, num_curve_points);
139 accumulated_lengths, sample_length, cyclic, resolution, num_curve_points);
148 const float sample_length,
150 const int resolution,
151 const int num_curve_points)
153 if (num_curve_points == 1) {
154 return {{0, 0}, 0.0f};
159 accumulated_lengths, sample_length, cyclic, resolution, num_curve_points);
163 evaluated_points_by_curve,
177 accumulated_lengths, sample_length, cyclic, evaluated_points_by_curve[curve_index].
size());
198 const IndexRange points = dst_points_by_curve[curve_i];
201 handle_positions_left.
slice(points).
fill({0.0f, 0.0f, 0.0f});
202 handle_positions_right.
slice(points).
fill({0.0f, 0.0f, 0.0f});
224 dst_index += increment;
227 dst_data.
slice(dst_index, increment)
229 dst_index += increment;
234 dst_index += increment;
248 const bool src_cyclic)
252 if (insertion_point.
index == 0) {
253 i0 = src_cyclic ? src_data.
size() - 1 : insertion_point.
index;
256 i0 = insertion_point.
index - 1;
259 if (i3 == src_data.
size()) {
260 i3 = src_cyclic ? 0 : insertion_point.
next_index;
263 src_data[insertion_point.
index],
279 handles_right[insertion_point.
index],
304template<
typename T,
bool include_start_po
int = true>
316 if constexpr (!include_start_point) {
321 else if constexpr (!include_start_point) {
332 if (dst_range.
size() == 1) {
358 const bool src_cyclic)
371 if (dst_range.
size() == 1) {
389template<
bool include_start_po
int = true>
408 bool start_point_trimmed =
false;
411 if constexpr (!include_start_point) {
415 else if constexpr (!include_start_point) {
421 src_positions, src_handles_l, src_handles_r, start_point);
422 dst_positions[dst_range.
first()] = start_point_insert.
position;
425 dst_types_l[dst_range.
first()] = src_types_l[start_point.
index];
426 dst_types_r[dst_range.
first()] = src_types_r[start_point.
index];
428 start_point_trimmed =
true;
436 const IndexRange dst_range_to_end(dst_index, increment);
443 dst_index += increment;
445 if (dst_range.
size() == 1) {
451 if (src_range.
cycles() && increment > 0) {
452 const IndexRange dst_range_looped(dst_index, increment);
459 dst_index += increment;
462 if (start_point_trimmed) {
475 dst_handles_l[dst_range.
first()] = dst_positions[dst_range.
first()];
476 dst_handles_r[dst_range.
last()] = dst_positions[dst_range.
first()];
478 else if (start_point.
parameter == 1.0f) {
495 dst_handles_l[dst_range.
first()] = dst_positions[dst_range.
first()];
496 dst_handles_r[dst_range.
last()] = dst_positions[dst_range.
first()];
498 else if (start_point.
parameter == 1.0f) {
539 dst_handles_r[dst_index - 1],
548 src_positions, src_handles_l, src_handles_r, end_point);
559 dst_handles_r[dst_index - 1] = end_point_insert.
handle_prev;
560 dst_types_r[dst_index - 1] = src_types_l[end_point.
index];
562 dst_handles_l[dst_index] = end_point_insert.
left_handle;
563 dst_handles_r[dst_index] = end_point_insert.
right_handle;
564 dst_positions[dst_index] = end_point_insert.
position;
565 dst_types_l[dst_index] = src_types_l[end_point.
next_index];
566 dst_types_r[dst_index] = src_types_r[end_point.
next_index];
592 using T = decltype(dummy);
594 selection.foreach_index(GrainSize(512), [&](const int curve_i) {
595 const IndexRange src_points = src_points_by_curve[curve_i];
596 sample_interval_linear<T>(attribute.src.template typed<T>().slice(src_points),
597 attribute.dst.span.typed<T>(),
599 dst_points_by_curve[curve_i],
600 start_points[curve_i],
601 end_points[curve_i]);
621 const IndexRange src_points = src_points_by_curve[curve_i];
622 const IndexRange dst_points = dst_points_by_curve[curve_i];
628 start_points[curve_i],
629 end_points[curve_i]);
639 transfer_attributes);
657 const IndexRange src_points = src_points_by_curve[curve_i];
658 const IndexRange dst_points = dst_points_by_curve[curve_i];
664 start_points[curve_i],
666 src_cyclic[curve_i]);
673 using T = decltype(dummy);
675 selection.foreach_index(GrainSize(512), [&](const int curve_i) {
676 const IndexRange src_points = src_points_by_curve[curve_i];
677 const IndexRange dst_points = dst_points_by_curve[curve_i];
679 sample_interval_catmull_rom<T>(attribute.src.template typed<T>().slice(src_points),
680 attribute.dst.span.typed<T>(),
683 start_points[curve_i],
685 src_cyclic[curve_i]);
714 const IndexRange src_points = src_points_by_curve[curve_i];
715 const IndexRange dst_points = dst_points_by_curve[curve_i];
718 src_handles_l.
slice(src_points),
719 src_handles_r.
slice(src_points),
720 src_types_l.
slice(src_points),
721 src_types_r.
slice(src_points),
729 start_points[curve_i],
730 end_points[curve_i]);
739 transfer_attributes);
757 const IndexRange src_evaluated_points = src_evaluated_points_by_curve[curve_i];
758 const IndexRange dst_points = dst_points_by_curve[curve_i];
763 start_points[curve_i],
764 end_points[curve_i]);
771 using T = decltype(dummy);
773 selection.foreach_segment(GrainSize(512), [&](const IndexMaskSegment segment) {
774 Vector<std::byte> evaluated_buffer;
775 for (const int64_t curve_i : segment) {
776 const IndexRange src_points = src_points_by_curve[curve_i];
779 evaluated_buffer.reinitialize(sizeof(T) * src_evaluated_points_by_curve[curve_i].size());
780 MutableSpan<T> evaluated = evaluated_buffer.as_mutable_span().cast<T>();
781 src_curves.interpolate_to_evaluated(curve_i, attribute.src.slice(src_points), evaluated);
782 sample_interval_linear<T>(evaluated,
783 attribute.dst.span.typed<T>(),
785 dst_points_by_curve[curve_i],
786 start_points[curve_i],
787 end_points[curve_i]);
799 const float sample_length,
803 sample_length * accumulated_lengths.
last() :
805 return std::clamp(
length, 0.0f, accumulated_lengths.
last());
834 point_count = evaluated_points_by_curve[curve_i].
size();
837 point_count = points_by_curve[curve_i].
size();
839 if (point_count == 1) {
841 dst_curve_size[curve_i] = 1;
843 start_points[curve_i] = {{0, 0}, 0.0f};
844 end_points[curve_i] = {{0, 0}, 0.0f};
848 const bool cyclic = src_cyclic[curve_i];
855 bool equal_sample_point;
858 const float cyclic_start = start_length == lengths.
last() ? 0.0f : start_length;
859 const float cyclic_end = end_length == lengths.
last() ? 0.0f : end_length;
860 equal_sample_point = cyclic_start == cyclic_end;
863 end_length = ends[curve_i] <= starts[curve_i] ?
866 equal_sample_point = start_length == end_length;
870 evaluated_points_by_curve,
878 if (equal_sample_point) {
879 end_points[curve_i] = start_points[curve_i];
880 if (end_length <= start_length) {
882 dst_curve_size[curve_i] = 1;
883 if (start_points[curve_i].is_controlpoint()) {
885 const int single_point_index = start_points[curve_i].parameter == 1.0f ?
886 start_points[curve_i].next_index :
887 start_points[curve_i].index;
889 single_point_index, 1, point_count);
896 start_points[curve_i], end_points[curve_i], point_count)
898 const int count = 1 + !start_points[curve_i].is_controlpoint() + point_count;
900 dst_curve_size[curve_i] =
count;
906 evaluated_points_by_curve,
916 start_points[curve_i], end_points[curve_i], point_count);
917 const int count = src_ranges[curve_i].
size() + !start_points[curve_i].is_controlpoint() +
918 !end_points[curve_i].is_controlpoint();
920 dst_curve_size[curve_i] =
count;
967 Set<std::string> transfer_curve_skip = {
"cyclic",
"curve_type",
"nurbs_order",
"knots_mode"};
970 transfer_curve_skip.
remove(
"nurbs_order");
971 transfer_curve_skip.
remove(
"knots_mode");
987 auto trim_catmull = [&](
const IndexMask &selection) {
994 transfer_attributes);
996 auto trim_poly = [&](
const IndexMask &selection) {
1003 transfer_attributes);
1005 auto trim_bezier = [&](
const IndexMask &selection) {
1012 transfer_attributes);
1014 auto trim_evaluated = [&](
const IndexMask &selection) {
1024 transfer_attributes);
1038 attribute.dst.finish();
1057 copy_point_skip.
add(
"nurbs_weight");
1065 src_points_by_curve,
1066 dst_points_by_curve,
Low-level operations for curves.
Low-level operations for curves.
GeometryNodeCurveSampleMode
@ GEO_NODE_CURVE_SAMPLE_FACTOR
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
constexpr const T & last(const int64_t n=0) const
constexpr int64_t first() const
constexpr int64_t one_after_last() const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr void fill(const T &value) const
constexpr void copy_from(Span< T > values) const
bool remove(const Key &key)
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr const T & last(const int64_t n=0) const
constexpr const T * end() const
constexpr const T * begin() const
VArray< int8_t > handle_types_left() const
void remove_attributes_based_on_types()
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
MutableSpan< int8_t > handle_types_right_for_write()
VArray< int8_t > handle_types_right() const
void ensure_can_interpolate_to_evaluated() const
IndexRange curves_range() const
const std::array< int, CURVE_TYPES_NUM > & curve_type_counts() const
MutableSpan< float3 > handle_positions_left_for_write()
MutableAttributeAccessor attributes_for_write()
MutableSpan< float3 > handle_positions_right_for_write()
Span< float > evaluated_lengths_for_curve(int curve_index, bool cyclic) const
VArray< int > resolution() const
Span< int > bezier_evaluated_offsets_for_curve(int curve_index) const
Span< int > offsets() const
std::optional< Span< float3 > > handle_positions_left() const
Span< float3 > positions() const
OffsetIndices< int > evaluated_points_by_curve() const
bool has_curve_with_type(CurveType type) const
std::optional< Span< float3 > > handle_positions_right() const
MutableSpan< float > nurbs_weights_for_write()
void tag_topology_changed()
void resize(int points_num, int curves_num)
void fill_curve_types(CurveType type)
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
bool nurbs_has_custom_knots() const
void ensure_evaluated_lengths() const
Span< float3 > evaluated_positions() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
MutableSpan< int8_t > handle_types_left_for_write()
bool remove(const StringRef attribute_id)
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
constexpr int first() const
constexpr IndexRangeCyclic drop_front(const int n=1) const
constexpr int size_after_loop() const
constexpr int size_range() const
constexpr IndexRange curve_range() const
static IndexRangeCyclic get_range_between_endpoints(const CurvePoint start_point, const CurvePoint end_point, const int iterable_range_size)
constexpr int size_before_loop() const
constexpr int one_after_last() const
static IndexRangeCyclic get_range_from_size(const int start_index, const int iterator_size, const int iterable_range_size)
constexpr int cycles() const
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
float length(VecOp< float, D >) RET
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
T mix2(float factor, const T &a, const T &b)
Insertion insert(const float3 &point_prev, const float3 &handle_prev, const float3 &handle_next, const float3 &point_next, float parameter)
bool has_vector_handles(int num_curve_points, int64_t evaluated_size, bool cyclic, int resolution)
T interpolate(const T &a, const T &b, const T &c, const T &d, const float parameter)
void update_custom_knot_modes(const IndexMask &mask, const KnotsMode mode_for_regular, const KnotsMode mode_for_cyclic, bke::CurvesGeometry &curves)
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
void fill_points(OffsetIndices< int > points_by_curve, const IndexMask &curve_selection, GPointer value, GMutableSpan dst)
void foreach_curve_by_type(const VArray< int8_t > &types, const std::array< int, CURVE_TYPES_NUM > &type_counts, const IndexMask &selection, FunctionRef< void(IndexMask)> catmull_rom_fn, FunctionRef< void(IndexMask)> poly_fn, FunctionRef< void(IndexMask)> bezier_fn, FunctionRef< void(IndexMask)> nurbs_fn)
Vector< AttributeTransferData > retrieve_attributes_for_transfer(const AttributeAccessor src_attributes, MutableAttributeAccessor dst_attributes, AttrDomainMask domain_mask, const AttributeFilter &attribute_filter={})
auto attribute_filter_with_skip_ref(AttributeFilter filter, const Span< StringRef > skip)
void copy_attributes_group_to_group(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, OffsetIndices< int > src_offsets, OffsetIndices< int > dst_offsets, const IndexMask &selection, MutableAttributeAccessor dst_attributes)
static void trim_bezier_curves(const bke::CurvesGeometry &src_curves, bke::CurvesGeometry &dst_curves, const IndexMask &selection, const Span< bke::curves::CurvePoint > start_points, const Span< bke::curves::CurvePoint > end_points, const Span< bke::curves::IndexRangeCyclic > src_ranges, MutableSpan< bke::AttributeTransferData > transfer_attributes)
static bke::curves::CurvePoint lookup_point_bezier(const Span< int > bezier_offsets, const Span< float > lengths, const float sample_length, const bool cyclic, const int num_curve_points)
static void sample_interval_linear(const Span< T > src_data, MutableSpan< T > dst_data, bke::curves::IndexRangeCyclic src_range, const IndexRange dst_range, const bke::curves::CurvePoint start_point, const bke::curves::CurvePoint end_point)
static bke::curves::CurvePoint lookup_curve_point(const bke::CurvesGeometry &src_curves, const OffsetIndices< int > evaluated_points_by_curve, const CurveType curve_type, const int64_t curve_index, const Span< float > accumulated_lengths, const float sample_length, const bool cyclic, const int resolution, const int num_curve_points)
static bke::curves::bezier::Insertion knot_insert_bezier(const Span< float3 > positions, const Span< float3 > handles_left, const Span< float3 > handles_right, const bke::curves::CurvePoint insertion_point)
bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves, const IndexMask &selection, const VArray< float > &starts, const VArray< float > &ends, GeometryNodeCurveSampleMode mode, const bke::AttributeFilter &attribute_filter)
static int64_t copy_point_data_between_endpoints(const Span< T > src_data, MutableSpan< T > dst_data, const bke::curves::IndexRangeCyclic src_range, int64_t dst_index)
static void trim_polygonal_curves(const bke::CurvesGeometry &src_curves, bke::CurvesGeometry &dst_curves, const IndexMask &selection, const Span< bke::curves::CurvePoint > start_points, const Span< bke::curves::CurvePoint > end_points, const Span< bke::curves::IndexRangeCyclic > src_ranges, MutableSpan< bke::AttributeTransferData > transfer_attributes)
static float trim_sample_length(const Span< float > accumulated_lengths, const float sample_length, const GeometryNodeCurveSampleMode mode)
static T interpolate_catmull_rom(const Span< T > src_data, const bke::curves::CurvePoint insertion_point, const bool src_cyclic)
static bke::curves::CurvePoint lookup_point_polygonal(const Span< float > lengths, const float sample_length, const bool cyclic, const int evaluated_size)
static bke::curves::CurvePoint lookup_point_uniform_spacing(const Span< float > lengths, const float sample_length, const bool cyclic, const int resolution, const int num_curve_points)
static void trim_attribute_linear(const bke::CurvesGeometry &src_curves, bke::CurvesGeometry &dst_curves, const IndexMask &selection, const Span< bke::curves::CurvePoint > start_points, const Span< bke::curves::CurvePoint > end_points, const Span< bke::curves::IndexRangeCyclic > src_ranges, MutableSpan< bke::AttributeTransferData > transfer_attributes)
static void compute_curve_trim_parameters(const bke::CurvesGeometry &curves, const IndexMask &selection, const VArray< float > &starts, const VArray< float > &ends, const GeometryNodeCurveSampleMode mode, MutableSpan< int > dst_curve_size, MutableSpan< bke::curves::CurvePoint > start_points, MutableSpan< bke::curves::CurvePoint > end_points, MutableSpan< bke::curves::IndexRangeCyclic > src_ranges)
static void sample_interval_catmull_rom(const Span< T > src_data, MutableSpan< T > dst_data, bke::curves::IndexRangeCyclic src_range, const IndexRange dst_range, const bke::curves::CurvePoint start_point, const bke::curves::CurvePoint end_point, const bool src_cyclic)
static void trim_catmull_rom_curves(const bke::CurvesGeometry &src_curves, bke::CurvesGeometry &dst_curves, const IndexMask &selection, const Span< bke::curves::CurvePoint > start_points, const Span< bke::curves::CurvePoint > end_points, const Span< bke::curves::IndexRangeCyclic > src_ranges, MutableSpan< bke::AttributeTransferData > transfer_attributes)
static void fill_nurbs_data(bke::CurvesGeometry &dst_curves, const IndexMask &selection)
static void sample_interval_bezier(const Span< float3 > src_positions, const Span< float3 > src_handles_l, const Span< float3 > src_handles_r, const Span< int8_t > src_types_l, const Span< int8_t > src_types_r, MutableSpan< float3 > dst_positions, MutableSpan< float3 > dst_handles_l, MutableSpan< float3 > dst_handles_r, MutableSpan< int8_t > dst_types_l, MutableSpan< int8_t > dst_types_r, bke::curves::IndexRangeCyclic src_range, const IndexRange dst_range, const bke::curves::CurvePoint start_point, const bke::curves::CurvePoint end_point)
static void trim_evaluated_curves(const bke::CurvesGeometry &src_curves, bke::CurvesGeometry &dst_curves, const IndexMask &selection, const Span< bke::curves::CurvePoint > start_points, const Span< bke::curves::CurvePoint > end_points, const Span< bke::curves::IndexRangeCyclic > src_ranges, MutableSpan< bke::AttributeTransferData > transfer_attributes)
static void fill_bezier_data(bke::CurvesGeometry &dst_curves, const IndexMask &selection)
void masked_fill(MutableSpan< T > data, const T &value, const IndexMask &mask)
void sample_at_length(const Span< float > accumulated_segment_lengths, const float sample_length, int &r_segment_index, float &r_factor, SampleSegmentHint *hint=nullptr)
void copy_group_sizes(OffsetIndices< int > offsets, const IndexMask &mask, MutableSpan< int > sizes)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
VecBase< float, 3 > float3
bool is_controlpoint() const