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
        );
}
Der Blitz
quelle
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
Daniel Vassallo
quelle
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).

DS.
quelle
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;
}
Schwarrior
quelle
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.

Herzog
quelle
1

Dies hat einen Rect-Typ, den Sie verwenden können. Es ist bereits JavaScript.

https://dxr.mozilla.org/mozilla-beta/source/toolkit/modules/Geometry.jsm

englebart
quelle
Dieser Code gibt false für die Bereiche A (0,0,100,100) und B (100,100,100,100) zurück. Ich denke, es sollte <= statt <sein
Stanislav S.
<= gibt ein Rechteck mit einer Höhe von 0 an. Für meine Zwecke nicht nützlich.
Englebart
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;
            }
Langerz
quelle