2011-11-29 9 views
0

考えると2つの単純な、長方形:2つの単純な矩形間のエッジ検出に最速のアルゴリズム。

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

Rectangle a; 
Rectangle b; 

と、次の列挙:

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

矩形bで衝突している長方形のエッジを検出する最も簡単な方法は何ですか?

Edges e = EdgeDetect(a, b); 
+1

素早く=少しコード、または、速い=速い:ここ

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; } 

は、この実装を検証する一連のテストですか?また:x、yコーナーまたは中点ですか?可能であれば、 – Efrain

+0

速い=速く。 – Rob

+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メソッドの利用可能性です。 :

[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); 
    }  
+0

素晴らしいレスポンスSteve :) - これは本当にうまくいきます。小さな問題は、長方形Bが長方形Aより大きく、それを完全に覆う場合には、同じが返されることです。おそらく、「同一」よりもむしろ「カバー」または「エンパルス」でなければならないでしょうか?ありがとう。 – Rob

+0

あなたが正しいです、私はコードを更新しました。新しい列挙値「Covered」が定義され、「DetectEdge」メソッドがわずかに変更されて最初に同一のものが検出され、次にカバーされ、エッジごとに検出されます。新しいテストも追加されました。 –

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つのエッジ交差を検出します。エッジを返すのではなく、ビットごとに、またはそれぞれの場合にはifでなければなりません。 –

+1

私は、別のrectAが外部からrectBに衝突する必要があると想定しました。提案通りのコードを修正しました – hungryMind