Blender V5.0
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
13
14#include "BLI_function_ref.hh"
16#include "BLI_index_range.hh"
17
18namespace blender::bke::curves {
19
20/* -------------------------------------------------------------------- */
23
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 }
231 BLI_assert(num_cycles >= 0);
232 BLI_assert(num_cycles > 0 ||
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 }
253 BLI_assert(num_cycles >= 0);
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 }
274 BLI_assert(num_cycles >= 0);
275 BLI_assert(num_cycles > 0 ||
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 }
296 BLI_assert(num_cycles >= 0);
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 return int(this->end_ - this->start_);
359 }
360
364 constexpr int cycles() const
365 {
366 return this->cycles_;
367 }
368
369 constexpr int first() const
370 {
371 return this->start_;
372 }
373
374 constexpr int last() const
375 {
376 BLI_assert(this->size() > 0);
377 return int(this->end_ - 1);
378 }
379
380 constexpr int one_after_last() const
381 {
382 return this->end_;
383 }
384
385 constexpr bool operator==(const IndexRangeCyclic &other) const
386 {
387 return this->start_ == other.start_ && this->end_ == other.end_ &&
388 this->cycles_ == other.cycles_ && this->range_size_ == other.range_size_;
389 }
390 constexpr bool operator!=(const IndexRangeCyclic &other) const
391 {
392 return !this->operator==(other);
393 }
394
395 struct CyclicIterator; /* Forward declaration */
396
397 constexpr CyclicIterator begin() const
398 {
399 return CyclicIterator(this->range_size_, this->start_, 0);
400 }
401
402 constexpr CyclicIterator end() const
403 {
404 return CyclicIterator(this->range_size_, this->end_, this->cycles_);
405 }
406
409
410 constexpr CyclicIterator(const int range_end, const int index, const int cycles)
411 : index_(index), range_end_(range_end), cycles_(cycles)
412 {
413 BLI_assert(0 <= index && index <= range_end);
414 }
415
416 constexpr CyclicIterator(const CyclicIterator &copy) = default;
417 ~CyclicIterator() = default;
418
420 {
421 if (this == &copy) {
422 return *this;
423 }
424 this->index_ = copy.index_;
425 this->range_end_ = copy.range_end_;
426 this->cycles_ = copy.cycles_;
427 return *this;
428 }
430 {
431 this->index_++;
432 if (this->index_ == this->range_end_) {
433 this->index_ = 0;
434 this->cycles_++;
435 }
436 return *this;
437 }
438
439 void increment(const int n)
440 {
441 for (int i = 0; i < n; i++) {
442 ++*this;
443 }
444 }
445
446 constexpr const int &operator*() const
447 {
448 return this->index_;
449 }
450
451 constexpr bool operator==(const CyclicIterator &other) const
452 {
453 return this->index_ == other.index_ && this->cycles_ == other.cycles_;
454 }
455 constexpr bool operator!=(const CyclicIterator &other) const
456 {
457 return !this->operator==(other);
458 }
459 };
460};
461
463
464/* -------------------------------------------------------------------- */
467
469 const IndexMask &curve_selection,
470 IndexMaskMemory &memory);
471
473 CurveType curve_type,
474 IndexMaskMemory &memory);
475
476void fill_points(OffsetIndices<int> points_by_curve,
477 const IndexMask &curve_selection,
478 GPointer value,
479 GMutableSpan dst);
480
481template<typename T>
482void fill_points(const OffsetIndices<int> points_by_curve,
483 const IndexMask &curve_selection,
484 const T &value,
485 MutableSpan<T> dst)
486{
487 fill_points(points_by_curve, curve_selection, &value, dst);
488}
489
500
502 const std::array<int, CURVE_TYPES_NUM> &type_counts,
503 const CurveType type,
504 const IndexMask &selection,
505 IndexMaskMemory &memory);
506
508 const std::array<int, CURVE_TYPES_NUM> &type_counts,
509 const IndexMask &selection,
510 FunctionRef<void(IndexMask)> catmull_rom_fn,
511 FunctionRef<void(IndexMask)> poly_fn,
512 FunctionRef<void(IndexMask)> bezier_fn,
513 FunctionRef<void(IndexMask)> nurbs_fn);
514
516 int curve_i, IndexRange curve_points, Span<IndexRange> selected_point_ranges)>;
518
527 OffsetIndices<int> points_by_curve,
528 SelectedCallback selected_fn);
529
540 OffsetIndices<int> points_by_curve,
541 SelectedCallback selected_fn,
542 UnselectedCallback unselected_fn);
543
544namespace bezier {
545
552 const IndexMask &curves_selection);
553
562 const IndexMask &curves_selection,
563 Span<float3> all_positions);
564
565} // namespace bezier
566
567namespace nurbs {
568
575 const IndexMask &src_curves,
576 int dst_curve_offset,
578
588 const KnotsMode mode_for_regular,
589 const KnotsMode mode_for_cyclic,
591
598void copy_custom_knots(const bke::CurvesGeometry &src_curves,
599 const IndexMask &exclude_curves,
600 bke::CurvesGeometry &dst_curves);
601
602} // namespace nurbs
603
605
606/* -------------------------------------------------------------------- */
609
611{
612 return parameter == 0.0 || parameter == 1.0;
613}
614
615inline bool CurvePoint::operator==(const CurvePoint &other) const
616{
617 return (parameter == other.parameter && index == other.index) ||
618 (parameter == 1.0 && other.parameter == 0.0 && next_index == other.index) ||
619 (parameter == 0.0 && other.parameter == 1.0 && index == other.next_index);
620}
621inline bool CurvePoint::operator!=(const CurvePoint &other) const
622{
623 return !this->operator==(other);
624}
625
626inline bool CurvePoint::operator<(const CurvePoint &other) const
627{
628 if (index == other.index) {
629 return parameter < other.parameter;
630 }
631 /* Use next index for cyclic comparison due to loop segment < first segment. */
632 return next_index < other.next_index &&
633 !(next_index == other.index && parameter == 1.0 && other.parameter == 0.0);
634}
635
637
638} // namespace blender::bke::curves
Low-level operations for curves.
#define BLI_assert(a)
Definition BLI_assert.h:46
KnotsMode
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
static char ** types
Definition makesdna.cc:71
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
#define T
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)
void gather_custom_knots(const bke::CurvesGeometry &src, const IndexMask &src_curves, int dst_curve_offset, bke::CurvesGeometry &dst)
void update_custom_knot_modes(const IndexMask &mask, const KnotsMode mode_for_regular, const KnotsMode mode_for_cyclic, bke::CurvesGeometry &curves)
void copy_custom_knots(const bke::CurvesGeometry &src_curves, const IndexMask &exclude_curves, bke::CurvesGeometry &dst_curves)
void foreach_selected_point_ranges_per_curve(const IndexMask &mask, OffsetIndices< int > points_by_curve, SelectedCallback selected_fn)
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
FunctionRef< void( int curve_i, IndexRange curve_points, Span< IndexRange > selected_point_ranges)> SelectedCallback
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)
IndexMask curve_type_point_selection(const bke::CurvesGeometry &curves, CurveType curve_type, IndexMaskMemory &memory)
IndexMask curve_to_point_selection(OffsetIndices< int > points_by_curve, const IndexMask &curve_selection, IndexMaskMemory &memory)
FunctionRef< void(IndexRange curves, IndexRange unselected_points)> UnselectedCallback
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 bool operator!=(const CyclicIterator &other) const
constexpr CyclicIterator & operator=(const CyclicIterator &copy)
constexpr CyclicIterator(const CyclicIterator &copy)=default
i
Definition text_draw.cc:230