Angenommen, Sie haben eine zweidimensionale Ebene mit 2 Punkten (a und b genannt), die durch eine x-Ganzzahl und eine ay-Ganzzahl für jeden Punkt dargestellt werden.
Wie können Sie feststellen, ob sich ein anderer Punkt c auf dem durch a und b definierten Liniensegment befindet?
Ich benutze am häufigsten Python, aber Beispiele in jeder Sprache wären hilfreich.
Antworten:
Überprüfen Sie, ob das Kreuzprodukt von (ba) und (ca) 0 ist, wie Darius Bacon mitteilt, ob die Punkte a, b und c ausgerichtet sind.
Wenn Sie jedoch wissen möchten, ob c zwischen a und b liegt, müssen Sie auch überprüfen, ob das Punktprodukt von (ba) und (ca) positiv ist und kleiner als das Quadrat des Abstands zwischen a und b ist.
Im nicht optimierten Pseudocode:
quelle
-epsilon < crossproduct < epsilon and min(a.x, b.x) <= c.x <= max(a.x, b.x) and min(a.y, b.y) <= c.y <= max(a.y, b.y)
ist ausreichend, nicht wahr?So würde ich es machen:
quelle
-epsilon < (distance(a, c) + distance(c, b) - distance(a, b)) < epsilon
==
ist in den meisten Fällen eine falsche Sache für Schwimmer .math.isclose()
könnte stattdessen verwendet werden. Es gabmath.isclose()
2008 keine und deshalb habe ich die explizite Ungleichung mitepsilon
(abs_tol
inmath.isclose()
speak) angegeben.Überprüfen Sie, ob das Kreuzprodukt von
b-a
undc-a
ist0
: Das bedeutet, dass alle Punkte kollinear sind. Wenn dies der Fall ist, überprüfen Sie, obc
die Koordinaten zwischena
und liegenb
. Verwendung entweder die X oder die Y - Koordinaten, so langea
undb
sind getrennt auf dieser Achse (oder sie sind die gleichen auf beiden).Diese Antwort bestand aus drei Updates. Die lohnende Information von ihnen: Brian Hayes ' Kapitel in Beautiful Code behandelt den Entwurfsraum für eine Kollinearitätstestfunktion - nützlicher Hintergrund. Vincents Antwort half, diese zu verbessern. Und es war Hayes, der vorschlug, nur eine der x- oder y-Koordinaten zu testen; ursprünglich hatte der Code
and
anstelle vonif a.x != b.x else
.quelle
Hier ist ein anderer Ansatz:
Punkt C (x3, y3) liegt zwischen A & B, wenn:
quelle
Die Länge des Segments ist nicht wichtig, daher ist die Verwendung einer Quadratwurzel nicht erforderlich und sollte vermieden werden, da wir an Genauigkeit verlieren könnten.
Ein zufälliges Anwendungsbeispiel:
quelle
==
inis_between()
fehlschlagen (übrigens ist es ein verkleidetes Kreuzprodukt).is_between()
:a, b = self.a, self.b
Berechnen Sie mit einem geometrischeren Ansatz die folgenden Abstände:
und testen Sie, ob ac + bc gleich ab ist :
Das liegt daran, dass es drei Möglichkeiten gibt:
quelle
Hier ist ein anderer Weg, mit Code in C ++. Bei zwei Punkten, l1 und l2, ist es trivial, das Liniensegment zwischen ihnen als auszudrücken
Dabei ist 0 <= A <= 1. Dies wird als Vektordarstellung einer Linie bezeichnet, wenn Sie mehr daran interessiert sind, sie nur für dieses Problem zu verwenden. Wir können die x- und y-Komponenten davon aufteilen und geben:
Nehmen Sie einen Punkt (x, y) und setzen Sie seine x- und y-Komponenten in diese beiden Ausdrücke ein, um nach A zu lösen. Der Punkt liegt auf der Linie, wenn die Lösungen für A in beiden Ausdrücken gleich sind und 0 <= A <= 1. Weil Das Lösen nach A erfordert eine Division. Es gibt spezielle Fälle, die behandelt werden müssen, um die Division durch Null zu stoppen, wenn das Liniensegment horizontal oder vertikal ist. Die endgültige Lösung lautet wie folgt:
quelle
Ok, viele Erwähnungen der linearen Algebra (Kreuzprodukt von Vektoren) und dies funktioniert in einem realen (dh kontinuierlichen oder Gleitkomma-) Raum, aber die Frage stellte speziell fest, dass die beiden Punkte als ganze Zahlen ausgedrückt wurden und daher ein Kreuzprodukt nicht das richtige ist Lösung, obwohl es eine ungefähre Lösung geben kann.
Die richtige Lösung besteht darin, den Bresenham-Linienalgorithmus zwischen den beiden Punkten zu verwenden und festzustellen, ob der dritte Punkt einer der Punkte auf der Linie ist. Wenn die Punkte so weit entfernt sind, dass die Berechnung des Algorithmus nicht performant ist (und es müsste wirklich groß sein, damit dies der Fall ist), könnten Sie sicher herumgraben und Optimierungen finden.
quelle
Das Skalarprodukt zwischen (ca) und (ba) muss gleich dem Produkt ihrer Länge sein (dies bedeutet, dass die Vektoren (ca) und (ba) ausgerichtet sind und dieselbe Richtung haben). Darüber hinaus muss die Länge von (ca) kleiner oder gleich der von (ba) sein. Pseudocode:
quelle
Ich brauchte dies für Javascript zur Verwendung in einer HTML5-Zeichenfläche, um festzustellen, ob sich der Cursor des Benutzers über oder in der Nähe einer bestimmten Zeile befand. Also habe ich die Antwort von Darius Bacon in Coffeescript geändert:
quelle
Sie können das Keil- und Punktprodukt verwenden:
quelle
So habe ich es in der Schule gemacht. Ich habe vergessen, warum es keine gute Idee ist.
BEARBEITEN:
@Darius Bacon: zitiert ein "Beautiful Code" -Buch, das eine Erklärung enthält, warum der unten stehende Code keine gute Idee ist.
quelle
Jeder Punkt auf dem Liniensegment ( a , b ) (wobei a und b Vektoren sind) kann als lineare Kombination der beiden Vektoren a und b ausgedrückt werden :
Mit anderen Worten, wenn c auf dem Liniensegment ( a , b ) liegt:
Wenn wir nach m auflösen , erhalten wir:
Unser Test wird also (in Python):
quelle
c # Von http://www.faqs.org/faqs/graphics/algorithms-faq/ -> Betreff 1.02: Wie finde ich den Abstand von einem Punkt zu einer Linie?
quelle
Hier ist ein Java-Code, der für mich funktioniert hat:
quelle
Wie wäre es nur sicherzustellen, dass die Steigung gleich ist und der Punkt zwischen den anderen liegt?
gegebene Punkte (x1, y1) und (x2, y2) (mit x2> x1) und Kandidatenpunkt (a, b)
wenn (b-y1) / (a-x1) = (y2-y2) / (x2-x1) und x1 <a <x2
Dann muss (a, b) zwischen (x1, y1) und (x2, y2) liegen.
quelle
Eine Antwort in C # mit einer Vector2D-Klasse
Beachten Sie, dass
ist das Punktprodukt des Segmentvektors durch Operatorüberladung in C #
Der Schlüssel besteht darin, die Projektion des Punktes auf die unendliche Linie auszunutzen und zu beobachten, dass die skalare Größe der Projektion uns trivial sagt, ob sich die Projektion auf dem Segment befindet oder nicht. Wir können die Grenzen der Skalargröße anpassen, um eine Fuzzy-Toleranz zu verwenden.
Wenn die Projektion innerhalb von Grenzen liegt, testen wir nur, ob der Abstand vom Punkt zur Projektion innerhalb von Grenzen liegt.
Der Vorteil gegenüber dem produktübergreifenden Ansatz besteht darin, dass die Toleranz einen sinnvollen Wert hat.
quelle
Hier ist meine Lösung mit C # in Unity.
quelle
C # -Version von Jules 'Antwort:
quelle
Sie können dies tun, indem Sie die Liniengleichung für dieses Liniensegment mit den Punktkoordinaten lösen. Sie wissen, ob sich dieser Punkt auf der Linie befindet, und überprüfen dann die Grenzen des Segments, um festzustellen, ob er sich innerhalb oder außerhalb des Segments befindet. Sie können einen bestimmten Schwellenwert anwenden, da er sich wahrscheinlich irgendwo im Raum befindet, der höchstwahrscheinlich durch einen Gleitkommawert definiert ist, und Sie dürfen den genauen nicht treffen. Beispiel in PHP
quelle