Liang-Barsky裁剪算法

说明

在阅读此博客前,请访问2018级山东大学计算机学院图形学实验汇总

原笔记通过latex编写,csdn只支持latex部分功能,所以下面主要是将pdf截屏上传。部分内容参考中国农业大学计算机图形学mooc。

算法介绍

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

代码

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "shader.h"
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;

const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
const char* vertexShaderPath="/Users/longzhengtian/Desktop/代码/C++代码/ComputerGraphics/shader.vs";
const char* fragmentShaderPath="/Users/longzhengtian/Desktop/代码/C++代码/ComputerGraphics/shader.fs";

struct node{double x,y;}a[2],b[2];
struct Node{double xleft,xright,ytop,ybottom;}rec;
unsigned int VBO[3], VAO[3];
int clickwho=-1;
bool DrawLine=false,DrawRec=false,DrawLineEnd=false,DrawRecEnd=false;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
void Liang_barsky();
bool distant(node p1,node p2){return (pow(fabs(p1.x-p2.x),2)+pow(fabs(p1.y-p2.y),2)<=25);}
float transX(double x){return (float)((float)(2*x)-SCR_WIDTH)/(SCR_WIDTH*1.0f);}
float transY(double y){return (float)(SCR_HEIGHT-2*(float)y)/(SCR_HEIGHT*1.0f);}

int main(){
    //实例化glfw函数
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    //创建glfw窗口
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LiangBarsky", nullptr, nullptr);
    if (window == nullptr){
        cout << "Failed to create GLFW window" << endl;
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);//将window设置为接下来操作的主窗口
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwSetKeyCallback(window, key_callback);
    glfwSetMouseButtonCallback(window, mouse_button_callback);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){//使用glad加载glfw的所有函数指针
        cout << "Failed to initialize GLAD" << endl;
        return -1;
    }

    Shader ourShader(vertexShaderPath,fragmentShaderPath);//创建着色器程序

    float RecVertices[13] = {};//裁剪窗口
    float Lin1Vertices[7] = {};//原始线
    float Lin2Vertices[7] = {};//裁剪窗口里面的线

    glGenVertexArrays(3, VAO);
    glGenBuffers(3, VBO);

    glBindVertexArray(VAO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(RecVertices), RecVertices, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glBindVertexArray(VAO[1]);
    glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Lin1Vertices), Lin1Vertices, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glBindVertexArray(VAO[2]);
    glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Lin2Vertices), Lin2Vertices, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    while (!glfwWindowShouldClose(window)){
        //输入
        processInput(window);
//        float timeValue = glfwGetTime();
//        float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
//        float redValue = (cos(timeValue) / 2.0f) + 0.5f;
//        float blueValue = (tan(timeValue) / 2.0f) + 0.5f;
//        glClearColor(redValue, greenValue, blueValue, 1.0f);

        //渲染命令
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        //裁剪窗口
        //ourShader.setVec4("ourColor",greenValue,blueValue,redValue,1.0f);
        ourShader.setVec4("ourColor",1.0f,1.0f,1.0f,1.0f);
        ourShader.use();
        glBindVertexArray(VAO[0]);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        //主线条
        ourShader.setVec4("ourColor",1.0f,0.0f,0.0f,1.0f);
        ourShader.use();
        glBindVertexArray(VAO[1]);
        glDrawArrays(GL_LINES, 0, 2);

        //窗口里面的线条
        ourShader.setVec4("ourColor",0.0f,0.0f,0.0f,1.0f);
        ourShader.use();
        glBindVertexArray(VAO[2]);
        glDrawArrays(GL_LINES, 0, 2);

        //检查并调用事件,交换缓冲
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glDeleteVertexArrays(3, VAO);
    glDeleteBuffers(3, VBO);
    glfwTerminate();
    return 0;
}
void Liang_barsky(){
    double p[5],q[5],umax=0,umin=1;
    memset(p,0,sizeof(p)); memset(q,0,sizeof(q));
    double xleft=min(rec.xleft,rec.xright),xright=max(rec.xleft,rec.xright);
    double ytop=max(rec.ytop,rec.ybottom),ybottom=min(rec.ytop,rec.ybottom);
    p[1]=a[0].x-a[1].x; q[1]=a[0].x-xleft;
    p[2]=a[1].x-a[0].x; q[2]=xright-a[0].x;
    p[3]=a[0].y-a[1].y; q[3]=a[0].y-ybottom;
    p[4]=a[1].y-a[0].y; q[4]=ytop-a[0].y;

    for (int i=1; i<=4; i++){
        if(p[i]<0) umax=max(umax,q[i]/p[i]);
        else if(p[i]>0) umin=min(umin,q[i]/p[i]);
        else if(p[i]==0 && q[i]<0){ umax=-1; break; }
    }
    if(umax<=umin && umax>=0 && umax<=1 && umin>=0 && umin<=1){
        b[0].x=a[0].x+umax*(a[1].x-a[0].x);
        b[0].y=a[0].y+umax*(a[1].y-a[0].y);
        b[1].x=a[0].x+umin*(a[1].x-a[0].x);
        b[1].y=a[0].y+umin*(a[1].y-a[0].y);
        float tempvec[]={transX(b[0].x),transY(b[0].y),1.0f,
                         transX(b[1].x),transY(b[1].y),1.0f
        };
        glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(tempvec), &tempvec);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
    else{
        b[0].x=0; b[0].y=0; b[1].x=0; b[1].y=0;
        float tempvec[]={0,0,1.0f,0,0,1.0f};
        glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(tempvec), &tempvec);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
}
void processInput(GLFWwindow *window){
    if(clickwho>=0 && clickwho<=3){//移动矩形
        double xpos,ypos;
        glfwGetCursorPos(window,&xpos,&ypos);
        if(clickwho==0){rec.xleft=xpos; rec.ybottom=ypos;}//"左下"
        else if(clickwho==1){rec.xright=xpos; rec.ytop=ypos;}//"右上"
        else if(clickwho==2){rec.xleft=xpos; rec.ytop=ypos;}//"左上"
        else if(clickwho==3){rec.xright=xpos; rec.ybottom=ypos;}//"右下"
        float tempvec[]={transX(rec.xleft),transY(rec.ybottom),1.0f,
                         transX(rec.xleft),transY(rec.ytop),1.0f,
                         transX(rec.xright),transY(rec.ybottom),1.0f,
                         transX(rec.xright),transY(rec.ytop),1.0f
        };
        glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
        glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(tempvec),&tempvec);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        if(DrawLineEnd || DrawRecEnd) Liang_barsky();//裁剪
    }
    else if(clickwho>=4){//移动直线
        double xpos,ypos;
        glfwGetCursorPos(window,&xpos,&ypos);
        a[clickwho-4].x=xpos; a[clickwho-4].y=ypos;
        float tempvec[]={transX(a[0].x),transY(a[0].y),1.0f,
                         transX(a[1].x),transY(a[1].y),1.0f
        };
        glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(tempvec), &tempvec);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        if(DrawLineEnd || DrawRecEnd) Liang_barsky();//裁剪
    }
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height){
    glViewport(0, 0, width, height);
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
    else if (key == GLFW_KEY_R && action == GLFW_PRESS) {//如果按下"R",画裁剪窗口
        if(!DrawLine){//此时不是属于画直线时刻
            if(!DrawRec){//开始画窗口
                double xpos,ypos;
                glfwGetCursorPos(window,&xpos,&ypos);
                rec.xleft=xpos; rec.ybottom=ypos;
                clickwho=1; DrawRec=true;//此时的状态和点击了"右上"是一样的,都是"右上"在移动
            }
            else {//结束画窗口
                clickwho=-1; DrawRec=false; DrawRecEnd=true;
                if(DrawLineEnd || DrawRecEnd) Liang_barsky();//裁剪
            }
        }
    }
    else if (key == GLFW_KEY_L && action == GLFW_PRESS) {//如果按下"L",画直线
        if(!DrawRec){//此时不是属于画裁剪窗口时刻
            if(!DrawLine){//开始画直线
                double xpos,ypos;
                glfwGetCursorPos(window,&xpos,&ypos);
                a[0].x=xpos; a[0].y=ypos;
                clickwho=5; DrawLine=true;//此时状态和点击了第二个点是一样点,都是第二个点在移动
            }
            else {//结束画直线
                clickwho=-1; DrawLine=false; DrawLineEnd=true;
                if(DrawLineEnd || DrawRecEnd) Liang_barsky();//裁剪
            }
        }
    }
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods){
    if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS && !DrawLine && !DrawRec){//此时没有画裁剪窗口和直线
        double xpos,ypos;
        glfwGetCursorPos(window,&xpos,&ypos);
        if(clickwho!=-1) clickwho=-1;//移动中点击了鼠标,肯定是要结束了
        else if(distant({rec.xleft,rec.ybottom},{xpos,ypos})) clickwho=0;//点击矩形"左下"
        else if(distant({rec.xright,rec.ytop},{xpos,ypos})) clickwho=1;//点击矩形"右上"
        else if(distant({rec.xleft,rec.ytop},{xpos,ypos})) clickwho=2;//点击矩形"左上"
        else if(distant({rec.xright,rec.ybottom},{xpos,ypos})) clickwho=3;//点击矩形"右下"
        else if(distant(a[0],{xpos,ypos})) clickwho=4;//点击直线的第一个点
        else if(distant(a[1],{xpos,ypos})) clickwho=5;//点击直线的第二个点
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值