38 const float sample_length,
41 const int num_curve_points)
43 BLI_assert(!cyclic || lengths.size() / resolution >= 2);
44 const int last_index = num_curve_points - 1;
45 if (sample_length <= 0.0f) {
46 return {{0, 1}, 0.0f};
48 if (sample_length >= lengths.last()) {
56 const int index = eval_index / resolution;
57 const int next_index = (index == last_index) ? 0 : index + 1;
58 const float parameter = (eval_factor + eval_index) / resolution - index;
67 const float sample_length,
69 const int evaluated_size)
71 const int last_index = evaluated_size - 1;
72 if (sample_length <= 0.0f) {
73 return {{0, 1}, 0.0f};
75 if (sample_length >= lengths.last()) {
84 const int next_eval_index = (eval_index == last_index) ? 0 : eval_index + 1;
93 const float sample_length,
95 const int num_curve_points)
97 const int last_index = num_curve_points - 1;
98 if (sample_length <= 0.0f) {
99 return {{0, 1}, 0.0f};
101 if (sample_length >= lengths.last()) {
110 const int *offset = std::upper_bound(bezier_offsets.
begin(), bezier_offsets.
end(), eval_index);
111 const int left = offset - bezier_offsets.
begin() - 1;
112 const int right = left == last_index ? 0 : left + 1;
114 const int prev_offset = bezier_offsets[
left];
115 const float offset_in_segment = eval_factor + (eval_index - prev_offset);
116 const int segment_resolution = bezier_offsets[left + 1] - prev_offset;
117 const float parameter = std::clamp(offset_in_segment / segment_resolution, 0.0f, 1.0f);
119 return {{
left, right}, parameter};
127 const float sample_length,
129 const int resolution,
130 const int num_curve_points)
133 num_curve_points, evaluated_points_by_curve[curve_index].
size(), cyclic, resolution))
137 bezier_offsets, accumulated_lengths, sample_length, cyclic, num_curve_points);
140 accumulated_lengths, sample_length, cyclic, resolution, num_curve_points);
149 const float sample_length,
151 const int resolution,
152 const int num_curve_points)
154 if (num_curve_points == 1) {
155 return {{0, 0}, 0.0f};
160 accumulated_lengths, sample_length, cyclic, resolution, num_curve_points);
164 evaluated_points_by_curve,
178 accumulated_lengths, sample_length, cyclic, evaluated_points_by_curve[curve_index].
size());
198 selection.foreach_index(
GrainSize(4096), [&](
const int curve_i) {
199 const IndexRange points = dst_points_by_curve[curve_i];
202 handle_positions_left.
slice(points).fill({0.0f, 0.0f, 0.0f});
203 handle_positions_right.
slice(points).fill({0.0f, 0.0f, 0.0f});
225 dst_index += increment;
228 dst_data.
slice(dst_index, increment)
230 dst_index += increment;
235 dst_index += increment;
249 const bool src_cyclic)
253 if (insertion_point.
index == 0) {
254 i0 = src_cyclic ? src_data.
size() - 1 : insertion_point.
index;
257 i0 = insertion_point.
index - 1;
260 if (i3 == src_data.
size()) {
261 i3 = src_cyclic ? 0 : insertion_point.
next_index;
264 src_data[insertion_point.
index],
280 handles_right[insertion_point.
index],
305template<
typename T,
bool include_start_po
int = true>
317 if constexpr (!include_start_point) {
322 else if constexpr (!include_start_point) {
333 if (dst_range.
size() == 1) {
359 const bool src_cyclic)
372 if (dst_range.
size() == 1) {
390template<
bool include_start_po
int = true>
409 bool start_point_trimmed =
false;
412 if constexpr (!include_start_point) {
416 else if constexpr (!include_start_point) {
422 src_positions, src_handles_l, src_handles_r, start_point);
423 dst_positions[dst_range.
first()] = start_point_insert.
position;
426 dst_types_l[dst_range.
first()] = src_types_l[start_point.
index];
427 dst_types_r[dst_range.
first()] = src_types_r[start_point.
index];
429 start_point_trimmed =
true;
437 const IndexRange dst_range_to_end(dst_index, increment);
444 dst_index += increment;
446 if (dst_range.
size() == 1) {
452 if (src_range.
cycles() && increment > 0) {
453 const IndexRange dst_range_looped(dst_index, increment);
460 dst_index += increment;
463 if (start_point_trimmed) {
476 dst_handles_l[dst_range.
first()] = dst_positions[dst_range.
first()];
477 dst_handles_r[dst_range.
last()] = dst_positions[dst_range.
first()];
479 else if (start_point.
parameter == 1.0f) {
496 dst_handles_l[dst_range.
first()] = dst_positions[dst_range.
first()];
497 dst_handles_r[dst_range.
last()] = dst_positions[dst_range.
first()];
499 else if (start_point.
parameter == 1.0f) {
540 dst_handles_r[dst_index - 1],
549 src_positions, src_handles_l, src_handles_r, end_point);
560 dst_handles_r[dst_index - 1] = end_point_insert.
handle_prev;
561 dst_types_r[dst_index - 1] = src_types_l[end_point.
index];
563 dst_handles_l[dst_index] = end_point_insert.
left_handle;
564 dst_handles_r[dst_index] = end_point_insert.
right_handle;
565 dst_positions[dst_index] = end_point_insert.
position;
566 dst_types_l[dst_index] = src_types_l[end_point.
next_index];
567 dst_types_r[dst_index] = src_types_r[end_point.
next_index];
593 using T = decltype(dummy);
595 selection.foreach_index(GrainSize(512), [&](const int curve_i) {
596 const IndexRange src_points = src_points_by_curve[curve_i];
597 sample_interval_linear<T>(attribute.src.template typed<T>().slice(src_points),
598 attribute.dst.span.typed<T>(),
600 dst_points_by_curve[curve_i],
601 start_points[curve_i],
602 end_points[curve_i]);
621 selection.foreach_index(
GrainSize(512), [&](
const int curve_i) {
622 const IndexRange src_points = src_points_by_curve[curve_i];
623 const IndexRange dst_points = dst_points_by_curve[curve_i];
625 sample_interval_linear<float3>(src_positions.
slice(src_points),
629 start_points[curve_i],
630 end_points[curve_i]);
640 transfer_attributes);
657 selection.foreach_index(
GrainSize(512), [&](
const int curve_i) {
658 const IndexRange src_points = src_points_by_curve[curve_i];
659 const IndexRange dst_points = dst_points_by_curve[curve_i];
661 sample_interval_catmull_rom<float3>(src_positions.
slice(src_points),
665 start_points[curve_i],
667 src_cyclic[curve_i]);
673 bke::attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](
auto dummy) {
674 using T = decltype(dummy);
676 selection.foreach_index(GrainSize(512), [&](const int curve_i) {
677 const IndexRange src_points = src_points_by_curve[curve_i];
678 const IndexRange dst_points = dst_points_by_curve[curve_i];
680 sample_interval_catmull_rom<T>(attribute.src.template typed<T>().slice(src_points),
681 attribute.dst.span.typed<T>(),
684 start_points[curve_i],
686 src_cyclic[curve_i]);
714 selection.foreach_index(
GrainSize(512), [&](
const int curve_i) {
715 const IndexRange src_points = src_points_by_curve[curve_i];
716 const IndexRange dst_points = dst_points_by_curve[curve_i];
719 src_handles_l.
slice(src_points),
720 src_handles_r.
slice(src_points),
721 src_types_l.
slice(src_points),
722 src_types_r.
slice(src_points),
730 start_points[curve_i],
731 end_points[curve_i]);
740 transfer_attributes);
757 selection.foreach_index(
GrainSize(512), [&](
const int curve_i) {
758 const IndexRange src_evaluated_points = src_evaluated_points_by_curve[curve_i];
759 const IndexRange dst_points = dst_points_by_curve[curve_i];
760 sample_interval_linear<float3>(src_eval_positions.
slice(src_evaluated_points),
764 start_points[curve_i],
765 end_points[curve_i]);
771 bke::attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](
auto dummy) {
772 using T = decltype(dummy);
774 selection.foreach_segment(GrainSize(512), [&](const IndexMaskSegment segment) {
775 Vector<std::byte> evaluated_buffer;
776 for (const int64_t curve_i : segment) {
777 const IndexRange src_points = src_points_by_curve[curve_i];
780 evaluated_buffer.reinitialize(sizeof(T) * src_evaluated_points_by_curve[curve_i].size());
781 MutableSpan<T> evaluated = evaluated_buffer.as_mutable_span().cast<T>();
782 src_curves.interpolate_to_evaluated(curve_i, attribute.src.slice(src_points), evaluated);
783 sample_interval_linear<T>(evaluated,
784 attribute.dst.span.typed<T>(),
786 dst_points_by_curve[curve_i],
787 start_points[curve_i],
788 end_points[curve_i]);
800 const float sample_length,
804 sample_length * accumulated_lengths.
last() :
806 return std::clamp(length, 0.0f, accumulated_lengths.
last());
822 const OffsetIndices points_by_curve = curves.points_by_curve();
823 const OffsetIndices evaluated_points_by_curve = curves.evaluated_points_by_curve();
825 const VArray<int> resolution = curves.resolution();
827 curves.ensure_can_interpolate_to_evaluated();
829 selection.foreach_index(
GrainSize(128), [&](
const int curve_i) {
835 point_count = evaluated_points_by_curve[curve_i].
size();
838 point_count = points_by_curve[curve_i].
size();
840 if (point_count == 1) {
842 dst_curve_size[curve_i] = 1;
844 start_points[curve_i] = {{0, 0}, 0.0f};
845 end_points[curve_i] = {{0, 0}, 0.0f};
849 const bool cyclic = src_cyclic[curve_i];
850 const Span<float> lengths = curves.evaluated_lengths_for_curve(curve_i, cyclic);
856 bool equal_sample_point;
859 const float cyclic_start = start_length == lengths.last() ? 0.0f : start_length;
860 const float cyclic_end = end_length == lengths.last() ? 0.0f : end_length;
861 equal_sample_point = cyclic_start == cyclic_end;
864 end_length = ends[curve_i] <= starts[curve_i] ?
867 equal_sample_point = start_length == end_length;
871 evaluated_points_by_curve,
879 if (equal_sample_point) {
880 end_points[curve_i] = start_points[curve_i];
881 if (end_length <= start_length) {
883 dst_curve_size[curve_i] = 1;
884 if (start_points[curve_i].is_controlpoint()) {
886 const int single_point_index = start_points[curve_i].parameter == 1.0f ?
887 start_points[curve_i].next_index :
888 start_points[curve_i].index;
889 src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_from_size(
890 single_point_index, 1, point_count);
896 src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_between_endpoints(
897 start_points[curve_i], end_points[curve_i], point_count)
899 const int count = 1 + !start_points[curve_i].is_controlpoint() + point_count;
901 dst_curve_size[curve_i] =
count;
907 evaluated_points_by_curve,
916 src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_between_endpoints(
917 start_points[curve_i], end_points[curve_i], point_count);
918 const int count = src_ranges[curve_i].
size() + !start_points[curve_i].is_controlpoint() +
919 !end_points[curve_i].is_controlpoint();
921 dst_curve_size[curve_i] =
count;
960 offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_curve_offsets);
961 offset_indices::accumulate_counts_to_offsets(dst_curve_offsets);
968 Set<std::string> transfer_curve_skip = {
"cyclic",
"curve_type",
"nurbs_order",
"knots_mode"};
971 transfer_curve_skip.
remove(
"nurbs_order");
972 transfer_curve_skip.
remove(
"knots_mode");
980 bke::attribute_filter_with_skip_ref(attribute_filter,
995 transfer_attributes);
1004 transfer_attributes);
1013 transfer_attributes);
1025 transfer_attributes);
1029 bke::curves::foreach_curve_by_type(src_curves.
curve_types(),
1039 attribute.dst.finish();
1050 index_mask::masked_fill(cyclic.span,
false, selection);
1058 copy_point_skip.
add(
"nurbs_weight");
1061 bke::copy_attributes_group_to_group(
1063 bke::AttrDomain::Point,
1064 bke::AttrDomain::Point,
1065 bke::attribute_filter_with_skip_ref(attribute_filter, copy_point_skip),
1066 src_points_by_curve,
1067 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 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 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
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< float3 > handle_positions_left() const
Span< int > bezier_evaluated_offsets_for_curve(int curve_index) const
Span< int > offsets() const
Span< float3 > positions() const
OffsetIndices< int > evaluated_points_by_curve() const
bool has_curve_with_type(CurveType type) const
MutableSpan< float > nurbs_weights_for_write()
void tag_topology_changed()
void resize(int points_num, int curves_num)
Span< float3 > handle_positions_right() const
void fill_curve_types(CurveType type)
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
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
constexpr int size_before_loop() const
constexpr int one_after_last() const
constexpr int cycles() const
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
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 fill_points(OffsetIndices< int > points_by_curve, const IndexMask &curve_selection, GPointer value, GMutableSpan dst)
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 sample_at_length(const Span< float > accumulated_segment_lengths, const float sample_length, int &r_segment_index, float &r_factor, SampleSegmentHint *hint=nullptr)
GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type pos vertex_in(1, Type::UINT, "data") .vertex_out(overlay_edit_curve_handle_iface) .geometry_layout(PrimitiveIn Frequency::GEOMETRY storage_buf(1, Qualifier::READ, "uint", "data[]", Frequency::GEOMETRY) .push_constant(Type Frequency::GEOMETRY selection[]
bool is_controlpoint() const