算法简介
Cohen-Sutherland端点编码法是由Dan Cohen与Ivan Sutherland提出的窗口裁剪线段的算法。
算法思路
- 计算线段端点P1、P2的码字,码字(code)用四位二进制表示,1234
- 针对P1,P2,先进行以下判断:
P是否在窗口左边?
P是否在窗口上边?
P是否在窗口右边?
P是否在窗口下边?
根据这四个问题,只可能得到9种编码(对应9宫格):
TTFF | FTFF | FTTF
TFFF | FFFF | FFTF
TFFT | FFFT | FFTT
转换成二进制,就是9个值:
1100 | 0100 | 0110
1000 | 0000 | 0010
1001 | 0001 | 0011
- 如果(P1 | P2)== 0,则表示线段在窗口内,无须裁剪。
- 如果 (P1&P2) != 0,则表示线段在窗口一侧,无须裁剪
- 否则,线段需要裁剪
编码实现
nt Cohen_Sutherland::Clip_line(int LineX1,int LineY1,int LineX2,int LineY2 ,
int RectX1,int RectY1,int RectX2,int RectY2 ,
int &LineX3,int &LineY3,int &LineX4,int &LineY4 )
{
#define CLIP_CODE_C 0x0000
#define CLIP_CODE_W 0x0001
#define CLIP_CODE_E 0x0002
#define CLIP_CODE_S 0x0004
#define CLIP_CODE_N 0x0008
#define CLIP_CODE_SW 0x0005
#define CLIP_CODE_SE 0x0006
#define CLIP_CODE_NW 0x0009
#define CLIP_CODE_NE 0x000a
int Code1 = 0,Code2 = 0,Temp = -1;
LineX3 = LineX1;
LineY3 = LineY1;
LineX4 = LineX2;
LineY4 = LineY2;
if (RectX1 > RectX2)
{
Temp = RectX2;
RectX2 = RectX1;
RectX1 = Temp;
}
if (RectY1 > RectY2)
{
Temp = RectY2;
RectY2 = RectY1;
RectY1 = Temp;
}
if (LineX1 < RectX1)
{
Code1 |= CLIP_CODE_W;
}
if (LineX1 > RectX2)
{
Code1 |= CLIP_CODE_E;
}
if (LineY1 < RectY1)
{
Code1 |= CLIP_CODE_N;
}
if (LineY1 > RectY2)
{
Code1 |= CLIP_CODE_S;
}
if (LineX2 < RectX1)
{
Code2 |= CLIP_CODE_W;
}
if (LineX2 > RectX2)
{
Code2 |= CLIP_CODE_E;
}
if (LineY2 < RectY1)
{
Code2 |= CLIP_CODE_N;
}
if (LineY2 > RectY2)
{
Code2 |= CLIP_CODE_S;
}
if (Code1 & Code2)
{
return 1;
}
if (Code1==0 && Code2==0)
{
return 0;
}
switch(Code1)
{
case CLIP_CODE_C:
break;
case CLIP_CODE_W:
{
LineX3 = RectX1;
LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
break;
}
case CLIP_CODE_E:
{
LineX3 = RectX2;
LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
break;
}
case CLIP_CODE_S:
{
LineY3 = RectY2;
LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
break;
}
case CLIP_CODE_N:
{
LineY3 = RectY1;
LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
break;
}
case CLIP_CODE_SW:
{
LineY3 = RectY2;
LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
if (LineX3 < RectX1)
{
LineX3 = RectX1;
LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
}
break;
}
case CLIP_CODE_SE:
{
LineY3 = RectY2;
LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
if (LineX3 > RectX2)
{
LineX3 = RectX2;
LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
}
break;
}
case CLIP_CODE_NW:
{
LineY3 = RectY1;
LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
if (LineX3 < RectX1)
{
LineX3 = RectX1;
LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
}
break;
}
case CLIP_CODE_NE:
{
LineY3 = RectY1;
LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
if (LineX3 > RectX2)
{
LineX3 = RectX2;
LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
}
break;
}
}
switch(Code2)
{
case CLIP_CODE_C:
break;
case CLIP_CODE_W:
{
LineX4 = RectX1;
LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
break;
}
case CLIP_CODE_E:
{
LineX4 = RectX2;
LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
break;
}
case CLIP_CODE_S:
{
LineY4 = RectY2;
LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
break;
}
case CLIP_CODE_N:
{
LineY4 = RectY1;
LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
break;
}
case CLIP_CODE_SW:
{
LineY4 = RectY2;
LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
if (LineX4 < RectX1)
{
LineX4 = RectX1;
LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
}
break;
}
case CLIP_CODE_SE:
{
LineY4 = RectY2;
LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
if (LineX4 > RectX2)
{
LineX4 = RectX2;
LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
}
break;
}
case CLIP_CODE_NW:
{
LineY4 = RectY1;
LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
if (LineX4 < RectX1)
{
LineX4 = RectX1;
LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
}
break;
}
case CLIP_CODE_NE:
{
LineY4 = RectY1;
LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
if (LineX4 > RectX2)
{
LineX4 = RectX2;
LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
}
break;
}
}
if (LineX3<RectX1 || LineX3>RectX2
|| LineX4<RectX1 || LineX4>RectX2
|| LineY3<RectY1 || LineY4>RectY2
|| LineX4<RectY1 || LineY4>RectY2)
{
return 1;
}
return 0;
}
值得注意的地方:
四舍五入取整可以将浮点数 +0.5 赋给整型实现。
两点式直线方程 ,y-y0 = (x-x0)*(y1-y0)/(x1-x0).