三维贝塞尔曲线的零切线,如何处理?

时间:2015-01-08 15:59:03

标签: exception math exception-handling bezier

如图所示,贝塞尔曲线的方向(切线)在某一点可能为零(0,0,0)。例如。对称贝塞尔曲线定义为:

    bezier.anchor1.copyFrom(new Vector3D(-1,0,0));
    bezier.control1.copyFrom(new Vector3D(1,0,0));
    bezier.anchor2.copyFrom(new Vector3D(1,0,0));
    bezier.control2.copyFrom(new Vector3D(-1.,0,0));

t = 0.5时的方向是(0,0,0)。这可能是一个罕见/极端的用例,但我肯定需要总是有一个非零的方向。

从编程上讲,我应该如何处理它?重新计算附近另一个t的方向(比如t1 = t * 0.99999 = 0.499995)然后返回那个方向?

2 个答案:

答案 0 :(得分:2)

我不知道为什么你不能将0范数向量作为导数。我想你试图沿曲线动画一些东西,然后那个衍生物就是速度......你那时的速度是零,因为你暂时不动。应该没有问题。

为什么0?让我们来看一个病态案例

请参阅此插图,其中锚点分别为(-1,-y,0)(-1,y,0)以及控制点(1,-y,0)(1,y,0)

enter image description here

现在您可以看到在参数定义的点t=0t=0.5t=1处绘制的切线会发生什么。在t=0.5处,切线在x轴中丢失了所有分量,但仍然朝着y轴缓慢移动,因此右边的切线很小。

但是,您将此y参数修改为0的次数越多,您就会展平曲线并获得一个细分。在点t=0.5处,您的切线不具有零x组合(如前所述),但也在y维度上,因为该图将是一维的。

所以零切线是一种病态情况,当你的身材尺寸太小时可能会出现这种情况。

解决方法:降低学位

贝塞尔曲线有许多订单,通用订单n的公式为:

P i 曲线的点,b i 称为{{3度数为n(参见Bernstein basis polynomials有关曲线不同阶数的不同说明)。

在您的情况下,您将从(-1,0,0)转到(1,0,0),控制点位于同一行,有效地绘制了细分[(-1,0,0), (1,0,0)]。因此,您绘制一个线段,并且您只需要2个点:您应该使用由t * P0 + (1-t) * P1定义的一阶多项式,这是一个平凡的插值。在你的形式主义中,我想:

bezier.anchor1.copyFrom(new Vector3D(-1,0,0));
bezier.anchor2.copyFrom(new Vector3D(1,0,0));

并没有控制点。 然后没有0切线(除非你得到一个尖点)!

答案 1 :(得分:2)

事情比你的例子更糟糕。很可能在{3}贝塞尔曲线中出现cusp。例如,控制点[80,214],[217,50],[75,50],[222,206]。你的例子实际上是一个扁平的尖点。

Picture of a cusp

如果你沿着切线跟随它们在尖点处经过180º翻转的曲线,尖点是非常棘手的。尖点也很常见,如果你有一个动画的曲线序列,当一个循环展开时,你可能会在一个帧中出现尖点。您可以在现实世界中经常看到它们,在茶杯底部的光线模式中,以及在3D中将曲线投影到2D上(例如将曲线(t,t ^ 2,t ^ 3)投影到YZ飞机)。好消息是它们通常是孤立的点,你只能得到一个立方贝塞尔曲线。

现在如何处理这些尖点可能取决于您的应用程序。如果它描述某个物体的路径会发生什么,那么物体在尖点处停止并沿相反方向离开。说对象此时具有零切向量可能是合理的。有可能将曲线分割为尖点。

您可以在带有画布的javascript中看到带有可移动控制点http://jsfiddle.net/SalixAlba/QQnvm/6/的交互式示例

var P = [{X:  80, Y: 214 }, 
         {X: 217, Y:  50 }, 
         {X:  75, Y:  50 }, 
         {X: 222, Y: 206 }, ];
ctx.beginPath();
ctx.moveTo(P[0].X, P[0].Y);
ctx.bezierCurveTo(P[1].X, P[1].Y, P[2].X, P[2].Y, P[3].X, P[3].Y);
ctx.stroke();