25using bke::CurvesGeometry;
31 const int samples_num)
35 sample_by_point[0] = 0.0f;
37 sample_by_point[
i] = sample_by_point[
i - 1] +
math::distance(positions[
i - 1], positions[
i]);
39 sample_by_point.
last() = cyclic ? sample_by_point[points.
size() - 1] +
41 sample_by_point[points.
size() - 1];
44 constexpr float length_epsilon = 1e-4f;
45 if (sample_by_point.
last() <= length_epsilon) {
49 const float total_length = sample_by_point.
last();
51 const float length_to_sample_count =
math::safe_divide(
float(samples_num), total_length);
52 for (
float &sample_value : sample_by_point) {
53 sample_value *= length_to_sample_count;
56 return sample_by_point;
71 const int num_free_samples = num_dst_points - int(src_points.
size());
73 src_positions, cyclic, num_free_samples);
75 int samples_start = 0;
76 for (
const int src_point_i : src_points) {
77 dst_sample_offsets[src_point_i] = samples_start;
80 const int free_samples =
math::round(sample_by_point[src_point_i + 1]) -
82 samples_start += 1 + free_samples;
86 dst_sample_offsets.
last() = num_dst_points;
94 const int num_dst_points = r_indices.
size();
98 if (num_dst_points == 0) {
101 if (num_dst_points == 1) {
102 r_indices.
first() = 0;
103 r_factors.
first() = 0.0f;
110 if (src_points.
size() == 1) {
112 r_factors.
fill(0.0f);
120 if (num_dst_points >= src_points.
size()) {
126 for (
const int src_point_i : src_points.
index_range()) {
127 const IndexRange samples = dst_samples_by_src_point[src_point_i];
129 r_indices.
slice(samples).
fill(src_point_i);
131 const int sample = samples[sample_i];
132 const float factor = float(sample_i) / samples.
size();
133 r_factors[
sample] = factor;
139 positions, cyclic, num_dst_points - (cyclic ? 0 : 1));
141 for (
const int src_point_i : src_points.
index_range()) {
142 const float sample_start = sample_by_point[src_point_i];
143 const float sample_end = sample_by_point[src_point_i + 1];
147 for (
const int sample : samples) {
148 r_indices[
sample] = src_point_i;
150 sample_end - sample_start);
154 r_indices.
last() = src_points.
size() - 1;
155 r_factors.
last() = 0.0f;
170 const int index = r_indices[
i];
171 const float factor = r_factors[
i];
172 const bool is_last_segment = index >= points_num - 1;
174 if (is_last_segment && factor > 0.0f) {
175 reverse_indices.
append(points_num - 1);
176 reverse_factors.
append(1.0f - factor);
181 const int index = r_indices[
i];
182 const float factor = r_factors[
i];
183 const bool is_last_segment = index >= points_num - 1;
187 if (is_last_segment) {
190 reverse_indices.
append(points_num - 2 - index);
191 reverse_factors.
append(1.0f - r_factors[
i]);
195 reverse_indices.
append(points_num - 1 - index);
196 reverse_factors.
append(0.0f);
205 const int curve_index,
217 const int points_num = positions.
size();
220 reverse_positions[
i] = positions[points_num - 1 -
i];
237 const std::array<int, CURVE_TYPES_NUM> &type_counts)
242 if (
ELEM(attribute_id,
"handle_type_left",
"handle_type_right",
"handle_left",
"handle_right")) {
245 if (
ELEM(attribute_id,
"nurbs_weight")) {
263 return !no_interpolation.
contains(attribute_id);
290 const GVArray src_from_attribute = *src_from_attributes.
lookup(ids[
i], domain);
291 if (src_from_attribute) {
294 const GVArray src_to_attribute = *src_to_attributes.
lookup(ids[
i], domain, data_type);
296 result.src_from.append(src_from_attribute);
300 const GVArray src_to_attribute = *src_to_attributes.
lookup(ids[
i], domain);
307 result.src_to.append(src_to_attribute);
311 ids[
i], domain, data_type);
312 result.dst.append(std::move(dst_attribute));
340 if (iter.name ==
"position") {
371 if (iter.name ==
"curve_type") {
388 const GSpan src_data,
402 const int dst_points_num = dst_data.
size();
408 using T =
decltype(dummy);
414 const int i_src_curve = src_curve_indices[
pos];
415 if (i_src_curve < 0) {
419 const IndexRange src_points = src_points_by_curve[i_src_curve];
420 const IndexRange dst_points = dst_points_by_curve[i_dst_curve];
424 dst_sample_indices.
slice(dst_points),
425 dst_sample_factors.
slice(dst_points),
426 dst.
slice(dst_points));
429 const IndexRange src_evaluated_points = src_evaluated_points_by_curve[i_src_curve];
430 evaluated_data.reinitialize(src_evaluated_points.
size());
432 i_src_curve, src.
slice(src_points), evaluated_data.as_mutable_span());
434 dst_sample_indices.
slice(dst_points),
435 dst_sample_factors.
slice(dst_points),
436 dst.
slice(dst_points));
445 const float mix_factor,
448 if (mix_factor == 0.0f) {
451 else if (mix_factor == 1.0f) {
468 using T = decltype(dummy);
469 const Span<T> from = src_from.typed<T>();
470 const Span<T> to = src_to.typed<T>();
471 const MutableSpan<T> dst_typed = dst.typed<T>();
472 selection.foreach_index(GrainSize(512), [&](const int curve) {
473 const float mix_factor = mix_factors[curve];
474 if (mix_factor == 0.0f) {
475 dst_typed[curve] = from[curve];
477 else if (mix_factor == 1.0f) {
478 dst_typed[curve] = to[curve];
481 dst_typed[curve] = math::interpolate(from[curve], to[curve], mix_factor);
497 using T = decltype(dummy);
498 const Span<T> from = src_from.typed<T>();
499 const Span<T> to = src_to.typed<T>();
500 const MutableSpan<T> dst_typed = dst.typed<T>();
501 mix_arrays(from.slice(range), to.slice(range), mix_factors[curve], dst_typed.slice(range));
515 const float mix_factor,
539 from_curves, to_curves, dst_curves);
541 from_curves, to_curves, dst_curves);
550 const int i_from_curve = from_curve_indices[
pos];
551 const int i_to_curve = to_curve_indices[
pos];
552 if (i_from_curve >= 0 && i_to_curve >= 0) {
553 mix_factors[i_dst_curve] = mix_factor;
554 mix_from_to[i_dst_curve] =
true;
555 exclusive_from[i_dst_curve] =
false;
556 exclusive_to[i_dst_curve] =
false;
558 else if (i_to_curve >= 0) {
559 mix_factors[i_dst_curve] = 1.0f;
560 mix_from_to[i_dst_curve] =
false;
561 exclusive_from[i_dst_curve] =
false;
562 exclusive_to[i_dst_curve] =
true;
565 mix_factors[i_dst_curve] = 0.0f;
566 mix_from_to[i_dst_curve] =
false;
567 exclusive_from[i_dst_curve] =
true;
568 exclusive_to[i_dst_curve] =
false;
581 for (
const int i_attribute : point_attributes.
dst.index_range()) {
583 if (!point_attributes.
dst[i_attribute]) {
587 const GSpan src_from = point_attributes.
src_from[i_attribute];
588 const GSpan src_to = point_attributes.
src_to[i_attribute];
612 mix_arrays(from_samples, to_samples, mix_factors, dst_curve_mask, dst_points_by_curve, dst);
644 from_evaluated_positions,
652 to_evaluated_positions,
666 for (
const int i_attribute : curve_attributes.
dst.index_range()) {
668 if (!curve_attributes.
dst[i_attribute]) {
672 const GSpan src_from = curve_attributes.
src_from[i_attribute];
673 const GSpan src_to = curve_attributes.
src_to[i_attribute];
690 mix_arrays(from_samples, to_samples, mix_factors, mix_curve_mask, dst);
711 const int curve_index,
720 r_segment_indices.
fill(0);
721 r_factors.
fill(0.0f);
727 segment_lengths, !cyclic, r_segment_indices, r_factors);
740 const float mix_factor,
763 const int i_from_curve = from_curve_indices[
pos];
764 const int i_to_curve = to_curve_indices[
pos];
766 const IndexRange dst_points = dst_points_by_curve[i_dst_curve];
770 from_curves_cyclic[i_from_curve],
776 to_curves_cyclic[i_to_curve],
777 dst_curve_flip_direction[i_dst_curve],
Low-level operations for curves.
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
Span< T > as_span() const
MutableSpan< T > as_mutable_span()
const T & last(const int64_t n=0) const
IndexRange index_range() const
const CPPType & type() const
MutableSpan< T > typed() const
const CPPType & type() const
const CPPType & type() const
static GVArray ForSpan(GSpan span)
constexpr int64_t size() const
constexpr bool is_empty() const
static constexpr IndexRange from_begin_end(const int64_t begin, const int64_t end)
constexpr bool contains(int64_t value) const
constexpr IndexRange index_range() const
constexpr IndexRange drop_front(int64_t n) const
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr void fill(const T &value) const
constexpr T & first() const
constexpr IndexRange index_range() const
constexpr void copy_from(Span< T > values) const
constexpr T & last(const int64_t n=0) const
bool contains(const Key &key) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr const T & first() const
constexpr int64_t size() const
constexpr const T & last(const int64_t n=0) const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
void append(const T &value)
void reserve(const int64_t min_capacity)
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
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
void interpolate_to_evaluated(int curve_index, GSpan src, GMutableSpan dst) const
Span< float3 > positions() const
OffsetIndices< int > evaluated_points_by_curve() const
void fill_curve_types(CurveType type)
AttributeAccessor attributes() const
void ensure_evaluated_lengths() const
Span< float3 > evaluated_positions() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
void foreach_index(Fn &&fn) const
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void fill_index_range(MutableSpan< T > span, const T start=0)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
bool attribute_name_is_anonymous(const StringRef name)
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
static AttributesForInterpolation gather_curve_attributes_to_interpolate(const CurvesGeometry &from_curves, const CurvesGeometry &to_curves, CurvesGeometry &dst_curves)
static void mix_arrays(const Span< T > from, const Span< T > to, const float mix_factor, const MutableSpan< T > dst)
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)
void interpolate_curves_with_samples(const bke::CurvesGeometry &from_curves, const bke::CurvesGeometry &to_curves, Span< int > from_curve_indices, Span< int > to_curve_indices, Span< int > from_sample_indices, Span< int > to_sample_indices, Span< float > from_sample_factors, Span< float > to_sample_factors, const IndexMask &dst_curve_mask, float mix_factor, bke::CurvesGeometry &dst_curves, IndexMaskMemory &memory)
static Array< float > build_point_to_sample_map(const Span< float3 > positions, const bool cyclic, const int samples_num)
void sample_curve_padded(const Span< float3 > positions, bool cyclic, MutableSpan< int > r_indices, MutableSpan< float > r_factors)
static void sample_curve_attribute(const bke::CurvesGeometry &src_curves, const Span< int > src_curve_indices, const OffsetIndices< int > dst_points_by_curve, const GSpan src_data, const IndexMask &dst_curve_mask, const Span< int > dst_sample_indices, const Span< float > dst_sample_factors, GMutableSpan dst_data)
static void sample_curve_uniform(const bke::CurvesGeometry &curves, const int curve_index, const bool cyclic, const bool reverse, MutableSpan< int > r_segment_indices, MutableSpan< float > r_factors)
void interpolate_curves(const bke::CurvesGeometry &from_curves, const bke::CurvesGeometry &to_curves, Span< int > from_curve_indices, Span< int > to_curve_indices, const IndexMask &dst_curve_mask, Span< bool > dst_curve_flip_direction, float mix_factor, bke::CurvesGeometry &dst_curves, IndexMaskMemory &memory)
static bool interpolate_attribute_to_poly_curve(const StringRef attribute_id)
static void assign_samples_to_segments(const int num_dst_points, const Span< float3 > src_positions, const bool cyclic, MutableSpan< int > dst_sample_offsets)
static bool interpolate_attribute_to_curves(const StringRef attribute_id, const std::array< int, CURVE_TYPES_NUM > &type_counts)
static AttributesForInterpolation gather_point_attributes_to_interpolate(const CurvesGeometry &from_curves, const CurvesGeometry &to_curves, CurvesGeometry &dst_curves)
static void reverse_samples(const int points_num, MutableSpan< int > r_indices, MutableSpan< float > r_factors)
void sample_uniform_reverse(Span< float > accumulated_segment_lengths, bool include_first_point, MutableSpan< int > r_segment_indices, MutableSpan< float > r_factors)
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)
T safe_divide(const T &a, const T &b)
T distance(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
Vector< bke::GSpanAttributeWriter > dst
Vector< GVArraySpan > src_from
Vector< GVArraySpan > src_to