Schneller Schnittpunkt von Rechteck zu Rechteck


80

Was ist ein schneller Weg, um zu testen, ob sich zwei Rechtecke schneiden?


Eine Suche im Internet ergab diesen Einzeiler (WOOT!), Aber ich verstehe nicht, wie man ihn in Javascript schreibt, er scheint in einer alten Form von C ++ geschrieben zu sein.

struct
{
    LONG    left;
    LONG    top;
    LONG    right;
    LONG    bottom;
} RECT; 

bool IntersectRect(const RECT * r1, const RECT * r2)
{
    return ! ( r2->left > r1->right
        || r2->right < r1->left
        || r2->top > r1->bottom
        || r2->bottom < r1->top
        );
}

5
Ich denke, Sie haben einen Tippfehler in Ihrem Kopieren / Einfügen gemacht
fmark

5
Der Originalartikel hat einen Tippfehler. r2->right leftmacht keinen Sinn. Möglicherweise ist es aufgrund von HTML-Problemen fehlerhaft.
Marcelo Cantos

42
Ich bin gespannt, wie sich der obige Code in einer "modernen" Form von C ++ unterscheiden würde.
Jamesdlin

3
Ich bin sicher, dass die fehlenden Zeichen <Symbole sind, weil HTML entkommen ist.
Devios1

1
@jamesdlin Sie würden die Funktion als Elementfunktion der Struktur erstellen, indem Sie einen Parameter verwenden. Zweitens würden Sie normalerweise const & anstelle von const * verwenden. Sie können Vorlagen verwenden, um sowohl int- als auch long- und double-Versionen zu haben, anstatt ein Win32-Makro zu verwenden ... (Es wird auch nicht kompiliert, da RECT eine Instanz einer unbenannten Struktur und kein Typname ist.) Beispiel : ideone.com/bnzwl3
Sebastian Wahl

Antworten:


141

So kann dieser Code in JavaScript übersetzt werden. Beachten Sie, dass Ihr Code und der des Artikels einen Tippfehler enthalten, wie in den Kommentaren vorgeschlagen. Insbesondere r2->right leftsollte r2->right < r1->leftund r2->bottom topsollte sein, r2->bottom < r1->topdamit die Funktion funktioniert.

function intersectRect(r1, r2) {
  return !(r2.left > r1.right || 
           r2.right < r1.left || 
           r2.top > r1.bottom ||
           r2.bottom < r1.top);
}

Testfall:

var rectA = {
  left:   10,
  top:    10,
  right:  30,
  bottom: 30
};

var rectB = {
  left:   20,
  top:    20,
  right:  50,
  bottom: 50
};

var rectC = {
  left:   70,
  top:    70,
  right:  90,
  bottom: 90
};

intersectRect(rectA, rectB);  // returns true
intersectRect(rectA, rectC);  // returns false

Nur um hinzuzufügen / zu bestätigen - dies testet drei Boxen, die 20px x 20px groß sind, mit Ausnahme von rectB, das 30px x 30px groß ist
Version

6
Wenn r1 und r2 identisch sind, würde die Funktion intersectRect false zurückgeben
zumalifeguard

Fantastische eloquente Implementierung. Liebe es! +1, hat perfekt für mein Spiel funktioniert.
Unome

1
@zumalifeguard Warum denkst du das?
Minix

Diese Funktion ist so genial. Daran hätte ich nie gedacht, stattdessen hätte ich versucht, die beiden Kästchen zu kreuzen.
Nikk Wong

69
function intersect(a, b) {
  return (a.left <= b.right &&
          b.left <= a.right &&
          a.top <= b.bottom &&
          b.top <= a.bottom)
}

Dies setzt voraus, dass die topnormalerweise kleiner als ist bottom(dh dass die yKoordinaten nach unten zunehmen).


Gute und funktionierende Lösung, sollte aber etwas langsamer sein, da alle Bedingungen bewertet werden müssen. Die andere Lösung wird durchgeführt, sobald eine der Bedingungen als wahr ausgewertet wird.
Gigo

21
Dies wird auch durchgeführt, sobald eine der Bedingungen als falsch ausgewertet wird. Dh in genau den gleichen Fällen wie der andere.
DS.

3
Dies ist besser, da dadurch die Negationsaktion entfernt wird.
Discipol

4
+1, so viel ordentlicher als die akzeptierte Antwort. Wenn Sie halboffene Bereiche verwenden (dh das Rechteck enthält oben und links, aber nicht unten und rechts, wie es in vielen Grafiksystemen üblich ist), sollte das Ändern <=in <funktionieren.
Jules

Ich mag diese Lösung, weil ich die =für jede Bedingung entfernen kann und die Rechtecke die Ränder "berühren" können.
Programmierer

19

Auf diese Weise implementiert .NET Framework Rectangle.Intersect

public bool IntersectsWith(Rectangle rect)
{
  if (rect.X < this.X + this.Width && this.X < rect.X + rect.Width && rect.Y < this.Y + this.Height)
    return this.Y < rect.Y + rect.Height;
  else
    return false;
}

Oder die statische Version:

public static Rectangle Intersect(Rectangle a, Rectangle b)
{
  int x = Math.Max(a.X, b.X);
  int num1 = Math.Min(a.X + a.Width, b.X + b.Width);
  int y = Math.Max(a.Y, b.Y);
  int num2 = Math.Min(a.Y + a.Height, b.Y + b.Height);
  if (num1 >= x && num2 >= y)
    return new Rectangle(x, y, num1 - x, num2 - y);
  else
    return Rectangle.Empty;
}

6

Ein anderer einfacher Weg. (Dies setzt voraus, dass die y-Achse nach unten zunimmt).

function intersect(a, b) {
  return Math.max(a.left, b.left) < Math.min(a.right, b.right) &&
          Math.max(a.top, b.top) < Math.min(a.bottom, b.bottom);
}

Die 4 Zahlen (Max und Min) in der obigen Bedingung geben auch die Schnittpunkte an.



0

Ich habe eine Mischung von Methoden verwendet, um ein kleineres Rechteck innerhalb eines großen Rechtecks ​​zu erkennen. Dies ist eine NodeJS-Methode, die Breite / Höhe verwendet, aber leicht angepasst werden kann.

            isIntersectingRect: function (r1, r2) {
              var quickCheck = (r1.x <= r2.x + r2.w &&
                      r2.x <= r1.x + r1.w &&
                      r1.y <= r2.y + r2.h &&
                      r2.y <= r1.y + r1.h)
              if (quickCheck) return true;
              var x_overlap = Math.max(0, Math.min(r1.x + r1.w, r2.x + r2.w) - Math.max(r1.x, r2.x));
              var y_overlap = Math.max(0, Math.min(r1.y + r1.h, r2.y + r2.h) - Math.max(r1.y, r2.y));
              var overlapArea = x_overlap * y_overlap;
              return overlapArea == 0;
            }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.