21 if (points_num < order) {
29 return (!cyclic || points_num % (order - 1) == 0);
47int knots_num(
const int points_num,
const int8_t order,
const bool cyclic)
50 return points_num + order * 2 - 1;
52 return points_num + order;
62 const float last_knot = custom_knots.
last();
63 const float shift = last_knot - knots[order - 1];
66 tail[knot] = knots[order + knot] + shift;
83 const int repeat_inner = is_bezier ? order - 1 : 1;
85 const int head = is_end_point ? (order - (cyclic ? 1 : 0)) :
86 (is_bezier ?
min_ii(2, repeat_inner) : 1);
89 const int tail = cyclic ? 2 * order - 1 : (is_end_point ? order : 0);
94 const int offset = is_end_point && cyclic ? 1 : 0;
109 const int tail_index = knots.
size() - tail;
111 knots[tail_index +
i] = current + (knots[
i] - knots[0]);
116 const int points_num,
141 if (knots[
i - 1] == knots[
i]) {
154 const int points_num,
160 const int order = degree + 1;
164 for (
const int i :
IndexRange(points_num + degree)) {
165 const bool knots_equal = knots[
i] == knots[
i + 1];
166 if (knots_equal || parameter < knots[
i] || parameter > knots[
i + 1]) {
170 start = std::max(
i - degree, 0);
177 buffer[end - start] = 1.0f;
179 for (
const int i_order :
IndexRange(2, degree)) {
180 if (end + i_order >= knots.
size()) {
181 end = points_num + degree - i_order;
184 const int knot_index = start +
i;
186 float new_basis = 0.0f;
187 if (buffer[
i] != 0.0f) {
188 new_basis += ((parameter - knots[knot_index]) * buffer[
i]) /
189 (knots[knot_index + i_order - 1] - knots[knot_index]);
192 if (buffer[
i + 1] != 0.0f) {
193 new_basis += ((knots[knot_index + i_order] - parameter) * buffer[
i + 1]) /
194 (knots[knot_index + i_order] - knots[knot_index + 1]);
197 buffer[
i] = new_basis;
203 r_start_index = start;
207 const int evaluated_num,
215 const int8_t degree = order - 1;
220 if (evaluated_num == 0) {
227 const int last_control_point_index = cyclic ? points_num + degree : points_num;
228 const int evaluated_segment_num =
segments_num(evaluated_num, cyclic);
230 const float start = knots[degree];
231 const float end = knots[last_control_point_index];
232 const float step = (end - start) / evaluated_segment_num;
235 const float parameter = std::clamp(start +
step *
i, knots[0], knots[points_num + degree]);
240 parameter, last_control_point_index, degree, knots, point_weights, basis_start_indices[
i]);
253 for (const int i : range) {
254 Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order);
255 for (const int j : point_weights.index_range()) {
256 const int point_index = (basis_cache.start_indices[i] + j) % src.size();
257 mixer.mix_in(i, src[point_index], point_weights[j]);
260 mixer.finalize(range);
274 for (const int i : range) {
275 Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order);
277 for (const int j : point_weights.index_range()) {
278 const int point_index = (basis_cache.start_indices[i] + j) % src.size();
279 const float weight = point_weights[j] * control_weights[point_index];
280 mixer.mix_in(i, src[point_index], weight);
283 mixer.finalize(range);
300 using T = decltype(dummy);
301 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
302 if (control_weights.is_empty()) {
303 interpolate_to_evaluated(basis_cache, order, src.typed<T>(), dst.typed<T>());
306 interpolate_to_evaluated_rational(
307 basis_cache, order, control_weights, src.typed<T>(), dst.typed<T>());
Low-level operations for curves.
MINLINE int min_ii(int a, int b)
#define UNUSED_VARS_NDEBUG(...)
@ NURBS_KNOT_MODE_ENDPOINT
@ NURBS_KNOT_MODE_ENDPOINT_BEZIER
void resize(const int64_t new_size)
Span< T > as_span() const
MutableSpan< T > as_mutable_span()
void copy_from(GSpan values)
const CPPType & type() const
constexpr bool is_empty() const
constexpr IndexRange drop_front(int64_t n) const
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr MutableSpan take_back(const int64_t n) const
constexpr IndexRange index_range() const
constexpr void copy_from(Span< T > values) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr const T & last(const int64_t n=0) const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
void append(const T &value)
void resize(const int64_t new_size)
void reserve(const int64_t min_capacity)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
typename DefaultMixerStruct< T >::type DefaultMixer
int calculate_evaluated_num(int points_num, int8_t order, bool cyclic, int resolution, KnotsMode knots_mode)
Vector< int > calculate_multiplicity_sequence(Span< float > knots)
bool check_valid_num_and_order(int points_num, int8_t order, bool cyclic, KnotsMode knots_mode)
void calculate_knots(int points_num, KnotsMode mode, int8_t order, bool cyclic, MutableSpan< float > knots)
void calculate_basis_cache(int points_num, int evaluated_num, int8_t order, bool cyclic, Span< float > knots, BasisCache &basis_cache)
static void calculate_basis_for_point(const float parameter, const int points_num, const int degree, const Span< float > knots, MutableSpan< float > r_weights, int &r_start_index)
int knots_num(int points_num, int8_t order, bool cyclic)
static void interpolate_to_evaluated_rational(const BasisCache &basis_cache, const int8_t order, const Span< float > control_weights, const Span< T > src, MutableSpan< T > dst)
void load_curve_knots(KnotsMode mode, int points_num, int8_t order, bool cyclic, IndexRange curve_knots, Span< float > custom_knots, MutableSpan< float > knots)
void copy_custom_knots(const bke::CurvesGeometry &src_curves, const IndexMask &exclude_curves, bke::CurvesGeometry &dst_curves)
void interpolate_to_evaluated(const BasisCache &basis_cache, int8_t order, Span< float > control_weights, GSpan src, GMutableSpan dst)
int segments_num(const int points_num, const bool cyclic)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Vector< int > start_indices