Blender  V3.3
node_geo_curve_trim.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BKE_curves.hh"
4 #include "BKE_spline.hh"
5 #include "BLI_task.hh"
6 
7 #include "UI_interface.h"
8 #include "UI_resources.h"
9 
11 
12 #include "node_geometry_util.hh"
13 
15 
17 
19 
21 {
22  b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
23  b.add_input<decl::Float>(N_("Start"))
24  .min(0.0f)
25  .max(1.0f)
26  .subtype(PROP_FACTOR)
27  .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; })
28  .supports_field();
29  b.add_input<decl::Float>(N_("End"))
30  .min(0.0f)
31  .max(1.0f)
32  .default_value(1.0f)
33  .subtype(PROP_FACTOR)
34  .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; })
35  .supports_field();
36  b.add_input<decl::Float>(N_("Start"), "Start_001")
37  .min(0.0f)
38  .subtype(PROP_DISTANCE)
39  .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; })
40  .supports_field();
41  b.add_input<decl::Float>(N_("End"), "End_001")
42  .min(0.0f)
43  .default_value(1.0f)
44  .subtype(PROP_DISTANCE)
45  .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; })
46  .supports_field();
47  b.add_output<decl::Geometry>(N_("Curve"));
48 }
49 
50 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
51 {
52  uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
53 }
54 
56 {
57  NodeGeometryCurveTrim *data = MEM_cnew<NodeGeometryCurveTrim>(__func__);
58 
60  node->storage = data;
61 }
62 
64 {
65  const NodeGeometryCurveTrim &storage = node_storage(*node);
67 
68  bNodeSocket *start_fac = ((bNodeSocket *)node->inputs.first)->next;
69  bNodeSocket *end_fac = start_fac->next;
70  bNodeSocket *start_len = end_fac->next;
71  bNodeSocket *end_len = start_len->next;
72 
77 }
78 
80  public:
84  {
85  bNode &node = params.add_node("GeometryNodeTrimCurve");
86  node_storage(node).mode = mode;
87  params.update_and_connect_available_socket(node, socket_name);
88  }
89 };
90 
92 {
93  const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
94 
96  search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
97 
98  if (params.in_out() == SOCK_IN) {
99  if (params.node_tree().typeinfo->validate_link(
100  static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
101  params.add_item(IFACE_("Start (Factor)"),
103  params.add_item(IFACE_("End (Factor)"), SocketSearchOp{"End", GEO_NODE_CURVE_SAMPLE_FACTOR});
104  params.add_item(IFACE_("Start (Length)"),
106  params.add_item(IFACE_("End (Length)"), SocketSearchOp{"End", GEO_NODE_CURVE_SAMPLE_LENGTH});
107  }
108  }
109 }
110 
111 struct TrimLocation {
112  /* Control point index at the start side of the trim location. */
114  /* Control point index at the end of the trim location's segment. */
116  /* The factor between the left and right indices. */
117  float factor;
118 };
119 
120 template<typename T>
121 static void shift_slice_to_start(MutableSpan<T> data, const int start_index, const int num)
122 {
123  BLI_assert(start_index + num - 1 <= data.size());
124  memmove(data.data(), &data[start_index], sizeof(T) * num);
125 }
126 
127 /* Shift slice to start of span and modifies start and end data. */
128 template<typename T>
129 static void linear_trim_data(const TrimLocation &start,
130  const TrimLocation &end,
132 {
133  const int num = end.right_index - start.left_index + 1;
134 
135  if (start.left_index > 0) {
136  shift_slice_to_start<T>(data, start.left_index, num);
137  }
138 
139  const T start_data = mix2<T>(start.factor, data.first(), data[1]);
140  const T end_data = mix2<T>(end.factor, data[num - 2], data[num - 1]);
141 
142  data.first() = start_data;
143  data[num - 1] = end_data;
144 }
145 
150 template<typename T>
151 static void linear_trim_to_output_data(const TrimLocation &start,
152  const TrimLocation &end,
153  Span<T> src,
154  MutableSpan<T> dst)
155 {
156  const int num = end.right_index - start.left_index + 1;
157 
158  const T start_data = mix2<T>(start.factor, src[start.left_index], src[start.right_index]);
159  const T end_data = mix2<T>(end.factor, src[end.left_index], src[end.right_index]);
160 
161  dst.copy_from(src.slice(start.left_index, num));
162  dst.first() = start_data;
163  dst.last() = end_data;
164 }
165 
166 /* Look up the control points to the left and right of factor, and get the factor between them. */
168  const BezierSpline &spline)
169 {
170  Span<int> offsets = spline.control_point_offsets();
171 
172  const int *offset = std::lower_bound(offsets.begin(), offsets.end(), lookup.evaluated_index);
173  const int index = offset - offsets.begin();
174 
175  const int left = offsets[index] > lookup.evaluated_index ? index - 1 : index;
176  const int right = left == (spline.size() - 1) ? 0 : left + 1;
177 
178  const float offset_in_segment = lookup.evaluated_index + lookup.factor - offsets[left];
179  const int segment_eval_num = offsets[left + 1] - offsets[left];
180  const float factor = std::clamp(offset_in_segment / segment_eval_num, 0.0f, 1.0f);
181 
182  return {left, right, factor};
183 }
184 
185 static void trim_poly_spline(Spline &spline,
186  const Spline::LookupResult &start_lookup,
187  const Spline::LookupResult &end_lookup)
188 {
189  /* Poly splines have a 1 to 1 mapping between control points and evaluated points. */
190  const TrimLocation start = {
191  start_lookup.evaluated_index, start_lookup.next_evaluated_index, start_lookup.factor};
192  const TrimLocation end = {
193  end_lookup.evaluated_index, end_lookup.next_evaluated_index, end_lookup.factor};
194 
195  const int num = end.right_index - start.left_index + 1;
196 
197  linear_trim_data<float3>(start, end, spline.positions());
198  linear_trim_data<float>(start, end, spline.radii());
199  linear_trim_data<float>(start, end, spline.tilts());
200 
202  [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
203  std::optional<GMutableSpan> src = spline.attributes.get_for_write(attribute_id);
204  BLI_assert(src);
205  attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
206  using T = decltype(dummy);
207  linear_trim_data<T>(start, end, src->typed<T>());
208  });
209  return true;
210  },
212 
213  spline.resize(num);
214 }
215 
219 static PolySpline trim_nurbs_spline(const Spline &spline,
220  const Spline::LookupResult &start_lookup,
221  const Spline::LookupResult &end_lookup)
222 {
223  /* Since this outputs a poly spline, the evaluated indices are the control point indices. */
224  const TrimLocation start = {
225  start_lookup.evaluated_index, start_lookup.next_evaluated_index, start_lookup.factor};
226  const TrimLocation end = {
227  end_lookup.evaluated_index, end_lookup.next_evaluated_index, end_lookup.factor};
228 
229  const int num = end.right_index - start.left_index + 1;
230 
231  /* Create poly spline and copy trimmed data to it. */
232  PolySpline new_spline;
233  new_spline.resize(num);
234 
235  /* Copy generic attribute data. */
237  [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
238  std::optional<GSpan> src = spline.attributes.get_for_read(attribute_id);
239  BLI_assert(src);
240  if (!new_spline.attributes.create(attribute_id, meta_data.data_type)) {
242  return false;
243  }
244  std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(attribute_id);
245  BLI_assert(dst);
246 
247  attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
248  using T = decltype(dummy);
249  VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>());
250  linear_trim_to_output_data<T>(
251  start, end, eval_data.get_internal_span(), dst->typed<T>());
252  });
253  return true;
254  },
256 
257  linear_trim_to_output_data<float3>(
258  start, end, spline.evaluated_positions(), new_spline.positions());
259 
260  VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii());
261  linear_trim_to_output_data<float>(
262  start, end, evaluated_radii.get_internal_span(), new_spline.radii());
263 
264  VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts());
265  linear_trim_to_output_data<float>(
266  start, end, evaluated_tilts.get_internal_span(), new_spline.tilts());
267 
268  return new_spline;
269 }
270 
275 static void trim_bezier_spline(Spline &spline,
276  const Spline::LookupResult &start_lookup,
277  const Spline::LookupResult &end_lookup)
278 {
279  BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline);
280 
281  const TrimLocation start = lookup_control_point_position(start_lookup, bezier_spline);
282  TrimLocation end = lookup_control_point_position(end_lookup, bezier_spline);
283 
284  const Span<int> control_offsets = bezier_spline.control_point_offsets();
285 
286  /* The number of control points in the resulting spline. */
287  const int num = end.right_index - start.left_index + 1;
288 
289  /* Trim the spline attributes. Done before end.factor recalculation as it needs
290  * the original end.factor value. */
291  linear_trim_data<float>(start, end, bezier_spline.radii());
292  linear_trim_data<float>(start, end, bezier_spline.tilts());
294  [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
295  std::optional<GMutableSpan> src = spline.attributes.get_for_write(attribute_id);
296  BLI_assert(src);
297  attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
298  using T = decltype(dummy);
299  linear_trim_data<T>(start, end, src->typed<T>());
300  });
301  return true;
302  },
304 
305  /* Recalculate end.factor if the `num` is two, because the adjustment in the
306  * position of the control point of the spline to the left of the new end point will change the
307  * factor between them. */
308  if (num == 2) {
309  if (start_lookup.factor == 1.0f) {
310  end.factor = 0.0f;
311  }
312  else {
313  end.factor = (end_lookup.evaluated_index + end_lookup.factor -
314  (start_lookup.evaluated_index + start_lookup.factor)) /
315  (control_offsets[end.right_index] -
316  (start_lookup.evaluated_index + start_lookup.factor));
317  end.factor = std::clamp(end.factor, 0.0f, 1.0f);
318  }
319  }
320 
321  BezierSpline::InsertResult start_point = bezier_spline.calculate_segment_insertion(
322  start.left_index, start.right_index, start.factor);
323 
324  /* Update the start control point parameters so they are used calculating the new end point. */
325  bezier_spline.positions()[start.left_index] = start_point.position;
326  bezier_spline.handle_positions_right()[start.left_index] = start_point.right_handle;
327  bezier_spline.handle_positions_left()[start.right_index] = start_point.handle_next;
328 
329  const BezierSpline::InsertResult end_point = bezier_spline.calculate_segment_insertion(
330  end.left_index, end.right_index, end.factor);
331 
332  /* If `num` is two, then the start point right handle needs to change to reflect the end point
333  * previous handle update. */
334  if (num == 2) {
335  start_point.right_handle = end_point.handle_prev;
336  }
337 
338  /* Shift control point position data to start at beginning of array. */
339  if (start.left_index > 0) {
340  shift_slice_to_start(bezier_spline.positions(), start.left_index, num);
341  shift_slice_to_start(bezier_spline.handle_positions_left(), start.left_index, num);
342  shift_slice_to_start(bezier_spline.handle_positions_right(), start.left_index, num);
343  }
344 
345  bezier_spline.positions().first() = start_point.position;
346  bezier_spline.positions()[num - 1] = end_point.position;
347 
348  bezier_spline.handle_positions_left().first() = start_point.left_handle;
349  bezier_spline.handle_positions_left()[num - 1] = end_point.left_handle;
350 
351  bezier_spline.handle_positions_right().first() = start_point.right_handle;
352  bezier_spline.handle_positions_right()[num - 1] = end_point.right_handle;
353 
354  /* If there is at least one control point between the endpoints, update the control
355  * point handle to the right of the start point and to the left of the end point. */
356  if (num > 2) {
357  bezier_spline.handle_positions_left()[start.right_index - start.left_index] =
358  start_point.handle_next;
359  bezier_spline.handle_positions_right()[end.left_index - start.left_index] =
360  end_point.handle_prev;
361  }
362 
363  bezier_spline.resize(num);
364 }
365 
366 static void trim_spline(SplinePtr &spline,
367  const Spline::LookupResult start,
368  const Spline::LookupResult end)
369 {
370  switch (spline->type()) {
371  case CURVE_TYPE_BEZIER:
372  trim_bezier_spline(*spline, start, end);
373  break;
374  case CURVE_TYPE_POLY:
375  trim_poly_spline(*spline, start, end);
376  break;
377  case CURVE_TYPE_NURBS:
378  spline = std::make_unique<PolySpline>(trim_nurbs_spline(*spline, start, end));
379  break;
382  spline = {};
383  }
384  spline->mark_cache_invalid();
385 }
386 
387 template<typename T>
389 {
390  data.first() = mix2<T>(trim.factor, data[trim.left_index], data[trim.right_index]);
391 }
392 template<typename T>
394 {
395  dst.first() = mix2<T>(trim.factor, src[trim.left_index], src[trim.right_index]);
396 }
397 
399 {
400  BezierSpline &bezier = static_cast<BezierSpline &>(spline);
401 
403 
405  trim.left_index, trim.right_index, trim.factor);
406  bezier.positions().first() = new_point.position;
407  bezier.handle_types_left().first() = BEZIER_HANDLE_FREE;
408  bezier.handle_types_right().first() = BEZIER_HANDLE_FREE;
409  bezier.handle_positions_left().first() = new_point.left_handle;
410  bezier.handle_positions_right().first() = new_point.right_handle;
411 
412  to_single_point_data<float>(trim, bezier.radii());
413  to_single_point_data<float>(trim, bezier.tilts());
415  [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
416  std::optional<GMutableSpan> data = spline.attributes.get_for_write(attribute_id);
417  attribute_math::convert_to_static_type(data->type(), [&](auto dummy) {
418  using T = decltype(dummy);
419  to_single_point_data<T>(trim, data->typed<T>());
420  });
421  return true;
422  },
424  spline.resize(1);
425 }
426 
428 {
429  const TrimLocation trim{lookup.evaluated_index, lookup.next_evaluated_index, lookup.factor};
430 
431  to_single_point_data<float3>(trim, spline.positions());
432  to_single_point_data<float>(trim, spline.radii());
433  to_single_point_data<float>(trim, spline.tilts());
435  [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
436  std::optional<GMutableSpan> data = spline.attributes.get_for_write(attribute_id);
437  attribute_math::convert_to_static_type(data->type(), [&](auto dummy) {
438  using T = decltype(dummy);
439  to_single_point_data<T>(trim, data->typed<T>());
440  });
441  return true;
442  },
444  spline.resize(1);
445 }
446 
448 {
449  /* Since this outputs a poly spline, the evaluated indices are the control point indices. */
450  const TrimLocation trim{lookup.evaluated_index, lookup.next_evaluated_index, lookup.factor};
451 
452  /* Create poly spline and copy trimmed data to it. */
453  PolySpline new_spline;
454  new_spline.resize(1);
455 
457  [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
458  new_spline.attributes.create(attribute_id, meta_data.data_type);
459  std::optional<GSpan> src = spline.attributes.get_for_read(attribute_id);
460  std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(attribute_id);
461  attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
462  using T = decltype(dummy);
463  VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>());
464  to_single_point_data<T>(trim, eval_data.get_internal_span(), dst->typed<T>());
465  });
466  return true;
467  },
469 
470  to_single_point_data<float3>(trim, spline.evaluated_positions(), new_spline.positions());
471 
472  VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii());
473  to_single_point_data<float>(trim, evaluated_radii.get_internal_span(), new_spline.radii());
474 
475  VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts());
476  to_single_point_data<float>(trim, evaluated_tilts.get_internal_span(), new_spline.tilts());
477 
478  return new_spline;
479 }
480 
482 {
483  switch (spline->type()) {
484  case CURVE_TYPE_BEZIER:
485  to_single_point_bezier(*spline, lookup);
486  break;
487  case CURVE_TYPE_POLY:
488  to_single_point_poly(*spline, lookup);
489  break;
490  case CURVE_TYPE_NURBS:
491  spline = std::make_unique<PolySpline>(to_single_point_nurbs(*spline, lookup));
492  break;
495  spline = {};
496  }
497 }
498 
499 static void geometry_set_curve_trim(GeometrySet &geometry_set,
500  const GeometryNodeCurveSampleMode mode,
501  Field<float> &start_field,
502  Field<float> &end_field)
503 {
504  if (!geometry_set.has_curves()) {
505  return;
506  }
507 
510  const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
511 
512  fn::FieldEvaluator evaluator{field_context, domain_size};
513  evaluator.add(start_field);
514  evaluator.add(end_field);
515  evaluator.evaluate();
516  const VArray<float> starts = evaluator.get_evaluated<float>(0);
517  const VArray<float> ends = evaluator.get_evaluated<float>(1);
518 
519  const Curves &src_curves_id = *geometry_set.get_curves_for_read();
520  std::unique_ptr<CurveEval> curve = curves_to_curve_eval(src_curves_id);
521  MutableSpan<SplinePtr> splines = curve->splines();
522 
523  threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
524  for (const int i : range) {
525  SplinePtr &spline = splines[i];
526 
527  /* Currently trimming cyclic splines is not supported. It could be in the future though. */
528  if (spline->is_cyclic()) {
529  continue;
530  }
531 
532  if (spline->evaluated_edges_num() == 0) {
533  continue;
534  }
535 
536  const float length = spline->length();
537  if (length == 0.0f) {
538  continue;
539  }
540 
541  const float start = starts[i];
542  const float end = ends[i];
543 
544  /* When the start and end samples are reversed, instead of implicitly reversing the spline
545  * or switching the parameters, create a single point spline with the end sample point. */
546  if (end <= start) {
547  if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
548  to_single_point_spline(spline,
549  spline->lookup_evaluated_length(std::clamp(start, 0.0f, length)));
550  }
551  else {
552  to_single_point_spline(spline,
553  spline->lookup_evaluated_factor(std::clamp(start, 0.0f, 1.0f)));
554  }
555  continue;
556  }
557 
558  if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
559  trim_spline(spline,
560  spline->lookup_evaluated_length(std::clamp(start, 0.0f, length)),
561  spline->lookup_evaluated_length(std::clamp(end, 0.0f, length)));
562  }
563  else {
564  trim_spline(spline,
565  spline->lookup_evaluated_factor(std::clamp(start, 0.0f, 1.0f)),
566  spline->lookup_evaluated_factor(std::clamp(end, 0.0f, 1.0f)));
567  }
568  }
569  });
570 
571  Curves *dst_curves_id = curve_eval_to_curves(*curve);
572  bke::curves_copy_parameters(src_curves_id, *dst_curves_id);
573  geometry_set.replace_curves(dst_curves_id);
574 }
575 
577 {
578  const NodeGeometryCurveTrim &storage = node_storage(params.node());
580 
581  GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
583 
584  if (mode == GEO_NODE_CURVE_SAMPLE_FACTOR) {
585  Field<float> start_field = params.extract_input<Field<float>>("Start");
586  Field<float> end_field = params.extract_input<Field<float>>("End");
587  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
588  geometry_set_curve_trim(geometry_set, mode, start_field, end_field);
589  });
590  }
591  else if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
592  Field<float> start_field = params.extract_input<Field<float>>("Start_001");
593  Field<float> end_field = params.extract_input<Field<float>>("End_001");
594  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
595  geometry_set_curve_trim(geometry_set, mode, start_field, end_field);
596  });
597  }
598 
599  params.set_output("Curve", std::move(geometry_set));
600 }
601 
602 } // namespace blender::nodes::node_geo_curve_trim_cc
603 
605 {
606  namespace file_ns = blender::nodes::node_geo_curve_trim_cc;
607 
608  static bNodeType ntype;
614  &ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage);
618  nodeRegisterType(&ntype);
619 }
@ ATTR_DOMAIN_CURVE
Definition: BKE_attribute.h:31
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
Low-level operations for curves.
@ GEO_COMPONENT_TYPE_CURVE
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4443
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available)
Definition: node.cc:3664
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
#define GEO_NODE_TRIM_CURVE
Definition: BKE_node.h:1416
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
Definition: node.cc:4426
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
std::unique_ptr< Spline > SplinePtr
Definition: BKE_spline.hh:26
std::unique_ptr< CurveEval > curves_to_curve_eval(const Curves &curves)
Definition: curve_eval.cc:373
Curves * curve_eval_to_curves(const CurveEval &curve_eval)
Definition: curve_eval.cc:463
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define UNUSED(x)
#define IFACE_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
@ CURVE_TYPE_BEZIER
@ CURVE_TYPE_NURBS
@ CURVE_TYPE_POLY
@ CURVE_TYPE_CATMULL_ROM
@ BEZIER_HANDLE_FREE
GeometryNodeCurveSampleMode
@ GEO_NODE_CURVE_SAMPLE_FACTOR
@ GEO_NODE_CURVE_SAMPLE_LENGTH
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_FLOAT
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble right
@ PROP_DISTANCE
Definition: RNA_types.h:149
@ PROP_FACTOR
Definition: RNA_types.h:144
@ UI_ITEM_R_EXPAND
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
int size() const final
blender::MutableSpan< float > tilts() final
blender::Span< blender::float3 > handle_positions_right() const
void resize(int size) final
blender::Span< blender::float3 > handle_positions_left() const
InsertResult calculate_segment_insertion(int index, int next_index, float parameter)
blender::Span< int8_t > handle_types_left() const
blender::Span< int > control_point_offsets() const
blender::Span< int8_t > handle_types_right() const
blender::MutableSpan< blender::float3 > positions() final
blender::MutableSpan< float > radii() final
static void remember_deformed_curve_positions_if_necessary(GeometrySet &geometry)
blender::MutableSpan< float > tilts() final
Definition: spline_poly.cc:59
blender::MutableSpan< float > radii() final
Definition: spline_poly.cc:51
blender::MutableSpan< blender::float3 > positions() final
Definition: spline_poly.cc:43
void resize(int size) final
Definition: spline_poly.cc:34
virtual blender::MutableSpan< blender::float3 > positions()=0
virtual blender::MutableSpan< float > tilts()=0
virtual void resize(int size)=0
blender::bke::CustomDataAttributes attributes
Definition: BKE_spline.hh:56
virtual blender::MutableSpan< float > radii()=0
virtual blender::GVArray interpolate_to_evaluated(const blender::GVArray &src) const =0
virtual blender::Span< blender::float3 > evaluated_positions() const =0
constexpr T & last(const int64_t n=0) const
Definition: BLI_span.hh:680
constexpr void copy_from(Span< T > values)
Definition: BLI_span.hh:707
constexpr T & first() const
Definition: BLI_span.hh:670
constexpr const T * end() const
Definition: BLI_span.hh:212
constexpr const T * begin() const
Definition: BLI_span.hh:208
Span< T > get_internal_span() const
std::optional< blender::GSpan > get_for_read(const AttributeIDRef &attribute_id) const
bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type)
std::optional< blender::GMutableSpan > get_for_write(const AttributeIDRef &attribute_id)
bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const
int add(GField field, GVArray *varray_ptr)
Definition: field.cc:731
Span< SocketDeclarationPtr > outputs() const
Span< SocketDeclarationPtr > inputs() const
OperationNode * node
Curve curve
SyclQueue void void * src
void * tree
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
ListBase splines
Definition: mask.c:265
static ulong * next
static int left
#define T
static char * trim(char *str)
Definition: msgfmt.c:60
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
T mix2(float factor, const T &a, const T &b)
GAttributeReader lookup(const void *owner, const AttributeIDRef &attribute_id)
void curves_copy_parameters(const Curves &src, Curves &dst)
Definition: curves.cc:391
T clamp(const T &a, const T &min, const T &max)
static PolySpline to_single_point_nurbs(const Spline &spline, const Spline::LookupResult &lookup)
static void trim_poly_spline(Spline &spline, const Spline::LookupResult &start_lookup, const Spline::LookupResult &end_lookup)
static void linear_trim_data(const TrimLocation &start, const TrimLocation &end, MutableSpan< T > data)
static void geometry_set_curve_trim(GeometrySet &geometry_set, const GeometryNodeCurveSampleMode mode, Field< float > &start_field, Field< float > &end_field)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void shift_slice_to_start(MutableSpan< T > data, const int start_index, const int num)
static PolySpline trim_nurbs_spline(const Spline &spline, const Spline::LookupResult &start_lookup, const Spline::LookupResult &end_lookup)
static TrimLocation lookup_control_point_position(const Spline::LookupResult &lookup, const BezierSpline &spline)
static void node_declare(NodeDeclarationBuilder &b)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_update(bNodeTree *ntree, bNode *node)
static void trim_bezier_spline(Spline &spline, const Spline::LookupResult &start_lookup, const Spline::LookupResult &end_lookup)
static void to_single_point_poly(Spline &spline, const Spline::LookupResult &lookup)
static void trim_spline(SplinePtr &spline, const Spline::LookupResult start, const Spline::LookupResult end)
static void linear_trim_to_output_data(const TrimLocation &start, const TrimLocation &end, Span< T > src, MutableSpan< T > dst)
static void to_single_point_spline(SplinePtr &spline, const Spline::LookupResult &lookup)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void to_single_point_bezier(Spline &spline, const Spline::LookupResult &lookup)
static void to_single_point_data(const TrimLocation &trim, MutableSpan< T > data)
static void node_geo_exec(GeoNodeExecParams params)
void search_link_ops_for_declarations(GatherLinkSearchOpParams &params, Span< SocketDeclarationPtr > declarations)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
Definition: node.cc:1082
void register_node_type_geo_curve_trim()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:55
void node_free_standard_storage(bNode *node)
Definition: node_util.c:43
#define min(a, b)
Definition: sort.c:35
blender::float3 right_handle
Definition: BKE_spline.hh:398
blender::float3 position
Definition: BKE_spline.hh:397
blender::float3 left_handle
Definition: BKE_spline.hh:396
blender::float3 handle_prev
Definition: BKE_spline.hh:395
blender::float3 handle_next
Definition: BKE_spline.hh:399
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
const Curves * get_curves_for_read() const
bool has_curves() const
struct bNodeSocket * next
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition: BKE_node.h:335
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480