三阶贝塞尔曲线拟合1/4圆

贝塞尔曲线(Bézier curve),又称 贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由 线段与 节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔 曲线工具,如PhotoShop等。在Flash4中还没有完整的曲线工具,而在Flash5里面已经提供出贝塞尔曲线工具。
贝塞尔曲线于1962,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由Paul de Casteljau于1959年运用de Casteljau演算法开发,以稳定数值的方法求出贝兹曲线。(感谢百度百科)

三阶贝塞尔曲线拟合1/4圆


根据贝塞尔曲线的知识,我们知道三阶贝塞尔曲线的参数方程如下,其中A、B、C、D为四个控制点坐标,P(t)表示曲线上的每一点。



因为要模拟1/4圆,所以通过P(0)和P(1)的切线方向,应该按照下图所示位置安放。

其中AB为水平方向,DC为垂直方向,并且线段长度|AB| = |DC| = h。

三阶贝塞尔曲线拟合1/4圆_第1张图片

那么这个问题实际上,就转换为计算出合理的h值,使得半径|OJ| = 1,也即J点刚好在圆弧上。

三阶贝塞尔曲线拟合1/4圆_第2张图片

根据贝塞尔曲线的对称性,不难想出J点在P(0.5)处,代入公式即可求得:


同样的结论,也可以直接由贝塞尔曲线的几何图形特征来推定,也即:




所以也可以再次确认P(0.5)和J是同一点。


代入四个控制点坐标A(0, 1),B(h, 1),C(1, h)和D(1, 0),可以求解P(0.5)点坐标如下:

三阶贝塞尔曲线拟合1/4圆_第3张图片

根据圆形方程定义,可以拟出下面方程:


从而求解出h的值为:


所以,可以最终求解出三阶贝塞尔曲线模拟1/4圆的参数方程P(t)定义如下:


另一方面,该方程描述的曲线与真实1/4圆有多大差异呢?下面就针对这个问题进行数值求解。

采用t = 0.0到1.0,步进值0.01,求解每个点到原点的距离与半径1的差异。

[cpp]  view plain copy
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5.   
  6. double bezier3(double a, double b, double c, double d, double t)  
  7. {  
  8.     double nt = 1.0 - t;  
  9.     double nt2 = nt * nt;  
  10.     double nt3 = nt * nt * nt;  
  11.     double t2 = t * t;  
  12.     double t3 = t * t * t;  
  13.   
  14.     return (a * nt3 + b * 3.0 * nt2 * t + c * 3.0 * nt * t2 + d * t3);  
  15. }  
  16.   
  17. int main()  
  18. {  
  19.         double t, a;  
  20.         double d, e;  
  21.         double max_e = 0.0, min_e = 1.0;  
  22.   
  23.         double x, y;  
  24.         double h = (sqrt(2) - 1.0) * 4.0 / 3.0;  
  25.         for(t = 0.0; t < 1.01; t+=0.01)  
  26.         {  
  27.                 x = bezier3(0, h, 1, 1, t);  
  28.                 y = bezier3(1, 1, h, 0, t);  
  29.                 d = sqrt(x * x + y * y);  
  30.                 e = d - 1.0;  
  31.   
  32.                 a = atan2(y, x);  
  33.                 a = a * 180.0 / 3.1415926;  
  34.   
  35.                 if(max_e < e) max_e = e;  
  36.                 if(min_e > e) min_e = e;  
  37.                 printf("%4.1f, %f\n", a, e);  
  38.         }  
  39.         printf("max_e = %f, min_e = %f\n", max_e, min_e);  
  40.     return 0;  
  41. }  

输出结果如下:

[cpp]  view plain copy
  1. 90.0, 0.000000  
  2. 89.1, 0.000003  
  3. 88.1, 0.000010  
  4. 87.2, 0.000022  
  5. 86.2, 0.000037  
  6. 85.3, 0.000054  
  7. 84.4, 0.000073  
  8. 83.4, 0.000092  
  9. 82.5, 0.000113  
  10. 81.6, 0.000133  
  11. 80.7, 0.000153  
  12. 79.7, 0.000172  
  13. 78.8, 0.000190  
  14. 77.9, 0.000206  
  15. 77.0, 0.000221  
  16. 76.1, 0.000234  
  17. 75.2, 0.000246  
  18. 74.3, 0.000255  
  19. 73.4, 0.000263  
  20. 72.5, 0.000268  
  21. 71.6, 0.000271  
  22. 70.7, 0.000273  
  23. 69.8, 0.000272  
  24. 68.9, 0.000269  
  25. 68.0, 0.000265  
  26. 67.1, 0.000259  
  27. 66.2, 0.000251  
  28. 65.3, 0.000242  
  29. 64.4, 0.000232  
  30. 63.5, 0.000220  
  31. 62.6, 0.000208  
  32. 61.8, 0.000194  
  33. 60.9, 0.000181  
  34. 60.0, 0.000166  
  35. 59.1, 0.000152  
  36. 58.2, 0.000137  
  37. 57.3, 0.000123  
  38. 56.5, 0.000108  
  39. 55.6, 0.000094  
  40. 54.7, 0.000081  
  41. 53.8, 0.000068  
  42. 52.9, 0.000056  
  43. 52.0, 0.000045  
  44. 51.2, 0.000035  
  45. 50.3, 0.000026  
  46. 49.4, 0.000018  
  47. 48.5, 0.000012  
  48. 47.6, 0.000007  
  49. 46.8, 0.000003  
  50. 45.9, 0.000001  
  51. 45.0, 0.000000  
  52. 44.1, 0.000001  
  53. 43.2, 0.000003  
  54. 42.4, 0.000007  
  55. 41.5, 0.000012  
  56. 40.6, 0.000018  
  57. 39.7, 0.000026  
  58. 38.8, 0.000035  
  59. 38.0, 0.000045  
  60. 37.1, 0.000056  
  61. 36.2, 0.000068  
  62. 35.3, 0.000081  
  63. 34.4, 0.000094  
  64. 33.5, 0.000108  
  65. 32.7, 0.000123  
  66. 31.8, 0.000137  
  67. 30.9, 0.000152  
  68. 30.0, 0.000166  
  69. 29.1, 0.000181  
  70. 28.2, 0.000194  
  71. 27.4, 0.000208  
  72. 26.5, 0.000220  
  73. 25.6, 0.000232  
  74. 24.7, 0.000242  
  75. 23.8, 0.000251  
  76. 22.9, 0.000259  
  77. 22.0, 0.000265  
  78. 21.1, 0.000269  
  79. 20.2, 0.000272  
  80. 19.3, 0.000273  
  81. 18.4, 0.000271  
  82. 17.5, 0.000268  
  83. 16.6, 0.000263  
  84. 15.7, 0.000255  
  85. 14.8, 0.000246  
  86. 13.9, 0.000234  
  87. 13.0, 0.000221  
  88. 12.1, 0.000206  
  89. 11.2, 0.000190  
  90. 10.3, 0.000172  
  91.  9.3, 0.000153  
  92.  8.4, 0.000133  
  93.  7.5, 0.000113  
  94.  6.6, 0.000092  
  95.  5.6, 0.000073  
  96.  4.7, 0.000054  
  97.  3.8, 0.000037  
  98.  2.8, 0.000022  
  99.  1.9, 0.000010  
  100.  0.9, 0.000003  
  101. -0.0, 0.000000  
  102. 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软件,使得方便排版文章中使用的公式和曲线。

     (感谢原创作者)

你可能感兴趣的:(c/c++,算法,曲线)