Blender  V3.3
node_geo_curve_spline_parameter.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_task.hh"
4 
5 #include "BKE_curves.hh"
6 
7 #include "node_geometry_util.hh"
8 
10 
12 {
13  b.add_output<decl::Float>(N_("Factor"))
14  .field_source()
15  .description(
16  N_("For points, the portion of the spline's total length at the control point. For "
17  "Splines, the factor of that spline within the entire curve"));
18  b.add_output<decl::Float>(N_("Length"))
19  .field_source()
20  .description(
21  N_("For points, the distance along the control point's spline, For splines, the "
22  "distance along the entire curve"));
23  b.add_output<decl::Int>(N_("Index"))
24  .field_source()
25  .description(N_("Each control point's index on its spline"));
26 }
27 
34 {
35  curves.ensure_evaluated_lengths();
36 
37  Array<float> lengths(curves.curves_num());
38  VArray<bool> cyclic = curves.cyclic();
39  float length = 0.0f;
40  for (const int i : curves.curves_range()) {
41  lengths[i] = length;
42  length += curves.evaluated_length_total_for_curve(i, cyclic[i]);
43  }
44 
45  return lengths;
46 }
47 
59 {
60  curves.ensure_evaluated_lengths();
61  const VArray<int8_t> types = curves.curve_types();
62  const VArray<int> resolutions = curves.resolution();
63  const VArray<bool> cyclic = curves.cyclic();
64 
65  Array<float> result(curves.points_num());
66 
67  threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) {
68  for (const int i_curve : range) {
69  const IndexRange points = curves.points_for_curve(i_curve);
70  const Span<float> evaluated_lengths = curves.evaluated_lengths_for_curve(i_curve,
71  cyclic[i_curve]);
72  MutableSpan<float> lengths = result.as_mutable_span().slice(points);
73  lengths.first() = 0.0f;
74  switch (types[i_curve]) {
75  case CURVE_TYPE_CATMULL_ROM: {
76  const int resolution = resolutions[i_curve];
77  for (const int i : IndexRange(points.size()).drop_back(1)) {
78  lengths[i + 1] = evaluated_lengths[resolution * (i + 1) - 1];
79  }
80  break;
81  }
82  case CURVE_TYPE_POLY:
83  lengths.drop_front(1).copy_from(evaluated_lengths.take_front(lengths.size() - 1));
84  break;
85  case CURVE_TYPE_BEZIER: {
86  const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve);
87  for (const int i : IndexRange(points.size()).drop_back(1)) {
88  lengths[i + 1] = evaluated_lengths[offsets[i] - 1];
89  }
90  break;
91  }
92  case CURVE_TYPE_NURBS: {
93  const Span<float3> positions = curves.positions().slice(points);
94  float length = 0.0f;
95  for (const int i : positions.index_range().drop_back(1)) {
96  lengths[i] = length;
97  length += math::distance(positions[i], positions[i + 1]);
98  }
99  lengths.last() = length;
100  break;
101  }
102  }
103  }
104  });
105  return result;
106 }
107 
109  const IndexMask UNUSED(mask),
110  const eAttrDomain domain)
111 {
112  VArray<bool> cyclic = curves.cyclic();
113 
114  if (domain == ATTR_DOMAIN_POINT) {
116  MutableSpan<float> lengths = result.as_mutable_span();
117 
118  threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange range) {
119  for (const int i_curve : range) {
120  const float total_length = curves.evaluated_length_total_for_curve(i_curve,
121  cyclic[i_curve]);
122  MutableSpan<float> curve_lengths = lengths.slice(curves.points_for_curve(i_curve));
123  if (total_length > 0.0f) {
124  const float factor = 1.0f / total_length;
125  for (float &value : curve_lengths) {
126  value *= factor;
127  }
128  }
129  else if (curve_lengths.size() == 1) {
130  /* The curve is a single point. */
131  curve_lengths[0] = 0.0f;
132  }
133  else {
134  /* It is arbitrary what to do in those rare cases when all the points are
135  * in the same position. In this case we are just arbitrarily giving a valid
136  * value in the range based on the point index. */
137  for (const int i : curve_lengths.index_range()) {
138  curve_lengths[i] = i / (curve_lengths.size() - 1.0f);
139  }
140  }
141  }
142  });
143  return VArray<float>::ForContainer(std::move(result));
144  }
145 
146  if (domain == ATTR_DOMAIN_CURVE) {
148 
149  const int last_index = curves.curves_num() - 1;
150  const float total_length = lengths.last() + curves.evaluated_length_total_for_curve(
151  last_index, cyclic[last_index]);
152  if (total_length > 0.0f) {
153  const float factor = 1.0f / total_length;
154  for (float &value : lengths) {
155  value *= factor;
156  }
157  }
158  else {
159  /* It is arbitrary what to do in those rare cases when all the points are
160  * in the same position. In this case we are just arbitrarily giving a valid
161  * value in the range based on the curve index. */
162  for (const int i : lengths.index_range()) {
163  lengths[i] = i / (lengths.size() - 1.0f);
164  }
165  }
166  return VArray<float>::ForContainer(std::move(lengths));
167  }
168  return {};
169 }
170 
172  const IndexMask UNUSED(mask),
173  const eAttrDomain domain)
174 {
175  curves.ensure_evaluated_lengths();
176 
177  if (domain == ATTR_DOMAIN_POINT) {
179  return VArray<float>::ForContainer(std::move(lengths));
180  }
181 
182  if (domain == ATTR_DOMAIN_CURVE) {
184  return VArray<float>::ForContainer(std::move(lengths));
185  }
186 
187  return {};
188 }
189 
191  const IndexMask UNUSED(mask),
192  const eAttrDomain domain)
193 {
194  if (domain == ATTR_DOMAIN_POINT) {
195  Array<int> result(curves.points_num());
196  MutableSpan<int> span = result.as_mutable_span();
197  threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange range) {
198  for (const int i_curve : range) {
199  MutableSpan<int> indices = span.slice(curves.points_for_curve(i_curve));
200  for (const int i : indices.index_range()) {
201  indices[i] = i;
202  }
203  }
204  });
205  return VArray<int>::ForContainer(std::move(result));
206  }
207  return {};
208 }
209 
211  public:
212  CurveParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Parameter node")
213  {
214  category_ = Category::Generated;
215  }
216 
218  const eAttrDomain domain,
219  IndexMask mask) const final
220  {
221  if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
222  const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
223  if (curve_component.has_curves()) {
224  const Curves &curves_id = *curve_component.get_for_read();
227  }
228  }
229  return {};
230  }
231 
232  uint64_t hash() const override
233  {
234  /* Some random constant hash. */
235  return 29837456298;
236  }
237 
238  bool is_equal_to(const fn::FieldNode &other) const override
239  {
240  return dynamic_cast<const CurveParameterFieldInput *>(&other) != nullptr;
241  }
242 };
243 
245  public:
247  {
248  category_ = Category::Generated;
249  }
250 
252  const eAttrDomain domain,
253  IndexMask mask) const final
254  {
255  if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
256  const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
257  if (curve_component.has_curves()) {
258  const Curves &curves_id = *curve_component.get_for_read();
261  }
262  }
263  return {};
264  }
265 
266  uint64_t hash() const override
267  {
268  /* Some random constant hash. */
269  return 345634563454;
270  }
271 
272  bool is_equal_to(const fn::FieldNode &other) const override
273  {
274  return dynamic_cast<const CurveLengthParameterFieldInput *>(&other) != nullptr;
275  }
276 };
277 
279  public:
280  IndexOnSplineFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Index")
281  {
282  category_ = Category::Generated;
283  }
284 
286  const eAttrDomain domain,
287  IndexMask mask) const final
288  {
289  if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
290  const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
291  if (curve_component.has_curves()) {
292  const Curves &curves_id = *curve_component.get_for_read();
295  }
296  }
297  return {};
298  }
299 
300  uint64_t hash() const override
301  {
302  /* Some random constant hash. */
303  return 4536246522;
304  }
305 
306  bool is_equal_to(const fn::FieldNode &other) const override
307  {
308  return dynamic_cast<const IndexOnSplineFieldInput *>(&other) != nullptr;
309  }
310 };
311 
313 {
314  Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()};
315  Field<float> length_field{std::make_shared<CurveLengthParameterFieldInput>()};
316  Field<int> index_on_spline_field{std::make_shared<IndexOnSplineFieldInput>()};
317  params.set_output("Factor", std::move(parameter_field));
318  params.set_output("Length", std::move(length_field));
319  params.set_output("Index", std::move(index_on_spline_field));
320 }
321 
322 } // namespace blender::nodes::node_geo_curve_spline_parameter_cc
323 
325 {
327 
328  static bNodeType ntype;
330  &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT);
333  nodeRegisterType(&ntype);
334 }
typedef float(TangentPoint)[2]
eAttrDomain
Definition: BKE_attribute.h:25
@ 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
#define GEO_NODE_CURVE_SPLINE_PARAMETER
Definition: BKE_node.h:1430
#define NODE_CLASS_INPUT
Definition: BKE_node.h:345
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
#define final(a, b, c)
Definition: BLI_hash.h:21
#define UNUSED(x)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
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
const Curves * get_for_read() const
int64_t size() const
Definition: BLI_array.hh:244
const T & last(const int64_t n=0) const
Definition: BLI_array.hh:284
IndexRange index_range() const
Definition: BLI_array.hh:348
static VArray ForContainer(ContainerT container)
GVArray get_varray_for_context(const GeometryComponent &component, const eAttrDomain domain, IndexMask mask) const final
GVArray get_varray_for_context(const GeometryComponent &component, const eAttrDomain domain, IndexMask mask) const final
GVArray get_varray_for_context(const GeometryComponent &component, const eAttrDomain domain, IndexMask mask) const final
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static char ** types
Definition: makesdna.c:67
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
T length(const vec_base< T, Size > &a)
static Array< float > accumulated_lengths_curve_domain(const bke::CurvesGeometry &curves)
static Array< float > curve_length_point_domain(const bke::CurvesGeometry &curves)
static VArray< int > construct_index_on_spline_varray(const bke::CurvesGeometry &curves, const IndexMask UNUSED(mask), const eAttrDomain domain)
static VArray< float > construct_curve_length_parameter_varray(const bke::CurvesGeometry &curves, const IndexMask UNUSED(mask), const eAttrDomain domain)
static VArray< float > construct_curve_parameter_varray(const bke::CurvesGeometry &curves, const IndexMask UNUSED(mask), const eAttrDomain domain)
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)
void register_node_type_geo_curve_spline_parameter()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
unsigned __int64 uint64_t
Definition: stdint.h:90
CurvesGeometry geometry
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
NodeDeclareFunction declare
Definition: BKE_node.h:324
#define N_(msgid)