eryar

PipeCAD - Plant Piping Design Software.
RvmTranslator - Translate AVEVA RVM to OBJ, glTF, etc.
posts - 603, comments - 590, trackbacks - 0, articles - 0

Bézier Curve

Posted on 2011-11-20 15:18 eryar 阅读(4375) 评论(0)  编辑 收藏 引用 所属分类: 2.OpenCASCADE

在产品零件设计中,许多自由曲面是通过自由曲线来构造的。对于自由曲线的设计,设计人员经常需要大致勾画出曲线的形状,用户希望有一种方法能不再采用一般的代数描述,而采用直观的具有明显几何意义的操作,使得设计的曲线能够逼近曲线的形状。采用插值方法,用户设计的曲线形状不但受曲线上型值点的约束,而且受到边界条件影响,用户不能灵活调整曲线形状。但在产品设计中,曲线的设计是经过多次修改和调整来完成的,已有的方法完成这样的功能并不容易。Bézier方法的出现改善了上述设计方法的不足,使用户能方便地实现曲线形状的修改。

一、Bézier曲线定义

1. 定义:用基函数表示的Bézier曲线为

clip_image002 clip_image004

Bernstein基函数:

clip_image006

N=3时,即特征多边形有四个顶点,由上式可得到三次Bernstein基函数:

clip_image008

因此根据定义可把三次Bézier曲线表示为:

clip_image010

也可根据上式写成矩阵形式,有点类似二次型:

clip_image012

由上可知,只要给定特征多边形的四个顶点矢量P0P1P2P3,并得用上式即可构造一条三次Bézier曲线。只要改变t值即可计算曲线上的点。对于曲线设计来说,采用这种特征多边形顶点的方法比较方便、直观。

二、编程实现

利用OpenGL的glut库根据Bézier曲线定义来实现曲线的绘制,源程序如下:


程序运行结果如图1所示:

Bezier Curve by definition

图1 根据定义实现的Bézier曲线

可修改特征多边形顶点变量controlPoint来看看相应的Bézier曲线的变化。

三、Bézier曲线的递推算法

计算Bézier曲线上的点,可用Bézier曲线方程直接计算,但使用de Casteljau提出的递推算法则要简单得多。

Bézier曲线的Bernstein基函数的递推性质

clip_image002[4]

由于组合数的递推性:

clip_image004[4]

因此有

clip_image006[4]

为了保证公式可计算,我们约定:在以上公式中,凡当指标超出范围,以至记号不具有意义时,都应理解为零,如:

clip_image008[4]

根据Bézier曲线定义可知:

clip_image010[4]

这说明一条n次Bézier曲线可表示为分别由前后n个控制顶点决定的两条n-1次Bézier曲线的线性组合。由此可得Bézier曲线上某一点递归求值的de Casteljau算法:

clip_image012[4]

其中:

——clip_image014, 是定义Bézier曲线的控制点;

——clip_image016,即是曲线P(t)上具有参数t的点;

用这一递推公式在给定参数下,求Bézier曲线上一点P(t)非常有效。de Casteljau算法稳定可靠,直观简便,可以编写出十分简捷的程序,是计算Bézier曲线的基本算法和标准算法。

四、de Casteljau算法的程序实现

根据递推公式可写出Bézier曲线的递归算法,如下:

/*
*/
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
.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所示:

Bezier Curve Comparation

图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);

glLoadIdentity();

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);

glEnd();

// draw control polygon

glColor3f(1.0, 0.0, 1.0f);

glBegin(GL_LINE_STRIP);

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);

glEnd();

} // 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) {

// initialize control points

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;

Point plotPoint[POINTS_NUM];

// 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] = PointOnBezierCurve(0,3,t);

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

}

glEnd();

// draw control points

glColor3f(1.0, 1.0, 1.0f);

glPointSize(6.0);

glBegin(GL_POINTS);

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);

glEnd();

// draw control polygon

glColor3f(0.0, 0.0, 1.0f);

glBegin(GL_LINE_STRIP);

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);

glEnd();

} // PlotBezierCurve

因此,根据递归算法绘制Bézier曲线的程序简单直观,便于把数学公式与程序对应。

Bezier Curve with different Control Points

图3 修改控制顶点后效果图


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理