Cohen-SutherLand直线裁剪算法

xiaoxiao2021-02-28  11

算法原理(递归的裁剪过程):

对于每条线段P1P2分为三种情况处理:

(1)若P1P2完全在窗口内,则显示该线段P1P2。

(2)若P1P2明显在窗口外,则丢弃该线段。

(3)若线段不满足(1)或(2)的条件,则在交点处把线段分为两段。其中一段完全在窗口外,可弃之。然后对另一段重复上述处理。

       为快速判断,采用如下编码方法:

       由窗口四条边所在直线把二维平面分成9个区域(右图),每个区域赋予一个四位编码:CtCbCrCl(上下右左);直线的端点都按其所处区域赋予相应的区域码,用来标识出端点相对于裁剪矩形边界的位置。

       各位编码含义:

       上:if y>ymax,Ct=1,else, 0;

       下:if y<ymax,Cb=1,else, 0;

       右:if x>xmax,Cr=1,else, 0;

       左:if x<xmax,Cl=1,else, 0;

对某线段的两个端点的区号进行位与运算,可知这两个端点是否同在视区的上、下、左、右;

‐        如果两端点的编码均为0000,表示直线在窗口内。

‐        如果两端点的编码相与不为0000,表示直线在窗口外。

‐     如果两端点的编码不全为0000,但相与为0000,则该直线部分可见,需计算直线与窗口的交点,确定哪一部分可见。

‐      

算法描述:

BOOL done,draw;(done表示是否完成,draw表示是否可见)

Unsigned char code1,code2;端点1,端点2的编码

While (!done)

begin

 if (判断code1,code2,若为第1种情况)

begin

      done = TRUE;

      draw = TRUE;

end

 else if (为第2种情况)

begin

      done = TRUE;

      draw = FALSE;

end

    elseif(检查code1,若在窗口内)/*第3种情况*/

begin

交换端点及端点的编码;以左,上,右,下的次序对端点1进行判断及求交;将交点的值赋给端点1;

end

end

 

算法分析:

本算法的优点在于简单,易于实现。用编码方法可快速判断线段的完全可见和显然不可见,他可以简单的描述为将直线在窗口左边的部分删去,按左,右,下,上的顺序依次进行,处理之后,剩余部分就是可见的了。在这个算法中求交点是很重要的,他决定了算法的速度。

本算法对于其他形状的窗口是否同样有效就值得讨论了,这也证明了在图形算法中,没有几个是对大多数情况有效的。

特别适用二种情形:大窗口场合;窗口特别小场合(光标拾取图形,光标看作小的裁剪窗口)。

源代码: #include <GL/glut.h> #define Left 1 #define Right 2 #define Bottom 4 #define Top 8 #define xl 200 #define xr 400 #define yb 200 #define yt 400 void creat() { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluOrtho2D(0.0, 480, 0.0, 480); } void Drawpixel(float x, float y) { glPointSize(1.0); glColor3f(1.0f, 1.0f, 1.0f); glVertex2i((float)(x), (float)(y)); } void DrawLine(float x0, float y0, float x1, float y1) { float a, b, d1, d2, d, x, y, k; a = y0 - y1, b = x1 - x0, d = 2 * a + b; d1 = 2 * a, d2 = 2 * (a + b); x = x0, y = y0; while (x <= x1) { if (d <= 0) { x++, y++, d += d2; } else { x++, d += d1; } Drawpixel(x, y); } if (x0 = x1) { while (y < y1) { Drawpixel(x, y); y++; } } } int Encode(float x, float y) { int c = 0; if (x < xl)c = c | Left; if (x>xr)c = c | Right; if (y < yb)c = c | Bottom; if (y>yt)c = c | Top; return c; } void CS_LineClip(float x1, float y1, float x2, float y2) { int code1, code2, code; float x, y; code1 = Encode(x1, y1); code2 = Encode(x2, y2); while (code1 != 0 || code2 != 0) { if (code1&&code2 != 0)return; if (code1 != 0)code = code1; else 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 = xl + (x2 - x1)*(yb - y1) / (y2 - y1); } else if ((Top&code) != 0) { y = yt; x = xl + (x2 - x1)*(yt - y1) / (y2 - y1); } if (code == code1) { x1 = x; y1 = y; code1 = Encode(x, y); } else { x2 = x; y2 = y; code2 = Encode(x, y); } } DrawLine(x1, y1, x2, y2); } void display(void) { glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_POINTS); CS_LineClip(100, 150, 350, 300); DrawLine(200, 200, 200, 400); DrawLine(200, 200, 400, 200); DrawLine(200, 400, 400, 400); DrawLine(400, 200, 400, 400); glEnd(); glFlush(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(400, 400); glutInitWindowPosition(300, 200); glutCreateWindow("裁剪直线算法"); creat(); glutDisplayFunc(display); glutMainLoop(); return 0; } 要运行此代码,需要在编译器上自行导入OpenGL库哦!
转载请注明原文地址: https://www.6miu.com/read-2650137.html

最新回复(0)