39 dst[
i] = src[
i * scale + offset];
51 dst[
i * 3 + 1] = src[
i];
52 dst[
i * 3 + 2] = src[
i];
59 using T = decltype(dummy);
60 bezier_generic_to_nurbs(src.typed<T>(), dst.typed<T>());
70 dst_positions[
i * 3] = src_handles_l[
i];
71 dst_positions[
i * 3 + 1] = src_positions[
i];
72 dst_positions[
i * 3 + 2] = src_handles_r[
i];
84 constexpr float handle_scale = 1.0f / 6.0f;
86 if (src_positions.
size() == 1) {
92 const float3 first_offset = cyclic ? src_positions[1] - src_positions.
last() :
93 src_positions[1] - src_positions[0];
94 dst_handles_r.
first() = src_positions.
first() + first_offset * handle_scale;
95 dst_handles_l.
first() = src_positions.
first() - first_offset * handle_scale;
97 const float3 last_offset = cyclic ? src_positions.
first() - src_positions.
last(1) :
98 src_positions.
last() - src_positions.
last(1);
99 dst_handles_l.
last() = src_positions.
last() - last_offset * handle_scale;
100 dst_handles_r.
last() = src_positions.
last() + last_offset * handle_scale;
103 const float3 left_offset = src_positions[
i - 1] - src_positions[
i + 1];
104 dst_handles_l[
i] = src_positions[
i] + left_offset * handle_scale;
106 const float3 right_offset = src_positions[
i + 1] - src_positions[
i - 1];
107 dst_handles_r[
i] = src_positions[
i] + right_offset * handle_scale;
128 switch (knots_mode) {
131 dst[
i] = src[(
i + 1) % src.
size()];
151 using T = decltype(dummy);
152 nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode);
159 const int nurbs_positions_num = nurbs_positions.
size();
165 handle_positions.
append(nurbs_positions[1] +
166 ((nurbs_positions[0] - nurbs_positions[1]) / 3));
169 handle_positions.
append(2 * nurbs_positions[0] - nurbs_positions[1]);
170 handle_positions.
append(nurbs_positions[1]);
175 const int segments_num = nurbs_positions_num - 1;
176 const bool ignore_interior_segment = segments_num == 3 && is_periodic ==
false;
177 if (ignore_interior_segment ==
false) {
178 const float mid_offset =
float(segments_num - 1) / 2.0f;
179 for (
const int i :
IndexRange(1, segments_num - 2)) {
181 const int divisor = is_periodic ?
183 std::min(3,
int(-std::abs(
i - mid_offset) + mid_offset + 1.0f));
184 const float3 &p1 = nurbs_positions[
i];
185 const float3 &p2 = nurbs_positions[
i + 1];
186 const float3 displacement = (p2 - p1) / divisor;
187 const int num_handles_on_segment = divisor < 3 ? 1 : 2;
188 for (
int j :
IndexRange(1, num_handles_on_segment)) {
189 handle_positions.
append(p1 + (displacement * j));
194 const int last_index = nurbs_positions_num - 1;
197 nurbs_positions[last_index - 1] +
198 ((nurbs_positions[last_index] - nurbs_positions[last_index - 1]) / 3));
201 handle_positions.
append(nurbs_positions[last_index - 1]);
202 handle_positions.
append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
206 for (
const int i :
IndexRange(nurbs_positions_num)) {
210 handle_positions.
append(nurbs_positions[
i]);
212 if (nurbs_positions_num % 3 == 1) {
215 else if (nurbs_positions_num % 3 == 2) {
216 const int last_index = nurbs_positions_num - 1;
217 handle_positions.
append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
221 return handle_positions;
232 handle_positions[
i * 2], handle_positions[
i * 2 + 1], 0.5f);
249 return cyclic ? src_size : std::max(1, src_size - 2);
251 return (src_size + 1) / 3;
293 src_points_by_curve[
i].
size());
308 "position",
"handle_type_left",
"handle_type_right",
"handle_right",
"handle_left"};
310 attributes_to_skip.
add_new(
"nurbs_weight");
313 auto catmull_rom_to_bezier = [&](
const IndexMask &selection) {
319 src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
322 const IndexRange src_points = src_points_by_curve[
i];
323 const IndexRange dst_points = dst_points_by_curve[
i];
326 dst_handles_l.
slice(dst_points),
327 dst_handles_r.
slice(dst_points));
331 if (attributes_to_skip.
contains(attribute.name)) {
335 src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
339 auto poly_to_bezier = [&](
const IndexMask &selection) {
341 src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
348 if (attributes_to_skip.
contains(attribute.name)) {
352 src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
356 auto bezier_to_bezier = [&](
const IndexMask &selection) {
363 src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
365 src_points_by_curve, dst_points_by_curve, selection, src_handles_l, dst_handles_l);
367 src_points_by_curve, dst_points_by_curve, selection, src_handles_r, dst_handles_r);
369 src_points_by_curve, dst_points_by_curve, selection, src_types_l, dst_types_l);
371 src_points_by_curve, dst_points_by_curve, selection, src_types_r, dst_types_r);
376 if (attributes_to_skip.
contains(attribute.name)) {
380 src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
384 auto nurbs_to_bezier = [&](
const IndexMask &selection) {
391 const IndexRange src_points = src_points_by_curve[
i];
392 const IndexRange dst_points = dst_points_by_curve[
i];
394 if (dst_points.
size() == 1) {
395 const float3 &position = src_positions[src_points.
first()];
396 dst_positions[dst_points.
first()] = position;
397 dst_handles_l[dst_points.
first()] = position;
398 dst_handles_r[dst_points.
first()] = position;
408 nurbs_positions_vector.
extend(src_curve_positions);
409 nurbs_positions_vector.
append(src_curve_positions[0]);
410 nurbs_positions_vector.
append(src_curve_positions[1]);
411 nurbs_positions = nurbs_positions_vector;
422 nurbs_positions, handle_positions, knots_mode, dst_positions.
slice(dst_points));
426 if (attributes_to_skip.
contains(attribute.name)) {
430 const IndexRange src_points = src_points_by_curve[
i];
431 const IndexRange dst_points = dst_points_by_curve[
i];
434 attribute.dst.span.slice(dst_points));
442 catmull_rom_to_bezier,
449 src_points_by_curve, dst_points_by_curve, unselected, attribute.src, attribute.dst.span);
451 attribute.dst.finish();
494 auto fill_weights_if_necessary = [&](
const IndexMask &selection) {
495 if (src_attributes.
contains(
"nurbs_weight")) {
501 auto catmull_rom_to_nurbs = [&](
const IndexMask &selection) {
505 fill_weights_if_necessary(selection);
508 for (
const int i : segment) {
509 const IndexRange src_points = src_points_by_curve[
i];
510 const IndexRange dst_points = dst_points_by_curve[
i];
512 src_positions.
slice(src_points), src_cyclic[
i], dst_positions.
slice(dst_points));
517 if (attributes_to_skip.
contains(attribute.name)) {
521 const IndexRange src_points = src_points_by_curve[
i];
522 const IndexRange dst_points = dst_points_by_curve[
i];
524 attribute.dst.span.slice(dst_points));
529 auto poly_to_nurbs = [&](
const IndexMask &selection) {
532 src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
533 fill_weights_if_necessary(selection);
552 if (attributes_to_skip.
contains(attribute.name)) {
556 src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
560 auto bezier_to_nurbs = [&](
const IndexMask &selection) {
567 fill_weights_if_necessary(selection);
570 const IndexRange src_points = src_points_by_curve[
i];
571 const IndexRange dst_points = dst_points_by_curve[
i];
573 src_handles_l.
slice(src_points),
574 src_handles_r.
slice(src_points),
575 dst_positions.
slice(dst_points));
579 if (attributes_to_skip.
contains(attribute.name)) {
583 const IndexRange src_points = src_points_by_curve[
i];
584 const IndexRange dst_points = dst_points_by_curve[
i];
586 attribute.dst.span.slice(dst_points));
591 auto nurbs_to_nurbs = [&](
const IndexMask &selection) {
593 src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
604 if (attributes_to_skip.
contains(attribute.name)) {
608 src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
615 catmull_rom_to_nurbs,
622 src_points_by_curve, dst_points_by_curve, unselected, attribute.src, attribute.dst.span);
624 attribute.dst.finish();
648 options.convert_bezier_handles_to_catmull_rom_points :
649 options.convert_bezier_handles_to_poly_points;
670 const IndexRange src_points = src_points_by_curve[
i];
672 int &
size = dst_offsets[
i];
695 auto convert_from_catmull_rom_or_poly_or_nurbs = [&](
const IndexMask &selection) {
697 src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
699 if (attributes_to_skip.
contains(attribute.name)) {
703 src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
707 auto convert_from_bezier = [&](
const IndexMask &selection) {
713 const IndexRange src_points = src_points_by_curve[curve_i];
714 const IndexRange dst_points = dst_points_by_curve[curve_i];
716 const int src_point_i = src_points[
i];
717 const int dst_points_start = dst_points.
start() + 3 *
i;
718 dst_positions[dst_points_start + 0] = src_left_handles[src_point_i];
719 dst_positions[dst_points_start + 1] = src_positions[src_point_i];
720 dst_positions[dst_points_start + 2] = src_right_handles[src_point_i];
726 if (attributes_to_skip.
contains(attribute.name)) {
729 const CPPType &cpp_type = attribute.src.type();
731 const IndexRange src_points = src_points_by_curve[curve_i];
732 const IndexRange dst_points = dst_points_by_curve[curve_i];
734 const int src_point_i = src_points[
i];
735 const int dst_points_start = dst_points.
start() + 3 *
i;
736 const void *src_value = attribute.src[src_point_i];
737 cpp_type.
fill_assign_n(src_value, attribute.dst.span[dst_points_start], 3);
746 convert_from_catmull_rom_or_poly_or_nurbs,
747 convert_from_catmull_rom_or_poly_or_nurbs,
749 convert_from_catmull_rom_or_poly_or_nurbs);
753 src_points_by_curve, dst_points_by_curve, unselected, attribute.src, attribute.dst.span);
755 attribute.dst.finish();
773 selection,
GrainSize(4096), memory, [&](
const int curve_i) {
796 src_curves, selection, dst_type, attribute_filter,
options);
800 if (!
options.keep_bezier_shape_as_nurbs || !
options.keep_catmull_rom_shape_as_nurbs) {
803 src_curves, selection,
options);
Low-level operations for curves.
Low-level operations for curves.
#define BLI_assert_unreachable()
@ NURBS_KNOT_MODE_ENDPOINT
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
void fill_assign_n(const void *value, void *dst, int64_t n) const
const CPPType & type() const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
constexpr int64_t first() const
constexpr IndexRange drop_back(int64_t n) const
constexpr int64_t size() const
constexpr int64_t start() const
constexpr IndexRange index_range() const
constexpr IndexRange drop_front(int64_t n) const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr T & first() const
constexpr IndexRange index_range() const
constexpr T & last(const int64_t n=0) const
bool contains(const Key &key) const
void add_new(const Key &key)
constexpr Span slice(int64_t start, int64_t size) const
constexpr const T & first() const
constexpr int64_t size() const
constexpr const T & last(const int64_t n=0) const
constexpr IndexRange index_range() const
T get_internal_single() const
void append(const T &value)
void extend(Span< T > array)
Span< T > as_span() const
bool contains(StringRef attribute_id) const
VArray< int8_t > handle_types_left() const
void remove_attributes_based_on_types()
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
MutableSpan< int8_t > handle_types_right_for_write()
VArray< int8_t > handle_types_right() const
IndexRange curves_range() const
const std::array< int, CURVE_TYPES_NUM > & curve_type_counts() const
MutableSpan< float3 > handle_positions_left_for_write()
MutableAttributeAccessor attributes_for_write()
MutableSpan< float3 > handle_positions_right_for_write()
MutableSpan< int8_t > nurbs_knots_modes_for_write()
std::optional< Span< float > > nurbs_weights() const
MutableSpan< int8_t > nurbs_orders_for_write()
VArray< int8_t > nurbs_knots_modes() const
std::optional< Span< float3 > > handle_positions_left() const
Span< float3 > positions() const
bool has_curve_with_type(CurveType type) const
std::optional< Span< float3 > > handle_positions_right() const
MutableSpan< float > nurbs_weights_for_write()
void resize(int points_num, int curves_num)
void fill_curve_types(CurveType type)
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
void calculate_bezier_auto_handles()
MutableSpan< int8_t > handle_types_left_for_write()
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
void foreach_segment(Fn &&fn) const
CCL_NAMESPACE_BEGIN struct Options options
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void copy_group_to_group(OffsetIndices< int > src_offsets, OffsetIndices< int > dst_offsets, const IndexMask &selection, GSpan src, GMutableSpan dst)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
void copy_custom_knots(const bke::CurvesGeometry &src_curves, const IndexMask &exclude_curves, bke::CurvesGeometry &dst_curves)
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
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)
Vector< AttributeTransferData > retrieve_attributes_for_transfer(const AttributeAccessor src_attributes, MutableAttributeAccessor dst_attributes, AttrDomainMask domain_mask, const AttributeFilter &attribute_filter={})
static bke::CurvesGeometry convert_bezier_or_catmull_rom_to_poly_before_conversion_to_nurbs(const bke::CurvesGeometry &src_curves, const IndexMask &selection, const ConvertCurvesOptions &options)
static bool is_nurbs_to_bezier_one_to_one(const KnotsMode knots_mode)
static void create_nurbs_to_bezier_positions(const Span< float3 > nurbs_positions, const Span< float3 > handle_positions, const KnotsMode knots_mode, MutableSpan< float3 > bezier_positions)
static void bezier_positions_to_nurbs(const Span< float3 > src_positions, const Span< float3 > src_handles_l, const Span< float3 > src_handles_r, MutableSpan< float3 > dst_positions)
static void nurbs_to_bezier_assign(const Span< T > src, const MutableSpan< T > dst, const KnotsMode knots_mode)
static int to_nurbs_size(const CurveType src_type, const int src_size)
static void catmull_rom_to_bezier_handles(const Span< float3 > src_positions, const bool cyclic, MutableSpan< float3 > dst_handles_l, MutableSpan< float3 > dst_handles_r)
static void bezier_generic_to_nurbs(const Span< T > src, MutableSpan< T > dst)
static bke::CurvesGeometry convert_curves_trivial(const bke::CurvesGeometry &src_curves, const IndexMask &selection, const CurveType dst_type)
static void catmull_rom_to_nurbs_positions(const Span< float3 > src_positions, const bool cyclic, MutableSpan< float3 > dst_positions)
static Vector< float3 > create_nurbs_to_bezier_handles(const Span< float3 > nurbs_positions, const KnotsMode knots_mode)
static void scale_input_assign(const Span< T > src, const int scale, const int offset, MutableSpan< T > dst)
static bke::CurvesGeometry convert_curves_to_nurbs(const bke::CurvesGeometry &src_curves, const IndexMask &selection, const bke::AttributeFilter &attribute_filter)
static bke::CurvesGeometry convert_curves_to_catmull_rom_or_poly(const bke::CurvesGeometry &src_curves, const IndexMask &selection, const CurveType dst_type, const bke::AttributeFilter &attribute_filter, const ConvertCurvesOptions &options)
static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &src_curves, const IndexMask &selection, const bke::AttributeFilter &attribute_filter)
static int to_bezier_size(const CurveType src_type, const bool cyclic, const KnotsMode knots_mode, const int src_size)
bke::CurvesGeometry convert_curves(const bke::CurvesGeometry &src_curves, const IndexMask &selection, CurveType dst_type, const bke::AttributeFilter &attribute_filter, const ConvertCurvesOptions &options={})
void masked_fill(MutableSpan< T > data, const T &value, const IndexMask &mask)
T interpolate(const T &a, const T &b, const FactorT &t)
void copy_group_sizes(OffsetIndices< int > offsets, const IndexMask &mask, MutableSpan< int > sizes)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
VecBase< float, 3 > float3
ListBase vertex_group_names