两种简单矩形之间边缘检测的最快算法。

时间:2011-11-29 08:34:23

标签: c# math collision

给出两个简单的矩形:

class Rectangle
{
    int x;
    int y;
    int width;
    int height;
}

Rectangle a;
Rectangle b;

以及以下枚举:

[Flags]
enum Edges
{
    None,
    Top,
    Bottom,
    Left,
    Right,
    Inside,
}

检测矩形b碰撞的矩形a 边缘的最快方法是什么?

Edges e = EdgeDetect(a, b);

2 个答案:

答案 0 :(得分:2)

public Edges DetectEdge(Rect A, Rect B) { 
   rectC = rectA.Intersect(rectB);
    if(rectC.IsEmpty) return Edges.None;
    Edge edge = Edges.Inside;
    if(rectA.X+rectA.Width == rectB.X || rectA.X == rectB.X){
     edge = Edges.Left;
    }
    if(rectA.Y+rectA.Height == rectB.Y || rectA.Y == rectB.Y){
     edge = edge | Edges.Top;
    }
    if(rectA.X  == rectB.X + rectB.Width 
         || rectA.X + rectA.Width == rectB.X + rectB.Width){
     edge = edge | Edges.Right;
    }
    if(rectA.Y == rectB.Y + rectB.Heigth 
         || rectA.Y + rectA.Height == rectB.Y + rectB.Height){
     edge = edge | Edges.Bottom;
    }
    return edge;
}

答案 1 :(得分:1)

首先,您必须明确定义枚举值,以使标志正常工作。在你的情况下Left == Top + Bottom + None。这是一个可能的声明:

[Flags]
public enum Edges
{
    None = 0,
    Top = 1,
    Bottom = 2,
    Left = 4,
    Right = 8,
    Identical = Top + Bottom + Left + Right,
    Inside = 16,
    Covers = 32
}

接下来,可能实现边缘碰撞检测。请注意,我使用内置System.Drawing.Rectangle而不是重写类。直接的优势是Intersect方法的可用性。 :

public static Edges DetectEdgesCollision(Rectangle a, Rectangle b)
{
    var result = Edges.None;

    if (a == b) return Edges.Identical;
    b.Intersect(a);
    if (b.IsEmpty) return Edges.None;
    if (a == b) return Edges.Covers;


    if (a.Top == b.Top && (a.Right >= b.Right && a.Left<=b.Left )) 
        result |= Edges.Top;
    if (a.Bottom == b.Bottom && (a.Right >= b.Right && a.Left<=b.Left ))
        result |= Edges.Bottom;
    if (a.Left == b.Left && (a.Bottom >= b.Bottom && a.Top <= b.Top)) 
        result |= Edges.Left;
    if (a.Right == b.Right && (a.Bottom >= b.Bottom && a.Top <= b.Top)) 
        result |= Edges.Right;


    return result == Edges.None ? Edges.Inside : result;
}

以下是一组验证此实现的测试:

    [TestMethod]
    public void RectDoesNotIntersect()
    {
        var a = new Rectangle(0, 0, 10, 10);
        var b = new Rectangle(20, 20, 10, 10);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.None, result);
    }


    [TestMethod]
    public void RectAreNested()
    {
        var a = new Rectangle(0, 0, 30,30);
        var b = new Rectangle(10, 10, 10, 10);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.Inside, result);
    }      
    [TestMethod]
    public void RectCollidesOnTopAndLeft()
    {
        var a = new Rectangle(10, 10, 10, 10);
        var b = new Rectangle(0, 0, 10, 10);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.Left | Edges.Top, result);
    }     
    [TestMethod]
    public void RectCollidesOnBottom()
    {
        var a = new Rectangle(0, 0, 20, 20);
        var b = new Rectangle(10, 10, 5, 50);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.Bottom , result);
    }        

    [TestMethod]
    public void RectAreIdenticals()
    {
        var a = new Rectangle(10, 10, 10, 10);
        var b = new Rectangle(10, 10, 10, 10);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.Identical, result);
    }  
    [TestMethod]
    public void RectBCoversA()
    {
        var a = new Rectangle(10, 10, 10, 10);
        var b = new Rectangle(0, 0, 30, 30);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.Covers, result);
    }