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

C# 快速检测与给定矩形相交的矩形的方法,c#,system.drawing,C#,System.drawing,我维护的应用程序具有自定义绘图功能,可以在曲面上绘制一些“对象”。对象边界是用 有时我需要检测矩形与给定矩形相交的对象 如果对象的数量足够大,可以进行如下简单迭代: var objectsToManage = _objects.Where(_ => rc.IntersectsWith(_.InscribeRect)); 显然,速度太慢(\u objects这里是List,IscribeRect是对象边界,rc是给定的矩形) 我正在考虑如何更快地完成这项工作。第一个想法是按矩形“排序”对象

我维护的应用程序具有自定义绘图功能,可以在曲面上绘制一些“对象”。对象边界是用

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

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

var objectsToManage = _objects.Where(_ => rc.IntersectsWith(_.InscribeRect));
显然,速度太慢(
\u objects
这里是
List
IscribeRect
是对象边界,
rc
是给定的矩形)

我正在考虑如何更快地完成这项工作。第一个想法是按矩形“排序”对象,并将其放入排序集。。。但我怀疑,我正在重新发明轮子

有什么众所周知的方法可以实现我想要的吗?

这可以通过使用。您可以在这里找到一个c#实现:(四叉树代码与WPF没有严格的关系),这里还有很多信息:这里还有另一个实现:

#region FnLineMerginRectandLines
公共静态布尔线交叉点(点p1、点p2、矩形r)
{
返回线相交线(p1、p2、新点(r.X、r.Y)、新点(r.X+r.Width、r.Y))||
直线相交直线(p1、p2、新点(r.X+r.Width,r.Y)、新点(r.X+r.Width,r.Y+r.Height))||
直线相交直线(p1、p2、新点(r.X+r.Width、r.Y+r.Height)、新点(r.X、r.Y+r.Height))||
直线相交直线(p1、p2、新点(r.X、r.Y+r.Height)、新点(r.X、r.Y))||
(r.Contains(p1)和r.Contains(p2));
}
专用静态布尔线相交线(点l1p1、点l1p2、点l2p1、点l2p2)
{
浮点q=(l1p1.Y-l2p1.Y)*(l2p2.X-l2p1.X)-(l1p1.X-l2p1.X)*(l2p2.Y-l2p1.Y);
浮点d=(l1p2.X-l1p1.X)*(l2p2.Y-l2p1.Y)-(l1p2.Y-l1p1.Y)*(l2p2.X-l2p1.X);
如果(d==0)
{
返回false;
}
浮点数r=q/d;
q=(l1p1.Y-l2p1.Y)*(l1p2.X-l1p1.X)-(l1p1.X-l2p1.X)*(l1p2.Y-l1p1.Y);
浮点数s=q/d;
如果(r<0 | | r>1 | | s<0 | | s>1)
{
返回false;
}
返回true;
}
#端区
公共班级线
{
私有int Point1X;
私有int Point1Y;
私有int Point2X;
私有int Point2Y;
公共点P1;
公共点P2;
公共电话线()
{
}
公共线(整数左、整数顶、整数宽、整数高)
{
this.Point1X=将.ToInt32转换为(左);
this.Point1Y=Convert.ToInt32(顶部);
this.Point2X=转换为32(宽度);
this.Point2Y=Convert.ToInt32(高度);
P1=新点(点1X,点1Y);
P2=新点(点2x,点2y);
}
公用线(左串、上串、宽串、高串)
{
this.Point1X=将.ToInt32转换为(左);
this.Point1Y=Convert.ToInt32(顶部);
this.Point2X=转换为32(宽度);
this.Point2Y=Convert.ToInt32(高度);
P1=新点(点1X,点1Y);
P2=新点(点2x,点2y);
}   
公共线路(p1点、P2点)
{
这是1.P1=P1;
这是P2=P2;
}
}
公共静态Listgetfourborders(矩形RT)
{
线顶线=新线(新点(RT.Left,RT.Top),新点(RT.Width+RT.Left,RT.Top));//顶线
Line leftline=新线((新点(RT.Left,RT.Top)),新点(RT.Left,RT.Top+RT.Height));//左线
Line rightline=新行((新点(RT.Left+RT.Width,RT.Top)),新点(RT.Left+RT.Width,RT.Top+RT.Height));//右行
行底线=新行((新点(RT.Left,RT.Top+RT.Height)),新点(RT.Left+RT.Width,RT.Top+RT.Height));//底线
列表边框=新列表();
边框。添加(左行);
边界线。添加(顶线);
边界线。添加(右行);
边界线。添加(底线);
返回边界;
}
//YourObjectList()包含一个矩形类型
公共类myobject
{
公共myobject(对象S、矩形RT)
{
这个。Rt=Rt;
this.anyobjecttype=S;
}
公共矩形Rt;
公共对象anyobjecttype;
}
公共列表比较矩形(列表矩形、矩形给定矩形)
{
List intersectingobjects=新列表();
矩形比较器带=新矩形();/“_对象。其中(=>rc.IntersectsWith(u.inscribestright));”
foreach(myobject在Rect中迭代)
{
列表边框=新列表();
AddRange(getfourborders(iterate.Rt));
bool Intersects=边界线。任意(x=>LineIntersectsRect(x.P1,x.P2,CompareWith));
如果(相交)
相交对象。添加(迭代);
}
返回相交对象;
}
创建另一个函数以获取所有边界线(从矩形1获取四个点并创建四条线),并检查是否有任何线与另一个矩形合并使用LineIntersects进行比较Rect如果其中任何一个返回true,则矩形1将与矩形R相交,您可以将其循环以检查矩形2与矩形相交比较等等。。
请确保在与直线相交的直线上未通过除零异常

谢谢,我将研究这些文章。@ernodeweard-即使链接消失,只要提到“四元树”一词就足够了。@ernodeweard:实际上,我是在问概念/链接。。。显然,这不是一个问题,可以通过几行代码来回答。我不明白你的想法。看起来它仍然需要对象集合上的迭代。不是吗?一个矩形要与另一个矩形相交,任何边界线都应该与第二个矩形相交。。因此,我得到我的第一个矩形边界,并检查是否有
    #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;
        }