原文:http://blog.sina.com.cn/s/blog_80a9926b01014ri6.html
算法思路
分别判断直线 ( 线段 ) 的两个端点落在哪个区域。判断的方法是将端点和裁剪框的边界比较。然后确定线段与矩形框上边界的交点 ( 四舍五入取整 ) ,端点落在 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).