[Bf-blender-cvs] [0c6b8158554] master: Geometry Nodes: Add Length Output to Curve Parameter Node

Johnny Matthews noreply at git.blender.org
Wed Nov 3 21:15:42 CET 2021


Commit: 0c6b81585544636de41c3743adb693ebaed9a4a2
Author: Johnny Matthews
Date:   Wed Nov 3 15:05:46 2021 -0500
Branches: master
https://developer.blender.org/rB0c6b81585544636de41c3743adb693ebaed9a4a2

Geometry Nodes: Add Length Output to Curve Parameter Node

Adds a length output to the curve parameter node which returns the
length of a spline at each point, or the length of the curve at
each spline depending on the domain.

Differential Revision: https://developer.blender.org/D12882

===================================================================

M	source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc

===================================================================

diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
index 4c89aba2e6d..ee7a78ccf71 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
@@ -24,7 +24,16 @@ namespace blender::nodes {
 
 static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b)
 {
-  b.add_output<decl::Float>(N_("Factor")).field_source();
+  b.add_output<decl::Float>(N_("Factor"))
+      .field_source()
+      .description(
+          N_("For points, the portion of the spline's total length at the control point. For "
+             "Splines, the factor of that spline within the entire curve"));
+  b.add_output<decl::Float>(N_("Length"))
+      .field_source()
+      .description(
+          N_("For points, the distance along the control point's spline, For splines, the "
+             "distance along the entire curve"));
 }
 
 /**
@@ -32,47 +41,42 @@ static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b)
  * average parameter for each spline would just be 0.5, or close to it. Instead, the parameter for
  * each spline is the portion of the total length at the start of the spline.
  */
-static Array<float> curve_parameter_spline_domain(const CurveEval &curve, const IndexMask mask)
+static Array<float> curve_length_spline_domain(const CurveEval &curve,
+                                               const IndexMask UNUSED(mask))
 {
   Span<SplinePtr> splines = curve.splines();
   float length = 0.0f;
-  Array<float> parameters(splines.size());
+  Array<float> lengths(splines.size());
   for (const int i : splines.index_range()) {
-    parameters[i] = length;
+    lengths[i] = length;
     length += splines[i]->length();
   }
-  const float total_length_inverse = length == 0.0f ? 0.0f : 1.0f / length;
-  mask.foreach_index([&](const int64_t i) { parameters[i] *= total_length_inverse; });
-
-  return parameters;
+  return lengths;
 }
 
 /**
  * The parameter at each control point is the factor at the corresponding evaluated point.
  */
-static void calculate_bezier_parameters(const BezierSpline &spline, MutableSpan<float> parameters)
+static void calculate_bezier_lengths(const BezierSpline &spline, MutableSpan<float> lengths)
 {
   Span<int> offsets = spline.control_point_offsets();
-  Span<float> lengths = spline.evaluated_lengths();
-  const float total_length = spline.length();
-  const float total_length_inverse = total_length == 0.0f ? 0.0f : 1.0f / total_length;
-
+  Span<float> lengths_eval = spline.evaluated_lengths();
   for (const int i : IndexRange(1, spline.size() - 1)) {
-    parameters[i] = lengths[offsets[i] - 1] * total_length_inverse;
+    lengths[i] = lengths_eval[offsets[i] - 1];
   }
 }
 
 /**
  * The parameter for poly splines is simply the evaluated lengths divided by the total length.
  */
-static void calculate_poly_parameters(const PolySpline &spline, MutableSpan<float> parameters)
+static void calculate_poly_length(const PolySpline &spline, MutableSpan<float> lengths)
 {
-  Span<float> lengths = spline.evaluated_lengths();
-  const float total_length = spline.length();
-  const float total_length_inverse = total_length == 0.0f ? 0.0f : 1.0f / total_length;
-
-  for (const int i : IndexRange(1, spline.size() - 1)) {
-    parameters[i] = lengths[i - 1] * total_length_inverse;
+  Span<float> lengths_eval = spline.evaluated_lengths();
+  if (spline.is_cyclic()) {
+    lengths.drop_front(1).copy_from(lengths_eval.drop_back(1));
+  }
+  else {
+    lengths.drop_front(1).copy_from(lengths_eval);
   }
 }
 
@@ -82,52 +86,47 @@ static void calculate_poly_parameters(const PolySpline &spline, MutableSpan<floa
  * each point is not well defined. So instead, treat the control points as if they were a poly
  * spline.
  */
-static void calculate_nurbs_parameters(const NURBSpline &spline, MutableSpan<float> parameters)
+static void calculate_nurbs_lengths(const NURBSpline &spline, MutableSpan<float> lengths)
 {
   Span<float3> positions = spline.positions();
   Array<float> control_point_lengths(spline.size());
-
   float length = 0.0f;
   for (const int i : IndexRange(positions.size() - 1)) {
-    parameters[i] = length;
+    lengths[i] = length;
     length += float3::distance(positions[i], positions[i + 1]);
   }
-
-  const float total_length_inverse = length == 0.0f ? 0.0f : 1.0f / length;
-  for (float &parameter : parameters) {
-    parameter *= total_length_inverse;
-  }
+  lengths.last() = length;
 }
 
-static Array<float> curve_parameter_point_domain(const CurveEval &curve)
+static Array<float> curve_length_point_domain(const CurveEval &curve)
 {
   Span<SplinePtr> splines = curve.splines();
   Array<int> offsets = curve.control_point_offsets();
   const int total_size = offsets.last();
-  Array<float> parameters(total_size);
+  Array<float> lengths(total_size);
 
   threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
     for (const int i : range) {
       const Spline &spline = *splines[i];
-      MutableSpan spline_factors{parameters.as_mutable_span().slice(offsets[i], spline.size())};
+      MutableSpan spline_factors{lengths.as_mutable_span().slice(offsets[i], spline.size())};
       spline_factors.first() = 0.0f;
       switch (splines[i]->type()) {
         case Spline::Type::Bezier: {
-          calculate_bezier_parameters(static_cast<const BezierSpline &>(spline), spline_factors);
+          calculate_bezier_lengths(static_cast<const BezierSpline &>(spline), spline_factors);
           break;
         }
         case Spline::Type::Poly: {
-          calculate_poly_parameters(static_cast<const PolySpline &>(spline), spline_factors);
+          calculate_poly_length(static_cast<const PolySpline &>(spline), spline_factors);
           break;
         }
         case Spline::Type::NURBS: {
-          calculate_nurbs_parameters(static_cast<const NURBSpline &>(spline), spline_factors);
+          calculate_nurbs_lengths(static_cast<const NURBSpline &>(spline), spline_factors);
           break;
         }
       }
     }
   });
-  return parameters;
+  return lengths;
 }
 
 static const GVArray *construct_curve_parameter_gvarray(const CurveEval &curve,
@@ -136,13 +135,50 @@ static const GVArray *construct_curve_parameter_gvarray(const CurveEval &curve,
                                                         ResourceScope &scope)
 {
   if (domain == ATTR_DOMAIN_POINT) {
-    Array<float> parameters = curve_parameter_point_domain(curve);
-    return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(parameters));
+    Span<SplinePtr> splines = curve.splines();
+    Array<float> values = curve_length_point_domain(curve);
+
+    const Array<int> offsets = curve.control_point_offsets();
+    for (const int i_spline : curve.splines().index_range()) {
+      const Spline &spline = *splines[i_spline];
+      const float spline_length = spline.length();
+      const float spline_length_inv = spline_length == 0.0f ? 0.0f : 1.0f / spline_length;
+      for (const int i : IndexRange(spline.size())) {
+        values[offsets[i_spline] + i] *= spline_length_inv;
+      }
+    }
+    return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(values));
   }
 
   if (domain == ATTR_DOMAIN_CURVE) {
-    Array<float> parameters = curve_parameter_spline_domain(curve, mask);
-    return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(parameters));
+    Array<float> values = curve.accumulated_spline_lengths();
+    const float total_length_inv = values.last() == 0.0f ? 0.0f : 1.0f / values.last();
+    for (const int i : mask) {
+      values[i] *= total_length_inv;
+    }
+    return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(values));
+  }
+  return nullptr;
+}
+
+static const GVArray *construct_curve_length_gvarray(const CurveEval &curve,
+                                                     const IndexMask mask,
+                                                     const AttributeDomain domain,
+                                                     ResourceScope &scope)
+{
+  if (domain == ATTR_DOMAIN_POINT) {
+    Array<float> lengths = curve_length_point_domain(curve);
+    return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(lengths));
+  }
+
+  if (domain == ATTR_DOMAIN_CURVE) {
+    if (curve.splines().size() == 1) {
+      Array<float> lengths(1, 0.0f);
+      return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(lengths));
+    }
+
+    Array<float> lengths = curve_length_spline_domain(curve, mask);
+    return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(lengths));
   }
 
   return nullptr;
@@ -188,10 +224,51 @@ class CurveParameterFieldInput final : public fn::FieldInput {
   }
 };
 
+class CurveLengthFieldInput final : public fn::FieldInput {
+ public:
+  CurveLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Length node")
+  {
+    category_ = Category::Generated;
+  }
+
+  const GVArray *get_varray_for_context(const fn::FieldContext &context,
+                                        IndexMask mask,
+                                        ResourceScope &scope) const final
+  {
+    if (const GeometryComponentFieldContext *geometry_context =
+            dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
+
+      const GeometryComponent &component = geometry_context->geometry_component();
+      const AttributeDomain domain = geometry_context->domain();
+      if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+        const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+        const CurveEval *curve = curve_component.get_for_read();
+        if (curve) {
+          return construct_curve_length_gvarray(*curve, mask, domain, scope);
+        }
+      }
+    }
+    return nullptr;
+  }
+
+  uint64_t hash() const override
+  {
+    /* Some random constant hash. */
+    return 345634563454;
+  }
+
+  bool is_equal_to(const fn::FieldNode &other) const override
+  {
+    return dynamic_cast<const

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list