1.先决定窗口范围:
initgraph(800, 600); line(200, 450, 200, 200); line(200, 200, 600, 200); line(600, 200, 600, 450); line(600, 450, 200, 450);//框
2.进行鼠标操作:鼠标左键按下:画点;鼠标右键按下:连线;鼠标中键按下:与初始点相连接,完成多边形的绘制。
void shubiao() { int a[3] = { 0 }, b[3] = { 0 }; int count = 0; int a1 = 0, b1 = 0;//初始点 int flag = 0; cout << "鼠标左键按下:画点\n鼠标右键按下:连线\n鼠标中键按下:与初始点相连接,完成多边形的绘制\n" << endl; while (flag==0) { if (MouseHit())//判断是否有鼠标信息 { settextcolor(RED);//默认为红色 MOUSEMSG msg; //定义一个鼠标消息 msg = GetMouseMsg();//获取鼠标消息 switch (msg.uMsg) { case WM_LBUTTONDOWN: { putpixel(msg.x, msg.y, RED);//画点 xx[count] = msg.x; yy[count] = msg.y; a[count % 2] = msg.x; b[count % 2] = msg.y; if (count == 0) { a1 = msg.x; b1 = msg.y; } count++; Vertex p(msg.x, msg.y); input_vertice.push_back(p); break; }// 左键按下消息 画点 case WM_RBUTTONDOWN: { setlinecolor(RED); line(a[0], b[0], a[1], b[1]); break; }// 右键按下消息 连线 case WM_MBUTTONDOWN: { setlinecolor(RED); line(a[(count - 1) % 2], b[(count - 1) % 2], a1, b1); cout << "已完成多边形的绘制" << endl; flag = 1; break; }// 中键按下消息 完成绘图 } } } }
最后与初始点连接时不要按右键,要按中键。
3.进行多边形裁剪:这里使用Sutherland-Hodgman算法。主要是Inside(判断点是否在裁剪边的可见侧),Intersect(直线段与窗口求交,返回交点),SutherlandHodgmanClip函数。
bool Inside(Vertex& testPT, EDGE ClipBoundary) {//判断点是否在裁剪边的可见侧 if (ClipBoundary.bx > ClipBoundary.ax) { if (testPT.y >= ClipBoundary.ay)//裁剪边为窗口下边 return true; } else if (ClipBoundary.bx < ClipBoundary.ax) { if (testPT.y <= ClipBoundary.ay)//裁剪边在窗口上边 return true; } else if (ClipBoundary.by > ClipBoundary.ay)//裁剪边在窗口右边 { if (testPT.x <= ClipBoundary.ax) return true; } else if (ClipBoundary.by < ClipBoundary.ay)//裁剪边在窗口左边 { if (testPT.x >= ClipBoundary.ax) return true; } return false; } void Intersect(Vertex& S, Vertex& P, EDGE ClipBoundary, Vertex& IntersectPt) { if (ClipBoundary.ay == ClipBoundary.by)//水平裁剪 { IntersectPt.y = ClipBoundary.ay; IntersectPt.x = S.x + (ClipBoundary.ay - S.y) * (P.x - S.x) / (P.y - S.y); } else//垂直裁剪 { IntersectPt.x = ClipBoundary.ax; IntersectPt.y = S.y + (ClipBoundary.ax - S.x) * (P.y - S.y) / (P.x - S.x); } } void SutherlandHodgmanClip(EDGE ClipBoundary) { Vertex S, P, ip; output_vertice.clear(); S = input_vertice[input_vertice.size() - 1];//先从最后一个点指向第一个点的线段开始检验 for (int j = 0; j < input_vertice.size(); j++) { P = input_vertice[j]; if (Inside(P, ClipBoundary))//P在里面 { if (Inside(S, ClipBoundary))//SP都在窗口内 { output_vertice.push_back(P); } else//P在里面 S在外面 { Intersect(S, P, ClipBoundary, ip); output_vertice.push_back(ip); output_vertice.push_back(P); } } else//P在外面 { if (Inside(S, ClipBoundary))//S在窗口内P在窗口外 { Intersect(S, P, ClipBoundary, ip); output_vertice.push_back(ip); } //SP都在外面则无输出 } S = P; } input_vertice = output_vertice;//这次的输出作为下一次的输入 }
4.键盘或鼠标响应裁剪命令。这里我使用“w”键。
void keyboard() { cout << "按w开始裁剪..." << endl; //settextcolor(BLUE);//填充蓝色 int key = _getch(); switch (key) { //w键 case 72: case'w': case'W': SutherlandHodgmanClip(::left); SutherlandHodgmanClip(bottom); SutherlandHodgmanClip(::right); SutherlandHodgmanClip(top); for (int i = 0; i < output_vertice.size() - 1; i++) { putpixel(output_vertice[i].x, output_vertice[i].y, RED); line(output_vertice[i].x, output_vertice[i].y, output_vertice[i + 1].x, output_vertice[i + 1].y); } line(output_vertice[output_vertice.size() - 1].x, output_vertice[output_vertice.size() - 1].y, output_vertice[0].x, output_vertice[0].y); break; default:cout << "输入有误!" << endl; } }
5.主函数:
int main() { initgraph(800, 600); line(200, 450, 200, 200); line(200, 200, 600, 200); line(600, 200, 600, 450); line(600, 450, 200, 450);//框 //多边形裁剪 shubiao(); setlinestyle(PS_SOLID, 5); keyboard(); system("pause"); closegraph(); return 0; }
6.最后结果:
7.最终代码:
#include <graphics.h> #include <vector> #include <algorithm> #include<iostream> #include<conio.h> using namespace std; const int maxn = 50; const int window_width = 800, window_height = 600; int xx[maxn] = { 0 }, yy[maxn] = { 0 };//存各点坐标 struct Vertex { float x; float y; Vertex() {} Vertex(float xx, float yy) :x(xx), y(yy) {} bool operator < (const Vertex& a)const //重载运算符 { return x < a.x; } }; typedef Vertex edge[2]; typedef Vertex vertexArray[maxn]; struct EDGE//Edge边 { float ax, ay, bx, by; EDGE() {} EDGE(float bxx, float byy, float exx, float eyy) :ax(bxx), ay(byy), bx(exx), by(eyy) {} }; vector<Vertex> input_vertice; //输入 vector<Vertex> output_vertice; //输出 EDGE left(200, 450, 200, 200); EDGE bottom(200, 200, 600, 200); EDGE right(600, 200, 600, 450); EDGE top(600, 450, 200, 450); bool Inside(Vertex& testPT, EDGE ClipBoundary) {//判断点是否在裁剪边的可见侧 if (ClipBoundary.bx > ClipBoundary.ax) { if (testPT.y >= ClipBoundary.ay)//裁剪边为窗口下边 return true; } else if (ClipBoundary.bx < ClipBoundary.ax) { if (testPT.y <= ClipBoundary.ay)//裁剪边在窗口上边 return true; } else if (ClipBoundary.by > ClipBoundary.ay)//裁剪边在窗口右边 { if (testPT.x <= ClipBoundary.ax) return true; } else if (ClipBoundary.by < ClipBoundary.ay)//裁剪边在窗口左边 { if (testPT.x >= ClipBoundary.ax) return true; } return false; } void Intersect(Vertex& S, Vertex& P, EDGE ClipBoundary, Vertex& IntersectPt) { if (ClipBoundary.ay == ClipBoundary.by)//水平裁剪 { IntersectPt.y = ClipBoundary.ay; IntersectPt.x = S.x + (ClipBoundary.ay - S.y) * (P.x - S.x) / (P.y - S.y); } else//垂直裁剪 { IntersectPt.x = ClipBoundary.ax; IntersectPt.y = S.y + (ClipBoundary.ax - S.x) * (P.y - S.y) / (P.x - S.x); } } void SutherlandHodgmanClip(EDGE ClipBoundary) { Vertex S, P, ip; output_vertice.clear(); S = input_vertice[input_vertice.size() - 1];//先从最后一个点指向第一个点的线段开始检验 for (int j = 0; j < input_vertice.size(); j++) { P = input_vertice[j]; if (Inside(P, ClipBoundary))//P在里面 { if (Inside(S, ClipBoundary))//SP都在窗口内 { output_vertice.push_back(P); } else//P在里面 S在外面 { Intersect(S, P, ClipBoundary, ip); output_vertice.push_back(ip); output_vertice.push_back(P); } } else//P在外面 { if (Inside(S, ClipBoundary))//S在窗口内P在窗口外 { Intersect(S, P, ClipBoundary, ip); output_vertice.push_back(ip); } //SP都在外面则无输出 } S = P; } input_vertice = output_vertice;//这次的输出作为下一次的输入 } void shubiao() { int a[3] = { 0 }, b[3] = { 0 }; int count = 0; int a1 = 0, b1 = 0;//初始点 int flag = 0; cout << "鼠标左键按下:画点\n鼠标右键按下:连线\n鼠标中键按下:与初始点相连接,完成多边形的绘制\n" << endl; while (flag == 0) { if (MouseHit())//判断是否有鼠标信息 { settextcolor(RED);//默认为红色 MOUSEMSG msg; //定义一个鼠标消息 msg = GetMouseMsg();//获取鼠标消息 switch (msg.uMsg) { case WM_LBUTTONDOWN: { putpixel(msg.x, msg.y, RED);//画点 xx[count] = msg.x; yy[count] = msg.y; a[count % 2] = msg.x; b[count % 2] = msg.y; if (count == 0) { a1 = msg.x; b1 = msg.y; } count++; Vertex P(msg.x, msg.y); input_vertice.push_back(P); break; }// 左键按下消息 画点 case WM_RBUTTONDOWN: { setlinecolor(RED); line(a[0], b[0], a[1], b[1]); break; }// 右键按下消息 连线 case WM_MBUTTONDOWN: { setlinecolor(RED); line(a[(count - 1) % 2], b[(count - 1) % 2], a1, b1); cout << "已完成多边形的绘制" << endl; flag = 1; break; }// 中键按下消息 完成绘图 } } } } void keyboard() { cout << "按w开始裁剪..." << endl; //settextcolor(BLUE);//填充蓝色 int key = _getch(); switch (key) { //w键 case 72: case'w': case'W': SutherlandHodgmanClip(::left); SutherlandHodgmanClip(bottom); SutherlandHodgmanClip(::right); SutherlandHodgmanClip(top); for (int i = 0; i < output_vertice.size() - 1; i++) { putpixel(output_vertice[i].x, output_vertice[i].y, RED); line(output_vertice[i].x, output_vertice[i].y, output_vertice[i + 1].x, output_vertice[i + 1].y); } line(output_vertice[output_vertice.size() - 1].x, output_vertice[output_vertice.size() - 1].y, output_vertice[0].x, output_vertice[0].y); break; default:cout << "输入有误!" << endl; } } int main() { initgraph(800, 600); line(200, 450, 200, 200); line(200, 200, 600, 200); line(600, 200, 600, 450); line(600, 450, 200, 450);//框 //多边形裁剪 shubiao(); setlinestyle(PS_SOLID, 5); keyboard(); system("pause"); closegraph(); return 0; }