Computer graphics - Experiment: Bezier Curve

This blog is based on the course "computer graphics", and the textbook is Computer graphics (4th Edition) [Computer Graphics with OpenGL, Fourth Edition] , some code templates come from this textbook and have been changed

Experimental ideas

Code ideas

  1. Void binomialcoeffs() function calculates the binomial coefficient, the number n of incoming points and the record array;
  2. The void computerBezPt() function calculates the coordinate position of the Bezier curve along the curve path; Input scale coefficient, point coordinate, control points, control point coordinate, binomial coefficient. In the function, for the sake of safety, first assign the point coordinates to 0, and then traverse each control point to calculate the x and y coordinates of the point affected by each control point each time in the cycle
  3. void Draw_ In the bezier() function, binomial coefficients are calculated by calling binomial coeffs() according to the passed in parameters, and then coordinates of each placed pixel are calculated by calling computerBezPt(). After calculating the coordinates in the loop, pixels are placed through GL_LINE_STRIP drawing mode can be connected into a curve
  4. The highlightctrlpt() function is used to generate a larger point, that is, a small rectangle, to represent the control point. Only GL is needed_ Polygon drawing mode, add or subtract a certain length from the x and y coordinates of the center point in turn.
  5. In the display() function, the first loop is used to generate the highlight of the control point, which is realized by calling the highghtctrlpt() function; Use the gllinestaple() function to draw the dotted line between the start point, control point and end point; The third loop is used to draw the Bezier curve by calling Draw_Bezier() function implementation

Problems and Solutions

  1. In highlightctrlpt(), use GL_POLYGON drawing mode: when drawing a filled polygon, the order of placing pixels is clockwise or counterclockwise, that is, the polygon is formed and filled according to the order of placing points
  2. Set the prototype of the linetype function glLineStipple() to void gllinestipple (glint factor, glushort pattern); Pattern: it is a 16 bit sequence composed of 1 or 0 (0x3F07 to binary 0011111100000111). Starting from the low order of this mode, it is processed pixel by pixel. If the corresponding bit in the model is 1, the pixel is drawn, otherwise it is not drawn. Factor: it is a repetition factor, which is multiplied by the continuous subsequences of 1 and 0. If there are 3 1's in the pattern and the factor is 2, it will be expanded to 6 continuous 1's

Implementation code

Core code and key step notes

void binomialCoeffs(int n, int* c) {
	int k, j;
	for (k = 0; k <= n; k++) {
		c[k] = 1;
		for (j = n; j >= k + 1; j--)
			c[k] *= j;
		for (j = n - k; j >= 2; j--)
			c[k] /= j;
	}
}
void computerBezPt(float u, CPoint2D* bezPt, int nctrl, CPoint2D* ctrlPts, int* c) {
	int k, n = nctrl - 1;
	float bezBlendFcn;
	bezPt->x = bezPt->y = 0.0;
	for (k = 0; k < nctrl; k++) {
		bezBlendFcn = c[k] * pow(u, k) * pow(1 - u, n - k);
		bezPt->x += ctrlPts[k].x * bezBlendFcn;
		bezPt->y += ctrlPts[k].y * bezBlendFcn;
	}
}
void highightCtrlPt(int x, int y) {
	glBegin(GL_POLYGON);
	glVertex2f(x + 5, y);
	glVertex2f(x, y + 5);
	glVertex2f(x - 5, y);
	glVertex2f(x, y - 5);
	glEnd();
}

All codes

// ====== Computer Graphics Experiment #7 ======
// |              Bezier curve                 |
// =============================================
//
// Requirement:
// (1) Implement algorithm to draw Bezier curve.
// (2)Implement interactive method to specify
//     Bezier curve control points by mouse clicking.
// (3) Implement display callback function

#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
#include <windows.h>

// 2D point class
class CPoint2D {
public:
	float x, y;
};

int n_cp; // Number of control points
int ic_cp; // Control point counter
int i_cp; // Index of control point being moved
CPoint2D* control_points; // Coordinates of control points

// Program window size
int pw_width, pw_height;

int running_state;
// 0 --- Setting up control points.
// 1 --- Normal state.
// 2 --- Moving control point.
void binomialCoeffs(int n, int* c) {
	int k, j;
	for (k = 0; k <= n; k++) {
		c[k] = 1;
		for (j = n; j >= k + 1; j--)
			c[k] *= j;
		for (j = n - k; j >= 2; j--)
			c[k] /= j;
	}
}
void computerBezPt(float u, CPoint2D* bezPt, int nctrl, CPoint2D* ctrlPts, int* c) {
	int k, n = nctrl - 1;
	float bezBlendFcn;
	bezPt->x = bezPt->y = 0.0;
	for (k = 0; k < nctrl; k++) {
		bezBlendFcn = c[k] * pow(u, k) * pow(1 - u, n - k);
		bezPt->x += ctrlPts[k].x * bezBlendFcn;
		bezPt->y += ctrlPts[k].y * bezBlendFcn;
	}
}
// Draw Bezier curve
void Draw_Bezier(int nctrl, CPoint2D* cp, int m)
// nctrl  --- Number of control points
// cp --- Array of control points
// m  --- Number of subdivision
{
	// Write your code here
	int i;
	float u;
	CPoint2D bezier;
	int c[nctrl];
	binomialCoeffs(nctrl - 1, c);
	glBegin(GL_LINE_STRIP);
	glVertex2f(cp[0].x, cp[0].y);
	for (i = 0; i < m; i++) {
		u = (float)i / (float)m;
		computerBezPt(u, &bezier, nctrl, cp, c);
		glVertex2f(bezier.x, bezier.y);
	}
	glVertex2f(cp[nctrl - 1].x, cp[nctrl - 1].y);
	glEnd();
}
void highightCtrlPt(int x, int y) {
	glBegin(GL_POLYGON);
	glVertex2f(x + 5, y);
	glVertex2f(x, y + 5);
	glVertex2f(x - 5, y);
	glVertex2f(x, y - 5);
	glEnd();
}
// Display callback function
void display(void) {
	glClear(GL_COLOR_BUFFER_BIT);

	// Draw control points
	// Write your code here
	for (int i = 0; i < ic_cp; i++) {
		highightCtrlPt(control_points[i].x, control_points[i].y);
	}
	// Draw control graph
	// Write your code here
	glLineStipple(1, 0x0f0f);
	glBegin(GL_LINE_STRIP);
	for (int i = 0; i < ic_cp; i++) {
		glVertex2f(control_points[i].x, control_points[i].y);
	}
	glEnd();
	// Draw Bezier curve
	// Write your code here
	glLineStipple(1, 0xffff);
	if (ic_cp == n_cp)
		Draw_Bezier(n_cp, control_points, 1000);
	glutSwapBuffers();
}

// Mouse callback function
void mouse_func(int button, int state, int x, int y) {
	float dis;

	if (button == GLUT_LEFT_BUTTON) {
		if ((state == GLUT_DOWN) & (running_state == 0) & (ic_cp < n_cp)) {
			control_points[ic_cp].x = x;
			control_points[ic_cp].y = pw_height - y;
			ic_cp++;
			if (ic_cp == n_cp)
				running_state = 1;
			glutPostRedisplay();
		} else if ((state == GLUT_DOWN) & (running_state == 1)) {
			for (int i = 0; i < n_cp; i++) {
				dis = abs((x - control_points[i].x) * (x - control_points[i].x) + (pw_height - y - control_points[i].y) * (pw_height - y - control_points[i].y));
				if (dis < 10) {
					i_cp = i;
					running_state = 2;
					break;
				}
			}
		} else if ((state == GLUT_DOWN) & (running_state == 2)) {
			control_points[i_cp].x = x;
			control_points[i_cp].y = pw_height - y;
			glutPostRedisplay();
		} else if ((state == GLUT_UP) & (running_state == 2)) {
			running_state = 1;
		}
	}
}
// Mouse motion callback function
void motion_func(int x, int y) {

	if (running_state == 2) {
		control_points[i_cp].x = x;
		control_points[i_cp].y = pw_height - y;
		glutPostRedisplay();
	}
}
// Initialization function
void init(void) {
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glEnable(GL_LINE_STIPPLE);
}

// Reshape callback function
void reshape(int w, int h) {
	pw_width = w;
	pw_height = h;

	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, w, 0.0, h);
}

// Keyboard callback function
void keyboard(unsigned char key, int x, int y) {
	switch (key) {
	case 27:
		exit(0);
	}
}

// Main program entrance
int main(int argc, char* argv[]) {
	// Input number of control points
	printf("Number of control points = ");
	scanf("%d", &n_cp);
	if (n_cp < 2)
		return 1;
	control_points = new CPoint2D[n_cp];
	running_state = 0;
	ic_cp = 0;

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	glutInitWindowSize(800, 800);
	glutCreateWindow("Test Bижzier Curve");
	init();
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	glutMouseFunc(mouse_func);
	glutMotionFunc(motion_func);
	glutDisplayFunc(display);
	glutMainLoop();

	delete[] control_points;
	return 0;
}

Added by jjacquay712 on Mon, 10 Jan 2022 09:40:20 +0200