openGL-多边形裁剪算法

综述:

这里只是简单记录了部分实现思想。该部分代码不具备实际使用功能。
考虑使用4把刀分别裁剪一个图形。核心思想是,有一个点在扫描整个图形的边界。在扫描过程中,如果从刀的内侧(需要自己定义)到刀的外侧那么就记录当前点p0,当再次从外侧进入内测时,将当前点和记录的p0连起来。对于“覆盖遮挡”的边界可以利用
(a^b)^b = a来实现“抹去还原”。

#include <GLUT/GLUT.h>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
float wid = 400;         //设置窗口的大小,约定窗口必须为正方形
float height = wid;      //设置窗口的大小
int numbers = 40;       //设置划分的网格的个数
float t = wid/numbers; //模拟像素下的单位1
int index_y;                 //记录下斜率为-1时的y的位置
int con[801][801];         //相当于我们的画布(其中的信息是有层次的)
int visited[801][801];
int flag = 0;                //标定移动轨迹的位置
int x_pos,y_pos,x_1=2*wid,y_1=2*wid;
int pixel_size = 8;       //统一设定所有的的pixel的大小;
/*
 参数设置说明:
 您应当确保参数范围在-400~400.且为整数。
 由于使用的是模拟像素,应保持数据为单位模拟像素值的倍数。
 */
int x=0;
int y=0;
int a  = 300;
int b  = 200;
void draw_point(float x, float y,float x1,float y1);
void add(int x, int y ,int data){
    con[x+400][y+400] = data ;
}
float translater(int x){
    /*
     函数说明:将像素坐标下的坐标转化为openGL坐标
     参数说明:传入点像素坐标-wid-wid,返回-1~1坐标
     */
    return  x/wid;
}


void draw_point(float x , float y){
    /*
     函数说明:绘制像素的点,这里将点的大小设置为7。
     颜色采用蓝色。利用圆八个部分的坐标对应关系进行绘图。
     加x1与y1是为了进行圆的平移
     参数说明:浮点数x,y是openGl坐标系。
     */
    glPointSize(pixel_size);
    glColor3f(1.0,0.0,0.0);
    glBegin(GL_POINTS);
    glVertex3f(x,y,0.0);
    glVertex3f(-x,y,0.0);              //关于y轴对称
    glVertex3f(x,-y,0.0);              //关于x轴对称
    glVertex3f(-x,-y,0.0);            //关于原点对称
    glEnd();
    glFlush();
}
bool out_of_index(int x,int y){
    if(y>=801||x>=801||x<0||y<0){
        return 0;
    }else{
        return 1;
    }
}

void draw_inner(int x, int y){
    glPointSize(pixel_size);
    glColor3f(0.0,1.0,1.0);
    glBegin(GL_POINTS);
    glVertex3f(translater(x-400),translater(y-400),0.0);
    glEnd();
    glFlush();
}
void draw_inner2(int x, int y){
    glPointSize(pixel_size);
    glColor3f(0.0,0.0,1.0);
    glBegin(GL_POINTS);
    glVertex3f(translater(x-400),translater(y-400),0.0);
    glEnd();
    glFlush();
}
void draw_line(int x,int y , int xx , int yy){
    for (int i = min(x,xx); i <= max(x,xx); i+=10) {
        for(int j  =min (y,yy);j<=max(y,yy);j+=10){
            if(con[i][j]!=1){
                int res= con[i][j]^1111;
            if(res  == -1){
                glPointSize(pixel_size);
                glColor3f(1.0,0.0,0.0);
                glBegin(GL_POINTS);
                glVertex3f(translater(i-400),translater(j-400),0.0);
                glEnd();
                glFlush();
            }else{
                draw_inner(i, j);
            }
                if(con[i][j] ==0){
                    con[i][j] = 1;
                    visited[i][j] =1;
                }else{
                    con[i][j] = res;
                }
            }
        }
    }
}
void draw_line2(int x,int y , int xx , int yy){
    for (int i = min(x,xx); i <= max(x,xx); i+=10) {
        for(int j  =min (y,yy);j<=max(y,yy);j+=10){
            if(con[i][j]!=1){
                int res= con[i][j]^1112;
                if(res  == -1&&res== ((-1)^1111)){
                    glPointSize(pixel_size);
                    glColor3f(1.0,0.0,0.0);
                    glBegin(GL_POINTS);
                    glVertex3f(translater(i-400),translater(j-400),0.0);
                    glEnd();
                    glFlush();
                }else{
                    draw_inner2(i, j);
                }
                con[i][j] = res;
            }
        }
    }
}

void search(int x,int y,int index){
    cout << index << " - - "<<endl;
    /*
     函数说明:进行Dfs搜索并模拟四把刀当中的其中一把刀
     可视化着色采用淡蓝色。
     参数说明:x y是坐标,index是指明哪一把刀。
     传入的xy是数组坐标!
     */
    if (visited[x][y] ==1) {
        return;
    }
    if(index == 1){
        //讨论下方的情况
        if(flag ==0){
            //如果本来在外侧
            if(y-400 >= -200){
                //从外侧进入内侧
                draw_inner(x, y);
                y_1 = min(y_1,y);
                x_1 = min(x_1,x);
                flag =1;
                x_pos= x;
                y_pos = y;
            }else{
                glPointSize(8);
                glColor3f(0.5,0.5,0.5);
                glBegin(GL_POINTS);
                glVertex3f(translater(x-400),translater(y-400),0.0);
                glEnd();
                glFlush();
                flag =0;
                con[x][y] = 0;
            }
        }else if(flag==1){
            //如果本来在内侧进入了外侧
            if(y-400 <= -200){
                draw_inner(x, y);
                //从内侧进入外侧
                draw_line(x_pos, y_pos, x, y);
                x_pos = 0;
                y_pos  =0;
                flag =0;
            }else{
                flag=1;
                draw_inner(x, y);
                y_1 = min(y_1,y);
                x_1 = min(x_1,x);
            }
        }
        visited[x][y] = 1;
        if(out_of_index(x+10, y)&&con[x+10][y]==1&&visited[x+10][y]==0){
            search(x+10,y,index);
            visited[x+10][y] =1;
        }
        if(out_of_index(x,y+10)&&con[x][y+10]==1&&visited[x][y+10]==0){
            search(x,y+10,index);
            visited[x][y+10] =1;
        }
        if(out_of_index(x+10,y+10)&&con[x+10][y+10]==1&&visited[x+10][y+10]==0){
            search(x+10,y+10,index);
            visited[x+10][y+10] =1;
        }
        if(out_of_index(x+10,y-10)&&con[x+10][y-10]==1&&visited[x+10][y-10]==0){
            search(x+10,y-10,index);
            visited[x+10][y-10] =1;
        }
        if(out_of_index(x,y-10)&&con[x][y-10]==1&&visited[x][y-10]==0){
            search(x,y-10,index);
            visited[x][y-10] =1;
        }
        if(out_of_index(x-10,y)&&con[x-10][y]==1&&visited[x-10][y]==0){
            search(x-10,y,index);
            visited[x-10][y] =1;
        }
        if(out_of_index(x-10,y+10)&&con[x-10][y+10]==1&&visited[x-10][y+10]==0){
            search(x-10,y+10,index);
            visited[x-10][y+10] =1;
        }
        if(out_of_index(x-10,y-10)&&con[x-10][y-10]==1&&visited[x-10][y-10]==0){
            search(x-10,y-10,index);
            visited[x-10][y-10] =1;
        }
    }else if(index ==2){
        //讨论左侧的情况
        if(flag ==0){
            //如果本来在外侧
            if(x-400 >= -300){
                draw_inner2(x, y);
                //从外侧进入内侧
                flag =1;
                x_pos= x;
                y_pos = y;
            }else{
                glPointSize(8);
                glColor3f(1.0,1.0,1.0);
                glBegin(GL_POINTS);
                glVertex3f(translater(x-400),translater(y-400),0.0);
                glEnd();
                glFlush();
                flag =0;
            }
        }else if(flag==1){
            //如果本来在内侧进入了外侧
            if(x-400 <= -300){
                draw_inner2(x, y);
                //从内侧进入外侧
                cout << "inner -> outer  "<< endl;
                cout << x_pos <<" == "<< y_pos <<endl;
                cout << x <<" === " <<  y <<endl;
                draw_line2(x_pos, y_pos, x, y);
                cout << con[x-10][y] <<"here !!  "<< endl;
                x_pos = 0;
                y_pos  =0;
                flag =0;
            }else{
                flag=1;
                draw_inner2(x, y);
            }
        }
        visited[x][y] = 1;
        if(out_of_index(x+10, y)&&(con[x+10][y]==1||con[x+10][y]==(-1^1111))&&visited[x+10][y]==0){
            search(x+10,y,index);
            visited[x+10][y] =1;
        }
        if(out_of_index(x,y+10)&&(con[x][y+10]==1||con[x][y+10]==(-1^1111))&&visited[x][y+10]==0){
            search(x,y+10,index);
            visited[x][y+10] =1;
        }
        if(out_of_index(x+10,y+10)&&(con[x+10][y+10]==1||con[x+10][y+10]==(-1^1111))&&visited[x+10][y+10]==0){
            search(x+10,y+10,index);
            visited[x+10][y+10] =1;
        }
        if(out_of_index(x+10,y-10)&&(con[x+10][y-10]==1||con[x+10][y-10]==(-1^1111))&&visited[x+10][y-10]==0){
            search(x+10,y-10,index);
            visited[x+10][y-10] =1;
        }
        if(out_of_index(x,y-10)&&(con[x][y-10]==1||con[x][y-10]==(-1^1111))&&visited[x][y-10]==0){
            search(x,y-10,index);
            visited[x][y-10] =1;
        }
        if(out_of_index(x-10,y)&&(con[x-10][y]==1||con[x-10][y]==(-1^1111))&&visited[x-10][y]==0){
            search(x-10,y,index);
            visited[x-10][y] =1;
        }
        if(out_of_index(x-10,y+10)&&(con[x-10][y+10]==1||con[x-10][y+10]==(-1^1111))&&visited[x-10][y+10]==0){
            search(x-10,y+10,index);
            visited[x-10][y+10] =1;
        }
        if(out_of_index(x-10,y-10)&&(con[x-10][y-10]==1||con[x-10][y-10]==(-1^1111))&&visited[x-10][y-10]==0){
            search(x-10,y-10,index);
            visited[x-10][y-10] =1;
        }
    }

}
void cutter(int x, int y){
    /*
     函数说明:这里包含四把刀
     参数说明:传入我们的起始坐标
     */
    //首先判断点的位置:框内?框外?
    for (int i = 0; i <801; i++) {
        for (int j  =0; j < 801; j++) {
            visited[i][j] = 0;
        }
    }
    if(y < -200){
        //在下方
        flag =0;            //在下方外侧
        search(x+400,y+400,1);

    }
    if(x < -300){
        //在左侧!
        flag = 0;
        for (int i = 0; i <801; i++) {
            for (int j  =0; j < 801; j++) {
                visited[i][j] = 0;
            }
        }
        glPointSize(pixel_size);
        glColor3f(0.9,0.89,0.1);
        glBegin(GL_POINTS);
        glVertex3f(translater(x_1-400),translater(y_1-400),0.0);
        glEnd();
        glFlush();
        cout << "xx "<< x_1 -400 <<"  " << y_1-400 <<endl;
        search(x_1,y_1,2);
    }


}
void p(float x , float y,float x1,float y1){
    /*
     函数说明:绘制像素的点,这里将点的大小设置为7。
     颜色采用蓝色。利用圆八个部分的坐标对应关系进行绘图。
     加x1与y1是为了进行圆的平移
     参数说明:浮点数x,y是openGl坐标系。
     */
    glPointSize(pixel_size);
    glColor3f(1.0,1.0,0.0);
    glBegin(GL_POINTS);
    glVertex3f(x+x1,y+y1,0.0);
    glEnd();
    glFlush();
}
void paint(int x ,int y ){
    add(x,y, 1);
    p(translater(x), translater(y), 0, 0);
}
void grid(){
    /*
     函数说明:绘制网格为了便于将真实的像素pixel转化为我们模拟的像素
     */
    glClearColor(0, 0, 0, 0);//这是设置背景色,必须要在glclear之前调用
    glClear(GL_COLOR_BUFFER_BIT);
    int hei_number = numbers;
    float delta_hei = height / hei_number;
    glColor3f(0.0,1.0,0);
    for (int i = 1; i < numbers *2; i ++ ) { //利用循环绘制网格
        glBegin(GL_LINES);
        glVertex2f(-1+i*delta_hei/height, -1);
        glVertex2f(-1+i*delta_hei/height, 1);
        glVertex2f(-1,-1+i*delta_hei/height);
        glVertex2f(1,-1+i*delta_hei/height);
        glEnd();
        glFlush();}
    glColor3f(1.0,0,0);
    glBegin(GL_LINES);          //绘制坐标系,便于观察
    glVertex2f(-1,0);
    glVertex2f(1,0);
    glVertex2f(0,-1);
    glVertex2f(0,1);
    glEnd();
    glFlush();
    //绘制我们的框图
    for (int i = 0; i <= 300; i+=t) {
        draw_point(translater( i),translater(200));
        add(i, 200, -1);
        add(-i, 200, -1);
        add(i, -200, -1);
        add(-i, -200, -1);

    }
    for (int i = 0; i <= 200; i+=t) {
        draw_point(translater(300),translater( i));
        add(300,i, -1);
        add(-300,i, -1);
        add(300,-i, -1);
        add(-300,-i, -1);
    }
    //绘制多边形
    int dm = -370;
    //设置偏移量
    for (int i = 140; i<=240; i+=10) {
        paint(i, i+dm);
    }
    for(int i  =240; i <=340 ; i+=10 ){
        paint(240, i+dm);
        //绘制横线
    }
    for(int i = 240;i>=-200;i-=10 ){
        paint(i, 340+dm);
    }
    for(int i  = -200;i>=-380;i-=10){
        paint(i, 540+i+dm);
    }
    for(int i  = -200;i>=-380;i-=10){
        paint(i, 540+i+dm);
    }
    for(int i = 160; i >= -20 ; i-=10){
        paint(-380, i+dm);
    }
    for (int i = 1;i <=30; i++) {
        paint(-380+i*10, -20+i*10+dm);
    }
    for (int i = 1;i <=14; i++) {
        paint(-80+i*10, 280-i*10+dm);
    }
    for(int i  =60; i <=140 ; i+=10 ){
        paint(i, 140+dm);
    }
    cutter(-380, -390);
    //刷新缓冲,保证绘图命令能被执行
}



int main(int argc, char *argv[]) {
    //初始化GLUT library
    glutInit(&argc, argv);
    //对窗口的大小进行初始化
    glutInitWindowSize(700,700);
    glutInitWindowPosition(300,200);
    // 设置窗口出现的位置
    //glutInitWindowPosition(int x, int y);
    glutInitDisplayMode(GLUT_RGBA);
    glutCreateWindow("hw_多边形裁剪");
    glutDisplayFunc(&grid);
    glutMainLoop();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ooffrankdura/article/details/79677989