Bézier Curve

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

一、Bézier曲线定义

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

Bernstein基函数:

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

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

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

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

二、编程实现

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

// Bezier Curve Program

#include <gl\glut.h>

#define POINTS_NUM	100

// point structure
typedef struct SPoint{
	float	x;
	float	y;
}Point;

Point	ctrlPoint[4];

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	=	200.0;
	ctrlPoint[1].x	=	300.0;
	ctrlPoint[1].y	=	300.0;
	ctrlPoint[2].x	=	400.0;
	ctrlPoint[2].y	=	500.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

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

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

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

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

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

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

由于组合数的递推性:

因此有

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

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

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

其中:

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

——,即是曲线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所示:

图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曲线的程序简单直观,便于把数学公式与程序对应。

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

时间: 2025-01-19 15:24:39

B&eacute;zier Curve的相关文章

用C#绘制曲线图(Curve图,增加自动适应和多曲线绘制)

在N久之前,我发过一个绘制曲线的文章 先发个绘制曲线图的:用ASP.NET with C# 绘制曲线图 (Curve图) 里面介绍了简单的绘制曲线图的方法.近来重新翻阅了这篇文章.心情大好之下又重新修改了 一下绘制方法,增加自动适应数据的处理和可以根据传入的数据绘制多条曲线 照例先上图: 比以前Cool吧?呵呵,其实就是根据数据自动计算边距和字体等. /// <summary> /// 自动根据参数调整图像大小 /// </summary> public void Fit() {

ZBrush中Curve Mode功能的使用技巧

  Curve Mode主要有两大功能:修改模型的表面和添加模型. Curve Mode只是一个笔刷调板,展开Stroke面板就可以看到Curve Mode.它必须依附在模型上,所以在使用Curve Mode前要先建立一个多边形模型才可. 展开笔刷调板,下面这14个笔刷都是开启了Curve Mode的笔刷,他们的前缀都包含了Curve这个单词.这些是官方提供的Curvemode笔刷,小伙伴们也可以选择任何一个笔刷,然后开启Curvemode就变成了Curvemode笔刷了.

Make Helix Curve in OpenCASCADE

Make Helix Curve in OpenCASCADE eryar@163.com Abstract. OpenCASCADE does not provide helix curve directly, but you can build a helix curve by the pcurve of a surface(curve on surface). When you understand the pcurve of a surface, you can make a helix

java-JAVA-JHepWork数据拟合(curve fitting)报错:“/ is a folder”

问题描述 JAVA-JHepWork数据拟合(curve fitting)报错:"/ is a folder" import java.awt.Color; import java.util.*; import jhplot.*; import jhplot.stat.LinReg; public class ScanTest2 { public static void main(String[] args) { HPlot c1=new HPlot("cad");

OpenCASCADE Curve Length Calculation

OpenCASCADE Curve Length Calculation eryar@163.com Abstract. The natural parametric equations of a curve are parametric equations that represent the curve in terms of a coordinate-independent parameter, generally arc length s, instead of an arbitray

B-Spline Curve Library in Open Cascade

B-Spline Curve Library in Open Cascade Open Cascade中的B样条曲线库 eryar@163.com 摘要Abstract:简要介绍Open Cascade中的B样条曲线库BSplCLib的使用方法,并且结合源程序来对Open Cascade中的B样条曲线的组成部分如节点矢量.重复度等概念进行介绍,以及通过对计算B样条基函数的算法进行分析,加深对B样条曲线概念的理解. 关键字Key Word:B Spline Curve.Open Cascade.K

OPEN CASCADE BSpline Curve Interpolation

OPEN CASCADE BSpline Curve Interpolation eryar@163.com Abstract. Global curve interpolation to point data is a way to construct curves. The paper focus on the interpolate algorithm in OPEN CASCADE, and give a simple example to demonstrate the usage o

Convert BSpline Curve to Arc Spline in OpenCASCADE

Convert BSpline Curve to Arc Spline in OpenCASCADE eryar@163.com Abstract. The paper based on OpenCASCADE algorithms to approximate the NURBS curve to arc spline. The method is most useful in numerical control to drive the cutter along straight line

PCurve - Curve on Surface

PCurve - Curve on Surface eryar@163.com Abstract. 本文通过给出曲面上曲线PCurve的定义来对OpenCascade中的Curve On Surface进行理解,并介绍了OpenCascade对应的类BRep_CurveOnSurface实现.通过Tcl脚本输出的球的拓朴信息,分析PCurve的实际应用. Key words. OpenCascade, ACIS, PCurve, Curve on Surface, Parametric Surf