三阶贝塞尔曲线拟合1/4圆
根据贝塞尔曲线的知识,我们知道三阶贝塞尔曲线的参数方程如下,其中A、B、C、D为四个控制点坐标,P(t)表示曲线上的每一点。
因为要模拟1/4圆,所以通过P(0)和P(1)的切线方向,应该按照下图所示位置安放。
其中AB为水平方向,DC为垂直方向,并且线段长度|AB| = |DC| = h。
那么这个问题实际上,就转换为计算出合理的h值,使得半径|OJ| = 1,也即J点刚好在圆弧上。
根据贝塞尔曲线的对称性,不难想出J点在P(0.5)处,代入公式即可求得:
同样的结论,也可以直接由贝塞尔曲线的几何图形特征来推定,也即:
所以也可以再次确认P(0.5)和J是同一点。
代入四个控制点坐标A(0, 1),B(h, 1),C(1, h)和D(1, 0),可以求解P(0.5)点坐标如下:
根据圆形方程定义,可以拟出下面方程:
从而求解出h的值为:
所以,可以最终求解出三阶贝塞尔曲线模拟1/4圆的参数方程P(t)定义如下:
另一方面,该方程描述的曲线与真实1/4圆有多大差异呢?下面就针对这个问题进行数值求解。
采用t = 0.0到1.0,步进值0.01,求解每个点到原点的距离与半径1的差异。
- #include
- #include
- #include
- #include
-
- double bezier3(double a, double b, double c, double d, double t)
- {
- double nt = 1.0 - t;
- double nt2 = nt * nt;
- double nt3 = nt * nt * nt;
- double t2 = t * t;
- double t3 = t * t * t;
-
- return (a * nt3 + b * 3.0 * nt2 * t + c * 3.0 * nt * t2 + d * t3);
- }
-
- int main()
- {
- double t, a;
- double d, e;
- double max_e = 0.0, min_e = 1.0;
-
- double x, y;
- double h = (sqrt(2) - 1.0) * 4.0 / 3.0;
- for(t = 0.0; t < 1.01; t+=0.01)
- {
- x = bezier3(0, h, 1, 1, t);
- y = bezier3(1, 1, h, 0, t);
- d = sqrt(x * x + y * y);
- e = d - 1.0;
-
- a = atan2(y, x);
- a = a * 180.0 / 3.1415926;
-
- if(max_e < e) max_e = e;
- if(min_e > e) min_e = e;
- printf("%4.1f, %f\n", a, e);
- }
- printf("max_e = %f, min_e = %f\n", max_e, min_e);
- return 0;
- }
输出结果如下:
- 90.0, 0.000000
- 89.1, 0.000003
- 88.1, 0.000010
- 87.2, 0.000022
- 86.2, 0.000037
- 85.3, 0.000054
- 84.4, 0.000073
- 83.4, 0.000092
- 82.5, 0.000113
- 81.6, 0.000133
- 80.7, 0.000153
- 79.7, 0.000172
- 78.8, 0.000190
- 77.9, 0.000206
- 77.0, 0.000221
- 76.1, 0.000234
- 75.2, 0.000246
- 74.3, 0.000255
- 73.4, 0.000263
- 72.5, 0.000268
- 71.6, 0.000271
- 70.7, 0.000273
- 69.8, 0.000272
- 68.9, 0.000269
- 68.0, 0.000265
- 67.1, 0.000259
- 66.2, 0.000251
- 65.3, 0.000242
- 64.4, 0.000232
- 63.5, 0.000220
- 62.6, 0.000208
- 61.8, 0.000194
- 60.9, 0.000181
- 60.0, 0.000166
- 59.1, 0.000152
- 58.2, 0.000137
- 57.3, 0.000123
- 56.5, 0.000108
- 55.6, 0.000094
- 54.7, 0.000081
- 53.8, 0.000068
- 52.9, 0.000056
- 52.0, 0.000045
- 51.2, 0.000035
- 50.3, 0.000026
- 49.4, 0.000018
- 48.5, 0.000012
- 47.6, 0.000007
- 46.8, 0.000003
- 45.9, 0.000001
- 45.0, 0.000000
- 44.1, 0.000001
- 43.2, 0.000003
- 42.4, 0.000007
- 41.5, 0.000012
- 40.6, 0.000018
- 39.7, 0.000026
- 38.8, 0.000035
- 38.0, 0.000045
- 37.1, 0.000056
- 36.2, 0.000068
- 35.3, 0.000081
- 34.4, 0.000094
- 33.5, 0.000108
- 32.7, 0.000123
- 31.8, 0.000137
- 30.9, 0.000152
- 30.0, 0.000166
- 29.1, 0.000181
- 28.2, 0.000194
- 27.4, 0.000208
- 26.5, 0.000220
- 25.6, 0.000232
- 24.7, 0.000242
- 23.8, 0.000251
- 22.9, 0.000259
- 22.0, 0.000265
- 21.1, 0.000269
- 20.2, 0.000272
- 19.3, 0.000273
- 18.4, 0.000271
- 17.5, 0.000268
- 16.6, 0.000263
- 15.7, 0.000255
- 14.8, 0.000246
- 13.9, 0.000234
- 13.0, 0.000221
- 12.1, 0.000206
- 11.2, 0.000190
- 10.3, 0.000172
- 9.3, 0.000153
- 8.4, 0.000133
- 7.5, 0.000113
- 6.6, 0.000092
- 5.6, 0.000073
- 4.7, 0.000054
- 3.8, 0.000037
- 2.8, 0.000022
- 1.9, 0.000010
- 0.9, 0.000003
- -0.0, 0.000000
- max_e = 0.000273, min_e = 0.000000
从输出结果分析可以看到,误差均为向着圆弧外凸,0度到45度一段,45度到90度一段。
在0度、45度和90度为最小误差0.000000,在19.3度和70.7度达到最大误差为0.000273,基本上非常接近1/4圆弧了。
以上,即为三阶贝塞尔曲线模拟1/4圆弧的全部内容。
感谢Grapher和GeoGebra软件,使得方便排版文章中使用的公式和曲线。