直线段裁剪Cohen-Sutherland算法

• 直线段裁剪算法是复杂图元裁剪的基础。
• 复杂的曲线可以通过折线段来近似,从而裁剪问题也可以化为直线段的裁剪问题。

Cohen-Sutherland裁剪

• 基本思想:
对于每条线段P1P2分为三种情况处理分为三种情况处理:
(1)若P1P2完全在窗口内,则显示该线段P1P2简称“取”之。
(2)若P1P2明显在窗口外,则丢弃该线段,简称“弃”之。
(3)若线段不满足“取”或 “弃”的条件,则在交点处把线段分为两段。其中一段完全在窗口外,可弃之。然后对另一段重复上述处理。
• 为快速判断,采用如下编码方法:
-----每个区域赋予4位编码CtCbCrCl
在这里插入图片描述
为提高效率,算法设计时应考虑:

  1. 快速判断情形(1)(2);
  2. 设法减少情形(3)求交次数和每次求交时所需的计算量。

(1)若P1P2完全在窗口内code1=0,且code2=0,则“取”
(2)若P1P2明显在窗口外code1&code2≠0,则“弃”
(3)在交点处把线段分为两段。其中一段完全在窗口外,
可弃之。然后对另一段重复上述处理。
直线段裁剪Cohen-Sutherland算法_第1张图片
代码实现

#include       // OPenGL实用工具库

#define LEFT 1
#define RIGHT 2
#define BOTTOM 4
#define TOP 8

int x1 = 150, y1 = 50, x2 = 250, y2 = 150, XL = 100, XR = 300, YB = 100, YT = 200;  //(x1,y1)、(x2,y2)为直线段的端点,XL为左边界,XR为右边界,YB为下边界,YT为上边界
int x1_init = 150, y1_init = 50, x2_init = 250, y2_init = 150;  //将直线段端点备份,以便画出裁剪前的直线段

char encode(float x, float y)
{
    char c = 0;
    if (x < XL) c |= LEFT;
    if (x > XR) c |= RIGHT;
    if (y < YB) c |= BOTTOM;
    if (y > YT) c |= TOP;
    return c;
}

void CS_LineClip(int &x1, int &y1, int &x2, int &y2, int XL, int XR, int YB, int YT) {
    char code1 = encode(x1, y1);
    char code2 = encode(x2, y2);
    char code;
    int x, y;
    while (code1 || code2) {
        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 = x1 + (x2 - x1) * (YB - y1) / (y2 - y1);
        }
        else if ((TOP & code) != 0) {
            y = YT; x = x1 + (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); }
    }
}

void init(void)
{
    glClearColor(1.0, 1.0, 1.0, 0.0);  // 设置背景颜色
    glMatrixMode(GL_PROJECTION);       // 设置投影参数
    gluOrtho2D(0.0, 600.0, 0.0, 400.0); // 设置场景的大小
}


void draw(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    glColor3f(1.0, 0.0, 0.0);      // 设置画图颜色
    glLineWidth(2);                // 设置边框宽度
    glPointSize(2);
    glPushMatrix();
    //glTranslatef(dx, dy, 0); //图形变换操作须放在绘制之前

    glBegin(GL_LINE_LOOP);
    glVertex2i(XL, YT);
    glVertex2i(XL, YB);
    glVertex2i(XR, YB);
    glVertex2i(XR, YT);
    glEnd();

    //绘制未裁剪前的线段
    glBegin(GL_LINES);
    glVertex2i(x1_init, y1_init);
    glVertex2i(x2_init, y2_init);
    glEnd();
    //绘制裁剪后的线段
    glColor3f(0.0, 0.0, 0.0);
    glBegin(GL_LINES);
    glVertex2i(x1, y1);
    glVertex2i(x2, y2);
    glEnd();

    CS_LineClip(x1, y1, x2, y2, XL, XR, YB, YT);
    glPopMatrix();
    glFlush();     // 处理绘图pipeLine
    //glutSwapBuffers(); //GLUT_DOUBLE
}

void main(int argc, char** argv)
{
    glutInit(&argc, argv);  // 初始化GLUT环境
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);   // GLUT显示模式:单缓冲区、RGB颜色模型
    //glutInitWindowPosition(50, 100);   // 窗口左上角的位置
    glutInitWindowSize(800, 600);      // 显示窗口的大小
    glutCreateWindow("Cohen-Sutherland裁剪算法"); // 创建显示窗口,加上标题
    init();
    glutDisplayFunc(draw);           // 调用绘图函数
    glutMainLoop();				 // 进入事件处理循环
}

运行截图
直线段裁剪Cohen-Sutherland算法_第2张图片

你可能感兴趣的:(c++,opengl,算法)