多边形的命中测试

这个代码示例依据的原理很简单,那就是从给定的要测试的点向下延伸,看看它能和多边形的几条边相交,如果有偶数条边相交,则说明该点不在多边形内,如果有奇数条边相交,则说明该点在多边形内部。

大体上实现的过程是:
 points是个Point类型的数组,保存多边形的点,
 ptMouse即要测试的点,
 count为计数器,确定相交点的个数.
首先,将points里的点分成两组,第一组里所有的点的X坐标都小于等于ptMouse.X,第二组的X坐标都大于ptMouse.X
其次,对于第一组的每个点pt找到它的前驱ptPrevi和后继ptNext(如果当前点是points里第一个点,则其前驱是points的最后一个点,如果当前点是points里最后一个点,则其后继是points里的第一个点)。
第三,如果它的前驱点在第二组里,则进行如下计算:如果(ptPrevi.Y-pt.Y)/(float)(ptPrevi.X-pt.X)<(ptMouse.Y-pt.Y)/(float)(ptMouse.X-pt.X)则证明相交,count加1;如果它的后继点在第二组里,也进行同样的计算,如果也相交,count加1;
最后,看count,如果是奇数则点ptMouse位于多边形内,否则位于多边形之外。
private bool hitTesting(Point[] points, Point ptMouse  )
        {
            int count = 0;
            Point[] pts1 = (from Point pt in points where pt.X <= ptMouse.X select pt).ToArray();
            Point[] pts2 = (from Point pt in points where pt.X > ptMouse.X select pt).ToArray();
            if (pts1 == null || pts1.Count() < 0) return false;
            if (pts2 == null || pts2.Count() < 0) return false;
            foreach (Point item in pts1)
            {
                int index =points.IndexOf(item);
                Point ptPrevi = index == 0 ? points[points.Count - 1] : points[index - 1];
                Point ptNext = index == points.Count - 1 ? points[0] : points[index + 1];
                float rate = GetQxRate(item, ptMouse);
                if (pts2.Contains(ptPrevi))
                {
                    if (GetQxRate(item,ptPrevi)>rate)
                    {
                        count++;
                    }
                   
                }
                if (pts2.Contains(ptNext))
                {
                    if (GetQxRate(item, ptNext) > rate)
                    {
                        count++;
                    }
                }
            }
            return count % 2 != 0;

        }
private float GetQxRate(Point item, Point ptMouse)
        {
            return (ptMouse.Y - item.Y) / (float)(ptMouse.X - item.X);
        }

 

 

在后面的代码中将实现多边形命中测试的功能,实现的代码主要是hitTest方法,由于这个方法要结合测试示例,所以与上面的同名方法存在一些不同。
在这个示例中,窗体最初有个最简单的三角形,

 

 

当前你也可以定义更复杂的形状,点“重新定义多边形”来擦除现有形状,然后依次在需要的地方点击鼠标,在最后一个点上右击以完成多边形的定义,并退出定义状态,进入测试状态,

 

 

 

测试的时候,在要测试的地方点击鼠标,状态栏会给出测试结果,并且多边形上凡是与位于该测试点上的竖线相交的边都会有提示(命中时为绿色,否则为红色)!

 

 

 


(这里的多边形指所有的边都是直边,不能存在弧线,后者的情况可使用GraphicsPath类的实例方法IsVisible,但必须精心的添加各个线段)

posted @ 2009-12-17 18:09  蒋启磊  阅读(264)  评论(0编辑  收藏  举报