Math 在多个点拆分三次bezier曲线
我正在写一个算法,将一条三次贝塞尔曲线分割成多条曲线(最多4条)。我从一开始就有我想要分割的每个点的t值。我还有一个算法,可以将曲线分割一次:Math 在多个点拆分三次bezier曲线,math,curve,bezier,Math,Curve,Bezier,我正在写一个算法,将一条三次贝塞尔曲线分割成多条曲线(最多4条)。我从一开始就有我想要分割的每个点的t值。我还有一个算法,可以将曲线分割一次: SubdivPoints subdivideBezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t) { Vector2 p11 = (p1 - p0) * t + p0; Vector2 p21 = (p2 - p1) * t + p1; Vector2 p3
SubdivPoints subdivideBezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
{
Vector2 p11 = (p1 - p0) * t + p0;
Vector2 p21 = (p2 - p1) * t + p1;
Vector2 p31 = (p3 - p2) * t + p2;
Vector2 p12 = (p21 - p11) * t + p11;
Vector2 p22 = (p31 - p21) * t + p21;
Vector2 p13 = (p22 - p12) * t + p12;
return SubdivPoints(p11, p12, p22, p31, p13);
}
我的问题是,有没有一种简单的方法可以将其扩展为多次拆分?我想在每次分割之后,我都想重新计算t值;我想知道的一件事是,简单的算术在这里是否有效。例如,假设t值为0.2和0.6。我在t=0.2时分割曲线,得到两条曲线。第二条曲线覆盖了原始曲线的t值0.2
子节点后面的内容。我可以想出两种方法:
代数的
如果你把你的问题看作是多项式的参数t
缩放,那么它就变得更清晰了。例如,您需要零件t=
的控制点。这意味着我们需要形成新的控制点,用参数u=
表示相同的曲线。怎么做
将BEZIER写成多项式
每个轴都可以以相同的方式单独完成。s让我们只关注x
-轴。我们有4个贝塞尔控制点,x坐标(x0,x1,x2,x3)
。如果我们应用bernstein多项式形成三次多项式,我们得到:
x(t)= ( ( x0))
+ t*( (3.0*x1)-(3.0*x0))
+ t*t*( (3.0*x2)-(6.0*x1)+(3.0*x0))
+t*t*t*(( x3)-(3.0*x2)+(3.0*x1)-( x0))
通过替换重新缩放参数
为此使用线性插值,以便:
t0=0.25 -> u0=0.0
t1=0.50 -> u1=1.0
t=t0+(t1-t0)*(u-u0)/(u1-u0)
t=0.25+0.5*u
现在用u
而不是t重写多项式
x(t)= ( ( x0))
+(0.25+u/2) *( (3.0*x1)-(3.0*x0))
+(0.25+u/2)^2*( (3.0*x2)-(6.0*x1)+(3.0*x0))
+(0.25+u/2)^3*(( x3)-(3.0*x2)+(3.0*x1)-( x0))
更改多项式形式以再次匹配贝塞尔方程
现在您需要为u^0、u^1、u^2、u^3
分离多项式项,并对每个项进行改革以匹配贝塞尔风格(来自#1)。从中提取新的控制点
例如,术语u^3是这样的。获得u^3的唯一可能性是从
(1/4+u/2)^3= (1/8)*u^3 + (3/16)*u^2 + (3/32)*u + (1/64)
因此,分隔的u^3
术语将为:
u*u*u*(( x3)-(3.0*x2)+(3.0*x1)-( x0))/8
其他的会有点复杂,因为你需要把所有的线组合在一起。。。简化后,需要分离新坐标。正如你所看到的,这有点疯狂,但也有代数解算器,比如为Windows导出
很抱歉,我没有时间/心情/胃口对所有术语进行完整的示例,但你会看到这将是一个相当疯狂的过程
曲线拟合
这是基于您正在查找控制点的坐标并检查它与所需曲线的距离。所以尽可能地测试“”“点并记住目标范围上的原始曲线和新曲线之间的紧密匹配。这是无法解决的,因为可能有无限多的控制点,所以我们需要通过开发一些东西将这些控制点缩减到可管理的规模。例如,我们现在的控制点将不会远离原始控制点,因此我们可以使用它来限制每个点的面积。您可以使用这个或任何其他最小化技术
如果使用插值立方,也可以获得更好的起点。看见因此:
从贝塞尔曲线计算4个新的插值立方控制点
所以如果我们的范围和以前一样的话
X0 = BEZIER(t0-(t1-t0))
X1 = BEZIER(t0)
X2 = BEZIER(t1)
X3 = BEZIER(t1+(t1-t0))
这些是插值立方控制点,而不是贝塞尔。它们应该均匀分布X1,X2
是曲线端点,X0,X3
在它们之前和之后,以尽可能保持局部形状和参数的线性
将(X0,X1,X2,X3)
转换回贝塞尔控制点(X0,X1,X2,X3)
您可以使用上面链接中的我的公式:
// input: X0,Y0,..X3,Y3 ... interpolation control points
// output: x0,y0,..x3,y3 ... Bezier control points
double x0,y0,x1,y1,x2,y2,x3,y3,m=1.0/9.0;
x0=X1; y0=Y1;
x1=X1+((X1-X0)*m); y1=Y1+((Y1-Y0)*m);
x2=X2+((X2-X3)*m); y2=Y2+((Y2-Y3)*m);
x3=X2; y3=Y2;
正如您所见,每个轴的计算方式相同
对BEZIER控制点应用近似搜索
新的(x0,x1,x2,x3)
还不精确,因为盲目地改变控制点,我们可能会错过一些曲线扭曲形状的局部极值。所以我们需要寻找真正的。幸运的是,新的控制点(x0',x1',x2',x3')
将非常接近这些点,因此现在我们必须搜索每个点,仅在其相对部分附近,周围有一些合理的半径(如边界框大小/8
或其他什么…,您将看到结果并可以调整
[notes]
如果您需要精确的结果,则只有#1方法可用。方法#2总是会有一些错误。如果形状不需要精确,有时将插值立方转换为BEZIER而无需最终拟合就足够了(如果切割区域内/附近的形状不太复杂)
正如我之前所写的,如果不知道您的子节点使用了哪种原则,就不可能回答重复使用它会产生什么结果
此外,您没有指定解决方案的约束,如结果的准确性、速度/运行时限制……如果范围是固定的(恒定的)或在运行期间可能会发生变化(这将使#1方法非常复杂,因为您需要将范围作为变量处理到最后),因为您的subdivideBezier()函数确实遵循了De Casteljau算法,我假设它可以在参数t处细分一条三次Bezier曲线。所以,是的,继续在不同的参数下细分(比如t2),您所需要做的就是找出细分后的曲线t2,根据该曲线计算新的t2*并细分。在您希望在t=0.2和0.6处细分的示例中,0.6的新参数应为(0.6-0.2)/(1-0.2)=0.5。所以,你可以简单地在t=0.5处细分第二条曲线。这就是我希望我能做的,但是这在数学上被证明了吗?我的意思是,我可以这样做,看看我能不能