Browse Source

support closed loops

Alec Jacobson 5 years ago
parent
commit
4ca4f8b341
2 changed files with 22 additions and 8 deletions
  1. 18 7
      include/igl/fit_cubic_bezier.cpp
  2. 4 1
      include/igl/fit_cubic_bezier.h

+ 18 - 7
include/igl/fit_cubic_bezier.cpp

@@ -44,10 +44,18 @@ IGL_INLINE void igl::fit_cubic_bezier(
     }
     }
     return t.normalized();
     return t.normalized();
   };
   };
-  const Eigen::RowVectorXd tHat1 = tangent(0,+1);
-  const Eigen::RowVectorXd tHat2 = tangent(nPts-1,-1);
+  Eigen::RowVectorXd tHat1 = tangent(0,+1);
+  Eigen::RowVectorXd tHat2 = tangent(nPts-1,-1);
+  // If first and last points are identically equal, then consider closed
+  const bool closed = (d.row(0) - d.row(d.rows()-1)).squaredNorm() == 0;
+  // If closed loop make tangents match
+  if(closed)
+  {
+    tHat1 = (tHat1 - tHat2).eval().normalized();
+    tHat2 = -tHat1;
+  }
   cubics.clear();
   cubics.clear();
-  fit_cubic_bezier_substring(d,0,nPts-1,tHat1,tHat2,error,cubics);
+  fit_cubic_bezier_substring(d,0,nPts-1,tHat1,tHat2,error,closed,cubics);
 };
 };
 
 
 IGL_INLINE void igl::fit_cubic_bezier_substring(
 IGL_INLINE void igl::fit_cubic_bezier_substring(
@@ -57,6 +65,7 @@ IGL_INLINE void igl::fit_cubic_bezier_substring(
   const Eigen::RowVectorXd & tHat1,
   const Eigen::RowVectorXd & tHat1,
   const Eigen::RowVectorXd & tHat2,
   const Eigen::RowVectorXd & tHat2,
   const double error,
   const double error,
+  const bool force_split,
   std::vector<Eigen::MatrixXd> & cubics)
   std::vector<Eigen::MatrixXd> & cubics)
 {
 {
   // Helper functions
   // Helper functions
@@ -252,7 +261,7 @@ IGL_INLINE void igl::fit_cubic_bezier_substring(
 
 
   int splitPoint;
   int splitPoint;
   double maxError = ComputeMaxError(d, first, last, bezCurve, u, splitPoint);
   double maxError = ComputeMaxError(d, first, last, bezCurve, u, splitPoint);
-  if (maxError < error)
+  if (!force_split && maxError < error)
   {
   {
     cubics.push_back(bezCurve);
     cubics.push_back(bezCurve);
     return;
     return;
@@ -272,7 +281,7 @@ IGL_INLINE void igl::fit_cubic_bezier_substring(
       }
       }
       GenerateBezier(d, first, last, uPrime, tHat1, tHat2, bezCurve);
       GenerateBezier(d, first, last, uPrime, tHat1, tHat2, bezCurve);
       maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, splitPoint);
       maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, splitPoint);
-      if (maxError < error) {
+      if (!force_split && maxError < error) {
         cubics.push_back(bezCurve);
         cubics.push_back(bezCurve);
         return;
         return;
       }
       }
@@ -284,8 +293,10 @@ IGL_INLINE void igl::fit_cubic_bezier_substring(
   const Eigen::RowVectorXd tHatCenter = 
   const Eigen::RowVectorXd tHatCenter = 
     (d.row(splitPoint-1)-d.row(splitPoint+1)).normalized();
     (d.row(splitPoint-1)-d.row(splitPoint+1)).normalized();
   //foobar
   //foobar
-  fit_cubic_bezier_substring(d,first,splitPoint,tHat1,tHatCenter,error,cubics);
-  fit_cubic_bezier_substring(d,splitPoint,last,(-tHatCenter).eval(),tHat2,error,cubics);
+  fit_cubic_bezier_substring(
+    d,first,splitPoint,tHat1,tHatCenter,error,false,cubics);
+  fit_cubic_bezier_substring(
+    d,splitPoint,last,(-tHatCenter).eval(),tHat2,error,false,cubics);
 }
 }
 
 
 
 

+ 4 - 1
include/igl/fit_cubic_bezier.h

@@ -18,7 +18,8 @@ namespace igl
   //
   //
   // Inputs:
   // Inputs:
   //   d  #d by dim list of points along a curve to be fit with a cubic bezier
   //   d  #d by dim list of points along a curve to be fit with a cubic bezier
-  //     spline (should probably be roughly uniformly spaced)
+  //     spline (should probably be roughly uniformly spaced). If d(0)==d(end),
+  //     then will treat as a closed curve.
   //   error  maximum squared distance allowed
   //   error  maximum squared distance allowed
   // Output:
   // Output:
   //   cubics #cubics list of 4 by dim lists of cubic control points
   //   cubics #cubics list of 4 by dim lists of cubic control points
@@ -34,6 +35,7 @@ namespace igl
   //    tHat1  tangent to use at beginning of spline
   //    tHat1  tangent to use at beginning of spline
   //    tHat2  tangent to use at end of spline
   //    tHat2  tangent to use at end of spline
   //    error  see above
   //    error  see above
+  //    force_split  whether to force a split (i.e., force a recursive call)
   //    cubics  running list of cubics so far
   //    cubics  running list of cubics so far
   // Outputs
   // Outputs
   //    cubics  running list of cubics so far (new cubics appended)
   //    cubics  running list of cubics so far (new cubics appended)
@@ -44,6 +46,7 @@ namespace igl
     const Eigen::RowVectorXd & tHat1,
     const Eigen::RowVectorXd & tHat1,
     const Eigen::RowVectorXd & tHat2,
     const Eigen::RowVectorXd & tHat2,
     const double error,
     const double error,
+    const bool force_split, 
     std::vector<Eigen::MatrixXd> & cubics);
     std::vector<Eigen::MatrixXd> & cubics);
 }
 }