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