贝塞尔曲线的绘制方法

         两年前调试全向轮底盘的时候,曾经用到过贝塞尔曲线做路径规划。今天同学突然问起这个东西,回查了一下当时的代码,觉得有必要写个博客备忘一下。

         在数学的数值分析领域中,贝塞尔曲线是计算机图形学中相当重要的参数曲线。更高维度的广泛化贝济埃曲线就称作贝济埃曲面,其中贝济埃三角是一种特殊的实例。

         贝塞尔曲线于1962年,由法国工程师皮埃尔·贝济埃(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由Paul de Casteljau于1959年运用de Casteljau算法开发,以稳定数值的方法求出贝塞尔曲线。

        接下来简单介绍贝塞尔曲线的绘制方法。如下图,假设给定了控制点P0,P1,P2。这里我们需要做辅助点Q0和Q1,使得:

P0Q0:P0P1=P1Q1:P1P2=t,这里0≤t≤1。现在,我们可以简单理解为三个控制点P0,P1,P2  “降维”  成了两个控制点Q0,Q1。按照同样的方法,再取辅助点B使得Q0B:Q0Q1=t,这里的 t 和上次 "降维"时的 t 是相等的。现在,我们已经降维成了只有一个点,那么这个点B就是该贝塞尔曲线中的一点

                           

        推广一下,我们考虑多个控制点的情景。对于4、5、6。。。n个控制点,首先选定一个比例 t ,以此按比例降维直到只有一个点,这个点就是比例 t 时贝塞尔曲线上的点。当把 t 从0到1按照一定比例依次选取时,就能绘制出一个贝塞尔曲线。

                        

          六个控制点的情形:

                                                               

根据之前的描述,绘制贝塞尔曲线的过程可以用如下公式表述:

式中,j是降了多少次维,i是第i个控制点。由于每降维一次,控制点就减少一个,所以i的取值范围是(0,n-j)。

C#程序如下:

        //==========================根据t获取贝塞尔曲线上一个点===========================
        const int ControlPointNum = 10 ; //控制点数目
        Point[] ControlPoint = new Point[ControlPointNum]; //控制点
        Point[] WorkPoint = new Point[ControlPointNum];  //一块用于存放临时数据的空间
        /// <summary>
        /// 获取本轮计算终点坐标
        /// </summary>
        /// <param name="t">贝塞尔曲线生成过程中的百分比</param>
        /// <param name="n">本层迭代控制点数目</param>
        /// <returns></returns>
        Point GetFinalPoint(double t, int n)
        {
            if (n == 1)
            {
                return WorkPoint[0];
            }
            else
            {
                //计算下一阶的贝塞尔控制点
                for (int i = 0; i < n - 1; i++)
                {
                    WorkPoint[i].X = (int)(WorkPoint[i].X * (1 - t) + WorkPoint[i + 1].X * t);
                    WorkPoint[i].Y = (int)(WorkPoint[i].Y * (1 - t) + WorkPoint[i + 1].Y * t);
                }
                //进入下一层
                return GetFinalPoint(t, n - 1);
            }
        }
 //==========================根据t绘制曲线======================================
            for(int i=0;i<256;i++)
            {
                for (int j = 0; j < ControlPointNum; j++)//赋值控制点坐标至临时工作空间
                {
                    WorkPoint[j] = ControlPoint[j];
                }
                double t = (double)i/255.0;
                Point FinalPoint = GetFinalPoint(t,ControlPointNum);
                DrawPoint(FinalPoint);                  //调用绘图函数
            }

效果:

                                                        

猜你喜欢

转载自blog.csdn.net/pofeiren1069/article/details/82889300
今日推荐