天天看點

Bezier

#pragma comment( linker, "/subsystem:windows /entry:mainCRTStartup" )//去除控制台視窗
#include <iostream>
#include <gl/GLUT.h>
#include <map>
#include <vector>
#include<cmath>
#include <list>
#include <algorithm>
using namespace std;

struct Point {
	float x, y;
	Point(float _x, float _y) :x(_x), y(_y) {}
	Point() {}
	void operator =(Point& r) {
		x = r.x; y = r.y;
	}
	Point operator+(Point p)
	{
		return Point(this->x + p.x, this-> y + p.y);
	}
};

Point P[1000];
vector<Point> v;
int choice_id = -1;
int window_size = 800;
float XL=200, XR=600, YB=200, YT=600;

//void green_line(Point a, Point b);
void control_polygon();
void draw_rp(float x, float y);
void OnMouse(int button, int state, int x, int y);
void InitEnvironment();
void myMotion(int x, int y);
void deCasteljau();

int main(int argc, char* argv[]) {
	glutInit(&argc, argv);   //初始化GLUT
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(300, 100);
	glutInitWindowSize(window_size, window_size);
	glutCreateWindow("Bezier");
	InitEnvironment();   //初始化
	glutMotionFunc(&myMotion);   //回調函數
	glutMouseFunc(&OnMouse);  //注冊滑鼠事件
	glutMainLoop();    //持續顯示,當視窗改變會重新繪制圖形

	return 0;
}

void InitEnvironment() {
	glClearColor(0.0, 0.0, 0.0, 1);
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glPointSize(6);
	glLineWidth(3);
	gluOrtho2D(0, window_size, 0, window_size);
	
}

void myMotion(int x, int y) {
	if (choice_id != -1) {
		v[choice_id].x = float(x);
		v[choice_id].y = float(y);
		deCasteljau();
	}
}

void draw_rp(float x, float y) {
	glBegin(GL_POINTS);
	glColor3f(1, 0, 0);
	glVertex2f(x, window_size - y);
	glEnd();
	glFlush();
}
void OnMouse(int button, int state, int x, int y)
//OnMouse坐标系x從左向右,y從上到下
{
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
		choice_id = -1;
		int t = v.size();
		draw_rp(x, y);
		for (int i = 0; i < t; i++) {
			if (abs(x - v[i].x) < 8 && abs(y - v[i].y) < 8) {//選中一個點
				choice_id = i; return;
			}
		}
		v.push_back(Point(x, y));
		deCasteljau();

	}
	else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN )
	{   //點選右鍵,選擇頂點删除
		int t = v.size();
		for (int i = 0; i < t; i++) {
			if (abs(x - v[i].x) < 8 && abs(y - v[i].y) < 8) {//選中一個點
				for(int j = i; j < v.size()-1; j++)v[j] = v[j + 1];
				v.pop_back();
				deCasteljau();
				break;
			}
		}
		
	}
}

void deCasteljau() {
	glClear(GL_COLOR_BUFFER_BIT);
	vector<Point>res;
	int n = v.size() - 1;
	for (int i = 0; i <=n; i++) {P[i] = v[i];}
	for(float t=0.0;t<=1;t=t+0.01){
		for (int i = n-1; i >= 0;i--) {
			for (int j = 0; j <= i; j++) {
				P[j].x = (1 - t) * P[j].x + t * P[j + 1].x;
				P[j].y = (1 - t) * P[j].y + t * P[j + 1].y;
			}
		}
		res.push_back(P[0]);
	}

	glBegin(GL_LINES);//多次調用畫圖的話,容易閃爍,這裡開頭調用一遍就夠了
	glColor3f(0, 1, 0);
	for (int i = 0; i < res.size()-1; i++){
		glVertex2f(res[i].x, window_size - res[i].y);
		glVertex2f(res[i+1].x, window_size - res[i + 1].y);
	}
	glEnd();
	glFlush();

	control_polygon();
}

void control_polygon() {
	int n = v.size()-1;
	
	glBegin(GL_LINES);
	for (int i = 0; i <=n-1; i++) {
		glColor3f(0, 0, 1);
		glVertex2f(v[i].x, window_size - v[i].y);
		glVertex2f(v[i + 1].x, window_size - v[i + 1].y);
		/*if (i <=n-2) {
			glColor3f(0.5, 0.5, 0.5);
			glVertex2f(v[i].x, window_size - v[i].y);
			glVertex2f(v[i + 2].x, window_size - v[i + 2].y);
		}*/
	}
	glEnd();
	glFlush();
	for (int i = 0; i <= n; i++) {//點和線不能交叉使用
		draw_rp(v[i].x, v[i].y);
	}
}
           

繼續閱讀