Geometry Nodes: Trim curve node selection input and corrections
Correct trim for cyclical curves mentioned in T101379, splitting the curves if the start/endpoint is at the 'loop point'. Correct implementation based on comments in D14481, request was made to use 'foreach_curve_by_type' to computing the point lookups. Included corrections from D16066 as it may not be a adopted solution. Exposed selection input by adding it as input to the node. Note: This is disabled for 3.4 to avoid making UI changes in Bcon3. Differential Revision: https://developer.blender.org/D16161
This commit is contained in:
parent
d01187c963
commit
11f6c65e61
Notes:
blender-bot
2023-02-14 03:59:42 +01:00
Referenced by issue #103632, Regression: Trim Curve at 100% Causing Jumping of vertices away from the original position Referenced by issue #101379, Regression: Trim curve make spline disapear.
|
@ -67,86 +67,228 @@ struct CurvePoint : public CurveSegment {
|
|||
};
|
||||
|
||||
/**
|
||||
* Cyclical index range. Iterates the interval [start, end).
|
||||
* Cyclical index range. Allows iteration over a plain 'IndexRange' interval on form [start, end)
|
||||
* while also supporting treating the underlying array as a cyclic array where the last index is
|
||||
* followed by the first nidex in the 'cyclical' range. The cyclical index range can then be
|
||||
* considered a combination of the intervals separated by the last index of the underlying array,
|
||||
* namely [start, range_size) and [0, end) where start/end is the indices iterated between and
|
||||
* range_size is the size of the underlying array. To cycle the underlying array the interval
|
||||
* [0, range_size) can be iterated over an arbitrary amount of times inbetween.
|
||||
*/
|
||||
class IndexRangeCyclic {
|
||||
/* Index to the start and end of the iterated range.
|
||||
*/
|
||||
int64_t start_ = 0;
|
||||
int64_t end_ = 0;
|
||||
/* Index for the start and end of the entire iterable range which contains the iterated range
|
||||
* (e.g. the point range for an individual spline/curve within the entire Curves point domain).
|
||||
int start_ = 0;
|
||||
int end_ = 0;
|
||||
/* Size of the underlying iterable range.
|
||||
*/
|
||||
int64_t range_start_ = 0;
|
||||
int64_t range_end_ = 0;
|
||||
int range_size_ = 0;
|
||||
/* Number of times the range end is passed when the range is iterated.
|
||||
*/
|
||||
int64_t cycles_ = 0;
|
||||
|
||||
constexpr IndexRangeCyclic(int64_t begin,
|
||||
int64_t end,
|
||||
int64_t iterable_range_start,
|
||||
int64_t iterable_range_end,
|
||||
int64_t cycles)
|
||||
: start_(begin),
|
||||
end_(end),
|
||||
range_start_(iterable_range_start),
|
||||
range_end_(iterable_range_end),
|
||||
cycles_(cycles)
|
||||
{
|
||||
}
|
||||
int cycles_ = 0;
|
||||
|
||||
public:
|
||||
constexpr IndexRangeCyclic() = default;
|
||||
~IndexRangeCyclic() = default;
|
||||
|
||||
constexpr IndexRangeCyclic(int64_t start, int64_t end, IndexRange iterable_range, int64_t cycles)
|
||||
: start_(start),
|
||||
end_(end),
|
||||
range_start_(iterable_range.first()),
|
||||
range_end_(iterable_range.one_after_last()),
|
||||
cycles_(cycles)
|
||||
constexpr IndexRangeCyclic(const int start,
|
||||
const int end,
|
||||
const int iterable_range_size,
|
||||
const int cycles)
|
||||
: start_(start), end_(end), range_size_(iterable_range_size), cycles_(cycles)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an iterator over the cyclical interval [start_index, end_index).
|
||||
*/
|
||||
constexpr IndexRangeCyclic(int64_t start, int64_t end, IndexRange iterable_range)
|
||||
constexpr IndexRangeCyclic(const int start, const int end, const int iterable_range_size)
|
||||
: start_(start),
|
||||
end_(end == iterable_range.one_after_last() ? iterable_range.first() : end),
|
||||
range_start_(iterable_range.first()),
|
||||
range_end_(iterable_range.one_after_last()),
|
||||
end_(end == iterable_range_size ? 0 : end),
|
||||
range_size_(iterable_range_size),
|
||||
cycles_(end < start)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the range by adding the given number of indices to the beginning of the range.
|
||||
* Create a cyclical iterator of the specified size.
|
||||
*
|
||||
* \param start_point: Point on the curve that define the starting point of the interval.
|
||||
* \param iterator_size: Number of elements to iterate (size of the iterated cyclical range).
|
||||
* \param iterable_range_size: Size of the underlying range (superset to the cyclical range).
|
||||
*/
|
||||
constexpr IndexRangeCyclic push_forward(int n)
|
||||
static IndexRangeCyclic get_range_from_size(const int start_index,
|
||||
const int iterator_size,
|
||||
const int iterable_range_size)
|
||||
{
|
||||
BLI_assert(n >= 0);
|
||||
int64_t nstart = start_ - n;
|
||||
int64_t cycles = cycles_;
|
||||
if (nstart < range_start_) {
|
||||
BLI_assert(start_index >= 0);
|
||||
BLI_assert(iterator_size >= 0);
|
||||
BLI_assert(iterable_range_size > 0);
|
||||
const int num_until_loop = iterable_range_size - start_index;
|
||||
if (iterator_size < num_until_loop) {
|
||||
return IndexRangeCyclic(start_index, start_index + iterator_size, iterable_range_size, 0);
|
||||
}
|
||||
|
||||
cycles += (int64_t)(n / (range_end_ - range_start_)) + (end_ < nstart) - (end_ < start_);
|
||||
}
|
||||
return {nstart, end_, range_start_, range_end_, cycles};
|
||||
const int num_remaining = iterator_size - num_until_loop;
|
||||
const int num_full_cycles = num_remaining /
|
||||
iterable_range_size; /* Integer division (rounded down). */
|
||||
const int end_index = num_remaining - num_full_cycles * iterable_range_size;
|
||||
return IndexRangeCyclic(start_index, end_index, iterable_range_size, num_full_cycles + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the range by adding the given number of indices to the end of the range.
|
||||
* Create a cyclical iterator for all control points within the interval [start_point, end_point]
|
||||
* including any control point at the start or end point.
|
||||
*
|
||||
* \param start_point: Point on the curve that define the starting point of the interval.
|
||||
* \param end_point: Point on the curve that define the end point of the interval (included).
|
||||
* \param iterable_range_size: Size of the underlying range (superset to the cyclical range).
|
||||
*/
|
||||
constexpr IndexRangeCyclic push_backward(int n)
|
||||
static IndexRangeCyclic get_range_between_endpoints(const CurvePoint start_point,
|
||||
const CurvePoint end_point,
|
||||
const int iterable_range_size)
|
||||
{
|
||||
BLI_assert(iterable_range_size > 0);
|
||||
const int start_index = start_point.parameter == 0.0 ? start_point.index :
|
||||
start_point.next_index;
|
||||
int end_index = end_point.parameter == 0.0 ? end_point.index : end_point.next_index;
|
||||
int cycles;
|
||||
|
||||
if (end_point.is_controlpoint()) {
|
||||
BLI_assert(end_index < iterable_range_size);
|
||||
++end_index;
|
||||
if (end_index == iterable_range_size) {
|
||||
end_index = 0;
|
||||
}
|
||||
/* end_point < start_point but parameter is irrelevant (end_point is controlpoint), and loop
|
||||
* when equal due to increment. */
|
||||
cycles = end_index <= start_index;
|
||||
}
|
||||
else {
|
||||
cycles = end_point < start_point || end_index < start_index;
|
||||
}
|
||||
return IndexRangeCyclic(start_index, end_index, iterable_range_size, cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Next index within the iterable range.
|
||||
*/
|
||||
template<typename IndexT> constexpr IndexT next_index(const IndexT index, const bool cyclic)
|
||||
{
|
||||
static_assert((is_same_any_v<IndexT, int, int>), "Expected signed integer type.");
|
||||
const IndexT next_index = index + 1;
|
||||
if (next_index == this->size_range()) {
|
||||
return cyclic ? 0 : index;
|
||||
}
|
||||
return next_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Previous index within the iterable range.
|
||||
*/
|
||||
template<typename IndexT> constexpr IndexT previous_index(const IndexT index, const bool cyclic)
|
||||
{
|
||||
static_assert((is_same_any_v<IndexT, int, int64_t>), "Expected signed integer type.");
|
||||
const IndexT prev_index = index - 1;
|
||||
if (prev_index < 0) {
|
||||
return cyclic ? this->size_range() - 1 : 0;
|
||||
}
|
||||
return prev_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the range by adding `n` loops to the range. This invokes undefined behavior when n
|
||||
* is negative.
|
||||
*/
|
||||
constexpr IndexRangeCyclic push_loop(const int n = 1) const
|
||||
{
|
||||
return {this->start_, this->end_, this->range_size_, this->cycles_ + n};
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the range by adding the given number of indices to the beginning of the iterated
|
||||
* range. This invokes undefined behavior when n is negative.
|
||||
*/
|
||||
constexpr IndexRangeCyclic push_front(const int n = 1) const
|
||||
{
|
||||
BLI_assert(n >= 0);
|
||||
int64_t new_end = end_ + n;
|
||||
int64_t cycles = cycles_;
|
||||
if (range_end_ <= new_end) {
|
||||
cycles += (int64_t)(n / (range_end_ - range_start_)) + (new_end < start_) - (end_ < start_);
|
||||
int new_start = this->start_ - n;
|
||||
int num_cycles = this->cycles_;
|
||||
if (new_start < 0) {
|
||||
const int new_cycles = n / this->size_range(); /* Integer division (floor) */
|
||||
const int remainder = new_start + this->size_range() * new_cycles;
|
||||
const bool underflow = remainder < 0;
|
||||
new_start = remainder + (underflow ? this->size_range() : 0);
|
||||
num_cycles += new_cycles + int(underflow);
|
||||
}
|
||||
return {start_, new_end, range_start_, range_end_, cycles};
|
||||
BLI_assert(num_cycles >= 0);
|
||||
BLI_assert(num_cycles > 0 ||
|
||||
(new_start <= this->end_ || (this->end_ == 0 && new_start < this->size_range())));
|
||||
return {new_start, this->end_, this->range_size_, num_cycles};
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the range by adding the given number of indices to the end of the iterated range.
|
||||
* This invokes undefined behavior when n is negative.
|
||||
*/
|
||||
constexpr IndexRangeCyclic push_back(const int n = 1) const
|
||||
{
|
||||
BLI_assert(n >= 0);
|
||||
int new_end = this->end_ + n;
|
||||
int num_cycles = this->cycles_;
|
||||
if (this->size_range() <= new_end) {
|
||||
const int new_cycles = n / this->size_range(); /* Integer division (floor) */
|
||||
const int remainder = new_end - this->size_range() * new_cycles;
|
||||
const bool overflow = remainder >= this->size_range();
|
||||
new_end = remainder - (overflow ? this->size_range() : 0);
|
||||
num_cycles += new_cycles + int(overflow);
|
||||
}
|
||||
BLI_assert(num_cycles >= 0);
|
||||
BLI_assert(num_cycles > 0 || (this->start_ <= new_end || new_end == 0));
|
||||
return {this->start_, new_end, this->range_size_, num_cycles};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new range with n indices removed from the beginning of the range.
|
||||
* This invokes undefined behavior.
|
||||
*/
|
||||
constexpr IndexRangeCyclic drop_front(const int n = 1) const
|
||||
{
|
||||
BLI_assert(n >= 0);
|
||||
int new_start = this->start_ + n;
|
||||
int num_cycles = this->cycles_;
|
||||
if (this->size_range() <= new_start) {
|
||||
const int dropped_cycles = n / this->size_range(); /* Integer division (floor) */
|
||||
const int remainder = new_start - this->size_range() * dropped_cycles;
|
||||
const bool overflow = remainder >= this->size_range();
|
||||
new_start = remainder - (overflow ? this->size_range() : 0);
|
||||
num_cycles -= dropped_cycles + int(overflow);
|
||||
}
|
||||
BLI_assert(num_cycles >= 0);
|
||||
BLI_assert(num_cycles > 0 ||
|
||||
(new_start <= this->end_ || (this->end_ == 0 && new_start < this->size_range())));
|
||||
return {new_start, this->end_, this->range_size_, num_cycles};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new range with n indices removed from the end of the range.
|
||||
* This invokes undefined behavior when n is negative or n is larger then the underlying range.
|
||||
*/
|
||||
constexpr IndexRangeCyclic drop_back(const int n = 1) const
|
||||
{
|
||||
BLI_assert(n >= 0);
|
||||
int new_end = this->end_ - n;
|
||||
int num_cycles = this->cycles_;
|
||||
if (0 >= new_end) {
|
||||
const int dropped_cycles = n / this->size_range(); /* Integer division (floor) */
|
||||
const int remainder = new_end + this->size_range() * dropped_cycles;
|
||||
const bool underflow = remainder < 0;
|
||||
new_end = remainder + (underflow ? this->size_range() : 0);
|
||||
num_cycles -= dropped_cycles + int(underflow);
|
||||
}
|
||||
BLI_assert(num_cycles >= 0);
|
||||
BLI_assert(num_cycles > 0 || (this->start_ <= new_end || new_end == 0));
|
||||
return {this->start_, new_end, this->range_size_, num_cycles};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,7 +296,7 @@ class IndexRangeCyclic {
|
|||
*/
|
||||
constexpr IndexRange curve_range() const
|
||||
{
|
||||
return IndexRange(range_start_, total_size());
|
||||
return IndexRange(0, this->size_range());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,7 +304,7 @@ class IndexRangeCyclic {
|
|||
*/
|
||||
constexpr IndexRange range_before_loop() const
|
||||
{
|
||||
return IndexRange(start_, size_before_loop());
|
||||
return IndexRange(this->start_, this->size_before_loop());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,88 +312,104 @@ class IndexRangeCyclic {
|
|||
*/
|
||||
constexpr IndexRange range_after_loop() const
|
||||
{
|
||||
return IndexRange(range_start_, size_after_loop());
|
||||
return IndexRange(0, this->size_after_loop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Size of the entire iterable range.
|
||||
* Number of elements in the underlying iterable range.
|
||||
*/
|
||||
constexpr int64_t total_size() const
|
||||
constexpr int size_range() const
|
||||
{
|
||||
return range_end_ - range_start_;
|
||||
return this->range_size_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of elements between the first element in the range up to the last element in the curve.
|
||||
*/
|
||||
constexpr int64_t size_before_loop() const
|
||||
constexpr int size_before_loop() const
|
||||
{
|
||||
return range_end_ - start_;
|
||||
return this->range_size_ - this->start_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of elements between the first element in the iterable range up to the last element in
|
||||
* the range.
|
||||
*/
|
||||
constexpr int64_t size_after_loop() const
|
||||
constexpr int size_after_loop() const
|
||||
{
|
||||
return end_ - range_start_;
|
||||
return this->end_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of elements iterated by the cyclical index range.
|
||||
* Number of elements iterated by the cyclical index range.
|
||||
*/
|
||||
constexpr int64_t size() const
|
||||
constexpr int size() const
|
||||
{
|
||||
if (cycles_ > 0) {
|
||||
return size_before_loop() + end_ + (cycles_ - 1) * (range_end_ - range_start_);
|
||||
if (this->cycles_ > 0) {
|
||||
return this->size_before_loop() + this->end_ + (this->cycles_ - 1) * this->range_size_;
|
||||
}
|
||||
else {
|
||||
return end_ - start_;
|
||||
return int(this->end_ - this->start_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of times the iterator will cycle before ending.
|
||||
*/
|
||||
constexpr int64_t cycles() const
|
||||
constexpr int cycles() const
|
||||
{
|
||||
return cycles_;
|
||||
return this->cycles_;
|
||||
}
|
||||
|
||||
constexpr int64_t first() const
|
||||
constexpr int first() const
|
||||
{
|
||||
return start_;
|
||||
return this->start_;
|
||||
}
|
||||
|
||||
constexpr int64_t one_after_last() const
|
||||
constexpr int last() const
|
||||
{
|
||||
return end_;
|
||||
BLI_assert(this->size() > 0);
|
||||
return int(this->end_ - 1);
|
||||
}
|
||||
|
||||
constexpr int one_after_last() const
|
||||
{
|
||||
return this->end_;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const IndexRangeCyclic &other) const
|
||||
{
|
||||
return this->start_ == other.start_ && this->end_ == other.end_ &&
|
||||
this->cycles_ == other.cycles_ && this->range_size_ == other.range_size_;
|
||||
}
|
||||
constexpr bool operator!=(const IndexRangeCyclic &other) const
|
||||
{
|
||||
return !this->operator==(other);
|
||||
}
|
||||
|
||||
struct CyclicIterator; /* Forward declaration */
|
||||
|
||||
constexpr CyclicIterator begin() const
|
||||
{
|
||||
return CyclicIterator(range_start_, range_end_, start_, 0);
|
||||
return CyclicIterator(this->range_size_, this->start_, 0);
|
||||
}
|
||||
|
||||
constexpr CyclicIterator end() const
|
||||
{
|
||||
return CyclicIterator(range_start_, range_end_, end_, cycles_);
|
||||
return CyclicIterator(this->range_size_, this->end_, this->cycles_);
|
||||
}
|
||||
|
||||
struct CyclicIterator {
|
||||
int64_t index_, begin_, end_, cycles_;
|
||||
int index_, range_end_, cycles_;
|
||||
|
||||
constexpr CyclicIterator(int64_t range_begin, int64_t range_end, int64_t index, int64_t cycles)
|
||||
: index_(index), begin_(range_begin), end_(range_end), cycles_(cycles)
|
||||
constexpr CyclicIterator(const int range_end, const int index, const int cycles)
|
||||
: index_(index), range_end_(range_end), cycles_(cycles)
|
||||
{
|
||||
BLI_assert(range_begin <= index && index <= range_end);
|
||||
BLI_assert(0 <= index && index <= range_end);
|
||||
}
|
||||
|
||||
constexpr CyclicIterator(const CyclicIterator ©)
|
||||
: index_(copy.index_), begin_(copy.begin_), end_(copy.end_), cycles_(copy.cycles_)
|
||||
: index_(copy.index_), range_end_(copy.range_end_), cycles_(copy.cycles_)
|
||||
{
|
||||
}
|
||||
~CyclicIterator() = default;
|
||||
|
@ -261,37 +419,36 @@ class IndexRangeCyclic {
|
|||
if (this == ©) {
|
||||
return *this;
|
||||
}
|
||||
index_ = copy.index_;
|
||||
begin_ = copy.begin_;
|
||||
end_ = copy.end_;
|
||||
cycles_ = copy.cycles_;
|
||||
this->index_ = copy.index_;
|
||||
this->range_end_ = copy.range_end_;
|
||||
this->cycles_ = copy.cycles_;
|
||||
return *this;
|
||||
}
|
||||
constexpr CyclicIterator &operator++()
|
||||
{
|
||||
index_++;
|
||||
if (index_ == end_) {
|
||||
index_ = begin_;
|
||||
cycles_++;
|
||||
this->index_++;
|
||||
if (this->index_ == this->range_end_) {
|
||||
this->index_ = 0;
|
||||
this->cycles_++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void increment(int64_t n)
|
||||
void increment(const int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
++*this;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const int64_t &operator*() const
|
||||
constexpr const int &operator*() const
|
||||
{
|
||||
return index_;
|
||||
return this->index_;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const CyclicIterator &other) const
|
||||
{
|
||||
return index_ == other.index_ && cycles_ == other.cycles_;
|
||||
return this->index_ == other.index_ && this->cycles_ == other.cycles_;
|
||||
}
|
||||
constexpr bool operator!=(const CyclicIterator &other) const
|
||||
{
|
||||
|
@ -386,6 +543,12 @@ IndexMask indices_for_type(const VArray<int8_t> &types,
|
|||
const IndexMask selection,
|
||||
Vector<int64_t> &r_indices);
|
||||
|
||||
void indices_for_each_type(const VArray<int8_t> &types,
|
||||
const std::array<int, CURVE_TYPES_NUM> &counts,
|
||||
const IndexMask selection,
|
||||
std::array<IndexMask, CURVE_TYPES_NUM> &r_type_masks,
|
||||
std::array<Vector<int64_t>, CURVE_TYPES_NUM> &r_type_indices);
|
||||
|
||||
void foreach_curve_by_type(const VArray<int8_t> &types,
|
||||
const std::array<int, CURVE_TYPES_NUM> &type_counts,
|
||||
IndexMask selection,
|
||||
|
@ -394,6 +557,15 @@ void foreach_curve_by_type(const VArray<int8_t> &types,
|
|||
FunctionRef<void(IndexMask)> bezier_fn,
|
||||
FunctionRef<void(IndexMask)> nurbs_fn);
|
||||
|
||||
/**
|
||||
* Same as 'by_type' but index mask for each curve type is pre-computed.
|
||||
*/
|
||||
void foreach_curve_by_type_mask(const std::array<IndexMask, CURVE_TYPES_NUM> &curve_type_mask,
|
||||
FunctionRef<void(IndexMask)> catmull_rom_fn,
|
||||
FunctionRef<void(IndexMask)> poly_fn,
|
||||
FunctionRef<void(IndexMask)> bezier_fn,
|
||||
FunctionRef<void(IndexMask)> nurbs_fn);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -128,6 +128,18 @@ IndexMask indices_for_type(const VArray<int8_t> &types,
|
|||
selection, 4096, r_indices, [&](const int index) { return types_span[index] == type; });
|
||||
}
|
||||
|
||||
void indices_for_each_type(const VArray<int8_t> &types,
|
||||
const std::array<int, CURVE_TYPES_NUM> &counts,
|
||||
const IndexMask selection,
|
||||
std::array<IndexMask, CURVE_TYPES_NUM> &r_type_masks,
|
||||
std::array<Vector<int64_t>, CURVE_TYPES_NUM> &r_type_indices)
|
||||
{
|
||||
for (const int64_t curve_type : IndexRange(CURVE_TYPES_NUM)) {
|
||||
r_type_masks[curve_type] = indices_for_type(
|
||||
types, counts, CurveType(curve_type), selection, r_type_indices[curve_type]);
|
||||
}
|
||||
}
|
||||
|
||||
void foreach_curve_by_type(const VArray<int8_t> &types,
|
||||
const std::array<int, CURVE_TYPES_NUM> &counts,
|
||||
const IndexMask selection,
|
||||
|
@ -150,4 +162,21 @@ void foreach_curve_by_type(const VArray<int8_t> &types,
|
|||
call_if_not_empty(CURVE_TYPE_NURBS, nurbs_fn);
|
||||
}
|
||||
|
||||
void foreach_curve_by_type_mask(const std::array<IndexMask, CURVE_TYPES_NUM> &curve_type_mask,
|
||||
FunctionRef<void(IndexMask)> catmull_rom_fn,
|
||||
FunctionRef<void(IndexMask)> poly_fn,
|
||||
FunctionRef<void(IndexMask)> bezier_fn,
|
||||
FunctionRef<void(IndexMask)> nurbs_fn)
|
||||
{
|
||||
auto call_if_not_empty = [&](const IndexMask curve_type_mask, FunctionRef<void(IndexMask)> fn) {
|
||||
if (!curve_type_mask.is_empty()) {
|
||||
fn(curve_type_mask);
|
||||
}
|
||||
};
|
||||
call_if_not_empty(curve_type_mask[0], catmull_rom_fn);
|
||||
call_if_not_empty(curve_type_mask[1], poly_fn);
|
||||
call_if_not_empty(curve_type_mask[2], bezier_fn);
|
||||
call_if_not_empty(curve_type_mask[3], nurbs_fn);
|
||||
}
|
||||
|
||||
} // namespace blender::bke::curves
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "BLI_span.hh"
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_curves_utils.hh"
|
||||
|
@ -16,21 +17,8 @@ namespace blender::geometry {
|
|||
*/
|
||||
bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
|
||||
IndexMask selection,
|
||||
Span<bke::curves::CurvePoint> start_points,
|
||||
Span<bke::curves::CurvePoint> end_points);
|
||||
|
||||
/**
|
||||
* Find the point(s) and piecewise segment corresponding to the given distance along the length of
|
||||
* the curve. Returns points on the evaluated curve for Catmull-Rom and NURBS splines.
|
||||
*
|
||||
* \param curves: Curve geometry to sample.
|
||||
* \param lengths: Distance along the curve on form [0.0, length] to determine the point for.
|
||||
* \param curve_indices: Curve index to lookup for each 'length', negative index are set to 0.
|
||||
* \param normalized_factors: If true, 'lengths' are normalized to the interval [0.0, 1.0].
|
||||
*/
|
||||
Array<bke::curves::CurvePoint, 12> lookup_curve_points(const bke::CurvesGeometry &curves,
|
||||
Span<float> lengths,
|
||||
Span<int64_t> curve_indices,
|
||||
bool normalized_factors);
|
||||
const VArray<float> &starts,
|
||||
const VArray<float> &ends,
|
||||
GeometryNodeCurveSampleMode mode);
|
||||
|
||||
} // namespace blender::geometry
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,6 +19,7 @@ NODE_STORAGE_FUNCS(NodeGeometryCurveTrim)
|
|||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
|
||||
// b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
|
||||
b.add_input<decl::Float>(N_("Start"))
|
||||
.min(0.0f)
|
||||
.max(1.0f)
|
||||
|
@ -64,6 +65,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
|
|||
const NodeGeometryCurveTrim &storage = node_storage(*node);
|
||||
const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
|
||||
|
||||
// bNodeSocket *start_fac = static_cast<bNodeSocket *>(node->inputs.first)->next->next;
|
||||
bNodeSocket *start_fac = static_cast<bNodeSocket *>(node->inputs.first)->next;
|
||||
bNodeSocket *end_fac = start_fac->next;
|
||||
bNodeSocket *start_len = end_fac->next;
|
||||
|
@ -109,6 +111,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
|
|||
|
||||
static void geometry_set_curve_trim(GeometrySet &geometry_set,
|
||||
const GeometryNodeCurveSampleMode mode,
|
||||
Field<bool> &selection_field,
|
||||
Field<float> &start_field,
|
||||
Field<float> &end_field)
|
||||
{
|
||||
|
@ -123,41 +126,21 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
|
|||
|
||||
bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
|
||||
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
|
||||
evaluator.add(selection_field);
|
||||
evaluator.add(start_field);
|
||||
evaluator.add(end_field);
|
||||
evaluator.evaluate();
|
||||
const VArray<float> starts = evaluator.get_evaluated<float>(0);
|
||||
const VArray<float> ends = evaluator.get_evaluated<float>(1);
|
||||
|
||||
const VArray<bool> cyclic = src_curves.cyclic();
|
||||
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
|
||||
const VArray<float> starts = evaluator.get_evaluated<float>(1);
|
||||
const VArray<float> ends = evaluator.get_evaluated<float>(2);
|
||||
|
||||
/* If node length input is on form [0, 1] instead of [0, length]*/
|
||||
const bool normalized_length_lookup = mode == GEO_NODE_CURVE_SAMPLE_FACTOR;
|
||||
|
||||
/* Stack start + end field. */
|
||||
Vector<float> length_factors(src_curves.curves_num() * 2);
|
||||
Vector<int64_t> lookup_indices(src_curves.curves_num() * 2);
|
||||
threading::parallel_for(src_curves.curves_range(), 512, [&](IndexRange curve_range) {
|
||||
for (const int64_t curve_i : curve_range) {
|
||||
const bool negative_trim = !cyclic[curve_i] && starts[curve_i] > ends[curve_i];
|
||||
length_factors[curve_i] = starts[curve_i];
|
||||
length_factors[curve_i + src_curves.curves_num()] = negative_trim ? starts[curve_i] :
|
||||
ends[curve_i];
|
||||
lookup_indices[curve_i] = curve_i;
|
||||
lookup_indices[curve_i + src_curves.curves_num()] = curve_i;
|
||||
}
|
||||
});
|
||||
|
||||
/* Create curve trim lookup table. */
|
||||
Array<bke::curves::CurvePoint, 12> point_lookups = geometry::lookup_curve_points(
|
||||
src_curves, length_factors, lookup_indices, normalized_length_lookup);
|
||||
if (selection.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bke::CurvesGeometry dst_curves = geometry::trim_curves(
|
||||
src_curves,
|
||||
src_curves.curves_range().as_span(),
|
||||
point_lookups.as_span().slice(0, src_curves.curves_num()),
|
||||
point_lookups.as_span().slice(src_curves.curves_num(), src_curves.curves_num()));
|
||||
|
||||
src_curves, selection, starts, ends, mode);
|
||||
Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
|
||||
bke::curves_copy_parameters(src_curves_id, *dst_curves_id);
|
||||
geometry_set.replace_curves(dst_curves_id);
|
||||
|
@ -171,18 +154,20 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
|
||||
GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(geometry_set);
|
||||
|
||||
// Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
Field<bool> selection_field = fn::make_constant_field<bool>(true);
|
||||
if (mode == GEO_NODE_CURVE_SAMPLE_FACTOR) {
|
||||
Field<float> start_field = params.extract_input<Field<float>>("Start");
|
||||
Field<float> end_field = params.extract_input<Field<float>>("End");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry_set_curve_trim(geometry_set, mode, start_field, end_field);
|
||||
geometry_set_curve_trim(geometry_set, mode, selection_field, start_field, end_field);
|
||||
});
|
||||
}
|
||||
else if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
|
||||
Field<float> start_field = params.extract_input<Field<float>>("Start_001");
|
||||
Field<float> end_field = params.extract_input<Field<float>>("End_001");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry_set_curve_trim(geometry_set, mode, start_field, end_field);
|
||||
geometry_set_curve_trim(geometry_set, mode, selection_field, start_field, end_field);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue