此算法能使用任意多边形对一条直线段进行裁剪。
类GLdoublePoint: 公有—GLdouble x ,y;
类line: 公有—GLdoublePoint first,second;
linelist: line型数据组成的链表,用于描述多边形;
伪代码:
int CyrusBeck(line& seg , linelist& l)
{
double numer , denom ;
double tIn = 0.0 , tOut = 1.0;
Vector c , temp;
c = seg.second - seg.first;
for(int i = 0 ; i < l.num ; i++)
{
temp = l.line[i].pt - first ; // pt为此时多边形某边上的任意一点
numer = dot(l.line[i].norn , temp);
denom = dot(l.line[i].norn , c); // dot()函数为求两向量的点积,自行编写
if(!chopCI(numer , denom , tIn , tOut)) return 0 ; // chopCI()是用来计算射线与多边型每条边相交 的时间,并判断射线在交点处是射入还是射出,伪代码在后面
}
if(tOUt < 1.0) //进行裁剪
{
seg.second.x = seg.first.x + c.x * tOut ;
seg.second.y = seg.first.y + c.y * tOut ;
}
if(tIn > 0.0)
{
seg.first.x = seg.first.x + c.x * tIn ;
seg.first.y = seg.first.y + c.y * tIn ;
}
return 1;
}
int chopCI(double numer , double denom ,double tIn ,double tOut)
{
double tHit;
if(denom < 0) //射线射入
{
tHit = numer / denom ;
if (tHit > tOut) return 0;
else if(tHit > tIn) tIn = tHit ;
}
else if(denom > 0) // 射线射出
{
tHit = numer / denom ;
if(tHit < hIn) return 0;
else if(tHIt > tIn) tOut = tHIt ;
}
else //射线与边平行
if(numer <= 0 ) return 0;
return 1;
}
说明:
设某射线起始点为A,单位向量为c;某直线l,其上任意一点B,法向量n;先判断A和B的关系。
假设A与B相交,则焦点A+t*c与B形成的向量与n垂直,则有:
n ●(A+c*t — B)= 0 (1)
此处可以将参数t看为是时间,则t为射线击中l的时间,记为tHit。
(1)式经变换可得:tHit = n ●(B—A)/ (n ● c)
由向量点积的性质可得:若n ● c>0 ,则射线沿法线方向
若n ● c<0 ,则射线与法线相反
若n ● c=0 ,则法线与射线平行
代码中的tIn和tOut可以理解为候选区间,也就是射线现存的部分,剪裁时就是根据射线是射入还是射出以及tHIt和tIn与tOut的关系来修改tOut和tIn,避免了频繁进行改变点的运算,因为计算机图形学中点与向量的定义很相似,容易出错。
Cyrus-Beck裁剪算法就是依据以上方法用多边形的每条边对seg进行判断,并把剪裁后的线段返回到seg中,思路简单但是运算量较大,也不实用来计算边数多的多边形,同时此算法也只适用于凸多边形。