如何在给定切线方向的二次贝塞尔曲线上找到一个点(如果有)?

nor*_*esh 3 python math bezier

我目前正在使用 python 库从 TrueType 字体中提取笔划 - 在这里,我将笔划定义为在测试点与其反射点之间运行的中线。我使用术语“反射点”来指代“墨水”区域另一侧的最近点,在正常情况下(除了在衬线词干处),该点的切线方向也与测试点相反.

我正在使用 fontTools 和从http://pomax.github.io/bezierinfo/#extremities 中描述的处理代码推出的贝塞尔库在 python 中工作。

目前我被困在如何找到具有给定切线的二次贝塞尔曲线上的点,我的数学技能在美好的一天非常基本,头脑清晰[现在不是仪式]所以我希望头脑更敏锐的人可以指出如何实现这一目标的鸟瞰概述。

目前,我唯一能想到的就是用类似于 Newton-Raphson 求根算法的方法在数值上接近它,但根据目标方向值评估一阶导数。然而,我希望有一个象征性的解决方案,因为这需要在字形轮廓中的每条曲线的每条其他曲线上运行。

unu*_*tbu 5

使用http://pomax.github.io/bezierinfo/#extremities 中给出的符号,二次贝塞尔曲线由下式给出:

B(t) = P1*(1-t)**2 + 2*P2*(1-t)*t + P3*t**2
Run Code Online (Sandbox Code Playgroud)

因此,(通过取导数B相对于t)的切线曲线由下式给出

B'(t) = -2*P1*(1-t) + 2*P2*(1-2*t) + 2*P3*t
      = 2*(P1 - 2*P2 + P3)*t + 2*(-P1 + P2)
Run Code Online (Sandbox Code Playgroud)

给定一些切线方向V,求解

B'(t) = V
Run Code Online (Sandbox Code Playgroud)

t。如果有解,t = ts,则贝塞尔曲线上具有切线方向的V点由 给出B(ts)


我们本质上想知道两个向量(B'(t)V)是平行还是反平行。有一个技巧可以做到这一点。

如果它们的点积为零,则两个向量XY是垂直的。如果和随后的点积和由下式给出X = (a,b)Y = (c,d)XY

a*c + b*d
Run Code Online (Sandbox Code Playgroud)

因此,如果和是垂直的,X并且 和Y是平行的,其中是垂直于 的向量。XY_perpY_perpY

在二维中,如果在坐标中,Y = (a,b)Y_perp = (-b, a). (还有两个垂直的向量可能的,但是这一次就行了。)请注意, -使用上述公式-的点积YY_perp

a*(-b) + b*(a) = 0
Run Code Online (Sandbox Code Playgroud)

因此,确实,这与垂直向量的点积等于 0 的说法不谋而合。

现在,要解决我们的问题:让

B'(t) = (a*t+b, c*t+d)
V = (e, f)
Run Code Online (Sandbox Code Playgroud)

ThenB'(t)平行(或反平行)到Vif 或 when B'(t)垂直于V_perp,这发生在

dot product((a*t+b, c*t+d), (-f, e)) = 0
-(a*t+b)*f + (c*t+d)*e = 0
Run Code Online (Sandbox Code Playgroud)

我们知道abcdef。求解t。如果t介于 0 和 1 之间,则B(t)P1和之间的贝塞尔曲线段的一部分P3