opengl算法学习--- 直线裁剪算法

bingxuelengmei 2020-05-13

裁剪是从数据集合提取信息的过程,它是计算机图形学许多重要问题的基础。裁剪典型的用途就是从一个大的场景中提取所需的信息,以显示某一局部场景或视图。比如浏览地图时,对感兴趣的区域放大显示,此时窗口内显示的内容会相应减少。确定图形的哪些部分在窗口内,哪些部分在窗口外(不可见区域),只显示窗口内的那部分图形,这个选择处理过程就是裁剪。
这里详细讲述两种算法

Cohen-Sutherland编码裁剪算法

稍后再补

Liang-Barsky算法

概念
opengl算法学习--- 直线裁剪算法

Liang-Barsky算法的基本思想是,从 A、B 和 P1中找出最靠近 P2的点,如图所示为 P1;从C 、D 和 P2中找出最靠近P1的点,显然为C 点;也即 PC1即为裁剪后部分。

具体实现
opengl算法学习--- 直线裁剪算法
对于区域内存在的线段P1P2,根据两点坐标构造方程

\[x=x_{1}+u(x_{2}-x_{1})\]
\[y=y_{1}+u(y_{2}-y_{1})\]

\(\Delta x=x_{2}-x_{1} \Delta y=y_{2}-y_{1}\)
即可推出

\[x=x_{1}+u\Delta x\]
\[y=y_{1}+u\Delta y\]

opengl算法学习--- 直线裁剪算法
Liang-Barsky算法通过计算两端点截取后的u值,绘制截取后的线段,设截取后线段的两端点u为\(u_{1}、u_{2}\)
\(u_{1}\)初始值=0,即线段初始点,\(u_{2}\)初始值=1,即线段终点
对于x而言

\[x_{l} \leqslant x \leqslant x_{r}\]

同理

\[y_{b} \leqslant y \leqslant y_{t}\]
\[\Rightarrow\left\{\begin{matrix} x_{l} \leqslant x_{1}+u\Delta x \leqslant x_{r} \\ y_{b} \leqslant y_{1}+u\Delta y \leqslant y_{t}\end{matrix}\right.\]

即可推得

\[\Rightarrow\left\{\begin{matrix} u\Delta x \leqslant x_{r}-x_{1} \\ -u\Delta x \leqslant x_{1}-x_{l} \ u\Delta y \leqslant y_{t}-y_{1} \\ -u\Delta y \leqslant y_{1}-y_{b} \end{matrix}\right.\]

构造

\[p_{k} \leqslant q_{k} ,k={1,2,3,4}\]

每个k对应上式每种情况

\[\Rightarrow\left\{\begin{matrix} p_{1}=\Delta x & q_{1}=x_{r}-x_{1} \\ p_{2}=-\Delta x & q_{2}=x_{1}-x_{l} \ p_{3}=\Delta y & q_{3}=y_{t}-y_{1} \\ p_{4}=-\Delta y & q_{4}=y_{1}-y_{b} \end{matrix}\right.\]

\(p_{k}=0\)时,该线段平行于轮廓线
如果\(q_{k}<0\)
当k=1时,\(x_{r}<x_{1}\)
当k=2时,\(x_{1}<x_{l}\)
当k=3时,\(y_{t}<y_{1}\)
当k=4时,\(y_{1}<y_{b}\)
可推出若\(q_{k}<0\)时,该线段位于裁剪区域外
如果\(q_{k}\geqslant 0\)
则该线段位于区域内
\(p_{k} \neq 0\)时,
此时线段延长线与轮廓线交点在上式中u值\(=\frac{q_{k}}{p_{k}}\)
\(p_{k}<0\) 则该线段部分为由边界外到边界内,\(u_{1}=max(u_{1},u)\)
\(p_{k}>0\) 则该线段部分为由边界内到边界外,\(u_{2}=min(u_{2},u)\)
通过以上过程,可推出截取后线段两端点的\(u_{1}\)\(u_{2}\),若\(u_{1}>u_{2}\),则该线段不为于裁剪区域内

代码实现

void LiangBarsky(Point p1,Point p2,Rectan rec)
{
    float u1=0,u2=1,p[4],q[4];
    p[0]=p1.x-p2.x;p[1]=p2.x-p1.x;
    p[2]=p1.y-p2.y;p[3]=p2.y-p1.y;
    q[0]=p1.x-rec.xl;q[1]=rec.xr-p1.x;
    q[2]=p1.y-rec.yb;q[3]=rec.yt-p1.x;
    for(int i=0;i<4;i++)
    {
        if(!p[i] && q[i]<0) return ;
        else if(p[i])
        {
            float u=q[i]/p[i];
            if(p[i]<0) u1=max(u1,u);
            else u2=min(u2,u);
        }
    }
    if(u1>u2) return ;
    drawline(Point(p1.x+u1*(p2.x-p1.x),p1.y+u1*(p2.y-p1.y)),Point(p1.x+u2*(p2.x-p1.x),p1.y+u2*(p2.y-p1.y)),BLUE);
}

相关推荐