• 机械版CG 实验4 裁剪


    1.实验目的:

    了解二维图形裁剪的原理(点的裁剪、直线的裁剪、多边形的裁剪),利用VC+OpenGL实现直线的裁剪算法。

     

    2.实验内容:

    (1)       理解直线裁剪的原理(Cohen-Surtherland算法)

    (2)       利用VC+OpenGL实现直线的编码裁剪算法,在屏幕上用一个封闭矩形裁剪任意一条直线。

    (3)       调试、编译、修改程序。

     

    3.实验原理:

    编码裁剪算法的主要思想是:对于每条线段,分为三种情况处理。(1)若线段完全在窗口之内,则显示该线段,称为;(2)若线段明显在窗口之外,则丢弃该线段,称为;(3)若线段既不满足的条件,也不满足的条件,则把线段分割为两段。其中一段完全在窗口之外,可弃之;对另一段则重复上述处理。

    算法中,为了快速判断一条直线段与矩形窗口的位置关系,采用了如图所示的空间划分和编码方案。延长窗口的四条边界,把未经裁剪的图形区域分为九个区,每个区有一个四位二进制的编码,从左到右各位依次表示上、下、右、左。例如,区号0101,左起第二位1表示该区在窗口的下方;右起第一位的1表示该区在窗口的左方。整个区号表示该区在窗口的左下方。

     

    裁剪一条线段时,先求出两端点所在的区号code1code2,若code1 = 0code2 = 0,则说明线段的两个端点均在窗口内,那么整条线段必在窗口内,应取之;若code1code2经按位与运算的结果不为0,则说明两个端点同在窗口的上方、下方、左方或右方。这种情况下,对线段的处理是弃之。如果上述两种条件都不成立,则按第三种情况处理。求出线段与窗口某边的交点,在交点处把线段一分为二,其中必有一段完全在窗口外,可弃之,对另一段则重复上述处理。

     

    4.实验代码:

    #include <GL/glut.h>

    #include <stdio.h>

    #define LEFT_EDGE   1 //代表0001

    #define RIGHT_EDGE 2         //代表0010

    #define BOTTOM_EDGE 4       //代表0100

    #define TOP_EDGE    8         //代表1000

    bool bInput, accept, bDraw;

    struct Rectangle

    {

             float xmin,xmax,ymin,ymax;

    };

    Rectangle rect;

    struct Point {    int x, y;};

    Point pt[2];

    void LineGL(Point pt0, Point pt1)

    {

             glBegin (GL_LINES);

             glColor3f (1.0f, 0.0f, 0.0f);   glVertex2f (pt0.x,pt0.y);

             glColor3f (0.0f, 1.0f, 0.0f);   glVertex2f (pt1.x,pt1.y); 

             glEnd ();

    }

    void PointGL(Point pt)

    {

             glPointSize(2);

             glBegin (GL_POINTS);

             glColor3f (1.0f, 0.0f, 0.0f);   glVertex2f (pt.x,pt.y);

             glEnd ();

    }

    int CompCode(Point pt,Rectangle rect)

    {

             int code=0x00;

             if(pt.y<rect.ymin)

                       code=code|BOTTOM_EDGE;

             if(pt.y>rect.ymax)

                       code=code|TOP_EDGE;

             if(pt.x>rect.xmax)

                       code=code|RIGHT_EDGE;

             if(pt.x<rect.xmin)

                       code=code|LEFT_EDGE;

             return code;

    }

    void cohensutherlandlineclip(Rectangle rect, Point &pt0, Point &pt1)

    {

             int &x0 = pt0.x;

             int &y0 = pt0.y;

             int &x1 = pt1.x;

             int &y1 = pt1.y;

             bool done = false;

             float x,y;

             int code0,code1, codeout;

             code0 = CompCode(pt0,rect);

             code1 = CompCode(pt1,rect);

             do{

                       if(!(code0 | code1))

                       {

                                accept=true;

                                done=true;

                       }

                       else if(code0 & code1)

                       {

                                done = true;

                       }

                       else

                       {  

                                if(code0!=0)

                                         codeout = code0;

                                else

                                         codeout = code1;

                                if(codeout&LEFT_EDGE){

                                         y=y0+(y1-y0)*(rect.xmin-x0)/(x1-x0);

                                         x=(float)rect.xmin;

                                }

                                else if(codeout&RIGHT_EDGE){

                                         y=y0+(y1-y0)*(rect.xmax-x0)/(x1-x0);

                                         x=(float)rect.xmax;

                                }

                                else if(codeout&BOTTOM_EDGE){

                                         x=x0+(x1-x0)*(rect.ymin-y0)/(y1-y0);

                                         y=(float)rect.ymin;

                                }

                                else if(codeout&TOP_EDGE){

                                         x=x0+(x1-x0)*(rect.ymax-y0)/(y1-y0);

                                         y=(float)rect.ymax;

                                }

                                if(codeout == code0)

                                {

                                         x0=x;y0=y;

                                         code0 = CompCode(pt0,rect);

                                }

                                else

                                {

                                         x1=x;y1=y;

                                         code1 = CompCode(pt1,rect);

                                }

                       }

             }while(!done);

    }

    void myDisplay()

    {

             glClear(GL_COLOR_BUFFER_BIT);

             glColor3f (1.0f, 0.0f, 0.0f);

             glRectf(rect.xmin,rect.ymin,rect.xmax,rect.ymax);

             if(accept)         

             {

                       if(bDraw)

                       {

                                LineGL(pt[0],pt[1]);

                       }

                      else

                                PointGL(pt[0]);

             }

             glFlush();

    }

    void Init()

    {

             glClearColor(0.0, 0.0, 0.0, 0.0);

             glShadeModel(GL_FLAT);

             rect.xmin=100;

             rect.xmax=300;

             rect.ymin=100;

             rect.ymax=300;

             accept = true;

             bInput = false;

             printf("Press Left Mouse Button to Draw two Point to create a line!"nPress key 'c' to Clip!"n");

    }

    void Reshape(int w, int h)

    {

             glViewport(0, 0, (GLsizei) w, (GLsizei) h);

             glMatrixMode(GL_PROJECTION);

             glLoadIdentity();

             gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);

    }

    void keyboard(unsigned char key, int x, int y)

    {

             switch (key)

             {

             case 'c':

                       cohensutherlandlineclip(rect, pt[0],pt[1]);     

                       glutPostRedisplay();

                       break;

             default:

                       break;

             }

    }

    void mouse(int button, int state, int x, int y) //鼠标处理回调函数

    {

             switch (button)

             {

             case GLUT_LEFT_BUTTON://鼠标左键

                       if (state == GLUT_DOWN)//按下

                       {

                                if (bInput == false)

                                {

                                         pt[0].x = x;

                                         pt[0].y = 480 - y;

                                         bInput = true;

                                         bDraw = false;

                                         accept = true;

                                         glutPostRedisplay();//

                                }

                                else

                                {

                                         pt[1].x = x;

                                         pt[1].y = 480 - y;

                                         bDraw = true;

                                         bInput = false;

                                         glutPostRedisplay();//

                                }       

                       }

                       break;

             default:

                       break;

             }

    }

    int main(int argc, char *argv[])
    {
     glutInit(&argc, argv);
     glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
     glutInitWindowPosition(100, 100);
     glutInitWindowSize(640, 480);
     glutCreateWindow("Hello World!");

     Init();
     glutDisplayFunc(myDisplay);
     glutReshapeFunc(Reshape);
     glutKeyboardFunc(keyboard);
     glutMouseFunc(mouse); // 注册鼠标处理函数
     glutMainLoop();
     return 0;
    }

    代码注释:

    (1)程序增加了鼠标功能,在窗口内不同位置点击左键可生成一条直线;

    (2)实现鼠标函数mouse(int button, int state, int x, int y):处理鼠标click事件的函数。一般有4个参数:第一个参数表明哪个鼠标键被按下或松开,这个变量可以是下面的三个值中的一个:

    GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON
    第二个参数表明,函数被调用发生时,鼠标的状态,也就是是被按下,或松开,可能取值如下:
    GLUT_DOWN, GLUT_UP
    当函数被调用时,state的值是GLUT_DOWN,那么程序可能会假定将会有个GLUT_UP事件,甚至鼠标移动到窗口外面,也如此。然而,如果程序调用glutMouseFunc传递NULL作为参数,那么GLUT将不会改变鼠标的状态。 

    剩下的两个参数(x,y)提供了鼠标当前的窗口坐标(以左上角为原点)。

    更多详细介绍请参考:http://blog.csdn.net/nauty_li/archive/2008/03/29/2227163.aspx 

    (3)为确保程序运行正确请不要用鼠标拖动改变窗口的大小。 

    (4)附MFC代码示例:/Files/opengl/LineClip_GDI.rar

     

     

    5.实验思考题

     请分别给出直线的三种不同位置情况,测试实验代码是否存在问题,有的话请调试改正

  • 相关阅读:
    结对编程-马尔科夫链作业成绩
    结对编程-四则运算(挑战出题)成绩及点评
    结对编程-四则运算成绩
    结对编程-四则运算(挑战出题)
    结对编程
    每天进步一点点-第二天卒
    每天进步一点点-深度学习入门-基于Python的理论与实现 (一)
    今天准备更新每天提高一点点系列
    Books
    WPF命令好状态刷新机制
  • 原文地址:https://www.cnblogs.com/opengl/p/947346.html
Copyright © 2020-2023  润新知