opengl算法學習---直線裁剪算法


裁剪是從數據集合提取信息的過程,它是計算機圖形學許多重要問題的基礎。裁剪典型的用途就是從一個大的場景中提取所需的信息,以顯示某一局部場景或視圖。比如瀏覽地圖時,對感興趣的區域放大顯示,此時窗口內顯示的內容會相應減少。確定圖形的哪些部分在窗口內,哪些部分在窗口外(不可見區域),只顯示窗口內的那部分圖形,這個選擇處理過程就是裁剪。
這里詳細講述兩種算法

Cohen-Sutherland編碼裁剪算法

Cohen-Sutherland編碼裁剪算法
算法思想
1)若線段完全在窗口之內則顯示該線段稱為“取”,
2)若線段明顯在窗口之外則丟棄該線段稱為“棄”
3)若線段既不滿足“取”的條件也不滿足“棄”的條件則把線段分割為兩段,對於完全在窗口之外的部分可棄之。

具體實現
為快速判斷一條直線段與矩形窗口的位置關系采用如圖所示的空間划分和編碼方案(四位二進制編碼上下右左)

裁剪一條線段時先求出兩端點所在的區號,若皆為零保留。
若端點編碼按位取與運算的結果不為零,意味着線段位於窗口之外,應舍棄。
否則求出線段與窗口某邊的交點並將該線段一分為二后,舍棄完全在窗口外的線段並對另一段重復上述處理。

代碼實現

稍后再補

Liang-Barsky算法

概念

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

具體實現

對於區域內存在的線段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 \]


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);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM