如何用连续闭合的 B 样条曲线插入一组点?

计算科学 插值 数学 b样条
2021-12-23 19:06:00

今年我一直在通过经典教材《The NURBS Book》学习NURBS理论。在第 9 章中,作者介绍了开曲线的非有理 B 样条曲线插值方法

我已经用 Wolfram Mathematica实现了这个全局 B 样条曲线插值算法有关详细信息,请参阅此处此处

另外,我知道如何通过控制点生成闭合 B 样条曲线。请参阅我关于关闭 B 样条曲线的答案

现在让我用Mathematica举一个简单的例子,我SplineClosed -> TrueBSplineCurve.

searchSpan[knots_, u0_] :=
 With[{max = Max[knots]},
  If[u0 == max, Position[knots, max][[1, 1]] - 2,
   Ordering[UnitStep[u0 - knots], 1][[1]] - 2]
 ]

Options[BSplineInterpolation] = {SplineDegree -> Automatic};

BSplineInterpolation[pts : {{_, _} ..}, opts : OptionsPattern[]] /;
 MatrixQ[pts, NumericQ] :=
 Module[{n, md, sd, paras, knots, coeffMat, ctrlpts},
  n = Length@pts - 1;
  sd = OptionValue[SplineDegree] /. Automatic -> 3 /. 
    deg_ :> n /; deg > n;
  paras =
   FoldList[Plus, 0, Normalize[(Norm /@ Differences[pts]), Total]] // N;
  (*calculate the knots*)
  knots =
   Join[ConstantArray[0, sd + 1],
     1/sd (Plus @@ (paras[[# + 1 ;; # + sd]]) & /@ Range[1, n - sd]),
     ConstantArray[1, sd + 1]] // N;
  (*calculate the coefficients of matrix*)
  coeffMat = Function[{u0},
     With[{i = searchSpan[knots, u0]},
      Join[ConstantArray[0, i - sd],
       BSplineBasis[{sd, knots}, #, u0] & /@ Range[i - sd, i],
       ConstantArray[0, n - i]]]] /@ paras;
  (*solve the control points of B-Spline curve*)
  ctrlpts = LinearSolve[coeffMat, pts];
  (*visualize the result*)
  Graphics[
   {BSplineCurve[ctrlpts,
     SplineClosed -> True, SplineDegree -> sd, SplineKnots -> knots],
    Red, PointSize[Medium], Point[pts]}]
  ]

测试

pts = 
 {{-1.5, -2}, {-3, -1}, {-2.7, 0.5}, {-1.75, 1.3}, {0.8, -1.5}, 
  {1.5, 0.4}, {0, 2}, {3, 2}};
BSplineInterpolation[pts]

在此处输入图像描述

显然,这条曲线不是连续的,也没有通过所有interpolation points.

再次试用(即删除选项SplineKnots -> knots

在此处输入图像描述


我已经搜索了Google Scholar关于封闭曲线插值的论文,但是,我没有发现任何有用的参考资料。

  • 如何实现连续闭合的 B 样条曲线?
2个回答

B-Splines 的经典著作是 de Boor, C. (1978)。样条曲线实用指南。纽约:Springer-Verlag,但我花了好几个星期在上面,但无法让他的算法工作。Phillips, GM, & Taylor, PJ (1996) 中的算法。样条和其他近似数值分析的理论和应用第 6 章(第 2 版,第 131-159 页)。伦敦,圣地亚哥:学术出版社,运作良好且易于理解。

看起来您的第一个示例正在运行,除了连接第一个和最后一个点的边缘情况。如果可行,一个简单的解决方案是在pts最后重复第一点。

我可能会稍后再检查,如果这不起作用,可能需要一段时间才能解决。