“[貝賽爾曲線](http://baike.baidu.com/view/4019466.htm)”是由法國數學家Pierre Bézier所發明,由此為計算機矢量圖形學奠定了基礎。它的主要意義在于無論是直線或曲線都能在數學上予以描述。貝塞爾曲線就是這樣的一條曲線,它是依據四個位置任意的點坐標繪制出的一條[光滑曲線](http://baike.baidu.com/view/1981214.htm)。
線性公式
給定點P0、P1,線性貝茲曲線只是一條兩點之間的直線。這條線由下式給出:

且其等同于線性插值。
##二次方公式
二次方貝茲曲線的路徑由給定點P0、P1、P2的函數B(t)追蹤:

TrueType字型就運用了以貝茲樣條組成的二次貝茲曲線。
## 三次方公式
P0、P1、P2、P3四個點在平面或在三維空間中定義了三次方貝茲曲線。曲線起始于P0走向P1,并從P2的方向來到P3。一般不會經過P1或P2;這兩個點只是在那里提供方向資訊。P0和P1之間的間距,決定了曲線在轉而趨進P3之前,走向P2方向的“長度有多長”。
曲線的參數形式為:

現代的成象系統,如PostScript、Asymptote和Metafont,運用了以貝茲樣條組成的三次貝茲曲線,用來描繪曲線輪廓。
## 一般參數公式
階貝茲曲線可如下推斷。給定點P0、P1、…、Pn,其貝茲曲線即:

如上公式可如下遞歸表達: 用表示由點P0、P1、…、Pn所決定的貝茲曲線。
用平常話來說,階的貝茲曲線,即雙階貝茲曲線之間的插值。
## 公式說明
1.開始于P0并結束于Pn的曲線,即所謂的端點插值法屬性。
2.曲線是直線的充分必要條件是所有的控制點都位在曲線上。同樣的,貝塞爾曲線是直線的充分必要條件是控制點共線。
3.曲線的起始點(結束點)相切于貝塞爾多邊形的第一節(最后一節)。
4.一條曲線可在任意點切割成兩條或任意多條子曲線,每一條子曲線仍是貝塞爾曲線。
5.一些看似簡單的曲線(如圓)無法以貝塞爾曲線精確的描述,或分段成貝塞爾曲線(雖然當每個內部控制點對單位圓上的外部控制點水平或垂直的的距離為時,分成四段的貝茲曲線,可以小于千分之一的最大半徑誤差近似于圓)。
6.位于固定偏移量的曲線(來自給定的貝塞爾曲線),又稱作偏移曲線(假平行于原來的曲線,如兩條鐵軌之間的偏移)無法以貝茲曲線精確的形成(某些瑣屑實例除外)。無論如何,現存的啟發法通常可為實際用途中給出近似值。
上述是百度百科中關于貝塞爾曲線的詳細描述,對于它的應用,最直觀的,就像PS里的鋼筆工具,今天,我將給出它的代碼實現:
1,貝塞爾類
~~~
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
namespace TestDemo
{
unsafe class Bezier
{
Point PointCubicBezier(Point[] cp, float t)
{
float ax, bx, cx, ay, by, cy, tS, tC;
cx = 1.0f * (cp[1].X - cp[0].X);
bx = 3.0f * (cp[2].X - cp[1].X) - cx;
ax = cp[3].X - cp[0].X - cx - bx;
cy = 1.0f * (cp[1].Y - cp[0].Y);
by = 3.0f * (cp[2].Y - cp[1].Y) - cy;
ay = cp[3].X - cp[0].Y - cx - by;
tS = t * t;
tC = tS * t;
int x = (int)((ax * tC) + (bx * tS) + (cx * t) + cp[0].X);
int y = (int)((ay * tC) + (by * tS) + (cy * t) + cp[0].Y);
return new Point(x, y);
}
public Bitmap DrawBezier(Bitmap src, Point[] cp)
{
Bitmap a = new Bitmap(src);
int w = a.Width;
int h = a.Height;
BitmapData srcData = a.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte* p = (byte*)srcData.Scan0;
float k = 0;
k = 1.0f / (w - 1);
Point temp;
for (int i = 0; i < w; i++)
{
temp = PointCubicBezier(cp, (float)i * k);
p[temp.X * 3 + temp.Y * srcData.Stride] = 0;
p[temp.X * 3 + 1 + temp.Y * srcData.Stride] = 0;
p[temp.X * 3 + 2 + temp.Y * srcData.Stride] = 0;
}
a.UnlockBits(srcData);
return a;
}
}
}
~~~
2,主界面代碼
~~~
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;
using System.Drawing.Imaging;
namespace TestDemo
{
unsafe public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
string startupPath = System.Windows.Forms.Application.StartupPath;
curBitmap = new Bitmap(startupPath + @"\mask.png");
//初始化
pa = new Point(button1.Location.X - pictureBox1.Location.X + 13, button1.Location.Y - pictureBox1.Location.Y + 11);
pb = new Point(button2.Location.X - pictureBox1.Location.X + 13, button2.Location.Y - pictureBox1.Location.Y + 11);
pc = new Point(button3.Location.X - pictureBox1.Location.X + 13, button3.Location.Y - pictureBox1.Location.Y + 11);
pd = new Point(button4.Location.X - pictureBox1.Location.X + 13, button4.Location.Y - pictureBox1.Location.Y + 11);
pictureBox1.Image = (Image)bezier.DrawBezier(curBitmap, new Point[] { pa, pb, pc, pd });
}
#region 變量聲明
//當前圖像變量
private Bitmap curBitmap = null;
private bool pointMoveStart = false;
private Point movePoint;
private Point pa;
private Point pb;
private Point pc;
private Point pd;
private Bezier bezier = new Bezier();
#endregion
#region Response
#endregion
#region MouseClick
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (pictureBox1.Image != null)
{
label1.Text = "X:" + e.X;
label2.Text = "Y:" + e.Y;
}
}
private void button1_MouseDown(object sender, MouseEventArgs e)
{
pointMoveStart = true;
if (e.Button == MouseButtons.Left)
movePoint = e.Location;
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && pointMoveStart)
{
button1.Location = new Point(button1.Location.X + e.X - movePoint.X, button1.Location.Y + e.Y - movePoint.Y);
}
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
pointMoveStart = false;
pa = new Point(button1.Location.X - pictureBox1.Location.X + 13, button1.Location.Y - pictureBox1.Location.Y + 11);
pb = new Point(button2.Location.X - pictureBox1.Location.X + 13, button2.Location.Y - pictureBox1.Location.Y + 11);
pc = new Point(button3.Location.X - pictureBox1.Location.X + 13, button3.Location.Y - pictureBox1.Location.Y + 11);
pd = new Point(button4.Location.X - pictureBox1.Location.X + 13, button4.Location.Y - pictureBox1.Location.Y + 11);
pictureBox1.Image = (Image)bezier.DrawBezier(curBitmap, new Point[] {pa, pb, pc, pd });
}
private void button2_MouseDown(object sender, MouseEventArgs e)
{
pointMoveStart = true;
if (e.Button == MouseButtons.Left)
movePoint = e.Location;
}
private void button2_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && pointMoveStart)
{
button2.Location = new Point(button2.Location.X + e.X - movePoint.X, button2.Location.Y + e.Y - movePoint.Y);
}
}
private void button2_MouseUp(object sender, MouseEventArgs e)
{
pointMoveStart = false;
pa = new Point(button1.Location.X - pictureBox1.Location.X + 13, button1.Location.Y - pictureBox1.Location.Y + 11);
pb = new Point(button2.Location.X - pictureBox1.Location.X + 13, button2.Location.Y - pictureBox1.Location.Y + 11);
pc = new Point(button3.Location.X - pictureBox1.Location.X + 13, button3.Location.Y - pictureBox1.Location.Y + 11);
pd = new Point(button4.Location.X - pictureBox1.Location.X + 13, button4.Location.Y - pictureBox1.Location.Y + 11);
pictureBox1.Image = (Image)bezier.DrawBezier(curBitmap, new Point[] { pa, pb, pc, pd });
}
private void button3_MouseDown(object sender, MouseEventArgs e)
{
pointMoveStart = true;
if (e.Button == MouseButtons.Left)
movePoint = e.Location;
}
private void button3_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && pointMoveStart)
{
button3.Location = new Point(button3.Location.X + e.X - movePoint.X, button3.Location.Y + e.Y - movePoint.Y);
}
}
private void button3_MouseUp(object sender, MouseEventArgs e)
{
pointMoveStart = false;
pa = new Point(button1.Location.X - pictureBox1.Location.X + 13, button1.Location.Y - pictureBox1.Location.Y + 11);
pb = new Point(button2.Location.X - pictureBox1.Location.X + 13, button2.Location.Y - pictureBox1.Location.Y + 11);
pc = new Point(button3.Location.X - pictureBox1.Location.X + 13, button3.Location.Y - pictureBox1.Location.Y + 11);
pd = new Point(button4.Location.X - pictureBox1.Location.X + 13, button4.Location.Y - pictureBox1.Location.Y + 11);
pictureBox1.Image = (Image)bezier.DrawBezier(curBitmap, new Point[] { pa, pb, pc, pd });
}
private void button4_MouseDown(object sender, MouseEventArgs e)
{
pointMoveStart = true;
if (e.Button == MouseButtons.Left)
movePoint = e.Location;
}
private void button4_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && pointMoveStart)
{
button4.Location = new Point(button4.Location.X + e.X - movePoint.X, button4.Location.Y + e.Y - movePoint.Y);
}
}
private void button4_MouseUp(object sender, MouseEventArgs e)
{
pointMoveStart = false;
pa = new Point(button1.Location.X - pictureBox1.Location.X + 13, button1.Location.Y - pictureBox1.Location.Y + 11);
pb = new Point(button2.Location.X - pictureBox1.Location.X + 13, button2.Location.Y - pictureBox1.Location.Y + 11);
pc = new Point(button3.Location.X - pictureBox1.Location.X + 13, button3.Location.Y - pictureBox1.Location.Y + 11);
pd = new Point(button4.Location.X - pictureBox1.Location.X + 13, button4.Location.Y - pictureBox1.Location.Y + 11);
pictureBox1.Image = (Image)bezier.DrawBezier(curBitmap, new Point[] { pa, pb, pc, pd });
}
#endregion
}
}
~~~
結果圖如下:


最后給出完整C#代碼DEMO:[點擊打開鏈接](http://www.zealpixel.com/portal.php?mod=view&aid=134)
? ? ? ?跟大家分享一下,希望大家喜歡!