版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/82918310
使用计算机处理图形信息时,计算机内部存储的图形往往比较大,而屏幕显示的只是图的一部分,因此需要确定图形中哪些图形显示在显示区之内,哪些落在显示区之外,这样便于只显示落在显示区内的那部分图形,以提高显示效率。
直线段裁剪算法比较简单,但比较重要,是复杂图元裁剪的基础。
裁剪前(矩形为窗口区):
裁剪后:
Cohen_Sutherland裁剪算法:对于每条线段P1,P2,分为三种情况处理。
1、若P1P2完全在窗口内,则显示该线段P1P2,简称取之。
2、若P1P2明显在窗口外,则丢弃该线段,简称弃之。
3、若前段既不满足取的条件,也不满足弃的条件,则在交点处把线段分为两段,其中一段完全在窗口外,可弃之,然后对另一段重复上述处理。
用编码判断一条直线段与窗口属何种关系。
1001|1000|1010
----|----|-----
0001|0000|0010
----|----|-----
0101|0100|0110
裁剪一条线段时,先求出P1P2所在的区号code1,code2,若code1=0,且code2=0,则线段P1P2在窗口内,应取之。若按位与运算code1&code2!=0,则两个端点同在窗口的上方、下方、左方或右方,可判断线段完全在窗口外,可弃之。否则按第三种情况处理。求出线段与窗口某边的交点,在交点处把线段一分为二,其中必有一段在窗口外,可弃之,再对说另一段重复上述处理。
定义的宏:
#define LEFT 1
#define RIGHT 2
#define BOTTOM 4
#define TOP 8
辅助函数:
int CDrawView::encode(int x,int y,int XL,int XR,int YB,int YT) //端点与窗口边界
{
//获得端点的编码
/*1001|1000|1010
----|----|-----
0001|0000|0010
----|----|-----
0101|0100|0110*/
int c=0;
if(x<XL)
c|=LEFT;
if(x>XR)
c|=RIGHT;
if(y>YB)
c|=BOTTOM;
if(y<YT)
c|=TOP;
return c;
}
实现源码:
void CDrawView::CS_Clip(int x1,int y1,int x2,int y2,int XL,int XR,int YB,int YT)
{
//Cohen_Sutherland裁剪算法
//对于每条线段p1p2分为3种情况处理:
//若p1p2完全落在窗口内,则显示该线段p1p2,取之 (两个编码都为0)
//若p1p2明显在窗外,则丢弃该线段,弃之 (code1&code2!=0)
//若线段不满足取得条件,也不满足弃的条件,则在交点出把先把线段分为两段,其中
//一段完全在窗口外,弃之,对另外一段重复处理
int code,code1,code2,x,y;
code1=encode(x1,y1,XL,XR,YB,YT); //获得编码
code2=encode(x2,y2,XL,XR,YB,YT);
while(code1!=0||code2!=0)
{
if(code1&code2)
return;
if(code1)
code=code1;
else
code=code2;
if(LEFT&code) //求得与窗口边界的交点
{
x=XL;
y=y1+(y2-y1)*(x-x1)/(x2-x1);
}
else if(RIGHT&code)
{
x=XR;
y=y1+(y2-y1)*(x-x1)/(x2-x1);
}
else if(BOTTOM&code)
{
y=YB;
x=x1+(x2-x1)*(y-y1)/(y2-y1);
}
else if(TOP&code)
{
y=YT;
x=x1+(x2-x1)*(y-y1)/(y2-y1);
}
if(code==code1) //更新code值
{
x1=x;
y1=y;
code1=encode(x1,y1,XL,XR,YB,YT);
}
else
{
x2=x;
y2=y;
code2=encode(x2,y2,XL,XR,YB,YT);
}
}
MiddleDrawline(x1,y1,x2,y2,RGB(255,0,0));//绘制在窗口内的线
}