• 计算机图形学 实验三 梁氏裁剪算法


    实验三:裁剪算法

    实验目的: 掌握 Liang-Barsky 裁剪算法

    基本要求:

     实现 Liang-Barsky 裁剪算法

     绘制任意方向数量线段,可移动的裁剪窗口,通过不同颜色标识裁剪窗口内外 的部分,效果可参考下图(可交互的移动裁剪窗口并实时显示裁剪效果)

     画线的命令可以使用 OpenGL 提供的画线函数

    实现:

    使用方法:邮件开启菜单。点击规划后开始画线段集合。画完线段集合后按回车就可以退出,然后鼠标左键拖动就可以任意剪裁了。

     

    #define EXIT_SUCCESS 0
    #include<stdio.h>
    #include <stdlib.h>
    #include<GL/glut.h>
    #include<math.h>
    #include<queue>
    #include<vector>
    #include<algorithm>
    #include "cross.h"
    #include<iostream>
    using  namespace std;
    // later Edition
    int MODE = 0;
    bool mouseLeftDown;     // 实时记录鼠标左键状态
    bool mouseRightDown;    // 实时记录鼠标左键状态
    float mouseX, mouseY;   // 实时记录鼠标位置,与下一次鼠标位置之间形成微分
    bool status = false;    // 标记当前是否为规划状态,规划状态下进行线段的绘制,非规划状态下进行任意的剪裁
    int startX=0, startY=0, endX=0, endY=0;
    int start[2] = { 0 };
    int end[2] = { 0 };
    float red=1.0,green=1.0, blue=0.0;
    float PI = 3.415926535;
    
    int clipX1, clipX2, clipY1, clipY2;
    
    Point sp, previous, now;
    bool start_pass = false;
    // 纯粹的交点模式,简单的交点判别法
    vector<pair<Point,Point> > q;// 存储边集,在编辑中存储需要的数据
    vector<vector<edge> > NET(501);
    vector<vector<edge> > AET(501);// 活性边 
    // 数据结构上,对于求交,需要以下几个数据结构
    // 1.存储所有边,然后存储边的所有交集。对于边的所有交集,目前可以按照一个简单的有序队列的方式进行。
    vector<vector<int> > t(501);// 存储所有扫描线与各个边的交点。
    
    ostream& operator<<(ostream& output,const Point& p) {
        cout <<"("<< p.x << "," << p.y << ")";
        return output;
    }
    
    bool ClipT(float p, float q, float* u1, float* u2) {
        float r;
        if (p < 0) {
            r = q / p;
            if (r > * u2)
                return false;
            if (r > * u1)
                *u1 = r;
        }
        else if (p > 0) {
            r = q / p;
            if (r < *u1)
                return false;
            if (r < *u2)
                *u2 = r;
        }
        else
            return (q >= 0);
        return true;
    }
    
    
    void LB_LineClip(float x1, float y1, float x2, float y2, float XL, float XR, float YB, float YT) {
        float dx, dy, u1, u2;
        dx = x2 - x1;dy = y2 - y1;
        u1 = 0;u2 = 1;
        if (ClipT(-dx, x1 - XL, &u1, &u2))
            if (ClipT(dx, XR - x1, &u1, &u2))
                if (ClipT(-dy, y1 - YB, &u1, &u2))
                    if (ClipT(dy, YT - y1, &u1, &u2)) {
                        glVertex2i(int(x1 + u1 * dx), int(y1 + u1 * dy));
                        glVertex2i(int(x1 + u2 * dx), int(y1 + u2 * dy));
                    }
    }
    
    int arr[500][500];
    
    void init(void)
    {
        //glClearColor(0.0, 0.0, 0.0, 0.0);/* select clearing color  */   // 设置背景颜色为黑色
        //glMatrixMode(GL_MODELVIEW);                   
        glClearColor(0.0, 0.0, 0.0, 0.0); /* white background */
        glColor3f(1.0, 0.0, 0.0); /* draw in red */
    
        /* set up viewing: */
        /* 500 x 500 window with origin lower left */
    
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(0.0, 500.0, 0.0, 500.0);
        glMatrixMode(GL_MODELVIEW);
    }
    
    
    
    
    #define RED 1233
    #define BLUE 1234
    #define GREEN 1235
    #define WHITE 12366
    #define YELLOW 12367
    #define SCAN_LINE 12368
    #define AET 12369
    void processMenuEvents(int option) {
        //option,就是传递过来的value的值。
        switch (option) {
        case RED:
            red = 1.0;
            green = 0.0;
            blue = 0.0; break;
        case GREEN:
            red = 0.0;
            green = 1.0;
            blue = 0.0; break;
        case BLUE:
            red = 0.0;
            green = 0.0;
            blue = 1.0; break;
        case WHITE:
            red = 1.0;
            green = 1.0;
            blue = 1.0; break;
        case YELLOW:
            red = 1.0;
            green = 1.0;
            blue = 0.0;break;
        case SCAN_LINE:
            for (int i = 1;i <= 500;i++)t[i].clear();
            q.clear(); // 将归去的全部线段全部清空
            sp.x = -1;sp.y = -1;
            startX = startY = endX = endY = -1;//将临时起点和中点全部清空。
            glutPostRedisplay();
            status = true;
            MODE = 0;break;
        case AET:
            MODE = 1;break;
        }
    }
    void createGLUTMenus() {
    
        int menu;
    
        // 创建菜单并告诉GLUT,processMenuEvents处理菜单事件。
        menu = glutCreateMenu(processMenuEvents);
    
        //给菜单增加条目
        glutAddMenuEntry("绘制线段集", SCAN_LINE);
        glutAddMenuEntry("红色", RED);
        glutAddMenuEntry("蓝色", BLUE);
        glutAddMenuEntry("绿色", GREEN);
        glutAddMenuEntry("白色", WHITE);
        glutAddMenuEntry("黄色", YELLOW);
        
    
        // 把菜单和鼠标右键关联起来。
        glutAttachMenu(GLUT_RIGHT_BUTTON);
    }
    
    
    void display(void)
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glColor3f(red, green,blue);
        glLoadIdentity();
    
        
        glLineWidth(1.0);
        // 规划模式下的线段集合进行作图,在任何模式下都会显示,但是内容有可能会被修改
        glBegin(GL_LINES);
        for (int i = 0;i < q.size();i++) {
            glVertex2i(q[i].first.x, q[i].first.y);
            glVertex2i(q[i].second.x, q[i].second.y);
        }
    
        glEnd();
        // 进行剪裁作图
        glColor3f(1 - red, 1 - green, 1 - blue);
        glLineWidth(3.0);
        glBegin(GL_LINES);
        for (int i = 0;i < q.size();i++) {
            LB_LineClip(q[i].first.x, q[i].first.y, q[i].second.x, q[i].second.y, min(clipX1, clipX2), max(clipX1, clipX2), min(clipY1, clipY2), max(clipY1, clipY2));
        }
        glEnd();
    
    
        // 实时显示的线段,仅在规划模式下显示。
        if (status) {// 规划模式下对绘制的直线进行实时显示
            glColor3f(1 - red/2, 1 - green/2, 1 - blue/2);
            glLineWidth(2.0);
            // 规划模式下的线段集合进行作图
            glBegin(GL_LINES);
            glVertex2i(startX,startY);
            glVertex2i(endX, endY);
    
            glEnd();
        }
    
    
    
        if (!status) {// 规划模式下对绘制的直线进行实时显示
            glColor3f(1 - red, 1 - green, 1 - blue);
            glLineWidth(3.0);
            // 规划模式下的线段集合进行作图
            glBegin(GL_LINES);
            glVertex2i(clipX1,clipY1);
            glVertex2i(clipX2, clipY1);
    
            glVertex2i(clipX1, clipY1);
            glVertex2i(clipX1, clipY2);
    
            glVertex2i(clipX2, clipY1);
            glVertex2i(clipX2, clipY2);
    
            glVertex2i(clipX2, clipY2);
            glVertex2i(clipX1, clipY2);
            
            glEnd();
    
        }
    
        glColor3f(red, green, blue);
        if (!status);// 在非规划模式下作图
        // Draw here
        
        
        glutSwapBuffers();
    }
    int saveStack = 0;
    void keyboard(unsigned char key, int x, int y)
    
    {
        switch (key) {
            case 'q':case 'Q':
                exit(EXIT_SUCCESS);
                break;
            case 13:
                if (status) {
                    status = false;// 回车退出规划模式,并且进行全部直线的正常绘制。
                    cout << "should display" << endl;
                    glutPostRedisplay();
                }
                
                break;
            case 'r':case 'R':
                for (int i = 1;i <= 500;i++)t[i].clear();
                q.clear();
                glutPostRedisplay();
                break;
        }
    }
    int ww, hh;
    
    void mouse_process(int button, int state, int x, int y)
    {
        mouseX = x;
        mouseY = y;
        printf("<%d,%d>
    ", x, y);
        cout << "===============" << endl;
        for (int i = 0;i < q.size();i++) {//显示当前的所有边
            cout << q[i].first <<"-"<< q[i].second << endl;
        }
        now = Point(x, hh - y);// 时刻记录当前的点位
    
        hh = glutGet(GLUT_WINDOW_HEIGHT);
        if (button == GLUT_LEFT_BUTTON)
        {
            if (state == GLUT_DOWN)
            {
                
                if (!mouseLeftDown&&status) {
                    startX=endX = x;startY =endY= hh-y;
                    sp = Point(x, hh - y);// 同步初始点位进行初始化。
                } 
                if (!mouseLeftDown && !status) {// 非规划的剪裁模式下,将会进行剪裁起点的刷新。
                    clipX1 = x;clipY1 = hh - y;
                }
               
                //glutPostRedisplay();
                // 鼠标左键按下的一刻只需要起始点即可,并不需要进行刷新。
                mouseLeftDown = true;
            }
            else if (state == GLUT_UP) {
                //在规划模式下进行线段输入
                
                // 画好了一个线段需要进行刷新
                pair<Point, Point> v(sp, now);
                if(status)q.push_back(v);
                
                glutPostRedisplay();
                mouseLeftDown = false;
       
            }
                
        }
    
        else if (button == GLUT_RIGHT_BUTTON)
        {
            if (state == GLUT_DOWN)
            {
                mouseRightDown = true;
            }
            else if (state == GLUT_UP)
                
                mouseRightDown = false;
        }
    
    
        
    }
    
    void mouse_process_active(int x, int y)
    {
        if (mouseLeftDown){
            if (status) {// 规划模式下对终点坐标进行实时更新
                endX = x;endY = hh - y;
                clipX1 = clipY1 = clipX2 = clipY2 = -1;
                
            }
            else {
                clipX2 = x;clipY2 = hh - y;
                endX  = -1;endY = -1;
            }
            glutPostRedisplay();
        }
        if(mouseRightDown)
        {
    
        }
        glutPostRedisplay();
    
    }
    void mouse_process_passtive(int x, int y) {}
    
    
    int main(int argc, char** argv)
    {
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
        glutInitWindowSize(500, 500);
        glutCreateWindow("右键开启菜单,回车退出规划");
    
        init();
    
        Point a(40, 40), b(150, 60), c(100, 100), d(10, 70);
        pair<Point, Point> v1(a, b), v2(b, c), v3(c, d), v4(d, a);
        q.push_back(v1);q.push_back(v2);q.push_back(v3);q.push_back(v4);
     
        glutDisplayFunc(display);
        
        // later Edition
        glutMouseFunc(mouse_process);
        glutMotionFunc(mouse_process_active);
        glutPassiveMotionFunc(mouse_process_passtive);
        createGLUTMenus();
        glutKeyboardFunc(keyboard);
        glutMainLoop();
    
        return 0;
    }
  • 相关阅读:
    nodejs日志管理log4js
    js数组去重的几种方法
    Echarts同一页面多个图表自适应浏览器窗口大小——window.onresize
    Echarts自适应浏览器大小
    [原创]Nodejs 远程执行linux shell
    ssh无需密码登录linux服务器
    Nodejs mysql pool使用实例
    Activity基础知识
    最大熵模型介绍
    node-sass element-plus 安装失败
  • 原文地址:https://www.cnblogs.com/PRCdefender/p/14606363.html
Copyright © 2020-2023  润新知