45 const int interval_offset,
47 int ¤t_interval,
52 const int first_elem = offsets[curve_index];
53 const int last_elem = offsets[curve_index + 1] - 1;
55 if (current_interval == 0) {
56 is_first_selected[curve_index] = range.
first() == first_elem && range.size() == 1;
57 if (!is_first_selected[curve_index]) {
61 curve_intervals[interval_offset + current_interval] = range.
first();
64 bool inside_curve = last_elem >= range.last();
66 curve_intervals[interval_offset + current_interval] = range.
last();
69 curve_intervals[interval_offset + current_interval] = last_elem;
70 range =
IndexRange(last_elem + 1, range.last() - last_elem);
102 if (curve_intervals[interval_offset + last_interval] != last_elem ||
103 curve_intervals[interval_offset + last_interval - 1] !=
104 curve_intervals[interval_offset + last_interval])
109 curve_intervals[interval_offset + last_interval] = last_elem;
111 else if (is_first_selected[curve_index] && last_interval == 1) {
113 curve_intervals[interval_offset + last_interval + 1] =
114 curve_intervals[interval_offset + last_interval];
115 is_first_selected[curve_index] =
false;
118 curve_interval_ranges[curve_index] =
IndexRange(interval_offset, last_interval);
119 calc_curve_offset(curve_index, interval_offset, offsets, new_offsets, curve_interval_ranges);
124 int &interval_offset,
125 int current_interval,
126 const std::optional<IndexRange> prev_range,
133 const int last = offsets[curve_index + 1] - 1;
135 if (prev_range.has_value() && prev_range.value().last() >= offsets[curve_index]) {
138 current_interval - 1,
143 curve_interval_ranges,
148 const int first = offsets[curve_index];
149 curve_interval_ranges[curve_index] =
IndexRange(interval_offset, 1);
150 is_first_selected[curve_index] =
false;
151 curve_intervals[interval_offset] = first;
152 curve_intervals[interval_offset + 1] = last;
153 calc_curve_offset(curve_index, interval_offset, offsets, new_offsets, curve_interval_ranges);
165 std::optional<IndexRange> prev_range;
166 int current_interval = 0;
169 int interval_offset = 0;
170 curve_intervals[interval_offset] = offsets[0];
171 new_offsets[0] = offsets[0];
173 selection.foreach_range([&](
const IndexRange range) {
175 if (range.first() > offsets[curve_index + 1] - 1) {
177 finish_curve_or_full_copy(curve_index,
184 curve_interval_ranges,
186 } while (range.first() > offsets[curve_index + 1] - 1);
187 current_interval = 0;
188 curve_intervals[interval_offset] = offsets[curve_index];
202 current_interval - 1,
203 offsets[curve_index + 1] - 1,
207 curve_interval_ranges,
209 current_interval = 0;
210 curve_intervals[interval_offset] = offsets[curve_index];
223 curve_interval_ranges,
226 }
while (curve_index < offsets.size() - 1);
232 if (selection_domain != bke::AttrDomain::Point) {
243 const Span<int> old_offsets = curves.offsets();
247 const int curves_num = curves.curves_num();
248 const int curve_intervals_size = extruded_points.
size() * 2 + curves_num * 2;
257 Array<int> curve_intervals(curve_intervals_size);
272 curve_interval_ranges,
279 std::array<GVArraySpan, 3> src_selection;
280 std::array<bke::GSpanAttributeWriter, 3> dst_selections;
283 for (
const int selection_i : selection_attr_names.
index_range()) {
284 const StringRef selection_name = selection_attr_names[selection_i];
286 GVArray src_selection_array = *src_attributes.
lookup(selection_name, bke::AttrDomain::Point);
287 if (!src_selection_array) {
291 src_selection[selection_i] = src_selection_array;
294 bke::AttrDomain::Point,
299 threading::parallel_for(curves.curves_range(), 256, [&](
IndexRange curves_range) {
300 for (const int curve : curves_range) {
301 const int first_index = curve_interval_ranges[curve].start();
302 const int first_value = curve_intervals[first_index];
303 bool is_selected = is_first_selected[curve];
305 for (const int i : curve_interval_ranges[curve]) {
306 const int dest_index = new_offsets[curve] + curve_intervals[i] - first_value + i -
308 const int size = curve_intervals[i + 1] - curve_intervals[i] + 1;
310 for (const int selection_i : selection_attr_names.index_range()) {
311 GMutableSpan dst_span = dst_selections[selection_i].span.slice(
312 IndexRange(dest_index, size));
314 src_selection[selection_i].type().copy_assign_n(
315 src_selection[selection_i].slice(IndexRange(curve_intervals[i], size)).data(),
320 fill_selection(dst_span, false);
324 is_selected = !is_selected;
329 for (
const int selection_i : selection_attr_names.index_range()) {
330 dst_selections[selection_i].
finish();
333 const Span<int> intervals = compress_intervals(curve_interval_ranges, curve_intervals);
337 for (
auto &attribute : bke::retrieve_attributes_for_transfer(
341 bke::attribute_filter_from_skip_ref(
342 {
".selection",
".selection_handle_left",
".selection_handle_right"})))
344 const CPPType &type = attribute.src.type();
345 threading::parallel_for(IndexRange(intervals.
size() - 1), 512, [&](IndexRange range) {
346 for (const int i : range) {
347 const int first = intervals[i];
348 const int size = intervals[i + 1] - first + 1;
349 const int dest_index = intervals[i] + i;
350 type.copy_assign_n(attribute.src.slice(IndexRange(first, size)).data(),
351 attribute.dst.span.slice(IndexRange(dest_index, size)).data(),
355 attribute.dst.finish();
357 curves_id.geometry.wrap() = std::move(new_curves);
static void finish_curve_or_full_copy(int &curve_index, int &interval_offset, int current_interval, const std::optional< IndexRange > prev_range, const Span< int > offsets, MutableSpan< int > new_offsets, MutableSpan< int > curve_intervals, MutableSpan< IndexRange > curve_interval_ranges, MutableSpan< bool > is_first_selected)
static void finish_curve(int &curve_index, int &interval_offset, int last_interval, int last_elem, const Span< int > offsets, MutableSpan< int > new_offsets, MutableSpan< int > curve_intervals, MutableSpan< IndexRange > curve_interval_ranges, MutableSpan< bool > is_first_selected)