#include<GL/glut.h>
#include<iostream>
#include<iterator>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
const int window_size = 600;
int last_x=-1, last_y=-1;
struct point {
int x, y;
};
struct node {
float x, ymax, delta_x;
bool operator < (const node &b) const {
if (x != b.x) {
return x < b.x;
}
else if(ymax!=b.ymax){
return ymax < b.ymax;
}
else {
return delta_x < b.delta_x;
}
}
};
set<node> AET, NET[window_size];
vector<node> temp;
vector<point> Vertexs;
int Y_MIN, Y_MAX;
void drawline(int x0,int y0,int x1,int y1) {
glColor3ub(25,160,95);
glBegin(GL_LINES);
glVertex2f(x0, y0);
glVertex2f(x1, y1);
glEnd();
glFlush();
}
void polyfill() {
//找ymin和ymax
int len = Vertexs.size();
for (int i = 0; i < len; i++) {
if (Vertexs[i].y > Y_MAX) Y_MAX = Vertexs[i].y;
if (Vertexs[i].y < Y_MIN)Y_MIN = Vertexs[i].y;
}
//初始化NET
for (int i = Y_MIN; i <= Y_MAX; i++) {
for (int j = 0; j < len; j++) {
if (Vertexs[j].y == i) {
cout << "当前的i是" << i << endl;
if (Vertexs[(j + len - 1) % len].y > Vertexs[j].y) {
float y_max = Vertexs[(j + len - 1) % len].y;
float x = Vertexs[j].x;
float dx = Vertexs[(j + len - 1) % len].x - Vertexs[j].x;
float dy = Vertexs[(j + len - 1) % len].y - Vertexs[j].y;
cout << "插入1" << endl;
NET[i].insert({ x,y_max,dx / dy });
}
if (Vertexs[(j + 1) % len].y > Vertexs[j].y) {
float y_max = Vertexs[(j + 1) % len].y;
float x = Vertexs[j].x;
float dx = Vertexs[(j + 1) % len].x - Vertexs[j].x;
float dy = Vertexs[(j + 1) % len].y - Vertexs[j].y;
NET[i].insert({ x,y_max,dx / dy });
cout << "插入2" << endl;
}
}
}
}
//AET
for (int i = Y_MIN; i <= Y_MAX; i++) {
//将NET[i]中的边结点用插入排序法插入AET,使之按x坐标递增顺序排列。
set<node>::iterator it = NET[i].begin();
for (; it != NET[i].end(); it++) {
AET.insert({it->x,it->ymax,it->delta_x});
cout << "当前的i是" << i << " ,插入了一次" << endl;
cout << "现在有" << AET.size() << "条活性边" << endl;
}
//删除ymax==i的节点
it = AET.begin();
for (; it != AET.end();) {
if (it->ymax == i) {
AET.erase(it++);
cout << "当前的i是" << i << " ,删除了一次" << endl;
cout << "现在有" << AET.size() << "条活性边" << endl;
}
else { it++; }
}
//匹配画线
it = AET.begin();
while (it != AET.end()) {
float x0 = it->x;
it++;
float x1 = it->x;
drawline(x0, i, x1, i);
it++;
}
//增量
temp.clear();
it = AET.begin();
for (; it != AET.end();) {
float x = it->x + it->delta_x;
float y = it->ymax;
float delta_x = it->delta_x;
AET.erase(it++);
temp.push_back({ x,y,delta_x });
}
for (int i = 0; i < temp.size(); i++) {
AET.insert(temp[i]);
}
}
}
void mymouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
Vertexs.push_back({ x,y });
cout << "顶点的坐标为(" << x << "," << y << ")" << endl;
glPointSize(5);
glColor3ub(211, 79, 67);
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
glFlush();
if (last_x > 0 && last_y > 0) {
glColor3ub(75, 140, 255);
glBegin(GL_LINES);
glVertex2i(x, y);
glVertex2i(last_x, last_y);
glEnd();
glFlush();
}
last_x = x, last_y = y;
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
polyfill();
}
}
void mykeyboard(unsigned char key, int x, int y) {
if (key == 'f' && Vertexs.size()) {
glBegin(GL_LINES);
glVertex2i(last_x, last_y);
glVertex2i(Vertexs[0].x, Vertexs[0].y);
glEnd();
glFlush();
}
if (key == 'c') {
cout << "按下了c键" << endl;
AET.clear();
for (int i = 0; i < window_size; i++) {
NET[i].clear();
}
Vertexs.clear();
temp.clear();
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
last_x = -1, last_y = -1;
glFlush();
}
}
void myDisplay() {
cout << "调用了一次回调函数" << endl;
}
void init() {
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluOrtho2D(0, window_size, window_size, 0);
Y_MIN = window_size; Y_MAX = 0;
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(300, 100);
glutInitWindowSize(window_size, window_size);
glutCreateWindow("扫描线填充多边形");
init();
glutMouseFunc(mymouse);
glutKeyboardFunc(mykeyboard);
glutDisplayFunc(myDisplay);
glutMainLoop();
return 0;
}
含内环的多边形
#include<GL/glut.h>
#include<iostream>
#include<iterator>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
const int window_size = 600,maxhole=255;
int poly_number = -1;
int last_x=-1, last_y=-1;
struct point {
int x, y;
};
struct node {
float x, ymax, delta_x;
bool operator < (const node &b) const {
if (x != b.x) {
return x < b.x;
}
else if(ymax!=b.ymax){
return ymax < b.ymax;
}
else {
return delta_x < b.delta_x;
}
}
};
set<node> AET, NET[window_size];
vector<node> temp;
vector<point> Vertexs[255];
int Y_MIN, Y_MAX;
void drawline(int x0,int y0,int x1,int y1) {
glColor3ub(25,160,95);
glBegin(GL_LINES);
glVertex2f(x0, y0);
glVertex2f(x1, y1);
glEnd();
glFlush();
}
void polyfill() {
//找ymin和ymax
for (int k = 0; k <= poly_number; k++) {
int len = Vertexs[k].size();
for (int i = 0; i < len; i++) {
if (Vertexs[k][i].y > Y_MAX) Y_MAX = Vertexs[k][i].y;
if (Vertexs[k][i].y < Y_MIN)Y_MIN = Vertexs[k][i].y;
}
}
//初始化NET
for (int i = Y_MIN; i <= Y_MAX; i++) {
for (int k = 0; k <= poly_number; k++) {
int len = Vertexs[k].size();
for (int j = 0; j < len; j++) {
if (Vertexs[k][j].y == i) {
cout << "当前的i是" << i << endl;
if (Vertexs[k][(j + len - 1) % len].y > Vertexs[k][j].y) {
float y_max = Vertexs[k][(j + len - 1) % len].y;
float x = Vertexs[k][j].x;
float dx = Vertexs[k][(j + len - 1) % len].x - Vertexs[k][j].x;
float dy = Vertexs[k][(j + len - 1) % len].y - Vertexs[k][j].y;
cout << "插入1" << endl;
NET[i].insert({ x,y_max,dx / dy });
}
if (Vertexs[k][(j + 1) % len].y > Vertexs[k][j].y) {
float y_max = Vertexs[k][(j + 1) % len].y;
float x = Vertexs[k][j].x;
float dx = Vertexs[k][(j + 1) % len].x - Vertexs[k][j].x;
float dy = Vertexs[k][(j + 1) % len].y - Vertexs[k][j].y;
NET[i].insert({ x,y_max,dx / dy });
cout << "插入2" << endl;
}
}
}
}
}
//AET
for (int i = Y_MIN; i <= Y_MAX; i++) {
//将NET[i]中的边结点用插入排序法插入AET,使之按x坐标递增顺序排列。
set<node>::iterator it = NET[i].begin();
for (; it != NET[i].end(); it++) {
AET.insert({it->x,it->ymax,it->delta_x});
cout << "当前的i是" << i << " ,插入了一次" << endl;
cout << "现在有" << AET.size() << "条活性边" << endl;
}
//删除ymax==i的节点
it = AET.begin();
for (; it != AET.end();) {
if (it->ymax == i) {
AET.erase(it++);
cout << "当前的i是" << i << " ,删除了一次" << endl;
cout << "现在有" << AET.size() << "条活性边" << endl;
}
else { it++; }
}
//匹配画线
it = AET.begin();
while (it != AET.end()) {
float x0 = it->x;
it++;
float x1 = it->x;
drawline(x0, i, x1, i);
it++;
}
//增量
temp.clear();
it = AET.begin();
for (; it != AET.end();) {
float x = it->x + it->delta_x;
float y = it->ymax;
float delta_x = it->delta_x;
AET.erase(it++);
temp.push_back({ x,y,delta_x });
}
for (int i = 0; i < temp.size(); i++) {
AET.insert(temp[i]);
}
}
}
void mymouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
if (last_x == -1 && last_y == -1) {
poly_number++;
}
Vertexs[poly_number].push_back({ x,y });
cout << "顶点的坐标为(" << x << "," << y << ")" << endl;
glPointSize(5);
glColor3ub(211, 79, 67);
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
glFlush();
if (last_x > 0 && last_y > 0) {
glColor3ub(75, 140, 255);
glBegin(GL_LINES);
glVertex2i(x, y);
glVertex2i(last_x, last_y);
glEnd();
glFlush();
}
last_x = x, last_y = y;
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
polyfill();
}
}
void mykeyboard(unsigned char key, int x, int y) {
if (key == 'f' && Vertexs[poly_number].size()) {
glBegin(GL_LINES);
glVertex2i(last_x, last_y);
glVertex2i(Vertexs[poly_number][0].x, Vertexs[poly_number][0].y);
glEnd();
glFlush();
last_x = -1, last_y = -1;
}
if (key == 'c') {
cout << "按下了c键" << endl;
AET.clear();
for (int i = 0; i < window_size; i++) {
NET[i].clear();
}
for (int i = 0; i <= poly_number; i++) {
Vertexs[i].clear();
}
temp.clear();
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
last_x = -1, last_y = -1;
glFlush();
}
}
void myDisplay() {
cout << "调用了一次回调函数" << endl;
}
void init() {
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluOrtho2D(0, window_size, window_size, 0);
Y_MIN = window_size; Y_MAX = 0;
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(300, 100);
glutInitWindowSize(window_size, window_size);
glutCreateWindow("扫描线填充多边形");
init();
glutMouseFunc(mymouse);
glutKeyboardFunc(mykeyboard);
glutDisplayFunc(myDisplay);
glutMainLoop();
return 0;
}
不足与改进:
set在插入边的时候,需要删除再插,复杂度过高。
解决方法:node里面再加一个值x’,非键值,y++的时候更新x’.等到了关键高度的时候再用x’去更新x.
也在一个关键节点时,将set的值先存到数组中,y++的时候对数组进行操作,等到了下一个关键节点的时候再将数组的值变成set