计算机图形学二(Sutherland_Hodgman算法)

一、功能介绍

主界面

单位为0.1的坐标系,依旧沿用实验一的Coordinate函数

 

多边形构造

通过鼠标左键在绘图区域内顺序点击依次获得多边形的各个顶点,顶点坐标储存在points[NUM][2]的二维数组中,其中NUM定义为10,即最多支持10个顶点。具体点的绘图在鼠标函数中实现。

 

菜单

点击鼠标右键可弹出菜单mymenu()

Line:将顶点连线成多边形

Cut:剪裁

Clear Screen:清屏

Exit:退出

正确的操作过程是先在绘图区域点出多边形各顶点,然后点击菜单Line选项可将顶点连线并且锁定多边形不能再修改,此时再点击绘图区域就会绘制剪裁框,此时再点击Cut选项就可完成剪裁。


二、核心代码

//此函数用于裁剪存储于points二维数组内的多边形
void Cut(){
    glColor3f(1.0f, 0.0f, 0.0f);            //多边形用红色连线,便于区分被裁剪部分
    glBegin(GL_LINE_LOOP);                //连线函数
    for (int i = 0; i<ptemp; i++)
        glVertex2f(points[i][0], points[i][1]);
    glEnd();
    for (int i = 0; i < ptemp; i++){                //左边界
        if (i != ptemp-1){    //因为循环最后一个点和第一个点下标不好写,做以区分
            if (points[i][0] >= cutsize[0][0]){            //当前点left-in
                if (points[i + 1][0] < cutsize[0][0])        //如果下一个点left-out
                    Intersection(points[i][0], points[i][1], points[i + 1][0], points[i + 1][1], cutsize[0][0], cutsize[0][1], cutsize[0][0], cutsize[1][1]);//求交点
                else{                //下一个点left-in
                    npoints[ntemp][0] = points[i + 1][0];    //把下一个点存入新数组
                    npoints[ntemp][1] = points[i + 1][1];
                    ntemp++;
                }

            }
            else {                            //当前点left-out
                if (points[i + 1][0] >= cutsize[0][0]){             //下一个点left-in
                    Intersection(points[i][0], points[i][1], points[i + 1][0], points[i + 1][1], cutsize[0][0], cutsize[0][1], cutsize[0][0], cutsize[1][1]);//求交点
                    npoints[ntemp][0] = points[i + 1][0]; //把下一个点存入新数组
                    npoints[ntemp][1] = points[i + 1][1];
                    ntemp++;
                }
            }
        }
        else{            //针对最后一个点和第一个点
            if (points[i][0] >= cutsize[0][0]){            //当前点left-in
                if (points[0][0] < cutsize[0][0])        //如果下一个点left-out
                    Intersection(points[i][0], points[i][1], points[0][0], points[0][1], cutsize[0][0], cutsize[0][1], cutsize[0][0], cutsize[1][1]); //求交点
                else{                //下一个点left-in
                    npoints[ntemp][0] = points[0][0];
                    npoints[ntemp][1] = points[0][1];
                    ntemp++;
                }
            }
            else {                            //当前点left-out
                if (points[0][0] >= cutsize[0][0]){             //下一个点left-in
                    Intersection(points[i][0], points[i][1], points[0][0], points[0][1], cutsize[0][0], cutsize[0][1], cutsize[0][0], cutsize[1][1]); //求交点
                    npoints[ntemp][0] = points[0][0];
                    npoints[ntemp][1] = points[0][1];
                    ntemp++;
                }
            }
        }
    }
    memset(points, 0,sizeof(points));    //清空原数组
    ptemp = ntemp;                        //记录左边界剪裁后生成点数
    for (int i = 0; i < ptemp; i++){        //把生成新数组复制会原数组接着做循环
        points[i][0] = npoints[i][0];
        points[i][1] = npoints[i][1];
    }
    memset(npoints, 0, sizeof(npoints));    //清空新数组(暂用数组)
    ntemp = 0;
//…………………..剩下三个边界相同
    glColor3f(0.0f, 1.0f, 0.0f);            //把剪裁后的用绿色连线
    glBegin(GL_LINE_LOOP);                //连线函数
    for (int i = 0; i < ntemp; i++)        
        glVertex2f(npoints[i][0], npoints[i][1]);
    glEnd();
    glFlush();
裁剪算法
//此函数用于求出被传入剪裁线段的两端点以及剪裁线的两端点连线的交点
void Intersection(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3){                           
    float k1 = 0, k2 = 0, b1 = 0, b2 = 0;
    float x=0, y=0;
    if (x2 == x3){            //当剪裁线为左右边界时计算线段方程(斜率无法计算)
            k1 = (y1 - y0) / (x1 - x0);    //计算斜率
            b1 = y1 - k1*x1;     //计算偏移量
            x = x2;
            y = k1*x + b1;
    }
    else {                        //当剪裁线为上下边界时
        if (x1 == x0){            //当被剪裁线为竖线时计算线段方程(斜率无法计算)
            x = x1;
            y = y2;
        }
        else{                    //一般线段方程
            k1 = (y1 - y0) / (x1 - x0);
            k2 = (y3 - y2) / (x3 - x2);
            b1 = y1 - k1*x1;
            b2 = y2 - k2*x2;
            x = (b2 - b1) / (k1 - k2);
            y = k1*x + b1;
        }
    }
    npoints[ntemp][0] = x;        //把交点存入新数组
    npoints[ntemp][1] = y;
    ntemp++;
}
求交点算法

三、问题探讨

因为多媒体大作业的缘故没有时间实现凹多边形剪裁不分成多个多边形的漏洞,但初步有个想法,一个最简单的实现就是预先把多边形每两个顶点的斜率计算并存储,然后把剪裁完存储的点再两两算斜率与存储斜率进行比对,斜率一致的证明该连线是原多边形线的剪裁并进行连线,不一致的便不连线,一定程度解决了问题。

原文地址:https://www.cnblogs.com/hesoyamlyf/p/5585210.html