判断任意多边形与矩形的相交(线段与矩形相交或线段与线段相交)


任意多边形与矩形的相交,其实就是判断多条线段是否与这个矩形相交,再简单点就是判断线段是否与矩形的每一条边相交了。那现在,我们先来看看判断一条线段与矩形的其中一条线段的相交的情况(上方水平线):

(图形中的a/b=d/c如果看不明白的,我也无语了,回去翻下几何图形的那中学课本。)图中已知的是红色的线段,就是要检测的线段,其起点就是star,重点是end,其坐标是已知的。图中的蓝色线是辅助理解的线。而图中的y0,x1,x2是矩形的其中一条线的参数,那,下面我们从代码去理解一下:

         public   static   bool  PointInLine(Vector2 point, Vector2[] vertices,  float  accuracy)
        {
            
if  (point  ==   null   ||  (vertices  ==   null   ||  vertices.Length  <   2 ))
                
return   false ;
            Rect pointRect 
=   new  Rect();
            pointRect.Width 
=  accuracy * 2 ;
            pointRect.Height 
=  accuracy * 2 ;
            pointRect.Center 
=  point;

            
return  LineIntersectRect(vertices, pointRect);
        }

其中point参数就是要检测的点,vertices是被检测的线段集合,accuracy是其精确性,如果为0,则精确到点,如果存在一定的模糊性,可以给这个参数赋值。(做图形开发的时候,鼠标点要精确到某条线上,那要求太高了,因此,一般会设置其精确值,这个值越小越精确。)从这段代码中可以理解成N条线段vertices去检测是否与这个存在一定精确性的矩形相交,那下面看看这个函数LineIntersectRect的代码:

         public   static   bool  LineIntersectRect(Vector2[] vertices, Rect rect)
        {
            
if  ((vertices  ==   null   ||  vertices.Length  <   2 ||  rect  ==  Rect.Empty)
                
return   false ;
            
for  ( int  i  =   0 ; i  <  vertices.Length  -   1 ; i ++ )
            {
                
if  (CheckRectLine(vertices[i], vertices[i  +   1 ], rect))
                    
return   true ;
            }
            
return   false ;
        }

这段代码很好理解,就是从数组中每2点去检测其是否与这个矩形相交。下面就看看CheckRectLine检测其线段与矩形检测的代码:

         private   static   bool  CheckRectLine(Vector2 start, Vector2 end, Rect rect)
        {
            
bool  result  =   false ;
            
if  (rect.Contains(start)  ||  rect.Contains(end))
                result 
=   true ;
            
else
            {
                result 
|=  CheckRectLineH(start, end, rect.LeftTop.Y, rect.LeftTop.X, rect.RightBottom.X);
                result 
|=  CheckRectLineH(start, end, rect.RightBottom.Y, rect.LeftTop.X, rect.RightBottom.X);
                result 
|=  CheckRectLineV(start, end, rect.LeftTop.X, rect.LeftTop.Y, rect.RightBottom.Y);
                result 
|=  CheckRectLineV(start, end, rect.RightBottom.X, rect.LeftTop.Y, rect.RightBottom.Y);
            }
            
return  result;
        }

线段与矩形是否相交的方法就变成了线段与矩形的4条边是否相交进行检测。这里,该方法CheckRectLineH是水平方向上的检测,就是检测矩形的上边线与下边线,那CheckRectLineV就是检测矩形的左边线和右边线了。我们先来看下CheckRectLineH这个函数的代码,然后再看看图来进行分析:

         private   static   bool  CheckRectLineH(Vector2 start, Vector2 end,  float  y0,  float  x1,  float  x2)
        {
            
// 直线在点的上方
             if  ((y0  <  start.Y)  &&  (y0  <  end.Y))
                
return   false ;
            
// 直线在点的下方
             if  ((y0  >  start.Y)  &&  (y0  >  end.Y))
                
return   false ;
            
// 水平直线
             if  (start.Y  ==  end.Y)
            {
                
// 水平直线与点处于同一水平。
                 if  (y0  ==  start.Y)
                {
                    
// 直线在点的左边
                     if  ((start.X  <  x1)  &&  (end.X  <  x1))
                        
return   false ;
                    
// 直线在x2垂直线右边
                     if  ((start.X  >  x2)  &&  (end.X  >  x2))
                        
return   false ;
                    
// 直线的部分或者全部处于点与x2垂直线之间
                     return   true ;
                }
                
else // 水平直线与点不处于同一水平。
                {
                    
return   false ;
                }
            }
            
// 斜线
             float  x  =  (end.X  -  start.X)  *  (y0  -  start.Y)  /  (end.Y  -  start.Y)  +  start.X;
            
return  ((x  >=  x1)  &&  (x  <=  x2));
        }

看完代码,我们再看最开始时候的图,协助分析,我们可以想到这个函数其实就是检测X1与Y0的交点与X2与Y0的交点是否与红色线段是否相交,如果相交,则判断其交点是否在x1与x2之间的范围。(根据调用的参数,可以知道其正好就是上下边线)我们根据图的理解,可以得出:

a=(end.X - start.X),b=(end.Y - start.Y),c=(y0 - start.Y),d=start.X+x。从而可以得出

x = (end.X - start.X) * (y0 - start.Y) / (end.Y - start.Y) + start.X。

同理,CheckRectLineV的分析刚好是x和Y倒转过来。下面贴出代码:(分析就不再细说了)

         private   static   bool  CheckRectLineV(Vector2 start, Vector2 end,  float  x0,  float  y1,  float  y2)
        {
            
if  ((x0  <  start.X)  &&  (x0  <  end.X))
                
return   false ;
            
if  ((x0  >  start.X)  &&  (x0  >  end.X))
                
return   false ;
            
if  (start.X  ==  end.X)
            {
                
if  (x0  ==  start.X)
                {
                    
if  ((start.Y  <  y1)  &&  (end.Y  <  y1))
                        
return   false ;
                    
if  ((start.Y  >  y2)  &&  (end.Y  >  y2))
                        
return   false ;
                    
return   true ;
                }
                
else
                {
                    
return   false ;
                }
            }
            
float  y  =  (end.Y  -  start.Y)  *  (x0  -  start.X)  /  (end.X  -  start.X)  +  start.Y;
            
return  ((y  >=  y1)  &&  (y  <=  y2));
        }

 

备注:这里由于是用Vortex2D的源码进行分析的,其中Vector2其实就是point的类型,只是该Vector2封装了更多的方法而已。其Rect的类型也不是系统的Rect,也是Vortex2D自己封装了更多方法的Rect类型,如果大家在使用该部分代码时,有编译出错的情况,请注意自行修改。这里提出的是一个思路。懂得了这个思路,自然就懂得如何修改各自的代码。

 

原创作品出自努力偷懒,转载请说明文章出处http://www.cnblogs.com/kfarvid/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值