Math 计算三次贝塞尔曲线的拐点?

Math 计算三次贝塞尔曲线的拐点?,math,graphics,geometry,bezier,Math,Graphics,Geometry,Bezier,我有四个点组成一条三次贝塞尔曲线: P1 = (10, 5) P2 = (9, 12) P3 = (24, -2) P4 = (25, 3) 现在我想找到这条曲线的拐点。我在谷歌上搜索过,但每个人都提到一个网站: 不幸的是,这些小程序不起作用,我根本无法把它们放在一起。有人能告诉我如何计算曲线的拐点吗 对于贝塞尔曲线,有两个参数方程X(t)和Y(t)。 要确定参数曲线的拐点,需要找到曲线曲率()改变符号的位置。所以你需要找到上述函数的一阶和二阶导数,然后解方程: C(t) = X' * Y''

我有四个点组成一条三次贝塞尔曲线:

P1 = (10, 5)
P2 = (9, 12)
P3 = (24, -2)
P4 = (25, 3)
现在我想找到这条曲线的拐点。我在谷歌上搜索过,但每个人都提到一个网站:

不幸的是,这些小程序不起作用,我根本无法把它们放在一起。有人能告诉我如何计算曲线的拐点吗


对于贝塞尔曲线,有两个参数方程X(t)和Y(t)。 要确定参数曲线的拐点,需要找到曲线曲率()改变符号的位置。所以你需要找到上述函数的一阶和二阶导数,然后解方程:

C(t) = X' * Y'' - X'' * Y' = 0
一阶导数是二次的,第二阶导数是线性的,所以对于
t
,方程是三次的,可能有多达3个解

编辑:已阅读链接文章,方程简化为二次方程,最多可有2个解

如果解决方案存在于t范围0..1内,您还必须检查它是否为真正的拐点-检查
C'(t)0
在该t值处

示例:蓝色圆圈是拐点(两个捕捉到的)

真实代码片段(Delphi)
给定:
P是控制点的数组
Cf是贝塞尔系数的幂基

P, Cf: array[0..3] of TPoint

//calculate Bezier coefficients
Cf[3].x := p[3].x - 3 * p[2].x + 3 * p[1].x - p[0].x;
Cf[2].x := 3 * (p[0].x - 2 * p[1].x + p[2].x);
Cf[1].x := 3 * (p[1].x - p[0].x);
Cf[0].x := p[0].x;
//the same for Y

//find parameters of quadratic equation
// a*t^2 + b*t + c = 0
a := 3 * (cf[2].X *cf[3].Y - cf[2].Y *cf[3].X);
b := 3 * (cf[1].X *cf[3].Y - cf[1].Y *cf[3].X);
c := cf[1].X *cf[2].Y - cf[1].Y *cf[2].X;

//here solve quadratic equations, find t parameters
//don't forget a lot of special cases like a=0, D<0, D=0, t outside 0..1 range
Discriminant := b * b - 4 * a * c;
....
P,Cf:TPoint的数组[0..3]
//计算贝塞尔系数
Cf[3].x:=p[3].x-3*p[2].x+3*p[1].x-p[0].x;
Cf[2].x:=3*(p[0].x-2*p[1].x+p[2].x);
Cf[1].x:=3*(p[1].x-p[0].x);
Cf[0].x:=p[0].x;
//Y也一样
//求二次方程的参数
//a*t^2+b*t+c=0
a:=3*(cf[2].X*cf[3].Y-cf[2].Y*cf[3].X);
b:=3*(cf[1].X*cf[3].Y-cf[1].Y*cf[3].X);
c:=cf[1].X*cf[2].Y-cf[1].Y*cf[2].X;
//在这里解二次方程,求t参数

//不要忘记很多特殊情况,比如a=0,D为了详细说明MBo的答案,
C(t)=X'*Y'-X'*Y'=0
几乎就是你想要的伪码,因为一阶导数和二阶导数很容易计算

下面是一个坐标为(x1,y1)…(x4,y4)的通用贝塞尔函数:

其中a=3(x2-x1)、b=3(x3-x2)和c=3(x4-x3),以及:

其中u=2(b-a)和v=2(c-b)。当然,y分量也是如此:

fy(t) = y1 (1-t)³ + 3·y2·(1-t)²·t + 3·y3·(1-t)·t² + y4·t³
fy'(t) = a'·(1-t)² + 2·b'·(1-t)·t + c'·t²
fy''(t) = u'·(1-t) + v'·t
其中
a'
a
相同,但具有
y
值等

计算
C(t)=fx'(t)·fy'(t)-fx'(t)·fy'(t)
的数学很烦人,但这就是我们拥有计算机的原因。如果您拥有树莓pi,您就拥有Mathematica的许可证,那么让我们使用它:

这是一个庞大的公式,但找到“任意”曲线的拐点有点愚蠢,因为贝塞尔曲线对线性仿射变换是不变的,所以无论我们检查“真实曲线”,拐点的
t
值都保持不变或者旋转/平移/缩放曲线,使其具有更方便的坐标。就像平移它,使(x1,y1)最终成为(0,0),并且(x4,y4)位于x轴上,使y4为零

如果我们这样做,那么我们会得到一个非常简单的公式:

这要简单多少?嗯:

18 times:
  -     x3 * y2
  + 3 * x3 * y2 * t
  - 3 * x3 * y2 * t^2
  -     x4 * y2 * t
  + 2 * x4 * y2 * t^2
  +     x2 * y3
  - 3 * x2 * y3 * t
  + 3 * x2 * y3 * t^2
  -     x4 * y3 * t^2
因为我们在编程,所以有很多可缓存的值。采取:

a = x3 * y2
b = x4 * y2
c = x2 * y3
d = x4 * y3
我们可以将
C(t)
简化为:

1/18 * C(t) = -a + 3at - 3at^2 - bt + 2bt^2 + c - 3ct + 3ct^2 - dt^2
= -3at^2 + 2bt^2 + 3ct^2 - dt^2 + 3at - bt - 3ct - a + c
= (-3a + 2b + 3c - d)t^2 + (3a - b - 3c)t + (c - a)
再加上因子18,这只是一个简单的二次公式,我们可以使用二次根恒等式和更简单的值来求根:

v1 = (-3a + 2b + 3c - d) * 18
v2 = (3a - b - 3c) * 18
v3 = (c - a) * 18
并且,假设
3a+d
不等于
2b+3c
(因为在这种情况下没有根),我们得到:

扔掉不属于贝塞尔区间[0,1]的根,剩下的是原始曲线弯曲的
t

只是我不能以某种方式把东西组合在一起,所以我最终得到了一些很好的伪代码。这也是我给出一些点和坐标的原因。我想看到有人用实数来计算


尤其是在Stackoverflow上,最好不要在前面偷懒,而应该致力于学习新东西。

您熟悉参数化曲线表示吗?你们能把贝塞尔曲线从伯恩斯坦基转换成多项式基表示吗?我已经输入了Python,但我得到了错误的结果。是我还是遗漏了什么,还是有拼写错误??是的,显然这些输入将失败。重新阅读上面的一段“如果我们这样做,那么我们会得到一个非常简单的公式”,因为您构建代码所依据的分析要求您首先对曲线进行轴对齐。谢谢你,迈克!
1/18 * C(t) = -a + 3at - 3at^2 - bt + 2bt^2 + c - 3ct + 3ct^2 - dt^2
= -3at^2 + 2bt^2 + 3ct^2 - dt^2 + 3at - bt - 3ct - a + c
= (-3a + 2b + 3c - d)t^2 + (3a - b - 3c)t + (c - a)
v1 = (-3a + 2b + 3c - d) * 18
v2 = (3a - b - 3c) * 18
v3 = (c - a) * 18
  sqr = sqrt(v2^2 - 4 * v1 * v3)
    d = 2 * v1
root1 =  (sqr - v2) / d
root2 = -(sqr + v2) / d