梁巴尔斯基算法
Liang-Barsky 算法是一种线裁剪算法。该算法比 Cohen-Sutherland 线裁剪算法更有效,并且可以扩展到 3 维裁剪。该算法被认为是更快的参数化剪线算法。本剪辑中使用了以下概念:
- 线的参数方程。
- 描述裁剪窗口范围的不等式,用于确定线和裁剪窗口之间的交点。
直线的参数方程可以由下式给出,
X = x1 + t(x2-x1)
Y = y1 + t(y2-y1)
其中,t 介于 0 和 1 之间。
然后,以参数形式编写点裁剪条件:
xwmin <= x1 + t(x2-x1) <= xwmax
ywmin <= y1 + t(y2-y1) <= ywmax
上述4个不等式可以表示为,
tpk <= qk
其中 k = 1、2、3、4(分别对应于左、右、下和上边界)。
p 和 q 定义为,
p1 = -(x2-x1), q1 = x1 - xwmin (Left Boundary)
p2 = (x2-x1), q2 = xwmax - x1 (Right Boundary)
p3 = -(y2-y1), q3 = y1 - ywmin (Bottom Boundary)
p4 = (y2-y1), q4 = ywmax - y1 (Top Boundary)
当该线与视图窗口边界平行时,该边界的 p 值为零。
当 p k < 0 时,随着 t 的增加,线从外到内(进入)。
当 p k > 0 时,线路由内向外(退出)。
当 p k = 0 且 q k < 0 时,线几乎不可见,因为它在视窗之外。
当 p k = 0 且 q k > 0 时,该线位于相应的窗口边界内。
使用以下条件,可以确定线的位置:
Condition | Position of line |
---|---|
pk = 0 | parallel to the clipping boundaries |
pk = 0 and qk < 0 | completely outside the boundary |
pk = 0 and qk >= 0 | inside the parallel clipping boundary |
pk < 0 | line proceeds from outside to inside |
pk > 0 | line proceeds from inside to outside |
可以计算参数t 1和t 2来定义位于剪辑矩形内的线部分。
什么时候,
- p k < 0,取最大值(0, q k /p k )。
- p k > 0,取最小值(1, q k /p k )。
如果 t 1 > t 2 ,则该线完全在剪辑窗口之外并且可以被拒绝。否则,根据参数 t 的两个值计算剪裁线的端点。
算法 -
- 设置 t min =0,t max =1。
- 计算 t (t(left), t(right), t(top), t(bottom)) 的值,
(i) 如果 t < t min忽略它并移动到下一个边缘。
(ii) 否则使用内积将 t 值分隔为进入或退出值。
(iii) 如果 t 是输入值,则设置 t min = t;如果 t 是现有值,则设置 t max = t。 - 如果 t min < t max ,从 (x 1 + t min (x 2 -x 1 ), y 1 + t min (y 2 -y 1 )) 到 (x 1 + t max (x 2 -x ) 1 ), y 1 + t max (y 2 -y 1 ))
- 如果线穿过窗口,(x 1 + t min (x 2 -x 1 ), y 1 + t min (y 2 -y 1 )) 和 (x 1 + t max (x 2 -x 1 ), y 1 + t max (y 2 -y 1 )) 是线和边的交点。
该算法在以下代码中给出。线相交参数初始化为值 t 1 = 0 和 t 2 = 1。
#include"graphics.h"
#define ROUND(a) ((int)(a+0.5))
int clipTest (float p,float q, float * tl, float * t2)
{
float r ;
int retVal = TRUE;
//line entry point
if (p < 0.0) {
r = q /p ;
// line portion is outside the clipping edge
if ( r > *t2 )
retVal = FALSE;
else
if (r > *t1 )
*tl = r;
}
else
//line leaving point
if (p>0.0) {
r = q/p ;
// line portion is outside
if ( r<*t1 )
retVal = FALSE;
else i f (r<*t2)
*t2 = r;
}
// p = 0, so line is parallel to this clipping edge
else
// Line is outside clipping edge
if (q<0.0)
retVal = FALSE;
return ( retVal ) ;
}
void clipLine (dcPt winMin, dcPt winMax, wcPt2 pl , wcPt2 p2)
{
float t1 = 0.0, t2 = 1.0, dx = p2.x-p1.x, dy;
// inside test wrt left edge
if(clipTest (-dx, p1.x - winMin.x, &t1, &t2))
// inside test wrt right edge
if(clipTest (dx, winMax.x - p1.x, &t1, &t2))
{
dy = p2.y - p1.y;
// inside test wrt bottom edge
if(clipTest (-dy, p1.y - winMin.y, &t1, &t2))
// inside test wrt top edge
if(clipTest (dy, winMax.y - p1.y, &t1, &t2)) {
if(t2 < 1.0) {
p2.x = p1.x + t2*dx;
p2.y = p1.y + t2*dy;
}
if(t1 > 0.0) {
p1.x += t1*dx;
p1.y += t1*dy;
}
lineDDA ( ROUND(p1.x), ROUND(p1.y), ROUND(p2.x), ROUND(p2.y) );
}
}
}
参考资料: Donald Hearn, M.Pauline Baker 的计算机图形学