左键绘制贝塞尔曲线(Bezier)-代码_OpenGL

在这里插入图片描述

一段话总结

  贝塞尔曲线 给出n+1个控制点,画出n阶曲线。一直按某个固定比例,在控制点的连线和其衍生连线上取点,直到最后一阶用该比例取到将绘制到曲线上的点。
  de Casteljau算法作图的原理就是,在0~1范围内选取比例,每一比例都会产出不同的点。相邻的控制点连线,然后在连线的t比例位置取点再连线,在连线的t比例上取得绘制点,这个绘制点就是本曲线在t比例的点啦。不过二阶Bezier曲线(三个控制点的)的取点才结束的这么快。如果说是三阶,在连线上按照t比例取点,此时还会有另一条同级别的衍生连线,同样的按t比例取点,两点相连,此时没有其他同级别的衍生线,本级别只有一条了!可以在上面取点了,咋取?还是按t比例取。
更高阶,相邻控制点之间的连线,衍生连线,衍生连线又衍生出衍生连线的衍生连线,生就完事了,每相邻的两条生一条,每一阶段衍生出来的线,会比上一阶段的线少一条,最后只衍生出一条线的阶段,就是取点的阶段了。四点生三条,三条生两条,两条生一条,画!五点生四条,四条生三条,三条生…哦哟,递推计算公式就是这个道理吗?

  用一下网上的图!非常感谢制作者啦!ddd

画法

bzr
  为了绘制一条线,我们要得到线上各点的坐标。
计算Bezier曲线每个点,需要的数据有:
1.比例t
2.Cxx多项式系数。项的数量取决于阶数,二阶有三项。 Cmn=n!/m!(n-m)!
3.BEN基函数{多项式系数Cin × ti× (1-t)n-i
4.各控制点坐标()。
  1和2是用在3里的,3.×4.,即控制点坐标×基函数,得一项,各项的数据都加上,就是把诸多后续衍生的连线计算进去,就是把每个控制点的影响算进去。得到本比例t的点P。
  然后呢,只需要改变t,t分的越细,越微,则取得的点越多,线越光滑。两点之间当然是用直线拟合啦。

代码

计算部分的代码是这里的
图形算法:贝塞尔曲线

#include<gl/glut.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
typedef struct {
	float x, y, z;
}point3D;

typedef struct {
	int length;
	int * arr;
}intArray;

typedef struct {
	int length;
	point3D * arr;
}pointArray;

//该方法接受经过计算的贝塞尔点,并对相邻两个点进行连线处理
void drawLine(pointArray &bezPts);

//此方法用来计算二项式系数
//接受一个数组对象的引用
void binomialCoefficient(intArray &C) {
	int j, n = C.length - 1;
	for (int k = 0; k <= n; k++) {
		C.arr[k] = 1;		/*  C上m下n=n!/m!(n-m)!   */
		for (j = n; j > k; j--)		/* j!/k! */
			C.arr[k] *= j;
		for (j = n - k; j > 1; j--) /* (n-k)! */
			C.arr[k] /= j;
	}
}

//此方法计算在比例t时点的坐标位置
//接受的第一个参数为规律u,第二个参数为将要存放位置点的指针,第三个参数为所有控制点坐标数组,第四个参数为系数数组)
void computeBezPt(float t, point3D &bezPt, pointArray &ctrlPts, intArray &C) {
	int n = ctrlPts.length - 1;
	float bezFcn;//保存贝塞尔方程计算结果
	bezPt.x = bezPt.y = bezPt.z = 0;//初始化
	for (int k = 0; k <= n; k++) {     /* Cxx 多项式系数 * t^i* (1-t)^( n-i)  */
		bezFcn = C.arr[k] * pow(t, k)*pow(1 - t, n - k);
		bezPt.x += ctrlPts.arr[k].x*bezFcn;
		bezPt.y += ctrlPts.arr[k].y*bezFcn;
		bezPt.z += ctrlPts.arr[k].z*bezFcn;
	}
}

//此方法为调用方法,用来产生贝塞尔曲线
//第一个参数用来接受控制点数组,第二个参数为精度,精度越高两个点之间的距离越小,但是需要的计算时间也就越长
void bezier(pointArray &ctrlPts, int precision) {
	intArray C;//阶数+1
	C.length = ctrlPts.length;
	C.arr = new int[C.length];
	binomialCoefficient(C);//计算系数

	pointArray bezPts;//保存计算点的参数
	bezPts.length = precision + 1;
	bezPts.arr = new point3D[bezPts.length];

	float t;//规律参数
	for (int k = 0; k <= precision; k++) {
		t = float(k) / float(precision);
		computeBezPt(t, bezPts.arr[k], ctrlPts, C);//每次计算一个点。t从0-1,把所有占比用上,曲线就完成啦
	}
	drawLine(bezPts);
	delete[] bezPts.arr;
	delete[] C.arr;
}
void drawLine(pointArray &bezPts) {
	glBegin(GL_LINE_STRIP);
	for (int i = 0; i < bezPts.length; i++) {
		glVertex3f(bezPts.arr[i].x, bezPts.arr[i].y, bezPts.arr[i].z);
	}
	glEnd();
}

/***************************************/
static pointArray ctrlPts_;
static bool readyToDraw = false;
bool bInput, accept, bDraw;
const int MAX_CPTS = 13;
GLfloat clickPts[MAX_CPTS][3];
int ncpts = 0;
static int width = 500, height = 500;

void PointGL(int i) {
	glPointSize(2);
	glBegin(GL_POINTS);
	glColor3f(0.0f, 0.0f, 0.0f);
	glVertex2f(clickPts[i][0], clickPts[i][1]);
	glEnd();
}
void coolTransform() {

	int length = ncpts;
	point3D *ctrlPts;
	ctrlPts = (point3D *)malloc(length * sizeof(point3D));
	for (int i = 0; i < ncpts; i++) {
		ctrlPts[i].x = clickPts[i][0];
		ctrlPts[i].y = clickPts[i][1];
		ctrlPts[i].z = clickPts[i][2];
	}
	ctrlPts_.arr = ctrlPts;
	ctrlPts_.length = ncpts;

}
void mouse(int button, int state, int x, int y) {
	float wx, wy;
	if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN)
		return;
	wx = x;
	wy = height-y;

	if (ncpts == MAX_CPTS)
		return;
	clickPts[ncpts][0] = wx;
	clickPts[ncpts][1] = wy;
	clickPts[ncpts][2] = 0.0;
	ncpts++;
	glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y) {
	switch (key) {
	case 'q': case'Q':
		exit(1);
		break;
	case 'c':case'C':
		ncpts = 0;
		readyToDraw = false;
		glutPostRedisplay();
		break;
	case 'd':case'D':
		readyToDraw = true;
		coolTransform();
		glutPostRedisplay();
		break;
	default:
		break;
	}
}
void displayFcn(void) {
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1, 0, 0);
	if (readyToDraw)
		bezier(ctrlPts_, 100);
	if (ncpts > 0)
		for (int i = 0; i < ncpts; i++) {
			PointGL(i);
		}
	glFlush();
}
int main(int argc, char* argv[]) {

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(50, 50);
	glutInitWindowSize(width, height);
	glutCreateWindow("bezier curve_左键取点,按D绘制,按C清空,按Q退出");
	glClearColor(1, 1, 1, 0);
	glMatrixMode(GL_PROJECTION);
	gluOrtho2D(0, width, 0, height);
	glutDisplayFunc(displayFcn);
	glutKeyboardFunc(keyboard);
	glutMouseFunc(mouse);
	glutMainLoop();
	return 0;
}
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值