Blender V4.3
BLI_length_parameterize_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "BLI_math_color.hh"
6#include "BLI_math_vector.hh"
7
8#include "BLI_array.hh"
10#include "BLI_vector.hh"
11
12#include "testing/testing.h"
13
15
16template<typename T> Array<float> calculate_lengths(const Span<T> values, const bool cyclic)
17{
18 Array<float> lengths(segments_num(values.size(), cyclic));
19 accumulate_lengths<T>(values, cyclic, lengths);
20 return lengths;
21}
22
23template<typename T> void test_uniform_lengths(const Span<T> values)
24{
25 const float segment_length = math::distance(values.first(), values.last()) / (values.size() - 1);
26 for (const int i : values.index_range().drop_back(1)) {
27 EXPECT_NEAR(math::distance(values[i], values[i + 1]), segment_length, 1e-5);
28 }
29}
30
31TEST(length_parameterize, FloatSimple)
32{
33 Array<float> values{{0, 1, 4}};
34 Array<float> lengths = calculate_lengths(values.as_span(), false);
35
37 Array<float> factors(4);
38 sample_uniform(lengths, true, indices, factors);
39 Array<float> results(4);
40 interpolate<float>(values, indices, factors, results);
41 Array<float> expected({
42 0.0f,
43 1.33333f,
44 2.66667f,
45 4.0f,
46 });
47 for (const int i : results.index_range()) {
48 EXPECT_NEAR(results[i], expected[i], 1e-5);
49 }
51}
52
53TEST(length_parameterize, Float)
54{
55 Array<float> values{{1, 2, 3, 5, 10}};
56 Array<float> lengths = calculate_lengths(values.as_span(), false);
57
59 Array<float> factors(20);
60 sample_uniform(lengths, true, indices, factors);
61 Array<float> results(20);
62 interpolate<float>(values, indices, factors, results);
63 Array<float> expected({
64 1.0f, 1.47368f, 1.94737f, 2.42105f, 2.89474f, 3.36842f, 3.84211f,
65 4.31579f, 4.78947f, 5.26316f, 5.73684f, 6.21053f, 6.68421f, 7.1579f,
66 7.63158f, 8.10526f, 8.57895f, 9.05263f, 9.52632f, 10.0f,
67 });
68 for (const int i : results.index_range()) {
69 EXPECT_NEAR(results[i], expected[i], 1e-5);
70 }
72}
73
74TEST(length_parameterize, Float2)
75{
76 Array<float2> values{{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
77 Array<float> lengths = calculate_lengths(values.as_span(), false);
78
80 Array<float> factors(12);
81 sample_uniform(lengths, true, indices, factors);
82 Array<float2> results(12);
83 interpolate<float2>(values, indices, factors, results);
84 Array<float2> expected({
85 {0.0f, 0.0f},
86 {0.272727f, 0.0f},
87 {0.545455f, 0.0f},
88 {0.818182f, 0.0f},
89 {1.0f, 0.0909091f},
90 {1.0f, 0.363636f},
91 {1.0f, 0.636364f},
92 {1.0f, 0.909091f},
93 {0.818182f, 1.0f},
94 {0.545455f, 1.0f},
95 {0.272727f, 1.0f},
96 {0.0f, 1.0f},
97 });
98 for (const int i : results.index_range()) {
99 EXPECT_NEAR(results[i].x, expected[i].x, 1e-5);
100 EXPECT_NEAR(results[i].y, expected[i].y, 1e-5);
101 }
102}
103
104TEST(length_parameterize, Float2Cyclic)
105{
106 Array<float2> values{{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
107 Array<float> lengths = calculate_lengths(values.as_span(), true);
108
110 Array<float> factors(12);
111 sample_uniform(lengths, false, indices, factors);
112 Array<float2> results(12);
113 interpolate<float2>(values, indices, factors, results);
114 Array<float2> expected({
115 {0.0f, 0.0f},
116 {0.333333f, 0.0f},
117 {0.666667f, 0.0f},
118 {1.0f, 0.0f},
119 {1.0f, 0.333333f},
120 {1.0f, 0.666667f},
121 {1.0f, 1.0f},
122 {0.666667f, 1.0f},
123 {0.333333f, 1.0f},
124 {0.0f, 1.0f},
125 {0.0f, 0.666667f},
126 {0.0f, 0.333333f},
127 });
128 for (const int i : results.index_range()) {
129 EXPECT_NEAR(results[i].x, expected[i].x, 1e-5);
130 EXPECT_NEAR(results[i].y, expected[i].y, 1e-5);
131 }
132}
133
134TEST(length_parameterize, LineMany)
135{
136 Array<float> values{{1, 2}};
137 Array<float> lengths = calculate_lengths(values.as_span(), false);
138
139 Array<int> indices(5007);
140 Array<float> factors(5007);
141 sample_uniform(lengths, true, indices, factors);
142 Array<float> results(5007);
143 interpolate<float>(values, indices, factors, results);
144 Array<float> expected({
145 1.9962f, 1.9964f, 1.9966f, 1.9968f, 1.997f, 1.9972f, 1.9974f, 1.9976f, 1.9978f, 1.998f,
146 1.9982f, 1.9984f, 1.9986f, 1.9988f, 1.999f, 1.9992f, 1.9994f, 1.9996f, 1.9998f, 2.0f,
147 });
148 for (const int i : expected.index_range()) {
149 EXPECT_NEAR(results.as_span().take_back(20)[i], expected[i], 1e-5);
150 }
151}
152
153TEST(length_parameterize, CyclicMany)
154{
155 Array<float2> values{{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
156 Array<float> lengths = calculate_lengths(values.as_span(), true);
157
158 Array<int> indices(5007);
159 Array<float> factors(5007);
160 sample_uniform(lengths, false, indices, factors);
161 Array<float2> results(5007);
162 interpolate<float2>(values, indices, factors, results);
163 Array<float2> expected({
164 {0, 0.0159776}, {0, 0.0151787}, {0, 0.0143797}, {0, 0.013581}, {0, 0.0127821},
165 {0, 0.0119832}, {0, 0.0111842}, {0, 0.0103855}, {0, 0.00958657}, {0, 0.00878763},
166 {0, 0.00798869}, {0, 0.00718999}, {0, 0.00639105}, {0, 0.00559211}, {0, 0.00479317},
167 {0, 0.00399446}, {0, 0.00319552}, {0, 0.00239658}, {0, 0.00159764}, {0, 0.000798941},
168 });
169 for (const int i : expected.index_range()) {
170 EXPECT_NEAR(results.as_span().take_back(20)[i].x, expected[i].x, 1e-5);
171 EXPECT_NEAR(results.as_span().take_back(20)[i].y, expected[i].y, 1e-5);
172 }
173}
174
175TEST(length_parameterize, InterpolateColor)
176{
177 Array<float2> values{{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
178 Array<float> lengths = calculate_lengths(values.as_span(), true);
179
180 Array<ColorGeometry4f> colors{{{0, 0, 0, 1}, {1, 0, 0, 1}, {1, 1, 0, 1}, {0, 1, 0, 1}}};
181
183 Array<float> factors(10);
184 sample_uniform(lengths, false, indices, factors);
185 Array<ColorGeometry4f> results(10);
186 interpolate<ColorGeometry4f>(colors, indices, factors, results);
187 Array<ColorGeometry4f> expected({
188 {0, 0, 0, 1},
189 {0.4, 0, 0, 1},
190 {0.8, 0, 0, 1},
191 {1, 0.2, 0, 1},
192 {1, 0.6, 0, 1},
193 {1, 1, 0, 1},
194 {0.6, 1, 0, 1},
195 {0.2, 1, 0, 1},
196 {0, 0.8, 0, 1},
197 {0, 0.4, 0, 1},
198 });
199 for (const int i : results.index_range()) {
200 EXPECT_NEAR(results[i].r, expected[i].r, 1e-6);
201 EXPECT_NEAR(results[i].g, expected[i].g, 1e-6);
202 EXPECT_NEAR(results[i].b, expected[i].b, 1e-6);
203 EXPECT_NEAR(results[i].a, expected[i].a, 1e-6);
204 }
205}
206
207TEST(length_parameterize, ArbitraryFloatSimple)
208{
209 Array<float> values{{0, 1, 4}};
210 Array<float> lengths = calculate_lengths(values.as_span(), false);
211
212 Array<float> sample_lengths{{0.5f, 1.5f, 2.0f, 4.0f}};
214 Array<float> factors(4);
215 sample_at_lengths(lengths, sample_lengths, indices, factors);
216 Array<float> results(4);
217 interpolate<float>(values, indices, factors, results);
218 Array<float> expected({
219 0.5f,
220 1.5f,
221 2.0f,
222 4.0f,
223 });
224 for (const int i : results.index_range()) {
225 EXPECT_NEAR(results[i], expected[i], 1e-5);
226 }
227}
228
229TEST(length_parameterize, ArbitraryFloat2)
230{
231 Array<float2> values{{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
232 Array<float> lengths = calculate_lengths(values.as_span(), true);
233
234 Array<float> sample_lengths{
235 {0.5f, 1.5f, 2.0f, 2.0f, 2.1f, 2.5f, 3.5f, 3.6f, 3.8f, 3.85f, 3.90f, 4.0f}};
237 Array<float> factors(12);
238 sample_at_lengths(lengths, sample_lengths, indices, factors);
239 Array<float2> results(12);
240 interpolate<float2>(values, indices, factors, results);
241 Array<float2> expected({
242 {0.5f, 0.0f},
243 {1.0f, 0.5f},
244 {1.0f, 1.0f},
245 {1.0f, 1.0f},
246 {0.9f, 1.0f},
247 {0.5f, 1.0f},
248 {0.0f, 0.5f},
249 {0.0f, 0.4f},
250 {0.0f, 0.2f},
251 {0.0f, 0.15f},
252 {0.0f, 0.1f},
253 {0.0f, 0.0f},
254 });
255 for (const int i : results.index_range()) {
256 EXPECT_NEAR(results[i].x, expected[i].x, 1e-5);
257 EXPECT_NEAR(results[i].y, expected[i].y, 1e-5);
258 }
259}
260
261} // namespace blender::length_parameterize::tests
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
Span< T > as_span() const
Definition BLI_array.hh:232
IndexRange index_range() const
Definition BLI_array.hh:349
local_group_size(16, 16) .push_constant(Type b
static ushort indices[]
Array< float > calculate_lengths(const Span< T > values, const bool cyclic)
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 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 distance(const T &a, const T &b)