快速检测与给定矩形相交的矩形的方法

时间:2015-03-19 06:57:49

标签: c# system.drawing

我维护的应用程序具有自定义绘图功能,它吸引了一些对象"在Graphics表面上。使用Rectangle描述对象边界。

有时我需要检测矩形与给定矩形相交的对象。

如果对象的数量足够大,可以像这样进行简单的迭代:

var objectsToManage = _objects.Where(_ => rc.IntersectsWith(_.InscribeRect));

显然,速度太慢(_objects此处为List<MyObjType>IscribeRect为对象边界,rc为给定矩形。

我正在思考如何更快地完成这项工作。第一个想法是&#34;排序&#34;他们的长方形物体将它们分成几组......但是我怀疑,我正在重新发明轮子。

有没有任何众所周知的方法来实现我想要的目标?

2 个答案:

答案 0 :(得分:2)

可以使用Quadtrees完成此操作。您可以在此处找到c#实现:Virtualized WPF Canvas(四叉树代码与WPF并不严格相关),此处还有大量信息:ZoomableApplication2: A Million Items以及此处的其他实现:PriorityQuadTree

答案 1 :(得分:0)

    #region FnLineMerginRectandLines
    public static bool LineIntersectsRect(Point p1, Point p2, Rectangle r)
    {
        return LineIntersectsLine(p1, p2, new Point(r.X, r.Y), new Point(r.X + r.Width, r.Y)) ||
               LineIntersectsLine(p1, p2, new Point(r.X + r.Width, r.Y), new Point(r.X + r.Width, r.Y + r.Height)) ||
               LineIntersectsLine(p1, p2, new Point(r.X + r.Width, r.Y + r.Height), new Point(r.X, r.Y + r.Height)) ||
               LineIntersectsLine(p1, p2, new Point(r.X, r.Y + r.Height), new Point(r.X, r.Y)) ||
               (r.Contains(p1) && r.Contains(p2));
    }

    private static bool LineIntersectsLine(Point l1p1, Point l1p2, Point l2p1, Point l2p2)
    {
        float q = (l1p1.Y - l2p1.Y) * (l2p2.X - l2p1.X) - (l1p1.X - l2p1.X) * (l2p2.Y - l2p1.Y);
        float d = (l1p2.X - l1p1.X) * (l2p2.Y - l2p1.Y) - (l1p2.Y - l1p1.Y) * (l2p2.X - l2p1.X);

        if (d == 0)
        {
            return false;
        }

        float r = q / d;

        q = (l1p1.Y - l2p1.Y) * (l1p2.X - l1p1.X) - (l1p1.X - l2p1.X) * (l1p2.Y - l1p1.Y);
        float s = q / d;

        if (r < 0 || r > 1 || s < 0 || s > 1)
        {
            return false;
        }

        return true;
    }
    #endregion
public class Line
{
    private int Point1X;
    private int Point1Y;
    private int Point2X;
    private int Point2Y;
    public Point P1;
    public Point P2;

    public Line()
    {

    }
    public Line(int left, int top, int width, int height)
    {
        this.Point1X = Convert.ToInt32(left);
        this.Point1Y = Convert.ToInt32(top);
        this.Point2X = Convert.ToInt32(width);
        this.Point2Y = Convert.ToInt32(height);
        P1 = new Point(Point1X, Point1Y);
        P2 = new Point(Point2X, Point2Y);
    }
    public Line(string left, string top, string width, string height)
    {
        this.Point1X = Convert.ToInt32(left);
        this.Point1Y = Convert.ToInt32(top);
        this.Point2X = Convert.ToInt32(width);
        this.Point2Y = Convert.ToInt32(height);
        P1 = new Point(Point1X, Point1Y);
        P2 = new Point(Point2X, Point2Y);
    }   
    public Line(Point p1, Point P2)
    {
        this.P1 = p1;
        this.P2 = P2;
    }
}


public static List<Line>getfourborders(Rectangle RT)
    {
        Line topline = new Line(new Point(RT.Left,RT.Top),new Point(RT.Width+RT.Left,RT.Top));// Top Line
        Line leftline = new Line((new Point(RT.Left,RT.Top)),new Point(RT.Left,RT.Top+RT.Height));// left Line
        Line  rightline = new Line((new Point(RT.Left+RT.Width,RT.Top)),new Point(RT.Left + RT.Width,RT.Top+RT.Height));// Right Line
        Line bottomline = new Line((new Point(RT.Left,RT.Top+RT.Height)),new Point(RT.Left+RT.Width,RT.Top+RT.Height));//bottom line
        List<Line> borderlines = new List<Line>();
        borderlines.Add(leftline);
        borderlines.Add(topline);
        borderlines.Add(rightline);
        borderlines.Add(bottomline);
        return borderlines;
    }

 //YourObjectList() contains a rectangle type
        public class myobject
        {
            public myobject(object S, Rectangle RT)
            {
            this.Rt = RT;
            this.anyobjecttype= S;
            }
            public Rectangle Rt;
            public  object anyobjecttype ;
        }

        public List<myobject> CompareRectangles(List<myobject> Rect ,Rectangle GivenRectangle)
        {
            List<myobject> intersectingobjects = new List<myobject>();
            Rectangle CompareWith = new Rectangle();//"_objects.Where(_ => rc.IntersectsWith(_.InscribeRect));"

            foreach(myobject iterate in Rect)
            {
                List<Line> BorderLines = new List<Line>();
                BorderLines.AddRange(getfourborders(iterate.Rt));
                bool Intersects = BorderLines.Any(x=>LineIntersectsRect(x.P1,x.P2,CompareWith));
                if (Intersects)
                    intersectingobjects.Add(iterate);
            }
            return intersectingobjects;
        }

创建另一个函数来获取所有边框线(获取四个点并从矩形1创建四条线)并检查是否有任何线条使用lineintersectsRect与另一个rectanglecompare合并,如果其中任何一个返回true,则矩形1将与之相交您的矩形R,您可以循环它以检查矩形2与rectanglecompare相交等等。 确保你没有在与行

的行相交中通过除零异常