Blender V5.0
curves_remove_and_split.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_array_utils.hh"
6
7#include "BKE_attribute.hh"
8#include "BKE_curves.hh"
9#include "BKE_curves_utils.hh"
10#include "BKE_deform.hh"
11
13
14namespace blender::geometry {
15
17 const IndexMask &mask)
18{
19 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
20 const VArray<bool> src_cyclic = curves.cyclic();
21
22 Array<bool> points_to_delete(curves.points_num());
23 mask.to_bools(points_to_delete.as_mutable_span());
24 const int total_points = points_to_delete.as_span().count(false);
25
26 /* Return if deleting everything. */
27 if (total_points == 0) {
28 return {};
29 }
30
31 int curr_dst_point_id = 0;
32 Array<int> dst_to_src_point(total_points);
33 Vector<int> dst_curve_counts;
34 Vector<int> dst_to_src_curve;
35 Vector<bool> dst_cyclic;
36
37 for (const int curve_i : curves.curves_range()) {
38 const IndexRange points = points_by_curve[curve_i];
39 const Span<bool> curve_points_to_delete = points_to_delete.as_span().slice(points);
40 const bool curve_cyclic = src_cyclic[curve_i];
41
42 /* Note, these ranges start at zero and needed to be shifted by `points.first()` */
43 const Vector<IndexRange> ranges_to_keep = array_utils::find_all_ranges(curve_points_to_delete,
44 false);
45
46 if (ranges_to_keep.is_empty()) {
47 continue;
48 }
49
50 const bool is_last_segment_selected = curve_cyclic && ranges_to_keep.first().first() == 0 &&
51 ranges_to_keep.last().last() == points.size() - 1;
52 const bool is_curve_self_joined = is_last_segment_selected && ranges_to_keep.size() != 1;
53 const bool is_cyclic = ranges_to_keep.size() == 1 && is_last_segment_selected;
54
55 IndexRange range_ids = ranges_to_keep.index_range();
56 /* Skip the first range because it is joined to the end of the last range. */
57 for (const int range_i : ranges_to_keep.index_range().drop_front(is_curve_self_joined)) {
58 const IndexRange range = ranges_to_keep[range_i];
59
60 int count = range.size();
61 for (const int src_point : range.shift(points.first())) {
62 dst_to_src_point[curr_dst_point_id++] = src_point;
63 }
64
65 /* Join the first range to the end of the last range. */
66 if (is_curve_self_joined && range_i == range_ids.last()) {
67 const IndexRange first_range = ranges_to_keep[range_ids.first()];
68 for (const int src_point : first_range.shift(points.first())) {
69 dst_to_src_point[curr_dst_point_id++] = src_point;
70 }
71 count += first_range.size();
72 }
73
74 dst_curve_counts.append(count);
75 dst_to_src_curve.append(curve_i);
76 dst_cyclic.append(is_cyclic);
77 }
78 }
79
80 const int total_curves = dst_to_src_curve.size();
81
82 bke::CurvesGeometry dst_curves(total_points, total_curves);
83
85
86 MutableSpan<int> new_curve_offsets = dst_curves.offsets_for_write();
87 array_utils::copy(dst_curve_counts.as_span(), new_curve_offsets.drop_back(1));
89
90 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
91 const bke::AttributeAccessor src_attributes = curves.attributes();
92
93 /* Transfer curve attributes. */
94 gather_attributes(src_attributes,
98 dst_to_src_curve,
99 dst_attributes);
100 array_utils::copy(dst_cyclic.as_span(), dst_curves.cyclic_for_write());
101
102 /* Transfer point attributes. */
103 gather_attributes(src_attributes,
106 {},
107 dst_to_src_point,
108 dst_attributes);
109
110 dst_curves.update_curve_types();
112
113 if (curves.nurbs_has_custom_knots()) {
116 }
117 return dst_curves;
118}
119
120} // namespace blender::geometry
Low-level operations for curves.
Low-level operations for curves.
support for deformation groups and hooks.
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:73
@ NURBS_KNOT_MODE_NORMAL
Span< T > as_span() const
Definition BLI_array.hh:243
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
constexpr int64_t first() const
constexpr IndexRange shift(int64_t n) const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr IndexRange drop_front(int64_t n) const
constexpr MutableSpan drop_back(const int64_t n) const
Definition BLI_span.hh:618
int64_t size() const
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
IndexRange index_range() const
Span< T > as_span() const
const T & first() const
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
bool nurbs_has_custom_knots() const
VArray< bool > cyclic() const
MutableSpan< bool > cyclic_for_write()
static bool is_cyclic(const Nurb *nu)
int count
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
Vector< IndexRange > find_all_ranges(const Span< T > span, const T &value)
void update_custom_knot_modes(const IndexMask &mask, const KnotsMode mode_for_regular, const KnotsMode mode_for_cyclic, bke::CurvesGeometry &curves)
auto attribute_filter_from_skip_ref(const Span< StringRef > skip)
bke::CurvesGeometry remove_points_and_split(const bke::CurvesGeometry &curves, const IndexMask &mask)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
ListBase vertex_group_names