最近幾天由於項目關係,接觸到裁剪算法,今天算是真正把它其中一種最簡單的Cohen-Sutherland實現了一下,算法原理很簡單,我不想多講,任何一本計算機圖形學的書應該都會有涉及到該裁剪算法,我的參考書是《計算機圖形學》(OpenGL版,第3版,清華大學出版社)下面直接把代碼貼出來吧。
#define LEFT_EDGE 1
#define RIGHT_EDGE 2
#define BOTTOM_EDGE 4
#define TOP_EDGE 8
struct vertex
{
float x;
float y;
};
vertex CP;
float wxmax = 1.0, wxmin = -1.0, wymax = 1.0, wymin = -1.0;
void MoveTo(GLfloat x, GLfloat y)
{
CP.x = x; CP.y = y;
}
void LineTo(GLfloat x, GLfloat y)
{
glBegin(GL_LINES);
glVertex2f(CP.x, CP.y);
glVertex2f(x, y);
glEnd();
glFlush();
}
int CompCode(GLfloat x, GLfloat y)//位置編碼,原理上有9個位置,其實只要5個就可以了
{
int code = 0x00; //此處是二進制
if (y<wymin)
code = code | 4;
if (y>wymax)
code = code | 8;
if (x>wxmax)
code = code | 2;
if (x<wxmin)
code = code | 1;
return code;
}
void cohensutherlandlineclip()
{
vertex p1,p2;
int accept = 0;
float x = 0.0, y = 0.0;
int code0, code1, codeout;
for (int i = 0; i < v.nedge; i++)//輸入要裁剪的邊
{
p1 = v.edge[0][i];
p2 = v.edge[1][i];
code0 = CompCode(p1.x, p1.y);
code1 = CompCode(p2.x, p2.y);
do{
if (!(code0 | code1))//全部顯示(平凡接受)
{
accept = 1;
break;
}
if (code0 & code1)//完全不可見(平凡拒絕)
{
accept = 0;
break;
}
if (code0 != 0)//p1在窗口外面
{
codeout = code0;
if (codeout&LEFT_EDGE)//p1在窗口左邊
{
p1.y += (p2.y - p1.y)*(wxmin - p1.x) / (p2.x - p1.x);//左邊界截斷
p1.x = wxmin;
}
else if (codeout&RIGHT_EDGE)
{
p1.y += (p2.y - p1.y)*(wxmax - p1.x) / (p2.x - p1.x);
p1.x = wxmax;
}
else if (codeout&BOTTOM_EDGE)
{
p1.x += (p2.x - p1.x)*(wymin - p1.y) / (p2.y - p1.y);
p1.y = wymin;
}
else if (codeout&TOP_EDGE)
{
p1.x += (p2.x - p1.x)*(wymax - p1.y) / (p2.y - p1.y);
p1.y = wymax;
}
code0 = CompCode(p1.x, p1.y);
}
else//p2在窗口外
{
codeout = code1;
if (codeout&LEFT_EDGE)
{
p2.y += (p2.y - p1.y)*(wxmin-p2.x) / (p2.x - p1.x);
p2.x = wxmin;
}
else if (codeout&RIGHT_EDGE)
{
p2.y += (p2.y - p1.y)*(wxmax - p2.x) / (p2.x - p1.x);
p2.x = wxmax;
}
else if (codeout&BOTTOM_EDGE)
{
p2.x += (p2.x - p1.x)*(wymin - p2.y) / (p2.y - p1.y);
p2.y = wymin;
}
else if (codeout&TOP_EDGE)
{
p2.x += (p2.x - p1.x)*(wymax - p2.y) / (p2.y - p1.y);
p2.y = wymax;
}
code1 = CompCode(p2.x, p2.y);
}
} while (1);//並非死循環,最多四次裁剪就可以跳出循環
if (accept) //畫出所有被平凡接受的線段
{
MoveTo(p1.x, p1.y);
LineTo(p2.x, p2.y);
}
else//捨棄所有被平凡拒絕的邊
{
p1.x = 0.0; p1.y = 0.0; p2.x = 0.0; p2.y = 0.0;
MoveTo(p1.x, p1.y);
LineTo(p2.x, p2.y);
}
}
}
裁剪效果
裁之前:
裁之後: