Blender V4.3
BLI_length_parameterize.hh
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#pragma once
6
11#include "BLI_index_mask.hh"
12#include "BLI_math_base.hh"
13
15
22inline int segments_num(const int points_num, const bool cyclic)
23{
24 return cyclic ? points_num : points_num - 1;
25}
26
30template<typename T>
31void accumulate_lengths(const Span<T> values, const bool cyclic, MutableSpan<float> lengths)
32{
33 /* For cyclic curves with a single point the lengths array is empty. */
34 BLI_assert(lengths.size() ==
35 (cyclic && values.size() <= 1 ? 0 : segments_num(values.size(), cyclic)));
36 float length = 0.0f;
37 for (const int i : IndexRange(values.size() - 1)) {
38 length += math::distance(values[i], values[i + 1]);
39 lengths[i] = length;
40 }
41 if (cyclic && values.size() > 1) {
42 lengths.last() = length + math::distance(values.last(), values.first());
43 }
44}
45
46template<typename T>
47inline void interpolate_to_masked(const Span<T> src,
48 const Span<int> indices,
49 const Span<float> factors,
50 const IndexMask &dst_mask,
52{
53 BLI_assert(indices.size() == factors.size());
54 BLI_assert(indices.size() == dst_mask.size());
55 const int last_src_index = src.size() - 1;
56
57 dst_mask.foreach_segment_optimized([&](const auto dst_segment, const int64_t dst_segment_pos) {
58 for (const int i : dst_segment.index_range()) {
59 const int prev_index = indices[dst_segment_pos + i];
60 const float factor = factors[dst_segment_pos + i];
61 const bool is_cyclic_case = prev_index == last_src_index;
62 if (is_cyclic_case) {
63 dst[dst_segment[i]] = math::interpolate(src.last(), src.first(), factor);
64 }
65 else {
66 dst[dst_segment[i]] = math::interpolate(src[prev_index], src[prev_index + 1], factor);
67 }
68 }
69 });
70}
71
72template<typename T>
73inline void interpolate(const Span<T> src,
74 const Span<int> indices,
75 const Span<float> factors,
77{
78 interpolate_to_masked(src, indices, factors, dst.index_range(), dst);
79}
80
89
97inline void sample_at_length(const Span<float> accumulated_segment_lengths,
98 const float sample_length,
99 int &r_segment_index,
100 float &r_factor,
101 SampleSegmentHint *hint = nullptr)
102{
103 /* Use a shorter variable name. */
104 const Span<float> lengths = accumulated_segment_lengths;
105
106 BLI_assert(lengths.size() > 0);
107 BLI_assert(sample_length >= 0.0f);
108
109 if (hint != nullptr && hint->segment_index >= 0) {
110 const float length_in_segment = sample_length - hint->segment_start;
111 const float factor = length_in_segment * hint->segment_length_inv;
112 if (factor >= 0.0f && factor < 1.0f) {
113 r_segment_index = hint->segment_index;
114 r_factor = factor;
115 return;
116 }
117 }
118
119 const float total_length = lengths.last();
120 if (sample_length >= total_length) {
121 /* Return the last position on the last segment. */
122 r_segment_index = lengths.size() - 1;
123 r_factor = 1.0f;
124 return;
125 }
126
127 const int prev_point_index = std::upper_bound(lengths.begin(), lengths.end(), sample_length) -
128 lengths.begin();
129 const float segment_start = prev_point_index == 0 ? 0.0f : lengths[prev_point_index - 1];
130 const float segment_end = lengths[prev_point_index];
131 const float segment_length = segment_end - segment_start;
132 const float segment_length_inv = math::safe_divide(1.0f, segment_length);
133 const float length_in_segment = sample_length - segment_start;
134 const float factor = length_in_segment * segment_length_inv;
135
136 r_segment_index = prev_point_index;
137 r_factor = factor;
138
139 if (hint != nullptr) {
140 hint->segment_index = r_segment_index;
141 hint->segment_start = segment_start;
142 hint->segment_length_inv = segment_length_inv;
143 }
144}
145
155void sample_uniform(Span<float> accumulated_segment_lengths,
156 bool include_last_point,
157 MutableSpan<int> r_segment_indices,
158 MutableSpan<float> r_factors);
159
169void sample_uniform_reverse(Span<float> accumulated_segment_lengths,
170 bool include_first_point,
171 MutableSpan<int> r_segment_indices,
172 MutableSpan<float> r_factors);
173
184void sample_at_lengths(Span<float> accumulated_segment_lengths,
185 Span<float> sample_lengths,
186 MutableSpan<int> r_segment_indices,
187 MutableSpan<float> r_factors);
188
189} // namespace blender::length_parameterize
#define BLI_assert(a)
Definition BLI_assert.h:50
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
constexpr const T & first() const
Definition BLI_span.hh:316
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
void foreach_segment_optimized(Fn &&fn) const
int segments_num(const int points_num, const bool cyclic)
void accumulate_lengths(const Span< T > values, const bool cyclic, MutableSpan< float > lengths)
void sample_at_lengths(Span< float > accumulated_segment_lengths, Span< float > sample_lengths, MutableSpan< int > r_segment_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 sample_at_length(const Span< float > accumulated_segment_lengths, const float sample_length, int &r_segment_index, float &r_factor, SampleSegmentHint *hint=nullptr)
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)
void interpolate_to_masked(const Span< T > src, const Span< int > indices, const Span< float > factors, const IndexMask &dst_mask, MutableSpan< T > dst)
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)
__int64 int64_t
Definition stdint.h:89