天天看點

Bézier Curve

在産品零件設計中,許多自由曲面是通過自由曲線來構造的。對于自由曲線的設計,設計人員經常需要大緻勾畫出曲線的形狀,使用者希望有一種方法能不再采用一般的代數描述,而采用直覺的具有明顯幾何意義的操作,使得設計的曲線能夠逼近曲線的形狀。采用插值方法,使用者設計的曲線形狀不但受曲線上型值點的限制,而且受到邊界條件影響,使用者不能靈活調整曲線形狀。但在産品設計中,曲線的設計是經過多次修改和調整來完成的,已有的方法完成這樣的功能并不容易。Bézier方法的出現改善了上述設計方法的不足,使使用者能友善地實作曲線形狀的修改。

一、Bézier曲線定義

1. 定義:用基函數表示的Bézier曲線為

Bézier Curve

Bernstein基函數:

Bézier Curve

當N=3時,即特征多邊形有四個頂點,由上式可得到三次Bernstein基函數:

Bézier Curve

是以根據定義可把三次Bézier曲線表示為:

Bézier Curve

也可根據上式寫成矩陣形式,有點類似二次型:

Bézier Curve

由上可知,隻要給定特征多邊形的四個頂點矢量P0P1P2P3,并得用上式即可構造一條三次Bézier曲線。隻要改變t值即可計算曲線上的點。對于曲線設計來說,采用這種特征多邊形頂點的方法比較友善、直覺。

二、程式設計實作

利用OpenGL的glut庫根據Bézier曲線定義來實作曲線的繪制,源程式如下:

程式運作結果如圖1所示:

Bézier Curve

圖1 根據定義實作的Bézier曲線

可修改特征多邊形頂點變量controlPoint來看看相應的Bézier曲線的變化。

三、Bézier曲線的遞推算法

計算Bézier曲線上的點,可用Bézier曲線方程直接計算,但使用de Casteljau提出的遞推算法則要簡單得多。

Bézier曲線的Bernstein基函數的遞推性質

Bézier Curve

由于組合數的遞推性:

Bézier Curve

是以有

Bézier Curve

為了保證公式可計算,我們約定:在以上公式中,凡當名額超出範圍,以至記号不具有意義時,都應了解為零,如:

Bézier Curve

根據Bézier曲線定義可知:

Bézier Curve

這說明一條n次Bézier曲線可表示為分别由前後n個控制頂點決定的兩條n-1次Bézier曲線的線性組合。由此可得Bézier曲線上某一點遞歸求值的de Casteljau算法:

Bézier Curve

其中:

Bézier Curve
Bézier Curve

用這一遞推公式在給定參數下,求Bézier曲線上一點P(t)非常有效。de Casteljau算法穩定可靠,直覺簡便,可以編寫出十分簡捷的程式,是計算Bézier曲線的基本算法和标準算法。

四、de Casteljau算法的程式實作

根據遞推公式可寫出Bézier曲線的遞歸算法,如下:

.csharpcode, .csharpcode pre

{

font-size: small;

color: black;

font-family: consolas, "Courier New", courier, monospace;

background-color: #ffffff;

/*white-space: pre;*/

}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt

background-color: #f4f4f4;

width: 100%;

margin: 0em;

.csharpcode .lnum { color: #606060; }

其中,為了儲存資料的友善,控制頂點數組變量ctrlPoint為全局變量。

根據遞推算法實作Bézier曲線與根據定義實作的程式效果如下圖2所示:

Bézier Curve

圖2 圖中上面部分為用遞推算法實作,下面部分為用定義實作。

源程式如下:

// Bezier Curve Program

// File : BezierCurve.cpp

#include <gl\glut.h>

#define POINTS_NUM 100

// point structure

typedef struct SPoint{

float x;

float y;

}Point;

Point ctrlPoint[4]; // control point for recursive algorithm Bezier Curve

void Initialize(void);

void DrawScene(void);

void myReshape(GLsizei w, GLsizei h);

void PlotBezierCurveDirectly(void);

Point PointOnBezierCurve(int i, int k, float t);

void PlotBezierCurve(void);

void main(int argc, char* argv[]) {

glutInit(&argc, argv); // Initialize GLUT

glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); // Set display mode

glutInitWindowPosition(50,100); // Set top-left display window position

glutInitWindowSize(400, 300); // set display window width and height

glutCreateWindow("Bézier Curve"); // Create display window

Initialize(); // Execute initialization procedure

glutDisplayFunc(DrawScene); // Send graphics to display window

glutReshapeFunc(myReshape); //

glutMainLoop(); // Display everything and wait

/*

*/

void Initialize(void) {

//glClearColor(1.0, 1.0, 1.0, 0.0); // Set Display-window color to white

glMatrixMode(GL_PROJECTION); // Set projection parameters

glLoadIdentity();

gluOrtho2D(0.0, 200, 0.0, 150); //

} // Initialize

void myReshape(GLsizei w, GLsizei h) {

// Reset viewport and projection parameter

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

gluOrtho2D(0, w, 0, h);

glMatrixMode(GL_MODELVIEW);

} // myReshape

void DrawScene(void) {

glClear(GL_COLOR_BUFFER_BIT); // Clear display window

PlotBezierCurveDirectly();

PlotBezierCurve();

glFlush(); // Process all OpenGL routines as quickly possible

} // DrawScene

plot the Bezier Curve according to Definition.

void PlotBezierCurveDirectly(void) {

// Basis functions

#define B0(t) ((1.0 - t) * (1.0 - t) * (1.0 - t))

#define B1(t) (3.0 * t * (1.0 - t) * (1.0 - t))

#define B2(t) (3.0 * t * t * (1.0 - t))

#define B3(t) (t * t * t)

// initialize control points

Point controlPoint[4];

Point plotPoint[POINTS_NUM];

controlPoint[0].x = 100.0;

controlPoint[0].y = 100.0;

controlPoint[1].x = 300.0;

controlPoint[1].y = 200.0;

controlPoint[2].x = 400.0;

controlPoint[2].y = 200.0;

controlPoint[3].x = 600.0;

controlPoint[3].y = 100.0;

// calculate the points on the Bezier curve

glColor3f(1.0, 0.0, 0.0f); // set line segment geometry color to red

glBegin(GL_LINE_STRIP);

for (int i = 0; i < POINTS_NUM; ++i) {

float t = 1.0 * i / POINTS_NUM;

plotPoint[i].x = (B0(t) * controlPoint[0].x) +

(B1(t) * controlPoint[1].x) +

(B2(t) * controlPoint[2].x) +

(B3(t) * controlPoint[3].x);

plotPoint[i].y = (B0(t) * controlPoint[0].y) +

(B1(t) * controlPoint[1].y) +

(B2(t) * controlPoint[2].y) +

(B3(t) * controlPoint[3].y);

glVertex2f(plotPoint[i].x, plotPoint[i].y);

glEnd();

// draw control points

glColor3f(1.0, 1.0, 0.0f);

glPointSize(6.0);

glBegin(GL_POINTS);

glVertex2f(controlPoint[0].x, controlPoint[0].y);

glVertex2f(controlPoint[1].x, controlPoint[1].y);

glVertex2f(controlPoint[2].x, controlPoint[2].y);

glVertex2f(controlPoint[3].x, controlPoint[3].y);

// draw control polygon

glColor3f(1.0, 0.0, 1.0f);

} // PlotBezierCurveDirectly

Point PointOnBezierCurve(int i, int k, float t) {

if (k == 0) {

return ctrlPoint[i];

else {

Point point;

Point iPrev = PointOnBezierCurve(i, k-1, t);

Point iNext = PointOnBezierCurve(i+1, k-1, t);

point.x = (1.0 - t) * iPrev.x + t * iNext.x;

point.y = (1.0 - t) * iPrev.y + t * iNext.y;

return point;

} // PointOnBezierCurve

Use recursive algorithm to plot Bezier Curve.

void PlotBezierCurve(void) {

ctrlPoint[0].x = 100.0;

ctrlPoint[0].y = 300.0;

ctrlPoint[1].x = 300.0;

ctrlPoint[1].y = 400.0;

ctrlPoint[2].x = 400.0;

ctrlPoint[2].y = 400.0;

ctrlPoint[3].x = 600.0;

ctrlPoint[3].y = 300.0;

plotPoint[i] = PointOnBezierCurve(0,3,t);

glColor3f(1.0, 1.0, 1.0f);

glVertex2f(ctrlPoint[0].x, ctrlPoint[0].y);

glVertex2f(ctrlPoint[1].x, ctrlPoint[1].y);

glVertex2f(ctrlPoint[2].x, ctrlPoint[2].y);

glVertex2f(ctrlPoint[3].x, ctrlPoint[3].y);

glColor3f(0.0, 0.0, 1.0f);

} // PlotBezierCurve

是以,根據遞歸算法繪制Bézier曲線的程式簡單直覺,便于把數學公式與程式對應。

Bézier Curve

圖3 修改控制頂點後效果圖

繼續閱讀