天天看点

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 修改控制顶点后效果图

继续阅读