贝塞尔曲线(Bezier)

作者:追风剑情 发布于:2019-2-17 14:31 分类:Algorithms

几何作图法

几何作图法也称为de Casteljau算法,它利用了Bezier曲线的分割递推性实现Bezier曲线的绘制。

几何作图法的优点是直观性强,计算速度快。

9999.png(图1)

递推关系

888.png

上式含义是: 由点P0,P1,...,Pn所确定的n次Bezier曲线在点t的值,可以由点P0,P1,...,Pn-1所确定的n-1次Bezier曲线在点t的值,与由点P1,P2,...,Pn所确定的n-1次Bezier曲线在点t的值,通过递推关系的线性组合简单地求得。

n次Bezier曲线上控制点在t时的值P(t),可以归结为计算两个n-1次Bezier曲线在t时的值的线性组合,这一过程可以继续下去。图1中已知三次Bezier曲线的控制顶点P0,P1,P2,P3,递归计算先按t的比例在控制多边形各边上求得P0(1),P1(1),P2(1),再求得P0(2),P1(2),最后求得P0(3),即为P(t)对应的点。

示例:C#版——利用几何作图法算法实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BezierTest
{
    public class Bezier
    {
        /// <summary>
        /// 作图法算法实现
        /// </summary>
        /// <param name="P">控制点坐标</param>
        /// <param name="t">插值参数</param>
        /// <returns>返回曲线在参数t的坐标值</returns>
        public static Point Lerp(Point[] P, double t)
        {
            int m, i;//m 边数
            int n = P.Length; //n 控制点个数
            Point P0 = null;
            Point[] R, Q;
            R = new Point[n];
            Q = new Point[n];
            for (i = 0; i < n; i++)
            {
                R[i] = P[i];//将控制点坐标P保存于R中
                Q[i] = new Point();
            }
                
            //作n次外部循环,
            //每次循环都计算控制多边形上所有的m条边以参数t为分割比例的坐标值
            for(m=n-1; m > 0; m--)
            {
                //作m次内部循环,
                //每次循环计算控制多边形上一条边以参数t为分割比例的坐标值
                for(i=0; i <= m - 1; i++)
                {
                    //n次Bezier曲线在点t的值,可由两条n-1次bezier曲线
                    //在点t的值通过线性组合而求得
                    Q[i].x = R[i].x + t * (R[i+1].x - R[i].x);
                    Q[i].y = R[i].y + t * (R[i+1].y - R[i].y);
                }
                for (i = 0; i <= m - 1; i++)
                    R[i] = Q[i];
            }
            P0 = R[0];
            R = null;
            Q = null;
            return P0;
        }

        public class Point
        {
            public double x;
            public double y;
        }
    }
}
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace BezierTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public void PaintControlPoint(PaintEventArgs e, Bezier.Point[] P)
        {
            Graphics g = e.Graphics;
            Pen myPen = new Pen(Color.Red, 2);
            for(int i=0; i<P.Length; i++)
            {
                g.DrawEllipse(myPen, (float)P[i].x, (float)P[i].y, 3, 3);
            }
        }

        public void PaintCurvePoint(PaintEventArgs e, Bezier.Point[] P, double t)
        {
            Bezier.Point tp = Bezier.Lerp(P, t);

            Graphics g = e.Graphics;
            Pen myPen = new Pen(Color.Blue, 2);
            g.DrawEllipse(myPen, (float)tp.x, (float)tp.y, 1, 1);
            
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Bezier.Point[] P = new Bezier.Point[]
            {
                new Bezier.Point{ x=0, y=100},
                new Bezier.Point{ x=50, y=0},
                new Bezier.Point{ x=80, y=200},
                new Bezier.Point{ x=130, y=50},
                new Bezier.Point{ x=200, y=100},
            };

            PaintControlPoint(e, P);

            for (double t = 0; t <= 1; t += 0.02)
            {
                PaintCurvePoint(e, P, t);
            }
        }
    }
}


运行测试

红色为控制点,蓝色为曲线的插值点

55555.png7777.png

标签: Algorithms

Powered by emlog  蜀ICP备18021003号   sitemap

川公网安备 51019002001593号