多边形裁剪算法

简介: 多边形裁剪算法

1.先决定窗口范围:

initgraph(800, 600);
  line(200, 450, 200, 200);
  line(200, 200, 600, 200);
  line(600, 200, 600, 450);
  line(600, 450, 200, 450);//框


b9d744382fa844e3990a7720311e211f.jpg


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;
      }// 中键按下消息 完成绘图
      }
    }
  }
}


f2ec4ad5e1494ef2bc2d315920b4f87a.jpg

最后与初始点连接时不要按右键,要按中键。

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.最后结果:

e5be45783cca4aa5849fab62a7c93f95.jpg

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


相关文章
多边形扫描转换-扫描线算法
多边形扫描转换-扫描线算法
|
2月前
|
算法 图形学
【计算机图形学】实验三 用Cohen-Sutherland裁剪算法实现直线段裁剪
【计算机图形学】实验三 用Cohen-Sutherland裁剪算法实现直线段裁剪
240 2
|
2月前
|
算法 图形学
【头歌 计算机图形学 练习】多边形填充v1.0 (第1关:扫描线填充算法(活动边表AET法) 第2关:边缘填充法 第3关:区域四连通种子填充算法 第4关:区域扫描线种子填充算法)
【头歌 计算机图形学 练习】多边形填充v1.0 (第1关:扫描线填充算法(活动边表AET法) 第2关:边缘填充法 第3关:区域四连通种子填充算法 第4关:区域扫描线种子填充算法)
258 0
|
9月前
|
存储 算法 Java
基于Y向连贯性算法的多边形扫描线生成(适用于凸多边形和凹多边形)【原理+java实现】
基于Y向连贯性算法的多边形扫描线生成(适用于凸多边形和凹多边形)【原理+java实现】
137 0
|
算法 索引
连通不规则多边形算法
多边形连通和最小生成树本质上是一样的,问题在于确定权值。 下面算法由js实现,演示由svg提供。 let shown='hidden'; //核心算法 let caculatePath=function(){ ...
1116 0
|
算法 索引
一种求任意多边形内部水平方向似最大矩形的算法
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景        在前一篇中,我们探讨了如何求凸多边形中的似最大圆,但是针对实际情况需求,我们并没有完全解决问题。
2950 0
|
算法 异构计算
复杂多边形光栅化算法
虽然已经一年多没有维护gbox这个图形库项目了,最近确实时间不够用。。。 今年的重点是把xmake彻底正好,至少在架构和大功能(包依赖管理)上,要完全落实下来,后期就是零散的维护和插件功能扩展了。
1202 0
|
算法 C语言
裁剪算法
直线裁剪 program clipline;uses crt,graph;var   markseg:word;   gd,gm:integer;   startx,starty,endx,endy:integer;   x1,y1,x2,y2,x,y:integer;   ch:char;   ...
850 0