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