Blender V4.3
BKE_curves_utils.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
7#include "BKE_curves.hh"
8
14#include "BLI_function_ref.hh"
16#include "BLI_index_range.hh"
17
18namespace blender::bke::curves {
19
20/* -------------------------------------------------------------------- */
31 int index;
37};
38
46struct CurvePoint : public CurveSegment {
51 float parameter;
52
56 inline bool is_controlpoint() const;
57
58 /*
59 * Compare if the points are equal.
60 */
61 inline bool operator==(const CurvePoint &other) const;
62 inline bool operator!=(const CurvePoint &other) const;
63
68 inline bool operator<(const CurvePoint &other) const;
69};
70
84 int start_ = 0;
85 int end_ = 0;
89 int range_size_ = 0;
93 int cycles_ = 0;
94
95 public:
96 constexpr IndexRangeCyclic() = default;
97 ~IndexRangeCyclic() = default;
98
99 constexpr IndexRangeCyclic(const int start,
100 const int end,
101 const int iterable_range_size,
102 const int cycles)
103 : start_(start), end_(end), range_size_(iterable_range_size), cycles_(cycles)
104 {
105 }
106
110 constexpr IndexRangeCyclic(const int start, const int end, const int iterable_range_size)
111 : start_(start),
112 end_(end == iterable_range_size ? 0 : end),
113 range_size_(iterable_range_size),
114 cycles_(end < start)
115 {
116 }
117
125 static IndexRangeCyclic get_range_from_size(const int start_index,
126 const int iterator_size,
127 const int iterable_range_size)
128 {
129 BLI_assert(start_index >= 0);
130 BLI_assert(iterator_size >= 0);
131 BLI_assert(iterable_range_size > 0);
132 const int num_until_loop = iterable_range_size - start_index;
133 if (iterator_size < num_until_loop) {
134 return IndexRangeCyclic(start_index, start_index + iterator_size, iterable_range_size, 0);
135 }
136
137 const int num_remaining = iterator_size - num_until_loop;
138
139 /* Integer division (rounded down). */
140 const int num_full_cycles = num_remaining / iterable_range_size;
141
142 const int end_index = num_remaining - num_full_cycles * iterable_range_size;
143 return IndexRangeCyclic(start_index, end_index, iterable_range_size, num_full_cycles + 1);
144 }
145
155 const CurvePoint end_point,
156 const int iterable_range_size)
157 {
158 BLI_assert(iterable_range_size > 0);
159 const int start_index = start_point.parameter == 0.0 ? start_point.index :
160 start_point.next_index;
161 int end_index = end_point.parameter == 0.0 ? end_point.index : end_point.next_index;
162 int cycles;
163
164 if (end_point.is_controlpoint()) {
165 BLI_assert(end_index < iterable_range_size);
166 ++end_index;
167 if (end_index == iterable_range_size) {
168 end_index = 0;
169 }
170 /* end_point < start_point but parameter is irrelevant (end_point is controlpoint), and loop
171 * when equal due to increment. */
172 cycles = end_index <= start_index;
173 }
174 else {
175 cycles = end_point < start_point || end_index < start_index;
176 }
177 return IndexRangeCyclic(start_index, end_index, iterable_range_size, cycles);
178 }
179
183 template<typename IndexT> constexpr IndexT next_index(const IndexT index, const bool cyclic)
184 {
185 static_assert((is_same_any_v<IndexT, int, int>), "Expected signed integer type.");
186 const IndexT next_index = index + 1;
187 if (next_index == this->size_range()) {
188 return cyclic ? 0 : index;
189 }
190 return next_index;
191 }
192
196 template<typename IndexT> constexpr IndexT previous_index(const IndexT index, const bool cyclic)
197 {
198 static_assert((is_same_any_v<IndexT, int, int64_t>), "Expected signed integer type.");
199 const IndexT prev_index = index - 1;
200 if (prev_index < 0) {
201 return cyclic ? this->size_range() - 1 : 0;
202 }
203 return prev_index;
204 }
205
210 constexpr IndexRangeCyclic push_loop(const int n = 1) const
211 {
212 return {this->start_, this->end_, this->range_size_, this->cycles_ + n};
213 }
214
219 constexpr IndexRangeCyclic push_front(const int n = 1) const
220 {
221 BLI_assert(n >= 0);
222 int new_start = this->start_ - n;
223 int num_cycles = this->cycles_;
224 if (new_start < 0) {
225 const int new_cycles = n / this->size_range(); /* Integer division (floor) */
226 const int remainder = new_start + this->size_range() * new_cycles;
227 const bool underflow = remainder < 0;
228 new_start = remainder + (underflow ? this->size_range() : 0);
229 num_cycles += new_cycles + int(underflow);
230 }
233 (new_start <= this->end_ || (this->end_ == 0 && new_start < this->size_range())));
234 return {new_start, this->end_, this->range_size_, num_cycles};
235 }
236
241 constexpr IndexRangeCyclic push_back(const int n = 1) const
242 {
243 BLI_assert(n >= 0);
244 int new_end = this->end_ + n;
245 int num_cycles = this->cycles_;
246 if (this->size_range() <= new_end) {
247 const int new_cycles = n / this->size_range(); /* Integer division (floor) */
248 const int remainder = new_end - this->size_range() * new_cycles;
249 const bool overflow = remainder >= this->size_range();
250 new_end = remainder - (overflow ? this->size_range() : 0);
251 num_cycles += new_cycles + int(overflow);
252 }
254 BLI_assert(num_cycles > 0 || (this->start_ <= new_end || new_end == 0));
255 return {this->start_, new_end, this->range_size_, num_cycles};
256 }
257
262 constexpr IndexRangeCyclic drop_front(const int n = 1) const
263 {
264 BLI_assert(n >= 0);
265 int new_start = this->start_ + n;
266 int num_cycles = this->cycles_;
267 if (this->size_range() <= new_start) {
268 const int dropped_cycles = n / this->size_range(); /* Integer division (floor) */
269 const int remainder = new_start - this->size_range() * dropped_cycles;
270 const bool overflow = remainder >= this->size_range();
271 new_start = remainder - (overflow ? this->size_range() : 0);
272 num_cycles -= dropped_cycles + int(overflow);
273 }
276 (new_start <= this->end_ || (this->end_ == 0 && new_start < this->size_range())));
277 return {new_start, this->end_, this->range_size_, num_cycles};
278 }
279
284 constexpr IndexRangeCyclic drop_back(const int n = 1) const
285 {
286 BLI_assert(n >= 0);
287 int new_end = this->end_ - n;
288 int num_cycles = this->cycles_;
289 if (0 >= new_end) {
290 const int dropped_cycles = n / this->size_range(); /* Integer division (floor) */
291 const int remainder = new_end + this->size_range() * dropped_cycles;
292 const bool underflow = remainder < 0;
293 new_end = remainder + (underflow ? this->size_range() : 0);
294 num_cycles -= dropped_cycles + int(underflow);
295 }
297 BLI_assert(num_cycles > 0 || (this->start_ <= new_end || new_end == 0));
298 return {this->start_, new_end, this->range_size_, num_cycles};
299 }
300
304 constexpr IndexRange curve_range() const
305 {
306 return IndexRange(0, this->size_range());
307 }
308
313 {
314 return IndexRange(this->start_, this->size_before_loop());
315 }
316
320 constexpr IndexRange range_after_loop() const
321 {
322 return IndexRange(0, this->size_after_loop());
323 }
324
328 constexpr int size_range() const
329 {
330 return this->range_size_;
331 }
332
336 constexpr int size_before_loop() const
337 {
338 return this->range_size_ - this->start_;
339 }
340
345 constexpr int size_after_loop() const
346 {
347 return this->end_;
348 }
349
353 constexpr int size() const
354 {
355 if (this->cycles_ > 0) {
356 return this->size_before_loop() + this->end_ + (this->cycles_ - 1) * this->range_size_;
357 }
358 else {
359 return int(this->end_ - this->start_);
360 }
361 }
362
366 constexpr int cycles() const
367 {
368 return this->cycles_;
369 }
370
371 constexpr int first() const
372 {
373 return this->start_;
374 }
375
376 constexpr int last() const
377 {
378 BLI_assert(this->size() > 0);
379 return int(this->end_ - 1);
380 }
381
382 constexpr int one_after_last() const
383 {
384 return this->end_;
385 }
386
387 constexpr bool operator==(const IndexRangeCyclic &other) const
388 {
389 return this->start_ == other.start_ && this->end_ == other.end_ &&
390 this->cycles_ == other.cycles_ && this->range_size_ == other.range_size_;
391 }
392 constexpr bool operator!=(const IndexRangeCyclic &other) const
393 {
394 return !this->operator==(other);
395 }
396
397 struct CyclicIterator; /* Forward declaration */
398
399 constexpr CyclicIterator begin() const
400 {
401 return CyclicIterator(this->range_size_, this->start_, 0);
402 }
403
404 constexpr CyclicIterator end() const
405 {
406 return CyclicIterator(this->range_size_, this->end_, this->cycles_);
407 }
408
411
412 constexpr CyclicIterator(const int range_end, const int index, const int cycles)
413 : index_(index), range_end_(range_end), cycles_(cycles)
414 {
415 BLI_assert(0 <= index && index <= range_end);
416 }
417
422 ~CyclicIterator() = default;
423
425 {
426 if (this == &copy) {
427 return *this;
428 }
429 this->index_ = copy.index_;
430 this->range_end_ = copy.range_end_;
431 this->cycles_ = copy.cycles_;
432 return *this;
433 }
435 {
436 this->index_++;
437 if (this->index_ == this->range_end_) {
438 this->index_ = 0;
439 this->cycles_++;
440 }
441 return *this;
442 }
443
444 void increment(const int n)
445 {
446 for (int i = 0; i < n; i++) {
447 ++*this;
448 }
449 }
450
451 constexpr const int &operator*() const
452 {
453 return this->index_;
454 }
455
456 constexpr bool operator==(const CyclicIterator &other) const
457 {
458 return this->index_ == other.index_ && this->cycles_ == other.cycles_;
459 }
460 constexpr bool operator!=(const CyclicIterator &other) const
461 {
462 return !this->operator==(other);
463 }
464 };
465};
466
469/* -------------------------------------------------------------------- */
473void fill_points(OffsetIndices<int> points_by_curve,
474 const IndexMask &curve_selection,
475 GPointer value,
476 GMutableSpan dst);
477
478template<typename T>
479void fill_points(const OffsetIndices<int> points_by_curve,
480 const IndexMask &curve_selection,
481 const T &value,
482 MutableSpan<T> dst)
483{
484 fill_points(points_by_curve, curve_selection, &value, dst);
485}
486
497
499 const std::array<int, CURVE_TYPES_NUM> &type_counts,
500 const CurveType type,
501 const IndexMask &selection,
502 IndexMaskMemory &memory);
503
504void foreach_curve_by_type(const VArray<int8_t> &types,
505 const std::array<int, CURVE_TYPES_NUM> &type_counts,
506 const IndexMask &selection,
507 FunctionRef<void(IndexMask)> catmull_rom_fn,
508 FunctionRef<void(IndexMask)> poly_fn,
509 FunctionRef<void(IndexMask)> bezier_fn,
510 FunctionRef<void(IndexMask)> nurbs_fn);
511namespace bezier {
512
520 const IndexMask &curves_selection);
521
530 const IndexMask &curves_selection,
531 Span<float3> all_positions);
532
533} // namespace bezier
534
537/* -------------------------------------------------------------------- */
542{
543 return parameter == 0.0 || parameter == 1.0;
544}
545
546inline bool CurvePoint::operator==(const CurvePoint &other) const
547{
548 return (parameter == other.parameter && index == other.index) ||
549 (parameter == 1.0 && other.parameter == 0.0 && next_index == other.index) ||
550 (parameter == 0.0 && other.parameter == 1.0 && index == other.next_index);
551}
552inline bool CurvePoint::operator!=(const CurvePoint &other) const
553{
554 return !this->operator==(other);
555}
556
557inline bool CurvePoint::operator<(const CurvePoint &other) const
558{
559 if (index == other.index) {
560 return parameter < other.parameter;
561 }
562 else {
563 /* Use next index for cyclic comparison due to loop segment < first segment. */
564 return next_index < other.next_index &&
565 !(next_index == other.index && parameter == 1.0 && other.parameter == 0.0);
566 }
567}
568
571} // namespace blender::bke::curves
Low-level operations for curves.
#define BLI_assert(a)
Definition BLI_assert.h:50
CurveType
constexpr CyclicIterator begin() const
constexpr IndexRangeCyclic push_back(const int n=1) const
constexpr IndexRangeCyclic push_loop(const int n=1) const
constexpr IndexRangeCyclic drop_back(const int n=1) const
constexpr IndexRangeCyclic(const int start, const int end, const int iterable_range_size, const int cycles)
constexpr IndexRangeCyclic drop_front(const int n=1) const
constexpr IndexT previous_index(const IndexT index, const bool cyclic)
constexpr IndexRange curve_range() const
static IndexRangeCyclic get_range_between_endpoints(const CurvePoint start_point, const CurvePoint end_point, const int iterable_range_size)
constexpr IndexRangeCyclic push_front(const int n=1) const
static IndexRangeCyclic get_range_from_size(const int start_index, const int iterator_size, const int iterable_range_size)
constexpr IndexRange range_after_loop() const
constexpr bool operator==(const IndexRangeCyclic &other) const
constexpr bool operator!=(const IndexRangeCyclic &other) const
constexpr CyclicIterator end() const
constexpr IndexRangeCyclic(const int start, const int end, const int iterable_range_size)
constexpr IndexT next_index(const IndexT index, const bool cyclic)
constexpr IndexRange range_before_loop() const
int num_cycles
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
Array< float3 > retrieve_all_positions(const bke::CurvesGeometry &curves, const IndexMask &curves_selection)
void write_all_positions(bke::CurvesGeometry &curves, const IndexMask &curves_selection, Span< float3 > all_positions)
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
IndexMask indices_for_type(const VArray< int8_t > &types, const std::array< int, CURVE_TYPES_NUM > &type_counts, const CurveType type, const IndexMask &selection, IndexMaskMemory &memory)
void fill_points(OffsetIndices< int > points_by_curve, const IndexMask &curve_selection, GPointer value, GMutableSpan dst)
void foreach_curve_by_type(const VArray< int8_t > &types, const std::array< int, CURVE_TYPES_NUM > &type_counts, const IndexMask &selection, FunctionRef< void(IndexMask)> catmull_rom_fn, FunctionRef< void(IndexMask)> poly_fn, FunctionRef< void(IndexMask)> bezier_fn, FunctionRef< void(IndexMask)> nurbs_fn)
constexpr bool is_same_any_v
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
bool operator==(const CurvePoint &other) const
bool operator!=(const CurvePoint &other) const
bool operator<(const CurvePoint &other) const
constexpr bool operator==(const CyclicIterator &other) const
constexpr CyclicIterator(const int range_end, const int index, const int cycles)
constexpr CyclicIterator(const CyclicIterator &copy)
constexpr bool operator!=(const CyclicIterator &other) const
constexpr CyclicIterator & operator=(const CyclicIterator &copy)