[Bf-blender-cvs] [2c73e16d1cc] geometry-nodes-curve-support: Geometry Nodes Curves: Sample positions from NURBS curves

Hans Goudey noreply at git.blender.org
Tue Apr 20 21:38:56 CEST 2021


Commit: 2c73e16d1ccdcb2faf6862472385be39af2ed44a
Author: Hans Goudey
Date:   Tue Apr 20 14:38:46 2021 -0500
Branches: geometry-nodes-curve-support
https://developer.blender.org/rB2c73e16d1ccdcb2faf6862472385be39af2ed44a

Geometry Nodes Curves: Sample positions from NURBS curves

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

M	source/blender/blenkernel/BKE_derived_curve.hh
M	source/blender/blenkernel/intern/derived_curve.cc
M	source/blender/blenkernel/intern/derived_curve_spline_base.cc
M	source/blender/blenkernel/intern/derived_curve_spline_bezier.cc
M	source/blender/blenkernel/intern/derived_curve_spline_nurbs.cc

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

diff --git a/source/blender/blenkernel/BKE_derived_curve.hh b/source/blender/blenkernel/BKE_derived_curve.hh
index 646fa08e455..f662f53e7c1 100644
--- a/source/blender/blenkernel/BKE_derived_curve.hh
+++ b/source/blender/blenkernel/BKE_derived_curve.hh
@@ -119,6 +119,7 @@ class Spline {
   virtual SplinePtr copy() const = 0;
 
   virtual int size() const = 0;
+  int segments_size() const;
   virtual int resolution() const = 0;
   virtual void set_resolution(const int value) = 0;
 
@@ -290,6 +291,14 @@ class BezierSpline final : public Spline {
 };
 
 class NURBSpline final : public Spline {
+ public:
+  enum KnotsMode {
+    Normal,
+    EndPoint,
+    Bezier,
+  };
+  KnotsMode knots_mode;
+
  private:
   blender::Vector<blender::float3> positions_;
   blender::Vector<float> radii_;
@@ -298,6 +307,10 @@ class NURBSpline final : public Spline {
   int resolution_u_;
   uint8_t order_;
 
+  mutable bool knots_dirty_ = true;
+  mutable std::mutex knots_mutex_;
+  mutable blender::Vector<float> knots_;
+
  public:
   SplinePtr copy() const final;
   NURBSpline() = default;
@@ -318,6 +331,9 @@ class NURBSpline final : public Spline {
   uint8_t order() const;
   void set_order(const uint8_t value);
 
+  bool check_valid_size_and_order() const;
+  int knots_size() const;
+
   blender::MutableSpan<blender::float3> positions() final;
   blender::Span<blender::float3> positions() const final;
   blender::MutableSpan<float> radii() final;
@@ -325,6 +341,8 @@ class NURBSpline final : public Spline {
   blender::MutableSpan<float> tilts() final;
   blender::Span<float> tilts() const final;
 
+  blender::Span<float> knots() const;
+
   blender::MutableSpan<float> weights();
   blender::Span<float> weights() const;
 
@@ -341,6 +359,9 @@ class NURBSpline final : public Spline {
  protected:
   void correct_end_tangents() const final;
   void ensure_base_cache() const final;
+  void evaluate_position_and_mapping(blender::MutableSpan<blender::float3> positions,
+                                     blender::MutableSpan<PointMapping> mappings) const;
+  void calculate_knots() const;
 };
 
 class PolySpline final : public Spline {
diff --git a/source/blender/blenkernel/intern/derived_curve.cc b/source/blender/blenkernel/intern/derived_curve.cc
index ae217892ae8..36b3dd2aff6 100644
--- a/source/blender/blenkernel/intern/derived_curve.cc
+++ b/source/blender/blenkernel/intern/derived_curve.cc
@@ -122,6 +122,21 @@ static Spline::NormalCalculationMode normal_mode_from_dna_curve(const int twist_
   return Spline::NormalCalculationMode::Minimum;
 }
 
+static NURBSpline::KnotsMode knots_mode_from_dna_nurb(const short flag)
+{
+  switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
+    case CU_NURB_ENDPOINT:
+      return NURBSpline::KnotsMode::EndPoint;
+    case CU_NURB_BEZIER:
+      return NURBSpline::KnotsMode::Bezier;
+    default:
+      return NURBSpline::KnotsMode::Normal;
+  }
+
+  BLI_assert_unreachable();
+  return NURBSpline::KnotsMode::Normal;
+}
+
 DCurve *dcurve_from_dna_curve(const Curve &dna_curve)
 {
   DCurve *curve = new DCurve();
@@ -153,6 +168,18 @@ DCurve *dcurve_from_dna_curve(const Curve &dna_curve)
         break;
       }
       case CU_NURBS: {
+        std::unique_ptr<NURBSpline> spline = std::make_unique<NURBSpline>();
+        spline->set_resolution(nurb->resolu);
+        spline->type = Spline::Type::NURBS;
+        spline->is_cyclic = nurb->flagu & CU_NURB_CYCLIC;
+        spline->set_order(nurb->orderu);
+        spline->knots_mode = knots_mode_from_dna_nurb(nurb->flagu);
+
+        for (const BPoint &bp : Span(nurb->bp, nurb->pntsu)) {
+          spline->add_point(bp.vec, bp.radius, bp.tilt, bp.vec[3]);
+        }
+
+        curve->splines.append(std::move(spline));
         break;
       }
       case CU_POLY: {
diff --git a/source/blender/blenkernel/intern/derived_curve_spline_base.cc b/source/blender/blenkernel/intern/derived_curve_spline_base.cc
index e2b754660f2..3140a5d55ca 100644
--- a/source/blender/blenkernel/intern/derived_curve_spline_base.cc
+++ b/source/blender/blenkernel/intern/derived_curve_spline_base.cc
@@ -20,7 +20,6 @@
 
 #include "DNA_curve_types.h"
 
-#include "BKE_curve.h"
 #include "BKE_derived_curve.hh"
 
 using blender::Array;
@@ -61,6 +60,13 @@ Span<float3> Spline::evaluated_positions() const
   return evaluated_positions_cache_;
 }
 
+int Spline::segments_size() const
+{
+  const int points_len = this->size();
+
+  return this->is_cyclic ? points_len : points_len - 1;
+}
+
 /**
  * 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
diff --git a/source/blender/blenkernel/intern/derived_curve_spline_bezier.cc b/source/blender/blenkernel/intern/derived_curve_spline_bezier.cc
index c84d23b8c89..b0ff18116d1 100644
--- a/source/blender/blenkernel/intern/derived_curve_spline_bezier.cc
+++ b/source/blender/blenkernel/intern/derived_curve_spline_bezier.cc
@@ -18,7 +18,6 @@
 #include "BLI_listbase.h"
 #include "BLI_span.hh"
 
-#include "BKE_curve.h"
 #include "BKE_derived_curve.hh"
 
 using blender::Array;
diff --git a/source/blender/blenkernel/intern/derived_curve_spline_nurbs.cc b/source/blender/blenkernel/intern/derived_curve_spline_nurbs.cc
index 9d591b3d6b6..6e0bf81c13f 100644
--- a/source/blender/blenkernel/intern/derived_curve_spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/derived_curve_spline_nurbs.cc
@@ -18,7 +18,6 @@
 #include "BLI_listbase.h"
 #include "BLI_span.hh"
 
-#include "BKE_curve.h"
 #include "BKE_derived_curve.hh"
 
 using blender::Array;
@@ -56,6 +55,18 @@ void NURBSpline::set_resolution(const int value)
   this->mark_cache_invalid();
 }
 
+uint8_t NURBSpline::order() const
+{
+  return this->order_;
+}
+
+void NURBSpline::set_order(const uint8_t value)
+{
+  /* TODO: Check the spline length. */
+  BLI_assert(value >= 2 && value <= 6);
+  this->order_ = value;
+}
+
 void NURBSpline::add_point(const float3 position,
                            const float radius,
                            const float tilt,
@@ -65,6 +76,7 @@ void NURBSpline::add_point(const float3 position,
   this->radii_.append(radius);
   this->tilts_.append(tilt);
   this->weights_.append(weight);
+  this->knots_dirty_ = true;
 }
 
 void NURBSpline::drop_front(const int count)
@@ -123,13 +135,252 @@ Span<float> NURBSpline::weights() const
 
 int NURBSpline::evaluated_points_size() const
 {
-  return 0;
+  return this->resolution_u_ * this->segments_size();
 }
 
 void NURBSpline::correct_end_tangents() const
 {
 }
 
+bool NURBSpline::check_valid_size_and_order() const
+{
+  if (this->size() < this->order_) {
+    return false;
+  }
+
+  if (!this->is_cyclic && this->knots_mode == KnotsMode::Bezier) {
+    if (this->order_ == 4) {
+      if (this->size() < 5) {
+        return false;
+      }
+    }
+    else if (this->order_ != 3) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+int NURBSpline::knots_size() const
+{
+  const int size = this->size() + this->order_;
+  return this->is_cyclic ? size + this->order_ - 1 : size;
+}
+
+void NURBSpline::calculate_knots() const
+{
+  const KnotsMode mode = this->knots_mode;
+  const int length = this->size();
+  const int order = this->order_;
+
+  this->knots_.resize(this->knots_size());
+
+  MutableSpan<float> knots = this->knots_;
+
+  if (mode == NURBSpline::KnotsMode::Normal || this->is_cyclic) {
+    for (const int i : knots.index_range()) {
+      knots[i] = static_cast<float>(i);
+    }
+  }
+  else if (mode == NURBSpline::KnotsMode::EndPoint) {
+    float k = 0.0f;
+    for (const int i : IndexRange(1, knots.size())) {
+      knots[i - 1] = k;
+      if (i >= order && i <= length) {
+        k += 1.0f;
+      }
+    }
+  }
+  else if (mode == NURBSpline::KnotsMode::Bezier) {
+    BLI_assert(ELEM(order, 3, 4));
+    if (order == 3) {
+      float k = 0.6f;
+      for (const int i : knots.index_range()) {
+        if (i >= order && i <= length) {
+          k += 0.5f;
+        }
+        knots[i] = std::floor(k);
+      }
+    }
+    else {
+      float k = 0.34f;
+      for (const int i : knots.index_range()) {
+        knots[i] = std::floor(k);
+        k += 1.0f / 3.0f;
+      }
+    }
+  }
+
+  if (this->is_cyclic) {
+    const int b = length + order - 1;
+    if (order > 2) {
+      for (const int i : IndexRange(1, order - 2)) {
+        if (knots[b] != knots[b - i]) {
+          if (i == order - 1) {
+            knots[length + order - 2] += 1.0f;
+            break;
+          }
+        }
+      }
+    }
+
+    int c = order;
+    for (int i = b; i < this->knots_size(); i++) {
+      knots[i] = knots[i - 1] + (knots[c] - knots[c - 1]);
+      c--;
+    }
+  }
+}
+
+Span<float> NURBSpline::knots() const
+{
+  if (!this->knots_dirty_) {
+    BLI_assert(this->knots_.size() == this->size() + this->order_);
+    return this->knots_;
+  }
+
+  std::lock_guard lock{this->knots_mutex_};
+  if (!this->knots_dirty_) {
+    BLI_assert(this->knots_.size() == this->size() + this->order_);
+    return this->knots_;
+  }
+
+  this->calculate_knots();
+
+  this->base_cache_dirty_ = false;
+
+  return this->knots_;
+}
+
+/* TODO: Better variables names, simplify logic once it works. */
+static void nurb_basis(const float parameter,
+                       const int points_len,
+                       const int order,
+                       Span<float> knots,
+                       MutableSpan<float> basis,
+                       int &start,
+                       int &end)
+{
+  /* Clamp parameter due to floating point inaccuracy. TODO: Look into using doubles. */
+  const float t = std::clamp(parameter, knots[0], knots[points_len + order - 1]);
+
+  int i1 = 0;
+  int i2 = 0;
+  for (int i = 0; i < points_len + order - 1; i++) {
+    if ((knots[i] != knots[i + 1]) && (t >= knots[i]) && (t <= knots[i + 1])) {
+      basis[i] = 1.0f;
+      i1 = std::max(i - order - 1, 0);
+      i2 = i;
+      i++;
+      while (i < points_len + order - 1) {
+        basis[i] = 0.0f;
+        i++;
+      }
+      break;
+    }
+    basis[i] = 0.0f;
+  }
+  basis[points_len + order - 1] = 0.0f;
+
+  for (int i_order = 2; i_order <= order; i_order++) {
+    if (i2 + 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list