找到闭合的2d均匀立方B样条的面积

时间:2012-06-03 02:23:57

标签: python math numpy spline

我有一个2d点的列表,它是闭合均匀立方B样条的控制顶点(Dx)。我假设一条简单的曲线(非自相交,所有控制点都不同)。

我试图找到曲线所包围的区域:

enter image description here

如果我计算结点(Px),我可以将曲线视为多边形;然后我“只是”需要在实际曲线和连接结点的直线之间找到每个线段的剩余三角形区域。

据我所知,Bspline的形状(因此区域)在旋转和平移下是不变的 - 所以对于每个段,我可以找到一个平移,将t = 0结放在原点,旋转放置t + x轴上= 1节:

enter image description here

我可以通过插入点并重新分组来找到曲线的等式:

P(t) = (
    (t**3)*(-Dm1 + 3*D0 - 3*D1 + D2)
    + (t**2)*(3*Dm1 - 6*D0 + 3*D1)
    + t*(-3*Dm1 + 3*D1)
    + (Dm1 + 4*D0 + D1)
) / 6.

但是我正在试图整合它 - 我可以做到

 1
/
| Py(t) dt
/
t=0

但这不会给我区域。我认为我需要的是

 Px(t=1)
/
| Py(t) (dPx(t) / dt) dt
/
x = Px(t=0)

但在我走得更远之前,我真的很想知道:

  1. 这是区域的正确计算吗?理想情况下,分析解决方案将成为我的一天!

  2. 一旦找到这个区域,我怎么知道是否需要在基础聚合物中添加或减去它(第一个图中的红色区域与绿色区域相比)?

  3. 是否有任何Python模块可以为我做这个计算? Numpy有一些评估立方Bsplines的方法,但没有一种方法可以用来处理区域。

  4. 有更简单的方法吗?我正在考虑在一堆点上评估P(t) - 比如t = numpy.arange(0.0, 1.0, 0.05) - 并将整个事物视为多边形。知道需要多少细分来保证给定的准确度(我想要错误<1%)?

3 个答案:

答案 0 :(得分:4)

就个人而言,我会使用样条曲线,并使用Green's theorem将区域积分重写为轮廓积分。

由于您已经知道了曲线,因此使用足够阶的高斯积分进行积分将是一件容易的事。没有恶作剧来估计所需的额外区域。我敢打赌,它也具有计算效率,因为高斯多项式的高斯正交表现得非常好。立方B样条将很好地集成。

我会以这样的方式编写代码,即第一个和最后一个点必须重合。这是问题的不变量。

这种方法甚至适用于有洞的区域。沿着外部曲线整合,形成一条连接外部曲线和内部曲线的假想直线,沿着内部曲线整合,然后沿着直线向外传递到外部。

答案 1 :(得分:3)

  1. 选择一些任意点作为枢轴 p 0 (例如原点(0,0))
  2. 沿曲线选择一些点 p 1 = (x,y)
  3. 区分该点的曲线,以获得速度 v =&lt; vx,vy &gt;
  4. 从三个点形成一个三角形,calculate the area。使用向量之间的交叉产品最简单 p 0 p 1 v ,除以二。
  5. 将此区域整合到 t 上,从0到1。
  6. 您得到的结果是整条曲线的一段的面积。有些将是负面的,因为它们面向相反的方向。如果总结所有段的面积,则得到整个曲线的面积。

    结果是:

      

    区域 i =(31 x i -1 y i + 28 x i -1 y i +1 + x i - 1 y i +2 - 31 x i y i -1 + 183 x i y i +1 + 28 x i y i +2 - 28 x i +1 y i -1 - 183 x i < / i> +1 y i + 31 x i < / i> +1 y i +2 - x i +2 y i -1 - 28 x i +2 y i - 31 x i +2 y i +1 )/ 720

    如果将其转换为矩阵形式,则会得到:

      

    区域 i =&lt; x i -1 x i x i +1 x i +2 &gt; · P ·&lt; y i -1 y i y i +1 y i 2 &GT; Ť

    其中 P

    [    0   31   28    1]
    [  -31    0  183   28] / 720
    [  -28 -183    0   31]
    [   -1  -28  -31    0]
    

    如果控制点为[(0,0) (1,0) (1,1) (0,1)],则生成的区域变为:

    [(0,0), (1,0), (1,1), (0,1)] -> 242/720
    [(1,0), (1,1), (0,1), (0,0)] -> 242/720
    [(1,1), (0,1), (0,0), (1,0)] ->   2/720
    [(0,1), (0,0), (1,0), (1,1)] ->   2/720
    

    总和为488/720 = 61/90。

答案 2 :(得分:1)

嗯......看起来你已经知道该怎么做了。

  1. 是的,这是计算细分下区域的正确方法,实际上是

    dS=Y*dX=Y*(dX/dt)*dt
    
  2. 您无需关心添加或减少。你需要一直添加,但是一些积分(红色段)将是负数(如果你总是将你的P n 设置在坐标的开头并且P n + 1 < / sub>沿X轴正方向)。因此,对于每个段,您需要计算平移和旋转,然后积分(所有分析完成)。

  3. 我不知道Python模块,但似乎制作这样一个模块最多需要一天。
  4. 我认为分析解决方案会更好,而且不会那么难。
  5. 无论如何,图形绝对令人惊叹