Blender  V3.3
set_curve_type.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BKE_attribute.hh"
4 #include "BKE_attribute_math.hh"
5 #include "BKE_curves.hh"
6 #include "BKE_curves_utils.hh"
7 
8 #include "BLI_task.hh"
9 
10 #include "GEO_set_curve_type.hh"
11 
12 namespace blender::geometry {
13 
20 static bool is_nurbs_to_bezier_one_to_one(const KnotsMode knots_mode)
21 {
23  return true;
24  }
25  return false;
26 }
27 
33 static bool conversion_can_change_point_num(const CurveType dst_type)
34 {
36  /* The conversion to Catmull Rom or Poly should never change the number of points, no matter
37  * the source type (Bezier to Catmull Rom conversion cannot maintain the same shape anyway). */
38  return false;
39  }
40  return true;
41 }
42 
43 template<typename T>
44 static void scale_input_assign(const Span<T> src,
45  const int scale,
46  const int offset,
47  MutableSpan<T> dst)
48 {
49  for (const int i : dst.index_range()) {
50  dst[i] = src[i * scale + offset];
51  }
52 }
53 
58 template<typename T> static void bezier_generic_to_nurbs(const Span<T> src, MutableSpan<T> dst)
59 {
60  for (const int i : src.index_range()) {
61  dst[i * 3] = src[i];
62  dst[i * 3 + 1] = src[i];
63  dst[i * 3 + 2] = src[i];
64  }
65 }
66 
68 {
69  attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
70  using T = decltype(dummy);
71  bezier_generic_to_nurbs(src.typed<T>(), dst.typed<T>());
72  });
73 }
74 
75 static void bezier_positions_to_nurbs(const Span<float3> src_positions,
76  const Span<float3> src_handles_l,
77  const Span<float3> src_handles_r,
78  MutableSpan<float3> dst_positions)
79 {
80  for (const int i : src_positions.index_range()) {
81  dst_positions[i * 3] = src_handles_l[i];
82  dst_positions[i * 3 + 1] = src_positions[i];
83  dst_positions[i * 3 + 2] = src_handles_r[i];
84  }
85 }
86 
87 static void catmull_rom_to_bezier_handles(const Span<float3> src_positions,
88  const bool cyclic,
89  MutableSpan<float3> dst_handles_l,
90  MutableSpan<float3> dst_handles_r)
91 {
92  /* Catmull Rom curves are the same as Bezier curves with automatically defined handle positions.
93  * This constant defines the portion of the distance between the next/previous points to use for
94  * the length of the handles. */
95  constexpr float handle_scale = 1.0f / 6.0f;
96 
97  if (src_positions.size() == 1) {
98  dst_handles_l.first() = src_positions.first();
99  dst_handles_r.first() = src_positions.first();
100  return;
101  }
102 
103  const float3 first_offset = cyclic ? src_positions[1] - src_positions.last() :
104  src_positions[1] - src_positions[0];
105  dst_handles_r.first() = src_positions.first() + first_offset * handle_scale;
106  dst_handles_l.first() = src_positions.first() - first_offset * handle_scale;
107 
108  const float3 last_offset = cyclic ? src_positions.first() - src_positions.last(1) :
109  src_positions.last() - src_positions.last(1);
110  dst_handles_l.last() = src_positions.last() - last_offset * handle_scale;
111  dst_handles_r.last() = src_positions.last() + last_offset * handle_scale;
112 
113  for (const int i : src_positions.index_range().drop_front(1).drop_back(1)) {
114  const float3 left_offset = src_positions[i - 1] - src_positions[i + 1];
115  dst_handles_l[i] = src_positions[i] + left_offset * handle_scale;
116 
117  const float3 right_offset = src_positions[i + 1] - src_positions[i - 1];
118  dst_handles_r[i] = src_positions[i] + right_offset * handle_scale;
119  }
120 }
121 
122 static void catmull_rom_to_nurbs_positions(const Span<float3> src_positions,
123  const bool cyclic,
124  MutableSpan<float3> dst_positions)
125 {
126  /* Convert the Catmull Rom position data to Bezier handles in order to reuse the Bezier to
127  * NURBS positions assignment. If this becomes a bottleneck, this step could be avoided. */
128  Array<float3, 32> bezier_handles_l(src_positions.size());
129  Array<float3, 32> bezier_handles_r(src_positions.size());
130  catmull_rom_to_bezier_handles(src_positions, cyclic, bezier_handles_l, bezier_handles_r);
131  bezier_positions_to_nurbs(src_positions, bezier_handles_l, bezier_handles_r, dst_positions);
132 }
133 
134 template<typename T>
136  const MutableSpan<T> dst,
137  const KnotsMode knots_mode)
138 {
139  switch (knots_mode) {
141  for (const int i : dst.index_range()) {
142  dst[i] = src[(i + 1) % src.size()];
143  }
144  break;
146  for (const int i : dst.index_range().drop_back(1).drop_front(1)) {
147  dst[i] = src[i + 1];
148  }
149  dst.first() = src.first();
150  dst.last() = src.last();
151  break;
152  default:
153  /* Every 3rd NURBS position (starting from index 1) should have its attributes transferred.
154  */
155  scale_input_assign<T>(src, 3, 1, dst);
156  }
157 }
158 
159 static void nurbs_to_bezier_assign(const GSpan src, const KnotsMode knots_mode, GMutableSpan dst)
160 {
161  attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
162  using T = decltype(dummy);
163  nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode);
164  });
165 }
166 
168  const KnotsMode knots_mode)
169 {
170  const int nurbs_positions_num = nurbs_positions.size();
171  Vector<float3> handle_positions;
172 
173  if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
174  const bool is_periodic = knots_mode == NURBS_KNOT_MODE_NORMAL;
175  if (is_periodic) {
176  handle_positions.append(nurbs_positions[1] +
177  ((nurbs_positions[0] - nurbs_positions[1]) / 3));
178  }
179  else {
180  handle_positions.append(2 * nurbs_positions[0] - nurbs_positions[1]);
181  handle_positions.append(nurbs_positions[1]);
182  }
183 
184  /* Place Bezier handles on interior NURBS hull segments. Those handles can be either placed on
185  * endpoints, midpoints or 1/3 of the distance of a hull segment. */
186  const int segments_num = nurbs_positions_num - 1;
187  const bool ignore_interior_segment = segments_num == 3 && is_periodic == false;
188  if (ignore_interior_segment == false) {
189  const float mid_offset = (float)(segments_num - 1) / 2.0f;
190  for (const int i : IndexRange(1, segments_num - 2)) {
191  /* Divisor can have values: 1, 2 or 3. */
192  const int divisor = is_periodic ?
193  3 :
194  std::min(3, (int)(-std::abs(i - mid_offset) + mid_offset + 1.0f));
195  const float3 &p1 = nurbs_positions[i];
196  const float3 &p2 = nurbs_positions[i + 1];
197  const float3 displacement = (p2 - p1) / divisor;
198  const int num_handles_on_segment = divisor < 3 ? 1 : 2;
199  for (int j : IndexRange(1, num_handles_on_segment)) {
200  handle_positions.append(p1 + (displacement * j));
201  }
202  }
203  }
204 
205  const int last_index = nurbs_positions_num - 1;
206  if (is_periodic) {
207  handle_positions.append(
208  nurbs_positions[last_index - 1] +
209  ((nurbs_positions[last_index] - nurbs_positions[last_index - 1]) / 3));
210  }
211  else {
212  handle_positions.append(nurbs_positions[last_index - 1]);
213  handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
214  }
215  }
216  else {
217  for (const int i : IndexRange(nurbs_positions_num)) {
218  if (i % 3 == 1) {
219  continue;
220  }
221  handle_positions.append(nurbs_positions[i]);
222  }
223  if (nurbs_positions_num % 3 == 1) {
224  handle_positions.pop_last();
225  }
226  else if (nurbs_positions_num % 3 == 2) {
227  const int last_index = nurbs_positions_num - 1;
228  handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
229  }
230  }
231 
232  return handle_positions;
233 }
234 
235 static void create_nurbs_to_bezier_positions(const Span<float3> nurbs_positions,
236  const Span<float3> handle_positions,
237  const KnotsMode knots_mode,
238  MutableSpan<float3> bezier_positions)
239 {
240  if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
241  for (const int i : bezier_positions.index_range()) {
242  bezier_positions[i] = math::interpolate(
243  handle_positions[i * 2], handle_positions[i * 2 + 1], 0.5f);
244  }
245  }
246  else {
247  /* Every 3rd NURBS position (starting from index 1) should be converted to Bezier position. */
248  scale_input_assign(nurbs_positions, 3, 1, bezier_positions);
249  }
250 }
251 
252 static int to_bezier_size(const CurveType src_type,
253  const bool cyclic,
254  const KnotsMode knots_mode,
255  const int src_size)
256 {
257  switch (src_type) {
258  case CURVE_TYPE_NURBS: {
259  if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
260  return cyclic ? src_size : src_size - 2;
261  }
262  return (src_size + 1) / 3;
263  }
264  default:
265  return src_size;
266  }
267 }
268 
269 static int to_nurbs_size(const CurveType src_type, const int src_size)
270 {
271  switch (src_type) {
272  case CURVE_TYPE_BEZIER:
274  return src_size * 3;
275  default:
276  return src_size;
277  }
278 }
279 
281 {
282  threading::parallel_for(curves.curves_range(), 4096, [&](IndexRange range) {
283  for (const int i : range) {
284  sizes[i] = curves.points_for_curve(i).size();
285  }
286  });
287 }
288 
292 
294 };
295 
297  bke::MutableAttributeAccessor &dst_attributes,
298  GenericAttributes &attributes)
299 {
300  src_attributes.for_all(
301  [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
302  if (meta_data.domain != ATTR_DOMAIN_POINT) {
303  /* Curve domain attributes are all copied directly to the result in one step. */
304  return true;
305  }
306  if (src_attributes.is_builtin(id)) {
307  if (!(id.is_named() && ELEM(id, "tilt", "radius"))) {
308  return true;
309  }
310  }
311 
312  GVArray src_attribute = src_attributes.lookup(id, ATTR_DOMAIN_POINT);
313  BLI_assert(src_attribute);
314  attributes.src.append(src_attribute.get_internal_span());
315 
316  bke::GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_span(
317  id, ATTR_DOMAIN_POINT, meta_data.data_type);
318  attributes.dst.append(dst_attribute.span);
319  attributes.attributes.append(std::move(dst_attribute));
320 
321  return true;
322  });
323 }
324 
326  const IndexMask selection)
327 {
328  const VArray<int8_t> src_knot_modes = src_curves.nurbs_knots_modes();
329  const VArray<int8_t> src_types = src_curves.curve_types();
330  const VArray<bool> src_cyclic = src_curves.cyclic();
331  const Span<float3> src_positions = src_curves.positions();
332 
334  dst_curves.fill_curve_types(selection, CURVE_TYPE_BEZIER);
335 
336  MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
337  retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write());
338  threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
339  for (const int i : selection.slice(range)) {
340  dst_offsets[i] = to_bezier_size(
341  CurveType(src_types[i]), src_cyclic[i], KnotsMode(src_knot_modes[i]), dst_offsets[i]);
342  }
343  });
345  dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
346 
347  const bke::AttributeAccessor src_attributes = src_curves.attributes();
348  bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
349 
350  GenericAttributes attributes;
351  retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes);
352 
353  MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
354  MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
355  MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
356  MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
357  MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
358  MutableSpan<float> dst_weights = dst_curves.nurbs_weights_for_write();
359 
360  auto catmull_rom_to_bezier = [&](IndexMask selection) {
361  bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
362  bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
363  bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
364 
365  threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
366  for (const int i : selection.slice(range)) {
367  const IndexRange src_points = src_curves.points_for_curve(i);
368  const IndexRange dst_points = dst_curves.points_for_curve(i);
369  catmull_rom_to_bezier_handles(src_positions.slice(src_points),
370  src_cyclic[i],
371  dst_handles_l.slice(dst_points),
372  dst_handles_r.slice(dst_points));
373  }
374  });
375 
376  for (const int i : attributes.src.index_range()) {
378  src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
379  }
380  };
381 
382  auto poly_to_bezier = [&](IndexMask selection) {
383  bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
384  bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_l);
385  bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_r);
386  dst_curves.calculate_bezier_auto_handles();
387  for (const int i : attributes.src.index_range()) {
389  src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
390  }
391  };
392 
393  auto bezier_to_bezier = [&](IndexMask selection) {
394  const VArraySpan<int8_t> src_types_l = src_curves.handle_types_left();
395  const VArraySpan<int8_t> src_types_r = src_curves.handle_types_right();
396  const Span<float3> src_handles_l = src_curves.handle_positions_left();
397  const Span<float3> src_handles_r = src_curves.handle_positions_right();
398 
399  bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
400  bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_l, dst_handles_l);
401  bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_r, dst_handles_r);
402  bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_l, dst_types_l);
403  bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_r, dst_types_r);
404 
405  dst_curves.calculate_bezier_auto_handles();
406 
407  for (const int i : attributes.src.index_range()) {
409  src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
410  }
411  };
412 
413  auto nurbs_to_bezier = [&](IndexMask selection) {
414  bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
415  bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
416  bke::curves::fill_points<float>(dst_curves, selection, 0.0f, dst_weights);
417 
418  threading::parallel_for(selection.index_range(), 64, [&](IndexRange range) {
419  for (const int i : selection.slice(range)) {
420  const IndexRange src_points = src_curves.points_for_curve(i);
421  const IndexRange dst_points = dst_curves.points_for_curve(i);
422  const Span<float3> src_curve_positions = src_positions.slice(src_points);
423 
424  KnotsMode knots_mode = KnotsMode(src_knot_modes[i]);
425  Span<float3> nurbs_positions = src_curve_positions;
426  Vector<float3> nurbs_positions_vector;
427  if (src_cyclic[i] && is_nurbs_to_bezier_one_to_one(knots_mode)) {
428  /* For conversion treat this as periodic closed curve. Extend NURBS hull to first and
429  * second point which will act as a skeleton for placing Bezier handles. */
430  nurbs_positions_vector.extend(src_curve_positions);
431  nurbs_positions_vector.append(src_curve_positions[0]);
432  nurbs_positions_vector.append(src_curve_positions[1]);
433  nurbs_positions = nurbs_positions_vector;
434  knots_mode = NURBS_KNOT_MODE_NORMAL;
435  }
436 
437  const Vector<float3> handle_positions = create_nurbs_to_bezier_handles(nurbs_positions,
438  knots_mode);
439 
440  scale_input_assign(handle_positions.as_span(), 2, 0, dst_handles_l.slice(dst_points));
441  scale_input_assign(handle_positions.as_span(), 2, 1, dst_handles_r.slice(dst_points));
442 
443  create_nurbs_to_bezier_positions(
444  nurbs_positions, handle_positions, knots_mode, dst_positions.slice(dst_points));
445  }
446  });
447 
448  for (const int i_attribute : attributes.src.index_range()) {
449  threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
450  for (const int i : selection.slice(range)) {
451  const IndexRange src_points = src_curves.points_for_curve(i);
452  const IndexRange dst_points = dst_curves.points_for_curve(i);
453  nurbs_to_bezier_assign(attributes.src[i_attribute].slice(src_points),
454  KnotsMode(src_knot_modes[i]),
455  attributes.dst[i_attribute].slice(dst_points));
456  }
457  });
458  }
459  };
460 
461  bke::curves::foreach_curve_by_type(src_curves.curve_types(),
462  src_curves.curve_type_counts(),
463  selection,
464  catmull_rom_to_bezier,
465  poly_to_bezier,
466  bezier_to_bezier,
467  nurbs_to_bezier);
468 
469  const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
470  src_curves.curves_range());
471 
472  for (const int i : attributes.src.index_range()) {
474  src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
475  }
476 
477  for (bke::GSpanAttributeWriter &attribute : attributes.attributes) {
478  attribute.finish();
479  }
480 
481  return dst_curves;
482 }
483 
485  const IndexMask selection)
486 {
487  const VArray<int8_t> src_types = src_curves.curve_types();
488  const VArray<bool> src_cyclic = src_curves.cyclic();
489  const Span<float3> src_positions = src_curves.positions();
490 
492  dst_curves.fill_curve_types(selection, CURVE_TYPE_NURBS);
493 
494  MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
495  retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write());
496  threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
497  for (const int i : selection.slice(range)) {
498  dst_offsets[i] = to_nurbs_size(CurveType(src_types[i]), dst_offsets[i]);
499  }
500  });
502  dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
503 
504  const bke::AttributeAccessor src_attributes = src_curves.attributes();
505  bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
506 
507  GenericAttributes attributes;
508  retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes);
509 
510  MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
511 
512  auto fill_weights_if_necessary = [&](const IndexMask selection) {
513  if (!src_curves.nurbs_weights().is_empty()) {
514  bke::curves::fill_points(dst_curves, selection, 1.0f, dst_curves.nurbs_weights_for_write());
515  }
516  };
517 
518  auto catmull_rom_to_nurbs = [&](IndexMask selection) {
519  dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
520  dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
521  fill_weights_if_necessary(selection);
522 
523  threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
524  for (const int i : selection.slice(range)) {
525  const IndexRange src_points = src_curves.points_for_curve(i);
526  const IndexRange dst_points = dst_curves.points_for_curve(i);
527  catmull_rom_to_nurbs_positions(
528  src_positions.slice(src_points), src_cyclic[i], dst_positions.slice(dst_points));
529  }
530  });
531 
532  for (const int i_attribute : attributes.src.index_range()) {
533  threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
534  for (const int i : selection.slice(range)) {
535  const IndexRange src_points = src_curves.points_for_curve(i);
536  const IndexRange dst_points = dst_curves.points_for_curve(i);
537  bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points),
538  attributes.dst[i_attribute].slice(dst_points));
539  }
540  });
541  }
542  };
543 
544  auto poly_to_nurbs = [&](IndexMask selection) {
545  dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
546  bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
547  fill_weights_if_necessary(selection);
548 
549  /* Avoid using "Endpoint" knots modes for cyclic curves, since it adds a sharp point at the
550  * start/end. */
551  if (src_cyclic.is_single()) {
552  dst_curves.nurbs_knots_modes_for_write().fill_indices(
553  selection,
554  src_cyclic.get_internal_single() ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT);
555  }
556  else {
557  VArraySpan<bool> cyclic{src_cyclic};
558  MutableSpan<int8_t> knots_modes = dst_curves.nurbs_knots_modes_for_write();
559  threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
560  for (const int i : selection.slice(range)) {
561  knots_modes[i] = cyclic[i] ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT;
562  }
563  });
564  }
565 
566  for (const int i_attribute : attributes.src.index_range()) {
567  bke::curves::copy_point_data(src_curves,
568  dst_curves,
569  selection,
570  attributes.src[i_attribute],
571  attributes.dst[i_attribute]);
572  }
573  };
574 
575  auto bezier_to_nurbs = [&](IndexMask selection) {
576  const Span<float3> src_handles_l = src_curves.handle_positions_left();
577  const Span<float3> src_handles_r = src_curves.handle_positions_right();
578 
579  dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
580  dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
581  fill_weights_if_necessary(selection);
582 
583  threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
584  for (const int i : selection.slice(range)) {
585  const IndexRange src_points = src_curves.points_for_curve(i);
586  const IndexRange dst_points = dst_curves.points_for_curve(i);
587  bezier_positions_to_nurbs(src_positions.slice(src_points),
588  src_handles_l.slice(src_points),
589  src_handles_r.slice(src_points),
590  dst_positions.slice(dst_points));
591  }
592  });
593 
594  for (const int i_attribute : attributes.src.index_range()) {
595  threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
596  for (const int i : selection.slice(range)) {
597  const IndexRange src_points = src_curves.points_for_curve(i);
598  const IndexRange dst_points = dst_curves.points_for_curve(i);
599  bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points),
600  attributes.dst[i_attribute].slice(dst_points));
601  }
602  });
603  }
604  };
605 
606  auto nurbs_to_nurbs = [&](IndexMask selection) {
607  bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
608 
609  if (!src_curves.nurbs_weights().is_empty()) {
610  bke::curves::copy_point_data(src_curves,
611  dst_curves,
612  selection,
613  src_curves.nurbs_weights(),
614  dst_curves.nurbs_weights_for_write());
615  }
616 
617  for (const int i_attribute : attributes.src.index_range()) {
618  bke::curves::copy_point_data(src_curves,
619  dst_curves,
620  selection,
621  attributes.src[i_attribute],
622  attributes.dst[i_attribute]);
623  }
624  };
625 
626  bke::curves::foreach_curve_by_type(src_curves.curve_types(),
627  src_curves.curve_type_counts(),
628  selection,
629  catmull_rom_to_nurbs,
630  poly_to_nurbs,
631  bezier_to_nurbs,
632  nurbs_to_nurbs);
633 
634  const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
635  src_curves.curves_range());
636 
637  for (const int i : attributes.src.index_range()) {
639  src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
640  }
641 
642  for (bke::GSpanAttributeWriter &attribute : attributes.attributes) {
643  attribute.finish();
644  }
645 
646  return dst_curves;
647 }
648 
650  const IndexMask selection,
651  const CurveType dst_type)
652 {
653  bke::CurvesGeometry dst_curves(src_curves);
654  dst_curves.fill_curve_types(selection, dst_type);
656  return dst_curves;
657 }
658 
660  const IndexMask selection,
661  const CurveType dst_type)
662 {
663  switch (dst_type) {
665  case CURVE_TYPE_POLY:
666  return convert_curves_trivial(src_curves, selection, dst_type);
667  case CURVE_TYPE_BEZIER:
668  return convert_curves_to_bezier(src_curves, selection);
669  case CURVE_TYPE_NURBS:
670  return convert_curves_to_nurbs(src_curves, selection);
671  }
673  return {};
674 }
675 
677  const CurveType dst_type,
678  FunctionRef<bke::CurvesGeometry &()> get_writable_curves_fn)
679 {
680  if (conversion_can_change_point_num(dst_type)) {
681  return false;
682  }
683  bke::CurvesGeometry &curves = get_writable_curves_fn();
684  curves.fill_curve_types(selection, dst_type);
685  curves.remove_attributes_based_on_types();
686  return true;
687 }
688 
689 } // namespace blender::geometry
typedef float(TangentPoint)[2]
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
Low-level operations for curves.
Low-level operations for curves.
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define ELEM(...)
CurveType
@ CURVE_TYPE_BEZIER
@ CURVE_TYPE_NURBS
@ CURVE_TYPE_POLY
@ CURVE_TYPE_CATMULL_ROM
@ BEZIER_HANDLE_ALIGN
@ BEZIER_HANDLE_VECTOR
KnotsMode
@ NURBS_KNOT_MODE_ENDPOINT
@ NURBS_KNOT_MODE_NORMAL
@ NURBS_KNOT_MODE_BEZIER
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
IndexRange index_range() const
constexpr IndexRange drop_back(int64_t n) const
constexpr IndexRange drop_front(int64_t n) const
constexpr T & last(const int64_t n=0) const
Definition: BLI_span.hh:680
constexpr IndexRange index_range() const
Definition: BLI_span.hh:661
constexpr T & first() const
Definition: BLI_span.hh:670
constexpr const T & first() const
Definition: BLI_span.hh:303
constexpr const T & last(const int64_t n=0) const
Definition: BLI_span.hh:313
constexpr int64_t size() const
Definition: BLI_span.hh:240
constexpr IndexRange index_range() const
Definition: BLI_span.hh:401
void append(const T &value)
Definition: BLI_vector.hh:433
bool is_builtin(const AttributeIDRef &attribute_id) const
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
bool for_all(const AttributeForeachCallback fn) const
VArray< int8_t > nurbs_knots_modes() const
Span< float3 > positions() const
void fill_curve_types(CurveType type)
MutableSpan< int > offsets_for_write()
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
GSpanAttributeWriter lookup_or_add_for_write_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefault())
SyclQueue void void * src
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
void accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
Definition: curves_utils.cc:28
int segments_num(const int points_num, const bool cyclic)
Definition: BKE_curves.hh:462
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
Definition: curves_utils.cc:87
void fill_points(const CurvesGeometry &curves, IndexMask curve_selection, GPointer value, GMutableSpan dst)
Definition: curves_utils.cc:72
void copy_point_data(const CurvesGeometry &src_curves, const CurvesGeometry &dst_curves, Span< IndexRange > curve_ranges, GSpan src, GMutableSpan dst)
Definition: curves_utils.cc:40
void foreach_curve_by_type(const VArray< int8_t > &types, const std::array< int, CURVE_TYPES_NUM > &type_counts, IndexMask selection, FunctionRef< void(IndexMask)> catmull_rom_fn, FunctionRef< void(IndexMask)> poly_fn, FunctionRef< void(IndexMask)> bezier_fn, FunctionRef< void(IndexMask)> nurbs_fn)
static Vector< float3 > create_nurbs_to_bezier_handles(const Span< float3 > nurbs_positions, const KnotsMode knots_mode)
static bke::CurvesGeometry convert_curves_to_nurbs(const bke::CurvesGeometry &src_curves, const IndexMask selection)
static void retrieve_generic_point_attributes(const bke::AttributeAccessor &src_attributes, bke::MutableAttributeAccessor &dst_attributes, GenericAttributes &attributes)
static bool is_nurbs_to_bezier_one_to_one(const KnotsMode knots_mode)
static bke::CurvesGeometry convert_curves_trivial(const bke::CurvesGeometry &src_curves, const IndexMask selection, const CurveType dst_type)
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 bool conversion_can_change_point_num(const CurveType dst_type)
bke::CurvesGeometry convert_curves(const bke::CurvesGeometry &src_curves, IndexMask selection, CurveType dst_type)
static void bezier_generic_to_nurbs(const Span< T > src, MutableSpan< T > dst)
static void catmull_rom_to_nurbs_positions(const Span< float3 > src_positions, const bool cyclic, MutableSpan< float3 > dst_positions)
bool try_curves_conversion_in_place(IndexMask selection, CurveType dst_type, FunctionRef< bke::CurvesGeometry &()> get_writable_curves_fn)
static void retrieve_curve_sizes(const bke::CurvesGeometry &curves, MutableSpan< int > sizes)
static void scale_input_assign(const Span< T > src, const int scale, const int offset, MutableSpan< T > dst)
static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &src_curves, const IndexMask selection)
static int to_bezier_size(const CurveType src_type, const bool cyclic, const KnotsMode knots_mode, const int src_size)
T abs(const T &a)
T interpolate(const T &a, const T &b, const FactorT &t)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
#define min(a, b)
Definition: sort.c:35
Vector< bke::GSpanAttributeWriter > attributes