22 if (points_num < order) {
34 return (!cyclic || points_num % (order - 1) == 0);
48 const int repeat_inner = is_bezier ? order - 1 : 1;
50 const int knots_before_geometry = order + int(is_bezier && !is_end_point && order > 2);
51 const int knots_after_geometry = order - 1 +
54 const int knots_total =
knots_num(points_num, order, cyclic);
56 const int geometry_knots = knots_total - knots_before_geometry - knots_after_geometry;
58 const int non_zero_knots = (geometry_knots + repeat_inner - 1) / repeat_inner;
59 return non_zero_knots;
64 return (knots[knot_span + 1] - knots[knot_span]) > 0.0f;
73 const int degree = order - 1;
93 const int nonzero_span_num = knots_mode == KnotsMode::NURBS_KNOT_MODE_CUSTOM &&
97 return resolution * nonzero_span_num + int(!cyclic);
107 const float last_knot = custom_knots.
last();
108 const float shift = last_knot - knots[order - 1];
111 tail[knot] = knots[order + knot] + shift;
128 const int repeat_inner = is_bezier ? order - 1 : 1;
130 const int head = is_end_point ? (order - (cyclic ? 1 : 0)) :
131 (is_bezier ?
min_ii(2, repeat_inner) : 1);
134 const int tail = cyclic ? 2 * order - 1 : (is_end_point ? order : 0);
137 float current = 0.0f;
139 const int offset = is_end_point && cyclic ? 1 : 0;
154 const int tail_index = knots.
size() - tail;
156 knots[tail_index +
i] = current + (knots[
i] - knots[0]);
161 const int points_num,
186 if (knots[
i - 1] == knots[
i]) {
202 const float parameter,
203 const int span_index,
210 BLI_assert(knots[span_index + 1] > knots[span_index]);
211 const int order = degree + 1;
213 r_start_index = span_index - degree;
220 left[j] = parameter - knots[span_index + 1 - j];
221 right[j] = knots[span_index + j] - parameter;
224 const float temp = r_weights[r] / (right[r + 1] +
left[j - r]);
225 r_weights[r] = saved + right[r + 1] * temp;
226 saved =
left[j - r] * temp;
228 r_weights[j] = saved;
233 const int evaluated_num,
235 const int resolution,
243 const int8_t degree = order - 1;
249 if (evaluated_num == 0) {
267 const int breakpoint_num = (evaluated_num - !cyclic) / resolution;
270 int breakpoint_count = 0;
273 span_offsets[breakpoint_count++] = span_index;
276 BLI_assert(breakpoint_count == breakpoint_num);
280 for (const int index : range) {
281 const int span_index = span_offsets[index];
282 int eval_point = index * resolution;
284 const float knot_delta = knots[span_index + 1] - knots[span_index];
285 const float knot_step = knot_delta / resolution;
286 BLI_assert(knot_delta > 0.0f);
288 for (const int step : IndexRange::from_begin_size(0, resolution)) {
289 const float parameter = knots[span_index] + step * knot_step;
290 calculate_basis_for_point(knots,
294 basis_weights.slice(eval_point * order, order),
295 basis_start_indices[eval_point]);
303 knots[wrapped_points_num],
305 basis_weights.slice(basis_weights.size() - order, order),
306 basis_start_indices.last());
319 for (const int i : range) {
320 Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order);
321 for (const int j : point_weights.index_range()) {
322 const int point_index = (basis_cache.start_indices[i] + j) % src.size();
323 mixer.mix_in(i, src[point_index], point_weights[j]);
326 mixer.finalize(range);
340 for (const int i : range) {
341 Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order);
343 for (const int j : point_weights.index_range()) {
344 const int point_index = (basis_cache.start_indices[i] + j) % src.size();
345 const float weight = point_weights[j] * control_weights[point_index];
346 mixer.mix_in(i, src[point_index], weight);
349 mixer.finalize(range);
366 using T = decltype(dummy);
367 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
368 if (control_weights.is_empty()) {
369 interpolate_to_evaluated(basis_cache, order, src.typed<T>(), dst.typed<T>());
372 interpolate_to_evaluated_rational(
373 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)
IndexRange index_range() const
void copy_from(GSpan values)
const CPPType & type() const
constexpr bool is_empty() const
static constexpr IndexRange from_begin_end(const int64_t begin, const int64_t end)
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)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
typename DefaultMixerStruct< T >::type DefaultMixer
Vector< int > calculate_multiplicity_sequence(Span< float > knots)
int calculate_evaluated_num(int points_num, int8_t order, bool cyclic, int resolution, KnotsMode knots_mode, Span< float > knots)
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, int resolution, bool cyclic, KnotsMode knots_mode, Span< float > knots, BasisCache &basis_cache)
static void calculate_basis_for_point(const Span< float > knots, const int degree, const float parameter, const int span_index, MutableSpan< float > r_weights, int &r_start_index)
bool check_valid_eval_params(int points_num, int8_t order, bool cyclic, KnotsMode knots_mode, int resolution)
int control_points_num(int num_control_points, int8_t order, bool cyclic)
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)
static bool is_breakpoint(const Span< float > knots, const int knot_span)
void load_curve_knots(KnotsMode mode, int points_num, int8_t order, bool cyclic, IndexRange curve_knots, Span< float > custom_knots, MutableSpan< float > knots)
static int count_nonzero_knot_spans(const int points_num, const int order, const bool cyclic, const Span< 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)
static int calc_nonzero_knot_spans(const int points_num, const KnotsMode mode, const int8_t order, 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