Blender  V3.3
BLI_length_parameterize.hh
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #pragma once
4 
9 #include "BLI_index_mask.hh"
10 #include "BLI_math_base.hh"
11 #include "BLI_math_color.hh"
12 #include "BLI_math_vector.hh"
13 
15 
22 inline int segments_num(const int points_num, const bool cyclic)
23 {
24  return cyclic ? points_num : points_num - 1;
25 }
26 
30 template<typename T>
31 void accumulate_lengths(const Span<T> values, const bool cyclic, MutableSpan<float> lengths)
32 {
33  BLI_assert(lengths.size() == segments_num(values.size(), cyclic));
34  float length = 0.0f;
35  for (const int i : IndexRange(values.size() - 1)) {
36  length += math::distance(values[i], values[i + 1]);
37  lengths[i] = length;
38  }
39  if (cyclic) {
40  lengths.last() = length + math::distance(values.last(), values.first());
41  }
42 }
43 
44 template<typename T>
45 inline void interpolate_to_masked(const Span<T> src,
46  const Span<int> indices,
47  const Span<float> factors,
48  const IndexMask dst_mask,
49  MutableSpan<T> dst)
50 {
51  BLI_assert(indices.size() == factors.size());
52  BLI_assert(indices.size() == dst_mask.size());
53  const int last_src_index = src.size() - 1;
54 
55  dst_mask.to_best_mask_type([&](auto dst_mask) {
56  for (const int i : IndexRange(dst_mask.size())) {
57  const int prev_index = indices[i];
58  const float factor = factors[i];
59  const bool is_cyclic_case = prev_index == last_src_index;
60  if (is_cyclic_case) {
61  dst[dst_mask[i]] = math::interpolate(src.last(), src.first(), factor);
62  }
63  else {
64  dst[dst_mask[i]] = math::interpolate(src[prev_index], src[prev_index + 1], factor);
65  }
66  }
67  });
68 }
69 
70 template<typename T>
71 inline void interpolate(const Span<T> src,
72  const Span<int> indices,
73  const Span<float> factors,
74  MutableSpan<T> dst)
75 {
76  interpolate_to_masked(src, indices, factors, dst.index_range(), dst);
77 }
78 
83  int segment_index = -1;
86 };
87 
97 inline 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  BLI_assert(sample_length <= lengths.last());
109 
110  if (hint != nullptr && hint->segment_index >= 0) {
111  const float length_in_segment = sample_length - hint->segment_start;
112  const float factor = length_in_segment * hint->segment_length_inv;
113  if (factor >= 0.0f && factor < 1.0f) {
114  r_segment_index = hint->segment_index;
115  r_factor = factor;
116  return;
117  }
118  }
119 
120  const float total_length = lengths.last();
121  if (sample_length >= total_length) {
122  /* Return the last position on the last segment. */
123  r_segment_index = lengths.size() - 1;
124  r_factor = 1.0f;
125  return;
126  }
127 
128  const int prev_point_index = std::upper_bound(lengths.begin(), lengths.end(), sample_length) -
129  lengths.begin();
130  const float segment_start = prev_point_index == 0 ? 0.0f : lengths[prev_point_index - 1];
131  const float segment_end = lengths[prev_point_index];
132  const float segment_length = segment_end - segment_start;
133  const float segment_length_inv = math::safe_divide(1.0f, segment_length);
134  const float length_in_segment = sample_length - segment_start;
135  const float factor = length_in_segment * segment_length_inv;
136 
137  r_segment_index = prev_point_index;
138  r_factor = factor;
139 
140  if (hint != nullptr) {
141  hint->segment_index = r_segment_index;
142  hint->segment_start = segment_start;
143  hint->segment_length_inv = segment_length_inv;
144  }
145 }
146 
156 void sample_uniform(Span<float> accumulated_segment_lengths,
157  bool include_last_point,
158  MutableSpan<int> r_segment_indices,
159  MutableSpan<float> r_factors);
160 
171 void sample_at_lengths(Span<float> accumulated_segment_lengths,
172  Span<float> sample_lengths,
173  MutableSpan<int> r_segment_indices,
174  MutableSpan<float> r_factors);
175 
176 } // namespace blender::length_parameterize
#define BLI_assert(a)
Definition: BLI_assert.h:46
int64_t size() const
void to_best_mask_type(const Fn &fn) const
constexpr int64_t size() const
Definition: BLI_span.hh:511
constexpr T & last(const int64_t n=0) const
Definition: BLI_span.hh:680
constexpr IndexRange index_range() const
Definition: BLI_span.hh:661
constexpr const T & first() const
Definition: BLI_span.hh:303
constexpr const T & last(const int64_t n=0) const
Definition: BLI_span.hh:313
constexpr int64_t size() const
Definition: BLI_span.hh:240
constexpr const T * end() const
Definition: BLI_span.hh:212
constexpr const T * begin() const
Definition: BLI_span.hh:208
SyclQueue void void * src
ccl_gpu_kernel_postfix int ccl_global int * indices
int segments_num(const int points_num, const bool cyclic)
void accumulate_lengths(const Span< T > values, const bool cyclic, MutableSpan< float > lengths)
void interpolate_to_masked(const Span< T > src, const Span< int > indices, const Span< float > factors, const IndexMask dst_mask, MutableSpan< T > dst)
void sample_at_lengths(Span< float > accumulated_segment_lengths, Span< float > sample_lengths, 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)
T length(const vec_base< T, Size > &a)
T distance(const T &a, const T &b)
T safe_divide(const T &a, const T &b)