[Bf-blender-cvs] [1d9e2dc954f] master: Fix: Cyclic single point bezier splines have multiple evaluated points

Hans Goudey noreply at git.blender.org
Sat Oct 23 00:13:34 CEST 2021


Commit: 1d9e2dc954ff837737c0bbc00ef8ae4b841f2427
Author: Hans Goudey
Date:   Fri Oct 22 17:13:26 2021 -0500
Branches: master
https://developer.blender.org/rB1d9e2dc954ff837737c0bbc00ef8ae4b841f2427

Fix: Cyclic single point bezier splines have multiple evaluated points

Because `segment_is_vector` didn't handle the combined cyclic and
single control point case, it returned false, that the "segment" should
have the resolution evaluated point count. To avoid checking the size in
every call, add an assert for the size and check it elsewhere.

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

M	source/blender/blenkernel/intern/spline_bezier.cc
M	source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc

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

diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index f719a1cfda2..36ccadf521b 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -345,8 +345,14 @@ bool BezierSpline::point_is_sharp(const int index) const
          ELEM(handle_types_right_[index], HandleType::Vector, HandleType::Free);
 }
 
+/**
+ * \warning: This functiona assumes that the spline has more than one point.
+ */
 bool BezierSpline::segment_is_vector(const int index) const
 {
+  /* Two control points are necessary to form a segment, that should be checked by the caller. */
+  BLI_assert(this->size() > 1);
+
   if (index == this->size() - 1) {
     if (is_cyclic_) {
       return handle_types_right_.last() == HandleType::Vector &&
@@ -507,13 +513,18 @@ Span<int> BezierSpline::control_point_offsets() const
   offset_cache_.resize(size + 1);
 
   MutableSpan<int> offsets = offset_cache_;
-
-  int offset = 0;
-  for (const int i : IndexRange(size)) {
-    offsets[i] = offset;
-    offset += this->segment_is_vector(i) ? 1 : resolution_;
+  if (size == 1) {
+    offsets.first() = 0;
+    offsets.last() = 1;
+  }
+  else {
+    int offset = 0;
+    for (const int i : IndexRange(size)) {
+      offsets[i] = offset;
+      offset += this->segment_is_vector(i) ? 1 : resolution_;
+    }
+    offsets.last() = offset;
   }
-  offsets.last() = offset;
 
   offset_cache_dirty_ = false;
   return offsets;
@@ -600,14 +611,22 @@ Span<float3> BezierSpline::evaluated_positions() const
     return evaluated_position_cache_;
   }
 
-  this->ensure_auto_handles();
-
   const int size = this->size();
   const int eval_size = this->evaluated_points_size();
   evaluated_position_cache_.resize(eval_size);
 
   MutableSpan<float3> positions = evaluated_position_cache_;
 
+  if (size == 1) {
+    /* Use a special case for single point splines to avoid checking in #evaluate_segment. */
+    BLI_assert(eval_size == 1);
+    positions.first() = positions_.first();
+    position_cache_dirty_ = false;
+    return positions;
+  }
+
+  this->ensure_auto_handles();
+
   Span<int> offsets = this->control_point_offsets();
 
   const int grain_size = std::max(512 / resolution_, 1);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
index f32a68bc042..61165902028 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
@@ -308,8 +308,12 @@ static SplinePtr subdivide_spline(const Spline &spline,
                                   const VArray<int> &cuts,
                                   const int spline_offset)
 {
-  /* Since we expect to access each value many times, it should be worth it to make sure the
-   * attribute is a real span (especially considering the note below). Using the offset at each
+  if (spline.size() <= 1) {
+    return spline.copy();
+  }
+
+  /* Since we expect to access each value many times, it should be worth it to make sure count
+   * of cuts is a real span (especially considering the note below). Using the offset at each
    * point facilitates subdividing in parallel later. */
   Array<int> offsets = get_subdivided_offsets(spline, cuts, spline_offset);
   const int result_size = offsets.last() + int(!spline.is_cyclic());
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index a856d593bc2..5a79fcffd4d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -283,8 +283,12 @@ static SplinePtr subdivide_spline(const Spline &spline,
                                   const VArray<int> &cuts,
                                   const int spline_offset)
 {
-  /* Since we expect to access each value many times, it should be worth it to make sure the
-   * attribute is a real span (especially considering the note below). Using the offset at each
+  if (spline.size() <= 1) {
+    return spline.copy();
+  }
+
+  /* Since we expect to access each value many times, it should be worth it to make sure count
+   * of cuts is a real span (especially considering the note below). Using the offset at each
    * point facilitates subdividing in parallel later. */
   Array<int> offsets = get_subdivided_offsets(spline, cuts, spline_offset);
   const int result_size = offsets.last() + int(!spline.is_cyclic());



More information about the Bf-blender-cvs mailing list