算法思路
分别判断直线 ( 线段 ) 的两个端点落在哪个区域。判断的方法是将端点和裁剪框的边界比较。然后确定线段与矩形框上边界的交点 ( 四舍五入取整 ) ,端点落在 C 区域无需求交点,落在其他区域需要。当端点落在 N 、 S 、 W 、 E 区域时只要将裁剪框边界值带入直线方程即可。当某端点落在 NW 、 NE 、 SW 、 SE 区域时有两个交点 C 、 D ( B 端点位于 S 或 SW 区域类似)。如图:
则 C 和 D 选正确的。
两个端点确定了位置之后,有下面几种情况:
1. 两个端点位于裁剪框边界同一侧,无法裁剪。
2. 端点都在 C 区域,无需裁剪。
具体算法
//返回0-成功,1-无法裁剪,线段不在裁剪框中,-1失败
//使用两点式求交点 y-y0 = (x-x0)*(y1-y0)/(x1-x0)
//y = (x-x0)*(y1-y0)/(x1-x0) + y0;
//x = (y-y0)*(x1-x0)/(y1-y0) + x0;
//浮点数+0.5再赋给整数即可将浮点数四舍五入
int 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).