Cohen-Sutherland裁剪算法

最近幾天由於項目關係,接觸到裁剪算法,今天算是真正把它其中一種最簡單的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);
        }
    }
}

裁剪效果
裁之前:
這裏寫圖片描述

裁之後:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章