直线段裁剪算法一:Cohen-Sutherland算法
//编译环境:Visual C++ 6.0,EasyX_20190219(beta)
#include <graphics.h>
#include <conio.h>
#include <iostream>
#define left 1
#define right 2
#define bottom 4
#define top 8
using namespace std;
//设置裁剪框的大小和位置
double xl=120,xr=320,yt=240,yb=150;
//编码
void encode(double x,double y,int &code)
{
int c=0;
if(x<xl) {c=c+left;}
else if(x>xr) {c=c+right;}
if(y<yb) {c=c+bottom;}
else if(y>yt) {c=c+top;}
code=c;
}
//Cohen-Sutherland裁剪算法
int CS_LineClip(double x1,double y1,double x2,double y2)
{
int code1,code2,code;
int x,y;
encode(x1,y1,code1);
encode(x2,y2,code2);
while(code1!=0||code2!=0)//都在里面时,直接画线,否则进行判断
{
if((code1&code2)!=0) return 0;//都在外面舍弃
code=code1;
if(code1==0) code=code2;
if((left&code)!=0)
{x=xl;y=y1+(y2-y1)*(xl-x1)/(x2-x1);}
else if((right&code)!=0)
{x=xr;y=y1+(y2-y1)*(xr-x1)/(x2-x1);}
else if ((bottom&code) != 0)
{y=yb;x=x1+(x2-x1)*(yb-y1)/(y2-y1);}
else if ((top&code) != 0)
{y=yt;x=x1+(x2-x1)*(yt-y1)/(y2-y1);}
if(code==code1)
{x1=x;y1=y;encode(x,y,code1);}
else
{x2=x;y2=y;encode(x,y,code2);}
}
line(x1,y1,x2,y2);
return 0;
}
int main()
{
double x1,y1,x2,y2;
initgraph(640, 480);
POINT points[]={ {xl,yt}, {xr,yt}, {xr,yb}, {xl,yb}};
polygon(points,4);
//用鼠标来获取两个点的坐标
MOUSEMSG m; // 定义结构体保存鼠标消息
while (true)
{flag:
m = GetMouseMsg();// 获取一次鼠标消息
switch (m.uMsg)//判断鼠标信息类型
{
case WM_LBUTTONDOWN:
x1 = m.x; y1 = m.y; //鼠标第一次按下时,获取鼠标当前坐标
while (true)
{
m = GetMouseMsg();// 再次获取一条鼠标消息
switch (m.uMsg)
{
case WM_LBUTTONDOWN:
x2 = m.x; y2 = m.y;//鼠标第二次按下时,得到坐标
setcolor(RED);
line(x1, y1, x2, y2);
setcolor(YELLOW);
CS_LineClip(x1, y1, x2, y2);
goto flag;
}
}
}
}
_getch();
closegraph();
return 0;
}
演示如下所示:
直线段裁剪算法二:梁友栋-Barsky线段裁剪算法
//编译环境:Visual C++ 6.0,EasyX_20190219(beta)
#include<graphics.h>
#include<conio.h>
#include<iostream>
using namespace std;
//设置裁剪框的大小和位置,全局变量
double xl=120,xr=250,yt=270,yb=160;
bool ClipT(double q,double d,double &t0,double &t1)
{//当线段完全不可见时,返回false,否则,返回true
double r;
if(q<0)
{
r=(double)d/(double)q;
if(r>t1)
return false;
else if(r>t0)
{t0=r;return true;}
}
else if(q>0)
{
r=(double)d/(double)q;
if(r<t0)
return false;
else if(r<t1)
{t1=r;return true;}
}
else if(d<0)
return false;
return true;
}
//梁友栋-Barsky线段裁剪算法
void LiangBarskyLineClip(double x0,double y0,double x1,double y1)
{
double delatx,delaty,t0,t1;
t0=0;t1=1;
delatx=x1-x0;
if(ClipT(-delatx,x0-xl,t0,t1))
if(ClipT(delatx,xr-x0,t0,t1))
{
delaty=y1-y0;
if(ClipT(-delaty,y0-yb,t0,t1))
if(ClipT(delaty,yt-y0,t0,t1))
{
line((int)(x0+t0*delatx),(int)(y0+t0*delaty),
(int)(x0+t1*delatx),(int)(y0+t1*delaty));
return;
}
}
}
int main()
{
double x0,x1,y0,y1;
initgraph(640,480);
POINT points[]={ {xl,yt}, {xr,yt}, {xr,yb}, {xl,yb}};
polygon(points,4);
//用鼠标来获取两个点的坐标
MOUSEMSG m;
while (true)
{flag:
m = GetMouseMsg();// 获取一次鼠标消息
switch (m.uMsg)//判断鼠标信息类型
{
case WM_LBUTTONDOWN:
x0 = m.x; y0 = m.y; //鼠标第一次按下时,获取鼠标当前坐标
//circle(x0,y0,2);
while (true)
{
m = GetMouseMsg();// 再次获取一条鼠标消息
switch (m.uMsg)
{
case WM_LBUTTONDOWN:
x1 = m.x; y1 = m.y;//鼠标第二次按下时,得到坐标
//circle(x1,y1,2);
//
setcolor(RED);
//line(x0, y0, x1, y1);
setcolor(YELLOW);
LiangBarskyLineClip(x0,y0,x1,y1);
goto flag;
}
}
}
}
_getch();
closegraph();
return 0;
}
直线时裁剪框以内的线段,演示如下: