[Bf-blender-cvs] [a80edb8865e] geometry-nodes-curve-support: Geometry nodes curves: Mostly working version of a curve trim node

Hans Goudey noreply at git.blender.org
Sun Apr 18 20:20:28 CEST 2021


Commit: a80edb8865ecf46d00ef18e062e7b0a2c7848e4d
Author: Hans Goudey
Date:   Sun Apr 18 13:20:21 2021 -0500
Branches: geometry-nodes-curve-support
https://developer.blender.org/rBa80edb8865ecf46d00ef18e062e7b0a2c7848e4d

Geometry nodes curves: Mostly working version of a curve trim node

This still needs some more fixes, but the basics are there now.

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

M	source/blender/blenkernel/BKE_derived_curve.hh
M	source/blender/blenkernel/intern/derived_curve.cc
M	source/blender/blenkernel/intern/geometry_component_curve.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc

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

diff --git a/source/blender/blenkernel/BKE_derived_curve.hh b/source/blender/blenkernel/BKE_derived_curve.hh
index 90af9f6a848..646fa08e455 100644
--- a/source/blender/blenkernel/BKE_derived_curve.hh
+++ b/source/blender/blenkernel/BKE_derived_curve.hh
@@ -27,14 +27,23 @@
 #include "BLI_vector.hh"
 
 #include "BKE_attribute_math.hh"
-#include "BKE_curve.h"
 
 struct Curve;
 
+/**
+ * Contains the information necessary to interpolate values from the original control points to
+ * evaluated points.
+ */
 struct PointMapping {
+  /**
+   * The index of the control point preceding the evaluated point at this index.
+   * For resolutions higher than 1, many evaluated points can share the same value.
+   */
   int control_point_index;
-  /* Linear interpolation factor starting at this control point with the index in
-   * `control_point_index`, and ending with the next control point. */
+  /**
+   * This evaluated point's portion of the total length between the `control_point_index` value
+   * and the next.
+   */
   float factor;
 };
 
@@ -127,23 +136,47 @@ class Spline {
   virtual int evaluated_points_size() const = 0;
   int evaluated_edges_size() const;
 
+  float length() const;
+
   blender::Span<blender::float3> evaluated_positions() const;
   blender::Span<PointMapping> evaluated_mappings() const;
   blender::Span<float> evaluated_lengths() const;
   blender::Span<blender::float3> evaluated_tangents() const;
   blender::Span<blender::float3> evaluated_normals() const;
 
-  /* TODO: Check for null default mixer. Use std::enable_if? */
+  struct LookupResult {
+    /*
+     * The index of the evaluated point before the result location.
+     * In other words, the index of the edge that the result lies on.
+     */
+    int evaluated_index;
+    /**
+     * The portion of the way from the evaluated point at #index to the next point.
+     */
+    float factor;
+  };
+  LookupResult lookup_evaluated_factor(const float factor) const;
+  LookupResult lookup_evaluated_length(const float length) const;
+
+  /**
+   * Interpolate data from the original control points to the corresponding ealuated points.
+   * \param source_data: Should have the same size as the number of control points.
+   * \param result_data: ...
+   */
   template<typename T>
   void interpolate_data_to_evaluated_points(blender::Span<T> source_data,
-                                            blender::MutableSpan<T> result_data) const
+                                            blender::MutableSpan<T> result_data,
+                                            const int offset = 0) const
   {
+    /* TODO: Onstead of "offset", it may be better to split a function that returns a single value.
+     * TODO: Check for null default mixer, possibly using std::enable_if? */
     const int control_points_len = this->size();
     blender::Span<PointMapping> mappings = this->evaluated_mappings();
 
     blender::attribute_math::DefaultMixer<T> mixer(result_data);
 
-    for (const int evaluated_point_index : mappings.index_range()) {
+    for (const int i : result_data.index_range()) {
+      const int evaluated_point_index = offset + i;
       const PointMapping &mapping = mappings[evaluated_point_index];
       const int index = mapping.control_point_index;
       const int next_index = (index + 1) % control_points_len;
@@ -152,8 +185,8 @@ class Spline {
       const T &value = source_data[index];
       const T &next_value = source_data[next_index];
 
-      mixer.mix_in(evaluated_point_index, value, 1.0f - factor);
-      mixer.mix_in(evaluated_point_index, next_value, factor);
+      mixer.mix_in(i, value, 1.0f - factor);
+      mixer.mix_in(i, next_value, factor);
     }
 
     mixer.finalize();
@@ -234,11 +267,11 @@ class BezierSpline final : public Spline {
 
   int evaluated_points_size() const final;
 
-  bool point_is_sharp(const int index) const
-  {
-    return ELEM(handle_types_start_[index], HandleType::Vector, HandleType::Free) ||
-           ELEM(handle_types_end_[index], HandleType::Vector, HandleType::Free);
-  }
+  bool point_is_sharp(const int index) const;
+  bool handle_start_is_automatic(const int index) const;
+  bool handle_end_is_automatic(const int index) const;
+
+  void move_control_point(const int index, const blender::float3 new_position);
 
  protected:
   void correct_final_tangents() const;
@@ -247,7 +280,7 @@ class BezierSpline final : public Spline {
   void correct_end_tangents() const final;
   void ensure_base_cache() const final;
   bool segment_is_vector(const int start_index) const;
-  void evaluate_bezier_segment(const int first_index,
+  void evaluate_bezier_segment(const int index,
                                const int next_index,
                                int &offset,
                                blender::MutableSpan<blender::float3> positions,
@@ -363,7 +396,7 @@ class DCurve {
   // DCurve *copy();
 
   void translate(const blender::float3 translation);
-  void transform(const blender::float4x4 &transform);
+  void transform(const blender::float4x4 &matrix);
 };
 
 DCurve *dcurve_from_dna_curve(const Curve &curve);
\ No newline at end of file
diff --git a/source/blender/blenkernel/intern/derived_curve.cc b/source/blender/blenkernel/intern/derived_curve.cc
index d13cc9954c6..6cea835d0d9 100644
--- a/source/blender/blenkernel/intern/derived_curve.cc
+++ b/source/blender/blenkernel/intern/derived_curve.cc
@@ -35,13 +35,6 @@ using blender::Vector;
 /** \name Utilities
  * \{ */
 
-/* TODO: This only works for trivial types? */
-template<typename T> static void vector_drop_front(Vector<T> vector, const int count)
-{
-  memcpy(vector.begin(), vector.begin() + count, sizeof(T) * count);
-  vector.resize(vector.size() - count);
-}
-
 /** \} */
 
 /* -------------------------------------------------------------------- */
@@ -207,6 +200,18 @@ DCurve *dcurve_from_dna_curve(const Curve &dna_curve)
 /** \name Spline
  * \{ */
 
+/**
+ * Mark all caches for recomputation. This must be called after any operation that would
+ * change the generated positions, tangents, normals, mapping, etc. of the evaluated points.
+ */
+void Spline::mark_cache_invalid()
+{
+  base_cache_dirty_ = true;
+  tangent_cache_dirty_ = true;
+  normal_cache_dirty_ = true;
+  length_cache_dirty_ = true;
+}
+
 int Spline::evaluated_edges_size() const
 {
   const int points_len = this->evaluated_points_size();
@@ -214,15 +219,30 @@ int Spline::evaluated_edges_size() const
   return this->is_cyclic ? points_len : points_len - 1;
 }
 
+float Spline::length() const
+{
+  return this->evaluated_lengths().last();
+}
+
 Span<float3> Spline::evaluated_positions() const
 {
   this->ensure_base_cache();
   return evaluated_positions_cache_;
 }
 
+/**
+ * Returns non-owning access to the cache of mappings from the evaluated points to
+ * the corresponing control points. Unless the spline is cyclic, the last control point
+ * index will never be included as an index.
+ */
 Span<PointMapping> Spline::evaluated_mappings() const
 {
   this->ensure_base_cache();
+#ifdef DEBUG
+  if (evaluated_mapping_cache_.last().control_point_index == this->size() - 1) {
+    BLI_assert(this->is_cyclic);
+  }
+#endif
   return evaluated_mapping_cache_;
 }
 
@@ -241,9 +261,10 @@ static void accumulate_lengths(Span<float3> positions,
 }
 
 /**
- * Return non-owning access to the cache of accumulated lengths along the curve. Each item is the
+ * Return non-owning access to the cache of accumulated lengths along the spline. Each item is the
  * length of the subsequent segment, i.e. the first value is the length of the first segment rather
- * than 0. This calculation only depends on the spline's evaluated positions.
+ * than 0. This calculation is rather trivial, and only depends on the evaluated positions.
+ * However, the results are used often, so it makes sense to cache it.
  */
 Span<float> Spline::evaluated_lengths() const
 {
@@ -479,16 +500,26 @@ Span<float3> Spline::evaluated_normals() const
   return evaluated_normals_cache_;
 }
 
-/**
- * Mark all caches for recomputation. This must be called after any operation that would
- * change the generated positions, tangents, normals, mapping, etc. of the evaluated points.
- */
-void Spline::mark_cache_invalid()
+Spline::LookupResult Spline::lookup_evaluated_factor(const float factor) const
 {
-  base_cache_dirty_ = true;
-  tangent_cache_dirty_ = true;
-  normal_cache_dirty_ = true;
-  length_cache_dirty_ = true;
+  return this->lookup_evaluated_length(this->length() * factor);
+}
+
+/* TODO: Support extrapolation somehow. */
+Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
+{
+  BLI_assert(length >= 0.0f && length <= this->length());
+
+  Span<float> lengths = this->evaluated_lengths();
+
+  const float *offset = std::lower_bound(lengths.begin(), lengths.end(), length);
+  const int index = offset - lengths.begin();
+
+  const float segment_length = lengths[index];
+  const float previous_length = (index == 0) ? 0.0f : lengths[index - 1];
+  const float factor = (length - previous_length) / (segment_length - previous_length);
+
+  return LookupResult{index, factor};
 }
 
 /** \} */
@@ -603,19 +634,21 @@ void BezierSpline::add_point(const float3 position,
 
 void BezierSpline::drop_front(const int count)
 {
+  std::cout << __func__ << ": " << count << "\n";
   BLI_assert(this->size() - count > 0);
-  vector_drop_front(this->handle_types_start_, count);
-  vector_drop_front(this->handle_positions_start_, count);
-  vector_drop_front(this->positions_, count);
-  vector_drop_front(this->handle_types_end_, count);
-  vector_drop_front(this->handle_positions_end_, count);
-  vector_drop_front(this->radii_, count);
-  vector_drop_front(this->tilts_, count);
+  this->handle_types_start_.remove(0, count);
+  this->handle_positions_start_.remove(0, count);
+  this->positions_.remove(0, count);
+  this->handle_types_end_.remove(0, count);
+  this->handle_positions_end_.remove(0, count);
+  this->radii_.remove(0, count);
+  this->tilts_.remove(0, count);
   this->mark_cache_invalid();
 }
 
 void BezierSpline::drop_back(const int count)
 {
+  std::cout << __func__ << ": " << count << "\n";
   const int new_size = this->size() - 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list