3D贝塞尔曲线的零切线,如何处理?
Zero tangent of a 3D Bezier curve, how to handle?
贝塞尔曲线的方向(切线)在某一点可能为零 (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)。这可能是一个 rare/extreme 用例,但我绝对需要手头始终有一个非零方向。
从程序上讲,我应该如何处理?重新计算附近另一个 t 的方向(比如 t1=t*0.99999=0.499995),然后 return 那个方向?
我不知道为什么不能将 0
范数向量作为导数。我想你正试图沿着曲线制作动画,那么导数就是速度......你在那个点的速度为零,因为你暂时没有移动。应该没有问题。
为什么 0
?来看一个病理案例
请参阅此图,其中锚点分别为 (-1,-y,0)
和 (-1,y,0)
以及控制点 (1,-y,0)
、(1,y,0)
。
现在您可以看到在 parameter-defined 点 t=0
、t=0.5
和 t=1
处绘制的切线发生了什么。在 t=0.5
处,切线已失去其在 x
轴中的所有分量,但仍在向 y
轴缓慢移动,因此向右有一条小切线。
然而,您将此y
参数修改得越多,变成0
,您就会使曲线变平并获得一段。在 t=0.5
点,您的切线没有零 x
分量(像以前一样),但在 y
维度上也是如此,因为图形将为 one-dimensional.
因此,零切线是一种病态情况,当您的图形尺寸太小时可能会出现这种情况。
Work-around : 减少程度
贝塞尔曲线的阶数很多,通用阶数n
的公式是:
with Pi 你曲线的点,bi 被称为 Bernstein basis polynomials of degree n (see this wikipedia section 用于不同阶数的曲线的不同插图)。
在你的例子中,你将从 (-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
切线(除非你得到尖点)!
情况比你的例子差一点。很可能在三次贝塞尔曲线中出现 cusp。例如,控制点 [80,214]、[217,50]、[75,50]、[222,206]。你的例子实际上是一个扁平的尖端。
。
如果您沿着曲线的切线在尖点处经过 180º 翻转,尖点就很难处理。尖点也很常见,如果你有一个动画序列的曲线,你很可能在循环展开时在一帧中出现尖点。你经常在现实世界中看到它们,在茶杯底部的光模式中,以及在 3D 曲线到 2D 的投影中(例如将曲线 (t,t^2,t^3) 投影到Y-Z 平面)。好消息是它们通常是孤立的点,你只会在三次贝塞尔曲线上得到一个。
现在如何处理这些尖端可能取决于您的应用程序。如果它描述了某个物体的路径,将会发生的事情是物体在尖点处停止并朝相反的方向离开。说该对象此时具有零切向量可能是非常合理的。或许可以在尖点处分割曲线。
您可以在 javascript 中看到带有可移动控制点的交互式示例 http://jsfiddle.net/SalixAlba/QQnvm/6/ canvas
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();
贝塞尔曲线的方向(切线)在某一点可能为零 (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)。这可能是一个 rare/extreme 用例,但我绝对需要手头始终有一个非零方向。
从程序上讲,我应该如何处理?重新计算附近另一个 t 的方向(比如 t1=t*0.99999=0.499995),然后 return 那个方向?
我不知道为什么不能将 0
范数向量作为导数。我想你正试图沿着曲线制作动画,那么导数就是速度......你在那个点的速度为零,因为你暂时没有移动。应该没有问题。
为什么 0
?来看一个病理案例
请参阅此图,其中锚点分别为 (-1,-y,0)
和 (-1,y,0)
以及控制点 (1,-y,0)
、(1,y,0)
。
现在您可以看到在 parameter-defined 点 t=0
、t=0.5
和 t=1
处绘制的切线发生了什么。在 t=0.5
处,切线已失去其在 x
轴中的所有分量,但仍在向 y
轴缓慢移动,因此向右有一条小切线。
然而,您将此y
参数修改得越多,变成0
,您就会使曲线变平并获得一段。在 t=0.5
点,您的切线没有零 x
分量(像以前一样),但在 y
维度上也是如此,因为图形将为 one-dimensional.
因此,零切线是一种病态情况,当您的图形尺寸太小时可能会出现这种情况。
Work-around : 减少程度
贝塞尔曲线的阶数很多,通用阶数n
的公式是:
with Pi 你曲线的点,bi 被称为 Bernstein basis polynomials of degree n (see this wikipedia section 用于不同阶数的曲线的不同插图)。
在你的例子中,你将从 (-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
切线(除非你得到尖点)!
情况比你的例子差一点。很可能在三次贝塞尔曲线中出现 cusp。例如,控制点 [80,214]、[217,50]、[75,50]、[222,206]。你的例子实际上是一个扁平的尖端。
如果您沿着曲线的切线在尖点处经过 180º 翻转,尖点就很难处理。尖点也很常见,如果你有一个动画序列的曲线,你很可能在循环展开时在一帧中出现尖点。你经常在现实世界中看到它们,在茶杯底部的光模式中,以及在 3D 曲线到 2D 的投影中(例如将曲线 (t,t^2,t^3) 投影到Y-Z 平面)。好消息是它们通常是孤立的点,你只会在三次贝塞尔曲线上得到一个。
现在如何处理这些尖端可能取决于您的应用程序。如果它描述了某个物体的路径,将会发生的事情是物体在尖点处停止并朝相反的方向离开。说该对象此时具有零切向量可能是非常合理的。或许可以在尖点处分割曲线。
您可以在 javascript 中看到带有可移动控制点的交互式示例 http://jsfiddle.net/SalixAlba/QQnvm/6/ canvas
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();