Blender V4.3
trim_curves.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_array_utils.hh"
11
12#include "BKE_attribute.hh"
13#include "BKE_attribute_math.hh"
14#include "BKE_curves.hh"
15#include "BKE_curves_utils.hh"
16
17#include "GEO_trim_curves.hh"
18
19namespace blender::geometry {
20
21/* -------------------------------------------------------------------- */
24
38 const float sample_length,
39 const bool cyclic,
40 const int resolution,
41 const int num_curve_points)
42{
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};
47 }
48 if (sample_length >= lengths.last()) {
49 return cyclic ? bke::curves::CurvePoint{{last_index, 0}, 1.0} :
50 bke::curves::CurvePoint{{last_index - 1, last_index}, 1.0};
51 }
52 int eval_index;
53 float eval_factor;
54 length_parameterize::sample_at_length(lengths, sample_length, eval_index, eval_factor);
55
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;
59
60 return bke::curves::CurvePoint{{index, next_index}, parameter};
61}
62
67 const float sample_length,
68 const bool cyclic,
69 const int evaluated_size)
70{
71 const int last_index = evaluated_size - 1;
72 if (sample_length <= 0.0f) {
73 return {{0, 1}, 0.0f};
74 }
75 if (sample_length >= lengths.last()) {
76 return cyclic ? bke::curves::CurvePoint{{last_index, 0}, 1.0} :
77 bke::curves::CurvePoint{{last_index - 1, last_index}, 1.0};
78 }
79
80 int eval_index;
81 float eval_factor;
82 length_parameterize::sample_at_length(lengths, sample_length, eval_index, eval_factor);
83
84 const int next_eval_index = (eval_index == last_index) ? 0 : eval_index + 1;
85 return bke::curves::CurvePoint{{eval_index, next_eval_index}, eval_factor};
86}
87
92 const Span<float> lengths,
93 const float sample_length,
94 const bool cyclic,
95 const int num_curve_points)
96{
97 const int last_index = num_curve_points - 1;
98 if (sample_length <= 0.0f) {
99 return {{0, 1}, 0.0f};
100 }
101 if (sample_length >= lengths.last()) {
102 return cyclic ? bke::curves::CurvePoint{{last_index, 0}, 1.0} :
103 bke::curves::CurvePoint{{last_index - 1, last_index}, 1.0};
104 }
105 int eval_index;
106 float eval_factor;
107 length_parameterize::sample_at_length(lengths, sample_length, eval_index, eval_factor);
108
109 /* Find the segment index from the offset mapping. */
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;
113
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);
118
119 return {{left, right}, parameter};
120}
121
123 const bke::CurvesGeometry &src_curves,
124 const OffsetIndices<int> evaluated_points_by_curve,
125 const int64_t curve_index,
126 const Span<float> accumulated_lengths,
127 const float sample_length,
128 const bool cyclic,
129 const int resolution,
130 const int num_curve_points)
131{
133 num_curve_points, evaluated_points_by_curve[curve_index].size(), cyclic, resolution))
134 {
135 const Span<int> bezier_offsets = src_curves.bezier_evaluated_offsets_for_curve(curve_index);
136 return lookup_point_bezier(
137 bezier_offsets, accumulated_lengths, sample_length, cyclic, num_curve_points);
138 }
140 accumulated_lengths, sample_length, cyclic, resolution, num_curve_points);
141}
142
144 const bke::CurvesGeometry &src_curves,
145 const OffsetIndices<int> evaluated_points_by_curve,
146 const CurveType curve_type,
147 const int64_t curve_index,
148 const Span<float> accumulated_lengths,
149 const float sample_length,
150 const bool cyclic,
151 const int resolution,
152 const int num_curve_points)
153{
154 if (num_curve_points == 1) {
155 return {{0, 0}, 0.0f};
156 }
157
158 if (curve_type == CURVE_TYPE_CATMULL_ROM) {
160 accumulated_lengths, sample_length, cyclic, resolution, num_curve_points);
161 }
162 else if (curve_type == CURVE_TYPE_BEZIER) {
163 return lookup_point_bezier(src_curves,
164 evaluated_points_by_curve,
165 curve_index,
166 accumulated_lengths,
167 sample_length,
168 cyclic,
169 resolution,
170 num_curve_points);
171 }
172 else if (curve_type == CURVE_TYPE_POLY) {
173 return lookup_point_polygonal(accumulated_lengths, sample_length, cyclic, num_curve_points);
174 }
175 /* Handle evaluated curve. */
176 BLI_assert(resolution > 0);
178 accumulated_lengths, sample_length, cyclic, evaluated_points_by_curve[curve_index].size());
179}
180
182
183/* -------------------------------------------------------------------- */
186
188{
189 if (!dst_curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
190 return;
191 }
192 const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
193 MutableSpan<float3> handle_positions_left = dst_curves.handle_positions_left_for_write();
194 MutableSpan<float3> handle_positions_right = dst_curves.handle_positions_right_for_write();
195 MutableSpan<int8_t> handle_types_left = dst_curves.handle_types_left_for_write();
196 MutableSpan<int8_t> handle_types_right = dst_curves.handle_types_right_for_write();
197
198 selection.foreach_index(GrainSize(4096), [&](const int curve_i) {
199 const IndexRange points = dst_points_by_curve[curve_i];
200 handle_types_right.slice(points).fill(int8_t(BEZIER_HANDLE_FREE));
201 handle_types_left.slice(points).fill(int8_t(BEZIER_HANDLE_FREE));
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});
204 });
205}
207{
208 if (!dst_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
209 return;
210 }
212 dst_curves.points_by_curve(), selection, 0.0f, dst_curves.nurbs_weights_for_write());
213}
214
215template<typename T>
217 MutableSpan<T> dst_data,
218 const bke::curves::IndexRangeCyclic src_range,
219 int64_t dst_index)
220{
221 int64_t increment;
222 if (src_range.cycles()) {
223 increment = src_range.size_before_loop();
224 dst_data.slice(dst_index, increment).copy_from(src_data.slice(src_range.first(), increment));
225 dst_index += increment;
226
227 increment = src_range.size_after_loop();
228 dst_data.slice(dst_index, increment)
229 .copy_from(src_data.slice(src_range.curve_range().first(), increment));
230 dst_index += increment;
231 }
232 else {
233 increment = src_range.one_after_last() - int64_t(src_range.first());
234 dst_data.slice(dst_index, increment).copy_from(src_data.slice(src_range.first(), increment));
235 dst_index += increment;
236 }
237 return dst_index;
238}
239
241
242/* -------------------------------------------------------------------- */
245
246template<typename T>
247static T interpolate_catmull_rom(const Span<T> src_data,
248 const bke::curves::CurvePoint insertion_point,
249 const bool src_cyclic)
250{
251 BLI_assert(insertion_point.index >= 0 && insertion_point.next_index < src_data.size());
252 int i0;
253 if (insertion_point.index == 0) {
254 i0 = src_cyclic ? src_data.size() - 1 : insertion_point.index;
255 }
256 else {
257 i0 = insertion_point.index - 1;
258 }
259 int i3 = insertion_point.next_index + 1;
260 if (i3 == src_data.size()) {
261 i3 = src_cyclic ? 0 : insertion_point.next_index;
262 }
264 src_data[insertion_point.index],
265 src_data[insertion_point.next_index],
266 src_data[i3],
267 insertion_point.parameter);
268}
269
271 const Span<float3> positions,
272 const Span<float3> handles_left,
273 const Span<float3> handles_right,
274 const bke::curves::CurvePoint insertion_point)
275{
277 insertion_point.index + 1 == insertion_point.next_index ||
278 (insertion_point.next_index >= 0 && insertion_point.next_index < insertion_point.index));
279 return bke::curves::bezier::insert(positions[insertion_point.index],
280 handles_right[insertion_point.index],
281 handles_left[insertion_point.next_index],
282 positions[insertion_point.next_index],
283 insertion_point.parameter);
284}
285
287
288/* -------------------------------------------------------------------- */
291
305template<typename T, bool include_start_point = true>
306static void sample_interval_linear(const Span<T> src_data,
307 MutableSpan<T> dst_data,
309 const IndexRange dst_range,
310 const bke::curves::CurvePoint start_point,
311 const bke::curves::CurvePoint end_point)
312{
313 int64_t dst_index = dst_range.first();
314
315 if (start_point.is_controlpoint()) {
316 /* 'start_point' is included in the copy iteration. */
317 if constexpr (!include_start_point) {
318 /* Skip first. */
319 src_range = src_range.drop_front();
320 }
321 }
322 else if constexpr (!include_start_point) {
323 /* Do nothing (excluded). */
324 }
325 else {
326 /* General case, sample 'start_point' */
327 dst_data[dst_index] = bke::attribute_math::mix2(
328 start_point.parameter, src_data[start_point.index], src_data[start_point.next_index]);
329 ++dst_index;
330 }
331
332 dst_index = copy_point_data_between_endpoints(src_data, dst_data, src_range, dst_index);
333 if (dst_range.size() == 1) {
334 BLI_assert(dst_index == dst_range.one_after_last());
335 return;
336 }
337
338 /* Handle last case */
339 if (end_point.is_controlpoint()) {
340 /* 'end_point' is included in the copy iteration. */
341 }
342 else {
343 dst_data[dst_index] = bke::attribute_math::mix2(
344 end_point.parameter, src_data[end_point.index], src_data[end_point.next_index]);
345#ifndef NDEBUG
346 ++dst_index;
347#endif
348 }
349 BLI_assert(dst_index == dst_range.one_after_last());
350}
351
352template<typename T>
353static void sample_interval_catmull_rom(const Span<T> src_data,
354 MutableSpan<T> dst_data,
356 const IndexRange dst_range,
357 const bke::curves::CurvePoint start_point,
358 const bke::curves::CurvePoint end_point,
359 const bool src_cyclic)
360{
361 int64_t dst_index = dst_range.first();
362
363 if (start_point.is_controlpoint()) {
364 }
365 else {
366 /* General case, sample 'start_point' */
367 dst_data[dst_index] = interpolate_catmull_rom(src_data, start_point, src_cyclic);
368 ++dst_index;
369 }
370
371 dst_index = copy_point_data_between_endpoints(src_data, dst_data, src_range, dst_index);
372 if (dst_range.size() == 1) {
373 BLI_assert(dst_index == dst_range.one_after_last());
374 return;
375 }
376
377 /* Handle last case */
378 if (end_point.is_controlpoint()) {
379 /* 'end_point' is included in the copy iteration. */
380 }
381 else {
382 dst_data[dst_index] = interpolate_catmull_rom(src_data, end_point, src_cyclic);
383#ifndef NDEBUG
384 ++dst_index;
385#endif
386 }
387 BLI_assert(dst_index == dst_range.one_after_last());
388}
389
390template<bool include_start_point = true>
391static void sample_interval_bezier(const Span<float3> src_positions,
392 const Span<float3> src_handles_l,
393 const Span<float3> src_handles_r,
394 const Span<int8_t> src_types_l,
395 const Span<int8_t> src_types_r,
396 MutableSpan<float3> dst_positions,
397 MutableSpan<float3> dst_handles_l,
398 MutableSpan<float3> dst_handles_r,
399 MutableSpan<int8_t> dst_types_l,
400 MutableSpan<int8_t> dst_types_r,
402 const IndexRange dst_range,
403 const bke::curves::CurvePoint start_point,
404 const bke::curves::CurvePoint end_point)
405{
406 bke::curves::bezier::Insertion start_point_insert;
407 int64_t dst_index = dst_range.first();
408
409 bool start_point_trimmed = false;
410 if (start_point.is_controlpoint()) {
411 /* The 'start_point' control point is included in the copy iteration. */
412 if constexpr (!include_start_point) {
413 src_range = src_range.drop_front();
414 }
415 }
416 else if constexpr (!include_start_point) {
417 /* Do nothing, 'start_point' is excluded. */
418 }
419 else {
420 /* General case, sample 'start_point'. */
421 start_point_insert = knot_insert_bezier(
422 src_positions, src_handles_l, src_handles_r, start_point);
423 dst_positions[dst_range.first()] = start_point_insert.position;
424 dst_handles_l[dst_range.first()] = start_point_insert.left_handle;
425 dst_handles_r[dst_range.first()] = start_point_insert.right_handle;
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];
428
429 start_point_trimmed = true;
430 ++dst_index;
431 }
432
433 /* Copy point data between the 'start_point' and 'end_point'. */
434 int64_t increment = src_range.cycles() ? src_range.size_before_loop() :
435 src_range.one_after_last() - src_range.first();
436
437 const IndexRange dst_range_to_end(dst_index, increment);
438 const IndexRange src_range_to_end(src_range.first(), increment);
439 dst_positions.slice(dst_range_to_end).copy_from(src_positions.slice(src_range_to_end));
440 dst_handles_l.slice(dst_range_to_end).copy_from(src_handles_l.slice(src_range_to_end));
441 dst_handles_r.slice(dst_range_to_end).copy_from(src_handles_r.slice(src_range_to_end));
442 dst_types_l.slice(dst_range_to_end).copy_from(src_types_l.slice(src_range_to_end));
443 dst_types_r.slice(dst_range_to_end).copy_from(src_types_r.slice(src_range_to_end));
444 dst_index += increment;
445
446 if (dst_range.size() == 1) {
447 BLI_assert(dst_index == dst_range.one_after_last());
448 return;
449 }
450
451 increment = src_range.size_after_loop();
452 if (src_range.cycles() && increment > 0) {
453 const IndexRange dst_range_looped(dst_index, increment);
454 const IndexRange src_range_looped(src_range.curve_range().first(), increment);
455 dst_positions.slice(dst_range_looped).copy_from(src_positions.slice(src_range_looped));
456 dst_handles_l.slice(dst_range_looped).copy_from(src_handles_l.slice(src_range_looped));
457 dst_handles_r.slice(dst_range_looped).copy_from(src_handles_r.slice(src_range_looped));
458 dst_types_l.slice(dst_range_looped).copy_from(src_types_l.slice(src_range_looped));
459 dst_types_r.slice(dst_range_looped).copy_from(src_types_r.slice(src_range_looped));
460 dst_index += increment;
461 }
462
463 if (start_point_trimmed) {
464 dst_handles_l[dst_range.first() + 1] = start_point_insert.handle_next;
465 /* No need to change handle type (remains the same). */
466 }
467
468 /* Handle 'end_point' */
469 bke::curves::bezier::Insertion end_point_insert;
470 if (end_point.parameter == 0.0f) {
471 if (end_point.index == start_point.index) {
472 /* Start point is same point or in the same segment. */
473 if (start_point.parameter == 0.0f) {
474 /* Same point. */
475 BLI_assert(dst_range.size() == 1LL + src_range.size_range());
476 dst_handles_l[dst_range.first()] = dst_positions[dst_range.first()];
477 dst_handles_r[dst_range.last()] = dst_positions[dst_range.first()];
478 }
479 else if (start_point.parameter == 1.0f) {
480 /* Start is next controlpoint, do nothing. */
481 }
482 else {
483 /* Within the segment. */
484 BLI_assert(dst_range.size() == 1LL + src_range.size_range() || dst_range.size() == 2);
485 dst_handles_r[dst_range.last()] = start_point_insert.handle_prev;
486 }
487 }
488 /* Start point is considered 'before' the endpoint and ignored. */
489 }
490 else if (end_point.parameter == 1.0f) {
491 if (end_point.next_index == start_point.index) {
492 /* Start point is same or in 'next' segment. */
493 if (start_point.parameter == 0.0f) {
494 /* Same point */
495 BLI_assert(dst_range.size() == 1LL + src_range.size_range());
496 dst_handles_l[dst_range.first()] = dst_positions[dst_range.first()];
497 dst_handles_r[dst_range.last()] = dst_positions[dst_range.first()];
498 }
499 else if (start_point.parameter == 1.0f) {
500 /* Start is next controlpoint, do nothing. */
501 }
502 else {
503 /* In next segment. */
504 BLI_assert(dst_range.size() == 1LL + src_range.size_range() || dst_range.size() == 2);
505 dst_handles_r[dst_range.last()] = start_point_insert.handle_prev;
506 }
507 }
508 }
509 else {
510 /* Trimmed in both ends within the same (and only) segment! Ensure both end points is not a
511 * loop. */
512 if (start_point.index == end_point.index && start_point.parameter < 1.0f) {
513 BLI_assert(dst_range.size() == 2 || dst_range.size() == 2ll + src_range.size_range() ||
514 dst_range.size() == 1LL + src_range.size_range());
515
516 if (start_point.parameter > end_point.parameter && start_point.parameter < 1.0f) {
517 /* Start point comes after the endpoint within the segment. */
518 BLI_assert(end_point.parameter >= 0.0f);
519
520 const float parameter = end_point.parameter / start_point.parameter;
521 end_point_insert = bke::curves::bezier::insert(dst_positions[dst_index - 1],
522 start_point_insert.handle_prev,
523 start_point_insert.left_handle,
524 start_point_insert.position,
525 parameter);
526
527 /* Update start-point handle. */
528 dst_handles_l[dst_range.first()] = end_point_insert.handle_next;
529 }
530 else {
531 /* Start point lies before the endpoint within the segment. */
532
533 const float parameter = (end_point.parameter - start_point.parameter) /
534 (1.0f - start_point.parameter);
535 /* Unused only when parameter == 0.0f! */
536 const float3 handle_next = start_point.parameter == 0.0f ?
537 src_handles_l[end_point.next_index] :
538 start_point_insert.handle_next;
539 end_point_insert = bke::curves::bezier::insert(dst_positions[dst_index - 1],
540 dst_handles_r[dst_index - 1],
541 handle_next,
542 src_positions[end_point.next_index],
543 parameter);
544 }
545 }
546 else {
547 /* General case, compute the insertion point. */
548 end_point_insert = knot_insert_bezier(
549 src_positions, src_handles_l, src_handles_r, end_point);
550
551 if ((start_point.parameter >= end_point.parameter && end_point.index == start_point.index) ||
552 (start_point.parameter == 0.0f && end_point.next_index == start_point.index))
553 {
554 /* Start point is next controlpoint. */
555 dst_handles_l[dst_range.first()] = end_point_insert.handle_next;
556 /* No need to change handle type (remains the same). */
557 }
558 }
559
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];
562
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];
568#ifndef NDEBUG
569 ++dst_index;
570#endif
571 }
572 BLI_assert(dst_index == dst_range.one_after_last());
573}
574
576
577/* -------------------------------------------------------------------- */
580
581static void trim_attribute_linear(const bke::CurvesGeometry &src_curves,
582 bke::CurvesGeometry &dst_curves,
583 const IndexMask &selection,
584 const Span<bke::curves::CurvePoint> start_points,
585 const Span<bke::curves::CurvePoint> end_points,
587 MutableSpan<bke::AttributeTransferData> transfer_attributes)
588{
589 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
590 const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
591 for (bke::AttributeTransferData &attribute : transfer_attributes) {
592 bke::attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
593 using T = decltype(dummy);
594
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>(),
599 src_ranges[curve_i],
600 dst_points_by_curve[curve_i],
601 start_points[curve_i],
602 end_points[curve_i]);
603 });
604 });
605 }
606}
607
608static void trim_polygonal_curves(const bke::CurvesGeometry &src_curves,
609 bke::CurvesGeometry &dst_curves,
610 const IndexMask &selection,
611 const Span<bke::curves::CurvePoint> start_points,
612 const Span<bke::curves::CurvePoint> end_points,
614 MutableSpan<bke::AttributeTransferData> transfer_attributes)
615{
616 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
617 const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
618 const Span<float3> src_positions = src_curves.positions();
619 MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
620
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];
624
625 sample_interval_linear<float3>(src_positions.slice(src_points),
626 dst_positions,
627 src_ranges[curve_i],
628 dst_points,
629 start_points[curve_i],
630 end_points[curve_i]);
631 });
632 fill_bezier_data(dst_curves, selection);
633 fill_nurbs_data(dst_curves, selection);
634 trim_attribute_linear(src_curves,
635 dst_curves,
636 selection,
637 start_points,
638 end_points,
639 src_ranges,
640 transfer_attributes);
641}
642
643static void trim_catmull_rom_curves(const bke::CurvesGeometry &src_curves,
644 bke::CurvesGeometry &dst_curves,
645 const IndexMask &selection,
646 const Span<bke::curves::CurvePoint> start_points,
647 const Span<bke::curves::CurvePoint> end_points,
649 MutableSpan<bke::AttributeTransferData> transfer_attributes)
650{
651 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
652 const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
653 const Span<float3> src_positions = src_curves.positions();
654 const VArray<bool> src_cyclic = src_curves.cyclic();
655 MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
656
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];
660
661 sample_interval_catmull_rom<float3>(src_positions.slice(src_points),
662 dst_positions,
663 src_ranges[curve_i],
664 dst_points,
665 start_points[curve_i],
666 end_points[curve_i],
667 src_cyclic[curve_i]);
668 });
669 fill_bezier_data(dst_curves, selection);
670 fill_nurbs_data(dst_curves, selection);
671
672 for (bke::AttributeTransferData &attribute : transfer_attributes) {
673 bke::attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
674 using T = decltype(dummy);
675
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];
679
680 sample_interval_catmull_rom<T>(attribute.src.template typed<T>().slice(src_points),
681 attribute.dst.span.typed<T>(),
682 src_ranges[curve_i],
683 dst_points,
684 start_points[curve_i],
685 end_points[curve_i],
686 src_cyclic[curve_i]);
687 });
688 });
689 }
690}
691
692static void trim_bezier_curves(const bke::CurvesGeometry &src_curves,
693 bke::CurvesGeometry &dst_curves,
694 const IndexMask &selection,
695 const Span<bke::curves::CurvePoint> start_points,
696 const Span<bke::curves::CurvePoint> end_points,
698 MutableSpan<bke::AttributeTransferData> transfer_attributes)
699{
700 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
701 const Span<float3> src_positions = src_curves.positions();
702 const VArraySpan<int8_t> src_types_l{src_curves.handle_types_left()};
703 const VArraySpan<int8_t> src_types_r{src_curves.handle_types_right()};
704 const Span<float3> src_handles_l = src_curves.handle_positions_left();
705 const Span<float3> src_handles_r = src_curves.handle_positions_right();
706
707 const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
708 MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
709 MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
710 MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
711 MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
712 MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
713
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];
717
718 sample_interval_bezier(src_positions.slice(src_points),
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),
723 dst_positions,
724 dst_handles_l,
725 dst_handles_r,
726 dst_types_l,
727 dst_types_r,
728 src_ranges[curve_i],
729 dst_points,
730 start_points[curve_i],
731 end_points[curve_i]);
732 });
733 fill_nurbs_data(dst_curves, selection);
734 trim_attribute_linear(src_curves,
735 dst_curves,
736 selection,
737 start_points,
738 end_points,
739 src_ranges,
740 transfer_attributes);
741}
742
743static void trim_evaluated_curves(const bke::CurvesGeometry &src_curves,
744 bke::CurvesGeometry &dst_curves,
745 const IndexMask &selection,
746 const Span<bke::curves::CurvePoint> start_points,
747 const Span<bke::curves::CurvePoint> end_points,
749 MutableSpan<bke::AttributeTransferData> transfer_attributes)
750{
751 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
752 const OffsetIndices src_evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
753 const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
754 const Span<float3> src_eval_positions = src_curves.evaluated_positions();
755 MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
756
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),
761 dst_positions,
762 src_ranges[curve_i],
763 dst_points,
764 start_points[curve_i],
765 end_points[curve_i]);
766 });
767 fill_bezier_data(dst_curves, selection);
768 fill_nurbs_data(dst_curves, selection);
769
770 for (bke::AttributeTransferData &attribute : transfer_attributes) {
771 bke::attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
772 using T = decltype(dummy);
773
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];
778
779 /* Interpolate onto the evaluated point domain and sample the evaluated domain. */
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>(),
785 src_ranges[curve_i],
786 dst_points_by_curve[curve_i],
787 start_points[curve_i],
788 end_points[curve_i]);
789 }
790 });
791 });
792 }
793}
794
795/* -------------------------------------------------------------------- */
798
799static float trim_sample_length(const Span<float> accumulated_lengths,
800 const float sample_length,
802{
803 float length = mode == GEO_NODE_CURVE_SAMPLE_FACTOR ?
804 sample_length * accumulated_lengths.last() :
805 sample_length;
806 return std::clamp(length, 0.0f, accumulated_lengths.last());
807}
808
813 const IndexMask &selection,
814 const VArray<float> &starts,
815 const VArray<float> &ends,
817 MutableSpan<int> dst_curve_size,
821{
822 const OffsetIndices points_by_curve = curves.points_by_curve();
823 const OffsetIndices evaluated_points_by_curve = curves.evaluated_points_by_curve();
824 const VArray<bool> src_cyclic = curves.cyclic();
825 const VArray<int> resolution = curves.resolution();
826 const VArray<int8_t> curve_types = curves.curve_types();
828
829 selection.foreach_index(GrainSize(128), [&](const int curve_i) {
830 CurveType curve_type = CurveType(curve_types[curve_i]);
831
832 int point_count;
833 if (curve_type == CURVE_TYPE_NURBS) {
834 /* The result curve is a poly curve. */
835 point_count = evaluated_points_by_curve[curve_i].size();
836 }
837 else {
838 point_count = points_by_curve[curve_i].size();
839 }
840 if (point_count == 1) {
841 /* Single point. */
842 dst_curve_size[curve_i] = 1;
843 src_ranges[curve_i] = bke::curves::IndexRangeCyclic(0, 0, 1, 1);
844 start_points[curve_i] = {{0, 0}, 0.0f};
845 end_points[curve_i] = {{0, 0}, 0.0f};
846 return;
847 }
848
849 const bool cyclic = src_cyclic[curve_i];
850 const Span<float> lengths = curves.evaluated_lengths_for_curve(curve_i, cyclic);
851 BLI_assert(lengths.size() > 0);
852
853 const float start_length = trim_sample_length(lengths, starts[curve_i], mode);
854 float end_length;
855
856 bool equal_sample_point;
857 if (cyclic) {
858 end_length = trim_sample_length(lengths, ends[curve_i], mode);
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;
862 }
863 else {
864 end_length = ends[curve_i] <= starts[curve_i] ?
865 start_length :
866 trim_sample_length(lengths, ends[curve_i], mode);
867 equal_sample_point = start_length == end_length;
868 }
869
870 start_points[curve_i] = lookup_curve_point(curves,
871 evaluated_points_by_curve,
872 curve_type,
873 curve_i,
874 lengths,
875 start_length,
876 cyclic,
877 resolution[curve_i],
878 point_count);
879 if (equal_sample_point) {
880 end_points[curve_i] = start_points[curve_i];
881 if (end_length <= start_length) {
882 /* Single point. */
883 dst_curve_size[curve_i] = 1;
884 if (start_points[curve_i].is_controlpoint()) {
885 /* Only iterate if control point. */
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;
890 single_point_index, 1, point_count);
891 }
892 /* else: leave empty range */
893 }
894 else {
895 /* Split. */
897 start_points[curve_i], end_points[curve_i], point_count)
898 .push_loop();
899 const int count = 1 + !start_points[curve_i].is_controlpoint() + point_count;
900 BLI_assert(count > 1);
901 dst_curve_size[curve_i] = count;
902 }
903 }
904 else {
905 /* General case. */
906 end_points[curve_i] = lookup_curve_point(curves,
907 evaluated_points_by_curve,
908 curve_type,
909 curve_i,
910 lengths,
911 end_length,
912 cyclic,
913 resolution[curve_i],
914 point_count);
915
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();
920 BLI_assert(count > 1);
921 dst_curve_size[curve_i] = count;
922 }
923 BLI_assert(dst_curve_size[curve_i] > 0);
924 });
925}
926
928
930 const IndexMask &selection,
931 const VArray<float> &starts,
932 const VArray<float> &ends,
934 const bke::AttributeFilter &attribute_filter)
935{
936 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
937 IndexMaskMemory memory;
938 const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
939
940 BLI_assert(selection.size() > 0);
941 BLI_assert(selection.last() <= src_curves.curves_num());
942 BLI_assert(starts.size() == src_curves.curves_num());
943 BLI_assert(starts.size() == ends.size());
944 src_curves.ensure_evaluated_lengths();
945
947 MutableSpan<int> dst_curve_offsets = dst_curves.offsets_for_write();
948 Array<bke::curves::CurvePoint, 16> start_points(src_curves.curves_num());
949 Array<bke::curves::CurvePoint, 16> end_points(src_curves.curves_num());
952 selection,
953 starts,
954 ends,
955 mode,
956 dst_curve_offsets,
957 start_points,
958 end_points,
959 src_ranges);
960 offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_curve_offsets);
962 const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
963 dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num());
964
965 /* Populate curve domain. */
966 const bke::AttributeAccessor src_attributes = src_curves.attributes();
967 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
968 Set<std::string> transfer_curve_skip = {"cyclic", "curve_type", "nurbs_order", "knots_mode"};
969 if (dst_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
970 /* If a NURBS curve is copied keep */
971 transfer_curve_skip.remove("nurbs_order");
972 transfer_curve_skip.remove("knots_mode");
973 }
974
975 /* Fetch custom point domain attributes for transfer (copy). */
977 src_attributes,
978 dst_attributes,
981 {"position",
982 "handle_left",
983 "handle_right",
984 "handle_type_left",
985 "handle_type_right",
986 "nurbs_weight"}));
987
988 auto trim_catmull = [&](const IndexMask &selection) {
989 trim_catmull_rom_curves(src_curves,
990 dst_curves,
991 selection,
992 start_points,
993 end_points,
994 src_ranges,
995 transfer_attributes);
996 };
997 auto trim_poly = [&](const IndexMask &selection) {
998 trim_polygonal_curves(src_curves,
999 dst_curves,
1000 selection,
1001 start_points,
1002 end_points,
1003 src_ranges,
1004 transfer_attributes);
1005 };
1006 auto trim_bezier = [&](const IndexMask &selection) {
1007 trim_bezier_curves(src_curves,
1008 dst_curves,
1009 selection,
1010 start_points,
1011 end_points,
1012 src_ranges,
1013 transfer_attributes);
1014 };
1015 auto trim_evaluated = [&](const IndexMask &selection) {
1017 /* Ensure evaluated positions are available. */
1018 src_curves.evaluated_positions();
1019 trim_evaluated_curves(src_curves,
1020 dst_curves,
1021 selection,
1022 start_points,
1023 end_points,
1024 src_ranges,
1025 transfer_attributes);
1026 };
1027
1028 /* Populate point domain. */
1030 src_curves.curve_type_counts(),
1031 selection,
1032 trim_catmull,
1033 trim_poly,
1034 trim_bezier,
1035 trim_evaluated);
1036
1037 /* Cleanup/close context */
1038 for (bke::AttributeTransferData &attribute : transfer_attributes) {
1039 attribute.dst.finish();
1040 }
1041
1042 /* Copy unselected */
1043 if (unselected.is_empty()) {
1044 /* Since all curves were trimmed, none of them are cyclic and the attribute can be removed. */
1045 dst_curves.attributes_for_write().remove("cyclic");
1046 }
1047 else {
1048 /* Only trimmed curves are no longer cyclic. */
1049 if (bke::SpanAttributeWriter cyclic = dst_attributes.lookup_for_write_span<bool>("cyclic")) {
1050 index_mask::masked_fill(cyclic.span, false, selection);
1051 cyclic.finish();
1052 }
1053
1054 Set<std::string> copy_point_skip;
1055 if (!dst_curves.has_curve_with_type(CURVE_TYPE_NURBS) &&
1057 {
1058 copy_point_skip.add("nurbs_weight");
1059 }
1060
1062 src_attributes,
1065 bke::attribute_filter_with_skip_ref(attribute_filter, copy_point_skip),
1066 src_points_by_curve,
1067 dst_points_by_curve,
1068 unselected,
1069 dst_attributes);
1070 }
1071
1073 dst_curves.tag_topology_changed();
1074 return dst_curves;
1075}
1076
1078
1079} // namespace blender::geometry
@ ATTR_DOMAIN_MASK_POINT
Low-level operations for curves.
Low-level operations for curves.
#define BLI_assert(a)
Definition BLI_assert.h:50
CurveType
@ CURVE_TYPE_BEZIER
@ CURVE_TYPE_NURBS
@ CURVE_TYPE_POLY
@ CURVE_TYPE_CATMULL_ROM
@ BEZIER_HANDLE_FREE
GeometryNodeCurveSampleMode
@ GEO_NODE_CURVE_SAMPLE_FACTOR
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
constexpr const T & last(const int64_t n=0) const
Definition BLI_span.hh:326
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
Definition BLI_span.hh:494
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:726
bool add(const Key &key)
Definition BLI_set.hh:248
bool remove(const Key &key)
Definition BLI_set.hh:366
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr const T & last(const int64_t n=0) const
Definition BLI_span.hh:326
constexpr const T * end() const
Definition BLI_span.hh:225
constexpr const T * begin() const
Definition BLI_span.hh:221
VArray< int8_t > handle_types_left() const
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
Span< float3 > handle_positions_left() const
VArray< int > resolution() const
Span< int > bezier_evaluated_offsets_for_curve(int curve_index) 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 resize(int points_num, int curves_num)
Span< float3 > handle_positions_right() const
void fill_curve_types(CurveType type)
MutableSpan< int > offsets_for_write()
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 IndexRangeCyclic drop_front(const int n=1) 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)
static IndexRangeCyclic get_range_from_size(const int start_index, const int iterator_size, const int iterable_range_size)
int count
static int left
#define T
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)
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
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[]
__int64 int64_t
Definition stdint.h:89
signed char int8_t
Definition stdint.h:75