Ios 如何确定三次bezier路径端点处的曲率

Ios 如何确定三次bezier路径端点处的曲率,ios,bezier,Ios,Bezier,我一直在做一个项目,我使用贝塞尔路径来绘制我需要的曲线。我的项目中的每个基本形状都由三条端对端排列的三次贝塞尔曲线组成,以便坡度匹配它们相交的位置 我需要解决的基本问题是,由三条贝塞尔曲线组成的复合曲线是否与自身相交。经过一段时间的思考,我发现在给定曲线约束的情况下,我可以将任务简化为其他任务: 三条Bezier路径中的每一条的曲率都应该在曲率方向上与其邻接的曲线相反。换句话说,应该有一个拐点,一条贝塞尔曲线与另一条贝塞尔曲线相邻。如果不是这样,我希望拒绝生成曲线的参数集,并选择另一个集 在任何

我一直在做一个项目,我使用贝塞尔路径来绘制我需要的曲线。我的项目中的每个基本形状都由三条端对端排列的三次贝塞尔曲线组成,以便坡度匹配它们相交的位置

我需要解决的基本问题是,由三条贝塞尔曲线组成的复合曲线是否与自身相交。经过一段时间的思考,我发现在给定曲线约束的情况下,我可以将任务简化为其他任务:

三条Bezier路径中的每一条的曲率都应该在曲率方向上与其邻接的曲线相反。换句话说,应该有一个拐点,一条贝塞尔曲线与另一条贝塞尔曲线相邻。如果不是这样,我希望拒绝生成曲线的参数集,并选择另一个集

在任何情况下,我的基本问题是如何检测曲线之间是否存在拐点

在图中,三条贝塞尔曲线中的每一条都使用不同的颜色显示。左侧黑色曲线在它们相交的点处以与红色曲线相反的方向弯曲,但右侧黑色曲线以相同的方向弯曲。存在一个拐点,红色和左侧黑色曲线相交,但红色和右侧黑色曲线不相交

编辑: 下面,我添加了另一个图像,显示了包围贝塞尔路径的多边形。黑色曲线中显示的多边形交叉线测试的是拐点,而不是回路。我猜想,可以通过检查封闭多边形是否相交来测试一条曲线与另一条曲线相交,如红色和蓝色曲线所示。

另外,由于存在一些关于限制的问题,我将在这里列出其中一些:

  • 最左边的点和最右边的点具有相同的y值
  • 最左侧点控制点的x值小于
    最右侧点的控制点的x值。这将保持
    黑色和蓝色的曲线相互交叉
  • 最左侧和最右侧点的坡度大约在+/-10范围内 水平度
  • 黑色和红色曲线的交点,以及 红色和蓝色曲线将整个曲线大致分成两部分 三分之一。我没有确切的数字,但一个样本界就是这样 红色曲线左端的x值介于25%之间 和最右边点x值的40%
  • 交点的y值为+/-某个小分数 总宽度的
  • 交叉点处的坡度大于0.6且小于3.0(正或负) 否定)

检查贝塞尔曲线是否具有双点或自相交的确定性方法之一是计算逆方程并计算根,因为贝塞尔曲线的逆方程在自相交点处始终为零。 如本例中所述。然后,为了检测两条贝塞尔曲线(问题中的红色和黑色)是否相交,有几种方法(更容易实现)和(效率和代码复杂度的很好平衡),隐式化(不值得)

但更有效的方法可能是将曲线细分为小线段并找到交点。特别是当您想知道路径是否自相交,但不想知道精确的交点时

如果您对分段bezier曲线(或上面提到的多边形bezier as@Pomax)的CV位置有明确的假设,您可以尝试您在问题中提到的基于曲率的方法

这是一个曲线图,在一个与问题类似的路径上。在类似的情况下,这似乎可以为您提供您正在寻找的解决方案。此外,在尖点的情况下,这种快速而肮脏的方法似乎仍然有效


曲率方程相当简单。你只需要曲率的符号,所以你可以略过一点数学。你基本上对一阶导数和二阶导数的叉积的符号感兴趣

这种简化仅适用于曲线平滑连接。如果切线不相等,则需要进行更复杂的测试

曲线p的曲率符号:

ax = P[1].x - P[0].x;               //  a = P1 - P0
ay = P[1].y - P[0].y;
bx = P[2].x - P[1].x - ax;          //  b = P2 - P1 - a
by = P[2].y - P[1].y - ay;
cx = P[3].x - P[2].x - bx*2 - ax;   //  c = P3 - P2 - 2b - a
cy = P[3].y - P[2].y - by*2 - ay;

bc = bx*cy - cx*by;
ac = ax*cy - cx*ay;
ab = ax*by - bx*ay;

r = ab + ac*t + bc*t*t;
请注意,r是一阶导数和二阶导数的叉积,符号表示曲率方向。在左曲线t=1处和右曲线t=0处计算r。如果产品为负值,则存在一个拐点

如果有曲线U、V和W,其中U为左黑色,V为中红色,W为右黑色,则计算上述各曲线的bc、ac和ab。如果两个连接都是拐点,则以下测试为真:

(Uab+Uac+Ubc)*(Vab) < 0 && (Vab+Vac+Vbc)*(Wab) < 0

假设有4个点:P0、P1、P2和P3,它们描述了一条三次贝塞尔曲线(cBc)。P0和P3是起点和终点,P1和P2是方向点

当P0、P1和P2共线时,cBc在P0处有一个拐点

当P1、P2和P3共线时,cBC在P3处有一个拐点

评论

1) 使用矢量积(分别为P0P1 x P1P2和P1P2 x P2P3)检查共线性。结果应为零长度向量

2) 避免出现P0、P1、P2和P3都是共线的情况,它们创建的cBc不是一般意义上的曲线

推论


当P1=P2时,cBc两边都有拐点。

@Victor Engel:谢谢你的澄清。现在,解决方案更容易了

简而言之,看看两条曲线的扭矩。如果它们拉在一起,就会出现“拐点”,如果它们相对,就会出现“曲率”
// start with the classic bezier curve equation
P = (1-t)^3*P0 + 3*(1-t)^2*t*P1 + 3*(1-t)*t^2*P2 + t^3*P3
// convert to polynomial
P = P0 + 3*t*(P1 - P0) + 3*t^2*(P2 - 2*P1 + P0) + t^3*(P3 - 3*P2 + 3*P1 - P0)
// rename the terms to a,b,c
P = P0 + 3at + 3btt + cttt
// find the first and second derivatives
P' = 3a + 6bt + 3ctt
P" =      6b  + 6ct
// and the cross product after some reduction 
P' x P" = ab + act + bctt
a = P2P3
b = P1P2
u = Q0Q1
v = Q1Q2
Tp = b x a 
if Tp=0            {very rarely vectors a, b can be parallel.}
    b = P0P1
    Tp = b x a 
    if Tp=0 
        No! It's can't be! Who straightened the curve???
        STOP
    endif
endif

Tq = u x v 
if Tq=0            {also  vectors u, v can be parallel.}
    v = Q2Q3
    Tq = u x v 
    if Tq=0 
        Oh no! What happened to my curve???
        STOP
    endif
endif
if Tp*Tq < 0  then    Houston! We have AN "INFLEXION"!
              else    WE CONTINUE THE TURN!