it-swarm.com.de

Wie kann man überprüfen, ob das Liniensegment ein Rechteck schneidet?

Wenn Sie zwei Punkte (x1, y1) und (x2, y2) haben, die zwei gegenüberliegende Ecken eines Rechtecks ​​darstellen, und zwei andere Punkte (x3, y3) und (x4, y4), die 2 Endpunkte von a darstellen Liniensegment, wie können Sie überprüfen, ob das Liniensegment das Rechteck schneidet?

(Das Liniensegment ist nur das Segment, das zwischen den angegebenen Endpunkten enthalten ist. Es ist keine unendlich lange Linie, die durch diese beiden Punkte definiert wird.)

26
omega

Eine sehr einfache Option wäre die Verwendung von einem Standardalgorithmus zum Prüfen, ob zwei Liniensegmente sich schneiden , um zu prüfen, ob die Liniensegmente eines der vier Liniensegmente schneiden, die die Ecken des Kastens bilden. Es ist rechnerisch sehr effizient zu prüfen, ob sich zwei Liniensegmente schneiden, daher würde ich davon ausgehen, dass dies sehr schnell ablaufen könnte.

Hoffe das hilft!

25
templatetypedef

Um zu verstehen, wie Sie die Formel zum Testen ermitteln, ob ein Liniensegment ein Rechteck schneidet, ist es wichtig, sich die Eigenschaften des Vektorpunktprodukts zu merken.

Stellen Sie das Liniensegment als Einheitsvektor und einen Abstand zwischen dem Startpunkt des Liniensegments und dem Ursprung dar. Hier ist ein C # -Code, um diesen aus den PointF variables a_ptStart und a_ptEnd zu berechnen, wobei eine Vector verwendet wird:

Vector vecLine = new Vector(a_ptEnd.X - a_ptStart.X, a_ptEnd.Y - a_ptStart.Y);
double dLengthLine = vecLine.Length;
vecLine /= dLengthLine;
double dDistLine = Vector.Multiply(vecLine, new Vector(a_ptStart.X, a_ptStart.Y));

Sie müssen auch den senkrechten Vektor und den Abstand zum Ursprung für das Liniensegment berechnen. Das Drehen eines Einheitsvektors um 90 ° ist easy .

Vector vecPerpLine = new Vector(-vecLine.Y, vecLine.X);
double dDistPerpLine = Vector.Multiply(vecPerpLine, new Vector(a_ptStart.X, a_ptStart.Y));

Angenommen, die vier Ecken des Rechtecks ​​befinden sich in Vector-Variablen, die als vecRect1, vecRect2, vecRect3 und vecRect4 bezeichnet werden, und berechnen die distance zwischen dem Liniensegment und allen vier Ecken des Begrenzungsrechtecks ​​des Ziels:

double dPerpLineDist1 = Vector.Multiply(vecPerpLine, vecRect1) - dDistPerpLine;
double dPerpLineDist2 = Vector.Multiply(vecPerpLine, vecRect2) - dDistPerpLine;
double dPerpLineDist3 = Vector.Multiply(vecPerpLine, vecRect3) - dDistPerpLine;
double dPerpLineDist4 = Vector.Multiply(vecPerpLine, vecRect4) - dDistPerpLine;
double dMinPerpLineDist = Math.Min(dPerpLineDist1, Math.Min(dPerpLineDist2,
    Math.Min(dPerpLineDist3, dPerpLineDist4)));
double dMaxPerpLineDist = Math.Max(dPerpLineDist1, Math.Max(dPerpLineDist2,
    Math.Max(dPerpLineDist3, dPerpLineDist4)));

Wenn alle Abstände positiv sind oder alle Abstände negativ sind, befindet sich das Rechteck auf der einen oder der anderen Seite der Linie, sodass es keinen Schnitt gibt. (Rechtecke mit der Ausdehnung null werden sich nicht mit einem Liniensegment schneiden.)

if (dMinPerpLineDist <= 0.0 && dMaxPerpLineDist <= 0.0
        || dMinPerpLineDist >= 0.0 && dMaxPerpLineDist >= 0.0)
    /* no intersection */;

Als nächstes projizieren Sie alle vier Ecken des Begrenzungsrechtecks ​​des Ziels auf das Liniensegment. Dies gibt uns den Abstand zwischen dem Ursprung der Linie und der Projektion der Rechteckecke an dieser Linie.

double dDistLine1 = Vector.Multiply(vecLine, vecRect1) - dDistLine;
double dDistLine2 = Vector.Multiply(vecLine, vecRect2) - dDistLine;
double dDistLine3 = Vector.Multiply(vecLine, vecRect3) - dDistLine;
double dDistLine4 = Vector.Multiply(vecLine, vecRect4) - dDistLine;
double dMinLineDist = Math.Min(dDistLine1, Math.Min(dDistLine2,
    Math.Min(dDistLine3, dDistLine4)));
double dMaxLineDist = Math.Max(dDistLine1, Math.Max(dDistLine2,
    Math.Max(dDistLine3, dDistLine4)));

Wenn die Punkte des Rechtecks ​​nicht in die Ausdehnung des Liniensegments fallen, gibt es keinen Schnittpunkt.

if (dMaxLineDist <= 0.0 || dMinLineDist >= dLengthLine)
    /* no intersection */;

Ich glaube das reicht aus.

1
ulatekh

Holen Sie sich das Punktprodukt aller 4 Scheitelpunkte (die Ecken des Rechtecks) mit dem Richtungsvektor des Liniensegments. Wenn alle 4 Werte mit demselben Vorzeichen haben, liegen alle Scheitelpunkte auf derselben Seite der Linie (nicht dem Liniensegment, sondern der unendlichen Linie), und daher schneidet die Linie das Rechteck nicht. Dieser Ansatz ist nur für die Erkennung von 2D-Schnittpunkten geeignet. Dies kann verwendet werden, um die meisten von ihnen schnell zu filtern (nur mit Multiplikationen und Zusätzen). Sie müssen weitere Prüfungen für Liniensegmente anstelle von Linien durchführen.

0
Srinivasan