#pragma comment( linker, "/subsystem:windows /entry:mainCRTStartup" )//去除控制台窗口
#include <iostream>
#include <gl/GLUT.h>
#include <map>
#include <vector>
#include <list>
#include <algorithm>
#include"PointAndLine.h"
using namespace std;
vector<Point>v; //多边形点集
vector<Point>cv; //裁剪后得到的点集
int flag = 1; //记录点击的次数,单次画点,双次画线。
bool if_drawable = 1; //是否结束画图
int window_size = 800;
float XL = 200, XR = 600, YB = 200, YT = 600;
Line line[5];
void draw_lines();
void draw_rectangle();
void Sutherland_Hodgman();
void OnMouse(int button, int state, int x, int y);
void InitEnvironment();
bool inRectangle(float x, float y);
int main(int argc, char* argv[]) {
glutInit(&argc, argv); //初始化GLUT
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(300, 100);
glutInitWindowSize(window_size, window_size);
glutCreateWindow("filling_line");
InitEnvironment(); //初始化
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);
draw_rectangle();
line[0].init(XL, YB, XL, YT);//左边界
line[1].init(XR, YB, XR, YT);//右边界
line[2].init(XL, YB, XR, YB);//下边界
line[3].init(XL, YT, XR, YT);//上边界
}
bool inRectangle(float x, float y) {
return (XL < x && x < XR && YB < y && y < YT);
}
void draw_rectangle() {
glBegin(GL_LINES);
glColor3f(1, 1, 0);
glVertex2f(XL, window_size - YB);
glVertex2f(XR, window_size - YB);
glVertex2f(XL, window_size - YT);
glVertex2f(XR, window_size - YT);
glVertex2f(XL, window_size - YB);
glVertex2f(XL, window_size - YT);
glVertex2f(XR, window_size - YB);
glVertex2f(XR, window_size - YT);
glEnd();
glFlush();
}
void draw_lines() {//跟着用户画线
glBegin(GL_LINES);
glColor3f(0.5, 0.5, 0.5);
int x1 = v[0].x, y1 = v[0].y;
int x2, y2;
for (int i = 1; i < v.size(); i++) {
x2 = v[i].x, y2 = v[i].y;
glVertex2f(x1, window_size - y1);
glVertex2f(x2, window_size - y2);
x1 = x2, y1 = y2;
}
if (if_drawable == 0) {//最终的display
glVertex2f(x1, window_size - y1);
glVertex2f(v[0].x, window_size - v[0].y);
glColor3f(1, 0, 0);
x1 = cv[0].x, y1 = cv[0].y;
cout << x1 << " " << y1 << endl;
for (int i = 1; i < cv.size(); i++) {
x2 = cv[i].x, y2 = cv[i].y;
cout << x2 << " " << y2 << endl;
glVertex2f(x1, window_size - y1);
glVertex2f(x2, window_size - y2);
x1 = x2, y1 = y2;
}
glVertex2f(x1, window_size - y1);
glVertex2f(cv[0].x, window_size - cv[0].y);
}
glEnd();
glFlush();
}
void OnMouse(int button, int state, int x, int y) {
//OnMouse坐标系x从左向右,y从上到下
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && if_drawable) {
if (flag == 1) {
flag++;
v.push_back(Point(x, y));
cv.push_back(Point(x, y));
glBegin(GL_POINTS);
glColor3f(0.5, 0.5, 0.5);
glVertex2f(x, window_size - y);
glEnd();
glFlush();
}
else {
v.push_back(Point(x, y));
cv.push_back(Point(x, y));
draw_lines();
}
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN && if_drawable)
{ //点击右键
if_drawable = 0;
v.push_back(Point(x, y));
cv.push_back(Point(x, y));
Sutherland_Hodgman();
draw_lines();
}
}
bool Inside(Point p,int i) {
if (i == 0) {//左边界
if (p.x >= XL)return 1;
}
else if (i == 1) {//右边界
if (p.x <= XR)return 1;
}
else if (i == 2) {//下边界
if (p.y >= YB)return 1;
}
else if (i == 3) {//上边界
if (p.y <= YT)return 1;
}
return 0;
}
void Intersect(Point S, Point P, int i, Point &ans) {
if (i < 2) {//垂直裁剪边
if (i == 0)ans.x = XL;
else ans.x = XR;
ans.y = S.y + (ans.x - S.x) * (P.y - S.y) / (P.x - S.x);
}
else {//水平裁剪边
if (i == 2)ans.y = YB;
else ans.y = YT;
ans.x = S.x + (ans.y - S.y) * (P.x - S.x) / (P.y - S.y);
}
}
void Sutherland_Hodgman() {
/*遍历矩形四个边界,每次都更新原来的点集*/
vector<Point>tmp;
Point ip;
for (int i = 0; i < 4; i++) {
Point S = cv[cv.size()-1],P;
for (int j = 0; j < cv.size(); j++) {
P = cv[j];
if (Inside(P, i)) {
if (Inside(S, i)) {
tmp.push_back(P);
}
else {
Intersect(S, P, i, ip);
tmp.push_back(ip);
tmp.push_back(P);
}
}
else if (Inside(S, i)) {
Intersect(S, P, i, ip);
tmp.push_back(ip);
}
S = P;
}
cv.clear();
for (int j = 0; j < tmp.size(); j++) {
cv.push_back(tmp[j]);
}
tmp.clear();
}
}
PointAndLine.h
#pragma once
#include<iostream>
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;
}
};
struct Line {
float A, B, C;
float X1, Y1, X2, Y2;
float x, y, dx, ym; //(x,y):第一个接触到扫描线的点,y和ym可以判断是否为横直线,dx:1/k,ym:最大y
Line() {}
Line(float x1, float y1, float x2, float y2) :
X1(x1), Y1(y1), X2(x2), Y2(y2) {
A = y2 - y1;
B = x1 - x2;
C = x2 * y1 - x1 * y2;
if (y1 == y2) { //横直线dx不能按正常算
this->y = y1;
this->ym = y1;
if (x1 < x2) { dx = x1; x = x2; }
else { dx = x2; x = x1; }
}
else if (y2 < y1) {
this->x = x2; //记录上方的x值一方便处理关键时刻(用于插入AET排序)
this->y = y2; //记录上方的y值,用于排序
this->ym = y1; //靠下者ym
dx = (x2 - x1) / (y2 - y1);
}
else {
this->x = x1;
this->y = y1;
this->ym = y2;
dx = (x2 - x1) / (y2 - y1);
}
}
void init(float x1, float y1, float x2, float y2) {
X1 = x1, Y1 = y1, X2 = x2, Y2 = y2;
A = y2 - y1;
B = x1 - x2;
C = x2 * y1 - x1 * y2;
}
bool inTheLine(float x, float y) {
float minx = min(X1, X2);
float maxx = max(X1, X2);
float miny = min(Y1, Y2);
float maxy = max(Y1, Y2);
if (minx <= x && x <= maxx && miny <= y && y <= maxy)return 1;
else { return 0; }
}
bool onSide(float x, float y) {
//返回在直线的某一侧
if (A * x + B * y + C > 0)return 1;
else return 0;
//(y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)
}
};
bool qujiao(float& x, float& y, Line l1, Line l2) {
//取交点
float m = l1.A * l2.B - l1.B * l2.A;
if (m == 0)return 0;
else {
x = (l2.C * l1.B - l1.C * l2.B) / m;
y = (l1.C * l2.A - l2.C * l1.A) / m;
return 1;
}
}