Blender V4.3
resample_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
5#include "BLI_array_utils.hh"
6#include "BLI_math_color.hh"
8
10#include "BLI_task.hh"
11
12#include "FN_field.hh"
14
15#include "BKE_attribute_math.hh"
16#include "BKE_curves.hh"
17#include "BKE_curves_utils.hh"
19
21
22namespace blender::geometry {
23
25{
26 static auto max_one_fn = mf::build::SI1_SO<int, int>(
27 "Clamp Above One",
28 [](int value) { return std::max(1, value); },
29 mf::build::exec_presets::AllSpanOrSingle());
30 return fn::Field<int>(fn::FieldOperation::Create(max_one_fn, {count_field}));
31}
32
34{
35 static auto get_count_fn = mf::build::SI2_SO<float, float, int>(
36 "Length Input to Count",
37 [](const float curve_length, const float sample_length) {
38 /* Find the number of sampled segments by dividing the total length by
39 * the sample length. Then there is one more sampled point than segment. */
40 if (UNLIKELY(sample_length == 0.0f)) {
41 return 1;
42 }
43 const int count = int(curve_length / sample_length) + 1;
44 return std::max(1, count);
45 },
46 mf::build::exec_presets::AllSpanOrSingle());
47
48 auto get_count_op = fn::FieldOperation::Create(
49 get_count_fn,
50 {fn::Field<float>(std::make_shared<bke::CurveLengthFieldInput>()), length_field});
51
52 return fn::Field<int>(std::move(get_count_op));
53}
54
59static bool interpolate_attribute_to_curves(const StringRef attribute_id,
60 const std::array<int, CURVE_TYPES_NUM> &type_counts)
61{
62 if (bke::attribute_name_is_anonymous(attribute_id)) {
63 return true;
64 }
65 if (ELEM(attribute_id, "handle_type_left", "handle_type_right", "handle_left", "handle_right")) {
66 return type_counts[CURVE_TYPE_BEZIER] != 0;
67 }
68 if (ELEM(attribute_id, "nurbs_weight")) {
69 return type_counts[CURVE_TYPE_NURBS] != 0;
70 }
71 return true;
72}
73
77static bool interpolate_attribute_to_poly_curve(const StringRef attribute_id)
78{
79 static const Set<StringRef> no_interpolation{{
80 "handle_type_left",
81 "handle_type_right",
82 "handle_right",
83 "handle_left",
84 "nurbs_weight",
85 }};
86 return !no_interpolation.contains(attribute_id);
87}
88
93 const CurvesGeometry &src_curves,
94 CurvesGeometry &dst_curves,
98{
99 const bke::AttributeAccessor src_attributes = src_curves.attributes();
100 for (const int i : ids.index_range()) {
101 const bke::GAttributeReader src_attribute = src_attributes.lookup(ids[i],
103 src.append(src_attribute.varray);
104
106 src_attribute.varray.type());
107 bke::GSpanAttributeWriter dst_attribute =
109 ids[i], bke::AttrDomain::Point, data_type);
110 dst.append(dst_attribute.span);
111 dst_attributes.append(std::move(dst_attribute));
112 }
113}
114
129
134 const CurvesGeometry &src_curves,
135 CurvesGeometry &dst_curves,
137 const ResampleCurvesOutputAttributeIDs &output_ids)
138{
140 VectorSet<StringRef> ids_no_interpolation;
141 src_curves.attributes().foreach_attribute([&](const bke::AttributeIter &iter) {
142 if (iter.domain != bke::AttrDomain::Point) {
143 return;
144 }
145 if (iter.data_type == CD_PROP_STRING) {
146 return;
147 }
148 if (!interpolate_attribute_to_curves(iter.name, dst_curves.curve_type_counts())) {
149 return;
150 }
152 ids.add_new(iter.name);
153 }
154 else {
155 ids_no_interpolation.add_new(iter.name);
156 }
157 });
158
159 /* Position is handled differently since it has non-generic interpolation for Bezier
160 * curves and because the evaluated positions are cached for each evaluated point. */
161 ids.remove_contained("position");
162
164 ids, src_curves, dst_curves, result.src, result.dst, result.dst_attributes);
165
166 /* Attributes that aren't interpolated like Bezier handles still have to be copied
167 * to the result when there are any unselected curves of the corresponding type. */
168 retrieve_attribute_spans(ids_no_interpolation,
169 src_curves,
170 dst_curves,
171 result.src_no_interpolation,
172 result.dst_no_interpolation,
173 result.dst_attributes);
174
175 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
176 if (output_ids.tangent_id) {
177 result.src_evaluated_tangents = src_curves.evaluated_tangents();
180 result.dst_tangents = dst_attribute.span.typed<float3>();
181 result.dst_attributes.append(std::move(dst_attribute));
182 }
183 if (output_ids.normal_id) {
184 result.src_evaluated_normals = src_curves.evaluated_normals();
187 result.dst_normals = dst_attribute.span.typed<float3>();
188 result.dst_attributes.append(std::move(dst_attribute));
189 }
190}
191
193 const IndexMask &unselected_curves,
194 const AttributesForResample &attributes,
195 CurvesGeometry &dst_curves)
196{
197 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
198 const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
199 array_utils::copy_group_to_group(src_points_by_curve,
200 dst_points_by_curve,
201 unselected_curves,
202 src_curves.positions(),
203 dst_curves.positions_for_write());
204
205 for (const int i : attributes.src.index_range()) {
206 array_utils::copy_group_to_group(src_points_by_curve,
207 dst_points_by_curve,
208 unselected_curves,
209 attributes.src[i],
210 attributes.dst[i]);
211 }
212 for (const int i : attributes.src_no_interpolation.index_range()) {
213 array_utils::copy_group_to_group(src_points_by_curve,
214 dst_points_by_curve,
215 unselected_curves,
216 attributes.src_no_interpolation[i],
217 attributes.dst_no_interpolation[i]);
218 }
219
220 if (!attributes.dst_tangents.is_empty()) {
222 dst_points_by_curve, unselected_curves, float3(0), attributes.dst_tangents);
223 }
224 if (!attributes.dst_normals.is_empty()) {
226 dst_points_by_curve, unselected_curves, float3(0), attributes.dst_normals);
227 }
228}
229
231{
232 for (const int i : data.index_range()) {
233 data[i] = math::normalize(data[i]);
234 }
235}
236
237static void normalize_curve_point_data(const IndexMaskSegment curve_selection,
238 const OffsetIndices<int> points_by_curve,
240{
241 for (const int i_curve : curve_selection) {
242 normalize_span(data.slice(points_by_curve[i_curve]));
243 }
244}
245
252 /* Use a default alignment that works for all attribute types, and don't use the inline buffer
253 * because it doesn't necessarily have the correct alignment. */
255 alignas(AllocatorType::min_alignment) std::array<std::byte, 1024> inline_buffer;
256
257 template<typename T> MutableSpan<T> resize(const int64_t size)
258 {
259 const int64_t size_in_bytes = sizeof(T) * size;
260 if (size_in_bytes <= this->inline_buffer.size()) {
261 return MutableSpan<std::byte>(this->inline_buffer).slice(0, size_in_bytes).cast<T>();
262 }
263 this->heap_allocated.resize(size_in_bytes);
264 return this->heap_allocated.as_mutable_span().cast<T>();
265 }
266};
267
268static void resample_to_uniform(const CurvesGeometry &src_curves,
269 const IndexMask &selection,
270 const ResampleCurvesOutputAttributeIDs &output_ids,
271 CurvesGeometry &dst_curves)
272{
273 if (src_curves.curves_range().is_empty()) {
274 return;
275 }
276
277 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
278 const OffsetIndices evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
279 const VArray<bool> curves_cyclic = src_curves.cyclic();
280 const VArray<int8_t> curve_types = src_curves.curve_types();
281 const Span<float3> evaluated_positions = src_curves.evaluated_positions();
282
283 /* All resampled curves are poly curves. */
285
286 MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
287
288 AttributesForResample attributes;
289 gather_point_attributes_to_interpolate(src_curves, dst_curves, attributes, output_ids);
290
291 src_curves.ensure_evaluated_lengths();
292
293 /* Sampling arbitrary attributes works by first interpolating them to the curve's standard
294 * "evaluated points" and then interpolating that result with the uniform samples. This is
295 * potentially wasteful when down-sampling a curve to many fewer points. There are two possible
296 * solutions: only sample the necessary points for interpolation, or first sample curve
297 * parameter/segment indices and evaluate the curve directly. */
298 Array<int> sample_indices(dst_curves.points_num());
299 Array<float> sample_factors(dst_curves.points_num());
300
301 const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
302
303 /* Use a "for each group of curves: for each attribute: for each curve" pattern to work on
304 * smaller sections of data that ideally fit into CPU cache better than simply one attribute at a
305 * time or one curve at a time. */
306 selection.foreach_segment(GrainSize(512), [&](const IndexMaskSegment selection_segment) {
307 EvalDataBuffer evaluated_buffer;
308
309 /* Gather uniform samples based on the accumulated lengths of the original curve. */
310 for (const int i_curve : selection_segment) {
311 const bool cyclic = curves_cyclic[i_curve];
312 const IndexRange dst_points = dst_points_by_curve[i_curve];
313 const Span<float> lengths = src_curves.evaluated_lengths_for_curve(i_curve, cyclic);
314 if (lengths.is_empty()) {
315 /* Handle curves with only one evaluated point. */
316 sample_indices.as_mutable_span().slice(dst_points).fill(0);
317 sample_factors.as_mutable_span().slice(dst_points).fill(0.0f);
318 }
319 else {
321 !curves_cyclic[i_curve],
322 sample_indices.as_mutable_span().slice(dst_points),
323 sample_factors.as_mutable_span().slice(dst_points));
324 }
325 }
326
327 /* For every attribute, evaluate attributes from every curve in the range in the original
328 * curve's "evaluated points", then use linear interpolation to sample to the result. */
329 for (const int i_attribute : attributes.dst.index_range()) {
330 const CPPType &type = attributes.src[i_attribute].type();
331 bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
332 using T = decltype(dummy);
333 Span<T> src = attributes.src[i_attribute].typed<T>();
334 MutableSpan<T> dst = attributes.dst[i_attribute].typed<T>();
335
336 for (const int i_curve : selection_segment) {
337 const IndexRange src_points = src_points_by_curve[i_curve];
338 const IndexRange dst_points = dst_points_by_curve[i_curve];
339
340 if (curve_types[i_curve] == CURVE_TYPE_POLY) {
342 sample_indices.as_span().slice(dst_points),
343 sample_factors.as_span().slice(dst_points),
344 dst.slice(dst_points));
345 }
346 else {
347 MutableSpan evaluated = evaluated_buffer.resize<T>(
348 evaluated_points_by_curve[i_curve].size());
349 src_curves.interpolate_to_evaluated(i_curve, src.slice(src_points), evaluated);
350
352 sample_indices.as_span().slice(dst_points),
353 sample_factors.as_span().slice(dst_points),
354 dst.slice(dst_points));
355 }
356 }
357 });
358 }
359
360 auto interpolate_evaluated_data = [&](const Span<float3> src, MutableSpan<float3> dst) {
361 for (const int i_curve : selection_segment) {
362 const IndexRange src_points = evaluated_points_by_curve[i_curve];
363 const IndexRange dst_points = dst_points_by_curve[i_curve];
365 sample_indices.as_span().slice(dst_points),
366 sample_factors.as_span().slice(dst_points),
367 dst.slice(dst_points));
368 }
369 };
370
371 /* Interpolate the evaluated positions to the resampled curves. */
372 interpolate_evaluated_data(evaluated_positions, dst_positions);
373
374 if (!attributes.dst_tangents.is_empty()) {
375 interpolate_evaluated_data(attributes.src_evaluated_tangents, attributes.dst_tangents);
376 normalize_curve_point_data(selection_segment, dst_points_by_curve, attributes.dst_tangents);
377 }
378 if (!attributes.dst_normals.is_empty()) {
379 interpolate_evaluated_data(attributes.src_evaluated_normals, attributes.dst_normals);
380 normalize_curve_point_data(selection_segment, dst_points_by_curve, attributes.dst_normals);
381 }
382
383 /* Fill the default value for non-interpolating attributes that still must be copied. */
384 for (GMutableSpan dst : attributes.dst_no_interpolation) {
385 for (const int i_curve : selection_segment) {
386 const IndexRange dst_points = dst_points_by_curve[i_curve];
387 dst.type().value_initialize_n(dst.slice(dst_points).data(), dst_points.size());
388 }
389 }
390 });
391
392 IndexMaskMemory memory;
393 const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
394 copy_or_defaults_for_unselected_curves(src_curves, unselected, attributes, dst_curves);
395
397 attribute.finish();
398 }
399}
400
402 const fn::FieldContext &field_context,
403 const fn::Field<bool> &selection_field,
404 const fn::Field<int> &count_field,
405 const ResampleCurvesOutputAttributeIDs &output_ids)
406{
407 if (src_curves.curves_range().is_empty()) {
408 return {};
409 }
410 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
411
413 MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
414
415 fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
416 evaluator.set_selection(selection_field);
417 evaluator.add_with_destination(count_field, dst_offsets.drop_back(1));
418 evaluator.evaluate();
420 IndexMaskMemory memory;
421 const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
422
423 /* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
424 offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
426 return {};
427 }
428 dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
429
430 resample_to_uniform(src_curves, selection, output_ids, dst_curves);
431
432 return dst_curves;
433}
434
436 const IndexMask &selection,
437 const VArray<int> &counts,
438 const ResampleCurvesOutputAttributeIDs &output_ids)
439{
440 if (src_curves.curves_range().is_empty()) {
441 return {};
442 }
443 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
444
446 MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
447
448 array_utils::copy(counts, selection, dst_offsets);
449
450 IndexMaskMemory memory;
451 const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
452
453 /* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
454 offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
455 /* We assume the counts are at least 1. */
456 BLI_assert(std::all_of(dst_offsets.begin(),
457 dst_offsets.drop_back(1).end(),
458 [&](const int count) { return count > 0; }));
460 dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
461
462 resample_to_uniform(src_curves, selection, output_ids, dst_curves);
463
464 return dst_curves;
465}
466
468 const fn::FieldContext &field_context,
469 const fn::Field<bool> &selection_field,
470 const fn::Field<int> &count_field,
471 const ResampleCurvesOutputAttributeIDs &output_ids)
472{
473 return resample_to_uniform(src_curves,
474 field_context,
475 selection_field,
476 get_count_input_max_one(count_field),
477 output_ids);
478}
479
481 const IndexMask &selection,
482 const VArray<float> &sample_lengths,
483 const ResampleCurvesOutputAttributeIDs &output_ids)
484{
485 if (src_curves.curves_range().is_empty()) {
486 return {};
487 }
488 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
489 const VArray<bool> curves_cyclic = src_curves.cyclic();
490
492 MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
493
494 src_curves.ensure_evaluated_lengths();
495 selection.foreach_index(GrainSize(1024), [&](const int curve_i) {
496 const float curve_length = src_curves.evaluated_length_total_for_curve(curve_i,
497 curves_cyclic[curve_i]);
498 dst_offsets[curve_i] = int(curve_length / sample_lengths[curve_i]) + 1;
499 });
500
501 IndexMaskMemory memory;
502 const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
503
504 /* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
505 offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
507 dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
508
509 resample_to_uniform(src_curves, selection, output_ids, dst_curves);
510
511 return dst_curves;
512}
513
515 const fn::FieldContext &field_context,
516 const fn::Field<bool> &selection_field,
517 const fn::Field<float> &segment_length_field,
518 const ResampleCurvesOutputAttributeIDs &output_ids)
519{
520 return resample_to_uniform(src_curves,
521 field_context,
522 selection_field,
523 get_count_input_from_length(segment_length_field),
524 output_ids);
525}
526
528 const IndexMask &selection,
529 const ResampleCurvesOutputAttributeIDs &output_ids)
530{
531 if (src_curves.curves_range().is_empty()) {
532 return {};
533 }
534 const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
535 const OffsetIndices src_evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
536 const Span<float3> evaluated_positions = src_curves.evaluated_positions();
537
538 IndexMaskMemory memory;
539 const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
540
543 MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
544 offset_indices::copy_group_sizes(src_evaluated_points_by_curve, selection, dst_offsets);
545 offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
547 const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
548
549 dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
550
551 MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
552
553 AttributesForResample attributes;
554 gather_point_attributes_to_interpolate(src_curves, dst_curves, attributes, output_ids);
555
557 selection.foreach_segment(GrainSize(512), [&](const IndexMaskSegment selection_segment) {
558 /* Evaluate generic point attributes directly to the result attributes. */
559 for (const int i_attribute : attributes.dst.index_range()) {
560 for (const int i_curve : selection_segment) {
561 const IndexRange src_points = src_points_by_curve[i_curve];
562 const IndexRange dst_points = dst_points_by_curve[i_curve];
563 src_curves.interpolate_to_evaluated(i_curve,
564 attributes.src[i_attribute].slice(src_points),
565 attributes.dst[i_attribute].slice(dst_points));
566 }
567 }
568
569 auto copy_evaluated_data = [&](const Span<float3> src, MutableSpan<float3> dst) {
570 for (const int i_curve : selection_segment) {
571 const IndexRange src_points = src_evaluated_points_by_curve[i_curve];
572 const IndexRange dst_points = dst_points_by_curve[i_curve];
573 dst.slice(dst_points).copy_from(src.slice(src_points));
574 }
575 };
576
577 /* Copy the evaluated positions to the selected curves. */
578 copy_evaluated_data(evaluated_positions, dst_positions);
579
580 if (!attributes.dst_tangents.is_empty()) {
581 copy_evaluated_data(attributes.src_evaluated_tangents, attributes.dst_tangents);
582 normalize_curve_point_data(selection_segment, dst_points_by_curve, attributes.dst_tangents);
583 }
584 if (!attributes.dst_normals.is_empty()) {
585 copy_evaluated_data(attributes.src_evaluated_normals, attributes.dst_normals);
586 normalize_curve_point_data(selection_segment, dst_points_by_curve, attributes.dst_normals);
587 }
588
589 /* Fill the default value for non-interpolating attributes that still must be copied. */
590 for (GMutableSpan dst : attributes.dst_no_interpolation) {
591 for (const int i_curve : selection_segment) {
592 const IndexRange dst_points = dst_points_by_curve[i_curve];
593 dst.type().value_initialize_n(dst.slice(dst_points).data(), dst_points.size());
594 }
595 }
596 });
597
598 copy_or_defaults_for_unselected_curves(src_curves, unselected, attributes, dst_curves);
599
601 attribute.finish();
602 }
603
604 return dst_curves;
605}
606
608 const fn::FieldContext &field_context,
609 const fn::Field<bool> &selection_field,
610 const ResampleCurvesOutputAttributeIDs &output_ids)
611{
612 if (src_curves.curves_range().is_empty()) {
613 return {};
614 }
615 fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
616 evaluator.set_selection(selection_field);
617 evaluator.evaluate();
619 src_curves, evaluator.get_evaluated_selection_as_mask(), output_ids);
620}
621
622} // namespace blender::geometry
Low-level operations for curves.
Low-level operations for curves.
#define BLI_assert(a)
Definition BLI_assert.h:50
#define UNLIKELY(x)
#define ELEM(...)
@ CURVE_TYPE_BEZIER
@ CURVE_TYPE_NURBS
@ CURVE_TYPE_POLY
@ CD_PROP_FLOAT3
@ CD_PROP_STRING
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
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
void value_initialize_n(void *ptr, int64_t n) const
GMutableSpan slice(const int64_t start, int64_t size) const
const CPPType & type() const
MutableSpan< T > typed() const
static constexpr size_t min_alignment
constexpr int64_t size() const
constexpr bool is_empty() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr MutableSpan< NewT > cast() const
Definition BLI_span.hh:736
constexpr MutableSpan drop_back(const int64_t n) const
Definition BLI_span.hh:619
constexpr Span< T > as_span() const
Definition BLI_span.hh:662
constexpr T * end() const
Definition BLI_span.hh:549
constexpr T * begin() const
Definition BLI_span.hh:545
constexpr T & last(const int64_t n=0) const
Definition BLI_span.hh:690
NonCopyable(const NonCopyable &other)=delete
NonMovable(NonMovable &&other)=delete
bool contains(const Key &key) const
Definition BLI_set.hh:291
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
void add_new(const Key &key)
void remove_contained(const Key &key)
void append(const T &value)
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
void ensure_can_interpolate_to_evaluated() const
IndexRange curves_range() const
const std::array< int, CURVE_TYPES_NUM > & curve_type_counts() const
MutableAttributeAccessor attributes_for_write()
Span< float > evaluated_lengths_for_curve(int curve_index, bool cyclic) const
Span< float3 > evaluated_tangents() const
void interpolate_to_evaluated(int curve_index, GSpan src, GMutableSpan dst) const
Span< float3 > evaluated_normals() const
Span< float3 > positions() const
OffsetIndices< int > evaluated_points_by_curve() const
void resize(int points_num, int curves_num)
void fill_curve_types(CurveType type)
float evaluated_length_total_for_curve(int curve_index, bool cyclic) const
MutableSpan< int > offsets_for_write()
Span< float3 > evaluated_positions() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
void set_selection(Field< bool > selection)
Definition FN_field.hh:385
IndexMask get_evaluated_selection_as_mask() const
Definition field.cc:822
int add_with_destination(GField field, GVMutableArray dst)
Definition field.cc:743
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:244
OffsetIndices slice(const IndexRange range) const
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
int count
#define T
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void copy_group_to_group(OffsetIndices< int > src_offsets, OffsetIndices< int > dst_offsets, const IndexMask &selection, GSpan src, GMutableSpan dst)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
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)
bool attribute_name_is_anonymous(const StringRef name)
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
static fn::Field< int > get_count_input_max_one(const fn::Field< int > &count_field)
static AttributesForInterpolation retrieve_attribute_spans(const Span< StringRef > ids, const CurvesGeometry &src_from_curves, const CurvesGeometry &src_to_curves, const bke::AttrDomain domain, CurvesGeometry &dst_curves)
static void normalize_span(MutableSpan< float3 > data)
static void copy_or_defaults_for_unselected_curves(const CurvesGeometry &src_curves, const IndexMask &unselected_curves, const AttributesForResample &attributes, CurvesGeometry &dst_curves)
CurvesGeometry resample_to_count(const CurvesGeometry &src_curves, const IndexMask &selection, const VArray< int > &counts, const ResampleCurvesOutputAttributeIDs &output_ids={})
static bool interpolate_attribute_to_poly_curve(const StringRef attribute_id)
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves, const IndexMask &selection, const ResampleCurvesOutputAttributeIDs &output_ids={})
static void resample_to_uniform(const CurvesGeometry &src_curves, const IndexMask &selection, const ResampleCurvesOutputAttributeIDs &output_ids, CurvesGeometry &dst_curves)
static bool interpolate_attribute_to_curves(const StringRef attribute_id, const std::array< int, CURVE_TYPES_NUM > &type_counts)
static fn::Field< int > get_count_input_from_length(const fn::Field< float > &length_field)
static AttributesForInterpolation gather_point_attributes_to_interpolate(const CurvesGeometry &from_curves, const CurvesGeometry &to_curves, CurvesGeometry &dst_curves)
static void normalize_curve_point_data(const IndexMaskSegment curve_selection, const OffsetIndices< int > points_by_curve, MutableSpan< float3 > data)
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves, const IndexMask &selection, const VArray< float > &sample_lengths, const ResampleCurvesOutputAttributeIDs &output_ids={})
void interpolate(const Span< T > src, const Span< int > indices, const Span< float > factors, MutableSpan< T > dst)
void sample_uniform(Span< float > accumulated_segment_lengths, bool include_last_point, MutableSpan< int > r_segment_indices, MutableSpan< float > r_factors)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
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)
std::optional< OffsetIndices< int > > accumulate_counts_to_offsets_with_overflow_check(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
Vector< bke::GSpanAttributeWriter > dst_attributes
GuardedAlignedAllocator<> AllocatorType
MutableSpan< T > resize(const int64_t size)
std::array< std::byte, 1024 > inline_buffer
Vector< std::byte, 0, AllocatorType > heap_allocated