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值;我想知道的一件事是简单的算法是否适用于此。例如。让我们说我的值为0.2和0.6。我在t = 0.2处分割曲线,给出了两条曲线。第二条曲线包括t值0.2
答案 0 :(得分:4)
由于你的subdivideBezier()函数确实遵循De Casteljau算法,我假设它可以在参数t下细分一个三次贝塞尔曲线。所以,是的,要继续细分一个不同的参数(比如说t2),你需要做的就是弄清楚哪个细分曲线t2落在上面,计算新的t2 *与该曲线并细分。在您想要在t = 0.2和0.6处细分的示例中,0.6的新参数应为(0.6-0.2)/(1-0.2)= 0.5。因此,您可以在t = 0.5时简单地细分第二条曲线。
答案 1 :(得分:1)
很难说,即使您当前的方法有效,我们也看不到SubdivPoints
背后的原因。我可以想到两种方法:
<强>代数强>
如果您将问题看作多项式的参数t
缩放,那么它就会变得更清晰。例如,您需要部分t = <0.25,0.5>
的控制点。这意味着我们需要形成表示具有参数u=<0.0,1.0>
的相同曲线的新控制点。怎么做?
每个轴可以以相同的方式单独完成,让我们只关注x
- 轴。我们有4个BEZIER控制点,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
分隔多项式项,并将每项更改为匹配BEZIER样式(来自#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
其他的将会更复杂,因为您需要将所有线组合在一起...在简化之后,您需要分离新的坐标。正如你所看到的那样是轻微的疯狂但是有像代数导出的代数解算器......
抱歉,我没有时间/情绪/胃来充分说明所有条款,但你会发现这将是一个多项式的疯狂......
曲线拟合
这是基于你找到控制点的坐标并检查它与你想要的曲线的距离。所以测试&#34;&#34;所有可能&#34;指出并记住目标范围内原始曲线与新曲线之间的闭合匹配。这是无法解决的,因为可能存在无数个控制点,因此我们需要通过利用某些东西来减少那些可管理的大小。例如,我们现在控制点不会远离原始控制点,因此我们可以使用它来限制每个点的面积。您可以将approximation search用于此项或任何其他最小化技术。
如果使用插值立方,你也可以获得更好的起点。见BEZIER vs Interpolation cubics。所以:从BEZIER曲线计算4个新的插值立方控制点
所以,如果我们有与之前相同的范围
X0 = BEZIER(t0-(t1-t0))
X1 = BEZIER(t0)
X2 = BEZIER(t1)
X3 = BEZIER(t1+(t1-t0))
这些是插值立方控制点而不是BEZIER。它们应该均匀分散。 X1,X2
是曲线端点,X0,X3
位于它们之前和之后,以尽可能地保留参数的局部形状和线性
从(X0,X1,X2,X3)
转换回BEZIER控制点(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')
将非常接近这些点,所以现在我们必须在其对应部分附近以一些合理的半径搜索每个点(比如边界框size/8
或者其他......你会看到结果,可以调整......
<强> [注释] 强>
如果您需要精确的精确结果,则只能使用#1 方法。方法#2 总会出现一些错误。如果形状不需要精确,有时插值立方体转换为BEZIER而没有最终拟合就足够了(如果在切割区域中/附近形状不太复杂)。
正如我之前所写的那样,在不知道你的SubdivPoints
中使用了哪个原则是不可能回答重复使用它的结果是什么......
此外,您没有指定解决方案的约束,如结果的准确性,速度/运行时限制......如果范围是固定的(常量),或者在运行期间可能会有所不同(这将使您需要的#1方法极为复杂化处理范围作为变量直到结束)