Blender V4.5
curves_utils.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 "BKE_curves_utils.hh"
10#include "BKE_customdata.hh"
11
12#include "BLI_array_utils.hh"
13
14namespace blender::bke::curves {
15
17 const IndexMask &curve_selection,
18 IndexMaskMemory &memory)
19{
20 Array<index_mask::IndexMask::Initializer> point_ranges(curve_selection.size());
21 curve_selection.foreach_index(GrainSize(2048), [&](const int curve, const int pos) {
22 point_ranges[pos] = points_by_curve[curve];
23 });
24 return IndexMask::from_initializers(point_ranges, memory);
25}
26
27void fill_points(const OffsetIndices<int> points_by_curve,
28 const IndexMask &curve_selection,
29 const GPointer value,
30 GMutableSpan dst)
31{
32 BLI_assert(*value.type() == dst.type());
33 const CPPType &type = dst.type();
34 curve_selection.foreach_index(GrainSize(512), [&](const int i) {
35 const IndexRange points = points_by_curve[i];
36 type.fill_assign_n(value.get(), dst.slice(points).data(), points.size());
37 });
38}
39
41{
42 CurvesGeometry dst_curves(0, src_curves.curves_num());
44 &src_curves.curve_data, &dst_curves.curve_data, CD_MASK_ALL, src_curves.curves_num());
45 dst_curves.runtime->type_counts = src_curves.runtime->type_counts;
46 return dst_curves;
47}
48
50 const std::array<int, CURVE_TYPES_NUM> &type_counts,
51 const CurveType type,
52 const IndexMask &selection,
53 IndexMaskMemory &memory)
54{
55 if (type_counts[type] == types.size()) {
56 return selection;
57 }
58 if (types.is_single()) {
59 return types.get_internal_single() == type ? IndexMask(types.size()) : IndexMask(0);
60 }
61 Span<int8_t> types_span = types.get_internal_span();
62 return IndexMask::from_predicate(selection, GrainSize(4096), memory, [&](const int index) {
63 return types_span[index] == type;
64 });
65}
66
68 const std::array<int, CURVE_TYPES_NUM> &counts,
69 const IndexMask &selection,
70 FunctionRef<void(IndexMask)> catmull_rom_fn,
71 FunctionRef<void(IndexMask)> poly_fn,
72 FunctionRef<void(IndexMask)> bezier_fn,
73 FunctionRef<void(IndexMask)> nurbs_fn)
74{
75 auto call_if_not_empty = [&](const CurveType type, FunctionRef<void(IndexMask)> fn) {
76 IndexMaskMemory memory;
77 const IndexMask mask = indices_for_type(types, counts, type, selection, memory);
78 if (!mask.is_empty()) {
79 fn(mask);
80 }
81 };
82 call_if_not_empty(CURVE_TYPE_CATMULL_ROM, catmull_rom_fn);
83 call_if_not_empty(CURVE_TYPE_POLY, poly_fn);
84 call_if_not_empty(CURVE_TYPE_BEZIER, bezier_fn);
85 call_if_not_empty(CURVE_TYPE_NURBS, nurbs_fn);
86}
87
88static void if_has_data_call_callback(const Span<int> offset_data,
89 const int begin,
90 const int end,
91 UnselectedCallback callback)
92{
93 if (begin < end) {
95 const IndexRange points = IndexRange::from_begin_end(offset_data[begin], offset_data[end]);
96 callback(curves, points);
97 }
98};
99
100template<typename Fn>
102 const OffsetIndices<int> points_by_curve,
103 SelectedCallback selected_fn,
104 Fn unselected_fn)
105{
106 Vector<IndexRange> ranges;
107 Span<int> offset_data = points_by_curve.data();
108
109 int curve_i = mask.is_empty() ? -1 : 0;
110
111 int range_first = mask.is_empty() ? 0 : mask.first();
112 int range_last = range_first - 1;
113
114 mask.foreach_index([&](const int64_t index) {
115 if (offset_data[curve_i + 1] <= index) {
116 int first_unselected_curve = curve_i;
117 if (range_last >= range_first) {
118 ranges.append(IndexRange::from_begin_end_inclusive(range_first, range_last));
119 selected_fn(curve_i, points_by_curve[curve_i], ranges);
120 ranges.clear();
121 first_unselected_curve++;
122 }
123 do {
124 ++curve_i;
125 } while (offset_data[curve_i + 1] <= index);
126 if constexpr (std::is_invocable_r_v<void, Fn, IndexRange, IndexRange>) {
127 if_has_data_call_callback(offset_data, first_unselected_curve, curve_i, unselected_fn);
128 }
129 range_first = index;
130 }
131 else if (range_last + 1 != index) {
132 ranges.append(IndexRange::from_begin_end_inclusive(range_first, range_last));
133 range_first = index;
134 }
135 range_last = index;
136 });
137
138 if (range_last - range_first >= 0) {
139 ranges.append(IndexRange::from_begin_end_inclusive(range_first, range_last));
140 selected_fn(curve_i, points_by_curve[curve_i], ranges);
141 }
142 if constexpr (std::is_invocable_r_v<void, Fn, IndexRange, IndexRange>) {
143 if_has_data_call_callback(offset_data, curve_i + 1, points_by_curve.size(), unselected_fn);
144 }
145}
146
153
162
163namespace bezier {
164
166 const IndexMask &curves_selection)
167{
168 if (curves.is_empty() || !curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
169 return {};
170 }
171 const OffsetIndices points_by_curve = curves.points_by_curve();
172 const Span<float3> positions = curves.positions();
173 const Span<float3> handle_positions_left = curves.handle_positions_left();
174 const Span<float3> handle_positions_right = curves.handle_positions_right();
175
176 Array<float3> all_positions(positions.size() * 3);
177 curves_selection.foreach_index(GrainSize(1024), [&](const int curve) {
178 const IndexRange points = points_by_curve[curve];
179 for (const int point : points) {
180 const int index = point * 3;
181 all_positions[index] = handle_positions_left[point];
182 all_positions[index + 1] = positions[point];
183 all_positions[index + 2] = handle_positions_right[point];
184 }
185 });
186
187 return all_positions;
188}
189
191 const IndexMask &curves_selection,
192 const Span<float3> all_positions)
193{
194 if (curves_selection.is_empty() || curves.is_empty() ||
195 !curves.has_curve_with_type(CURVE_TYPE_BEZIER))
196 {
197 return;
198 }
199
200 const OffsetIndices points_by_curve = curves.points_by_curve();
201 MutableSpan<float3> positions = curves.positions_for_write();
202 MutableSpan<float3> handle_positions_left = curves.handle_positions_left_for_write();
203 MutableSpan<float3> handle_positions_right = curves.handle_positions_right_for_write();
204
205 curves_selection.foreach_index(GrainSize(1024), [&](const int curve) {
206 const IndexRange points = points_by_curve[curve];
207 for (const int point : points) {
208 const int index = point * 3;
209 handle_positions_left[point] = all_positions[index];
210 positions[point] = all_positions[index + 1];
211 handle_positions_right[point] = all_positions[index + 2];
212 }
213 });
214}
215
216} // namespace bezier
217
218namespace nurbs {
219
221 const IndexMask &src_curves,
222 const int dst_curve_offset,
224{
225 const OffsetIndices<int> src_knots_by_curve = src.nurbs_custom_knots_by_curve();
226 const int start_offset = dst.nurbs_custom_knots_by_curve()[dst_curve_offset].start();
227 Array<int> dst_offsets(src_curves.size() + 1);
228
230 src_knots_by_curve, src_curves, start_offset, dst_offsets);
231
232 array_utils::gather_group_to_group(src_knots_by_curve,
233 dst_offsets.as_span(),
234 src_curves,
235 src.nurbs_custom_knots(),
237}
238
240 const KnotsMode mode_for_regular,
241 const KnotsMode mode_for_cyclic,
243{
244 const VArray<bool> cyclic = curves.cyclic();
245 MutableSpan<int8_t> knot_modes = curves.nurbs_knots_modes_for_write();
246 mask.foreach_index(GrainSize(512), [&](const int64_t curve) {
247 int8_t &knot_mode = knot_modes[curve];
248 if (knot_mode == NURBS_KNOT_MODE_CUSTOM) {
249 knot_mode = cyclic[curve] ? mode_for_cyclic : mode_for_regular;
250 }
251 });
252 curves.nurbs_custom_knots_update_size();
253}
254
256 const IndexMask &exclude_curves,
257 bke::CurvesGeometry &dst_curves)
258{
259 BLI_assert(src_curves.curves_num() == dst_curves.curves_num());
260
261 if (src_curves.nurbs_has_custom_knots()) {
262 /* Ensure excluded curves don't have NURBS_KNOT_MODE_CUSTOM set. */
264 exclude_curves, NURBS_KNOT_MODE_NORMAL, NURBS_KNOT_MODE_NORMAL, dst_curves);
265 IndexMaskMemory memory;
267 src_curves,
269 src_curves.nurbs_custom_knot_curves(memory), exclude_curves, memory),
270 0,
271 dst_curves);
272 }
273}
274
275} // namespace nurbs
276
277} // namespace blender::bke::curves
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
#define BLI_assert(a)
Definition BLI_assert.h:46
CurveType
@ CURVE_TYPE_BEZIER
@ CURVE_TYPE_NURBS
@ CURVE_TYPE_POLY
@ CURVE_TYPE_CATMULL_ROM
KnotsMode
@ NURBS_KNOT_MODE_NORMAL
@ NURBS_KNOT_MODE_CUSTOM
iter begin(iter)
long long int int64_t
Span< T > as_span() const
Definition BLI_array.hh:232
void fill_assign_n(const void *value, void *dst, int64_t n) const
GMutableSpan slice(const int64_t start, int64_t size) const
const CPPType & type() const
const CPPType * type() const
const void * get() const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_initializers(const Span< Initializer > initializers, IndexMaskMemory &memory)
static IndexMask from_difference(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
constexpr int64_t size() const
static constexpr IndexRange from_begin_end(const int64_t begin, const int64_t end)
static constexpr IndexRange from_begin_end_inclusive(const int64_t begin, const int64_t last)
constexpr int64_t size() const
Definition BLI_span.hh:252
void append(const T &value)
MutableSpan< float > nurbs_custom_knots_for_write()
Span< float > nurbs_custom_knots() const
IndexMask nurbs_custom_knot_curves(IndexMaskMemory &memory) const
bool nurbs_has_custom_knots() const
OffsetIndices< int > nurbs_custom_knots_by_curve() const
void foreach_index(Fn &&fn) const
uint pos
#define CD_MASK_ALL
static char ** types
Definition makesdna.cc:71
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void gather_group_to_group(const OffsetIndices< int > src_offsets, const OffsetIndices< int > dst_offsets, const IndexMask &selection, const Span< T > src, MutableSpan< T > dst)
Array< float3 > retrieve_all_positions(const bke::CurvesGeometry &curves, const IndexMask &curves_selection)
void write_all_positions(bke::CurvesGeometry &curves, const IndexMask &curves_selection, Span< float3 > all_positions)
void gather_custom_knots(const bke::CurvesGeometry &src, const IndexMask &src_curves, int dst_curve_offset, bke::CurvesGeometry &dst)
void update_custom_knot_modes(const IndexMask &mask, const KnotsMode mode_for_regular, const KnotsMode mode_for_cyclic, bke::CurvesGeometry &curves)
void copy_custom_knots(const bke::CurvesGeometry &src_curves, const IndexMask &exclude_curves, bke::CurvesGeometry &dst_curves)
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
FunctionRef< void( int curve_i, IndexRange curve_points, Span< IndexRange > selected_point_ranges)> SelectedCallback
IndexMask indices_for_type(const VArray< int8_t > &types, const std::array< int, CURVE_TYPES_NUM > &type_counts, const CurveType type, const IndexMask &selection, IndexMaskMemory &memory)
void foreach_selected_point_ranges_per_curve(const IndexMask &mask, const OffsetIndices< int > points_by_curve, SelectedCallback selected_fn)
static void if_has_data_call_callback(const Span< int > offset_data, const int begin, const int end, UnselectedCallback callback)
IndexMask curve_to_point_selection(OffsetIndices< int > points_by_curve, const IndexMask &curve_selection, IndexMaskMemory &memory)
FunctionRef< void(IndexRange curves, IndexRange unselected_points)> UnselectedCallback
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)
static void foreach_selected_point_ranges_per_curve_(const IndexMask &mask, const OffsetIndices< int > points_by_curve, SelectedCallback selected_fn, Fn unselected_fn)
OffsetIndices< int > gather_selected_offsets(OffsetIndices< int > src_offsets, const IndexMask &selection, int start_offset, MutableSpan< int > dst_offsets)
CurvesGeometryRuntimeHandle * runtime
CustomData curve_data
i
Definition text_draw.cc:230