Wie berechnet man den nächsten Punkt auf 2 Kurven?
15
Wie berechnen Sie unter Berücksichtigung der Punkte einer Linie und einer quadratischen Bezierkurve den nächstgelegenen Punkt? .... Wie erhält man angesichts der Punkte von 2 Kurven den nächstgelegenen Punkt?
Hier ist mein Versuch. Die folgenden Algorithmen sind alles andere als perfekt , aber sie sind einfach, und ich glaube, Sie sollten damit beginnen, prüfen, ob sie in Ihrer Situation funktionieren, und später zu etwas Schnellerem und / oder Genauerem wechseln.
Die Idee ist die folgende:
Nehmen Sie eine Stichprobe der Bézier-Kurve und suchen Sie den nächstgelegenen Punkt auf dieser Stichprobe
Probieren Sie eine Nachbarschaft um den gefundenen Punkt herum und suchen Sie einen neuen nächstgelegenen Punkt
Fahren Sie fort, bis sich der Punkt nicht mehr wesentlich ändert
Algorithmus für die Entfernung von der Bézier-Kurve zur Linie
Die Bézier-Kurve wird durch eine Funktion F(t)mit einer Reihe von Kontrollpunkten und einem variierenden Parameter parametrisiert t. Die Anzahl der Erzeugungspunkte ist unwichtig.
Die Linie wird durch zwei Punkte Aund parametriert B.
Lassen Sie SAMPLES = 10zum Beispiel
Beginnen Sie mit t0 = 0undt1 = 1
Lassen dt = (t1 - t0) / SAMPLES
Wenn dt < 1e-10(oder eine andere Genauigkeitsbedingung, die Sie für richtig halten), ist der Algorithmus beendet und die Antwort lautetF(t0) .
Berechnen Sie eine Liste von SAMPLES + 1Punkten auf der Bézier-Kurve:
L[0] = F(t0)
L[1] = F(t0 + dt)
L[2] = F(t0 + 2 * dt)
…
L[SAMPLES] = F(t0 + SAMPLES * dt)
Finden Sie den Punkt Lmit Index i, der der Linie am nächsten liegt. Verwenden Sie eine beliebige bekannte Punkt- / Linienentfernungsmethode , z. B. die Quadratentfernung, ||AB^L[i]A||² / ||AB||²bei der ^das Kreuzprodukt und ||…||die Entfernung angegeben sind.
Wenn i == 0, setze i = 1; wenn i == SAMPLES, setzei = SAMPLES - 1
Lass t1 = t0 + (i + 1) * dtundt0 = t0 + (i - 1) * dt
Fahren Sie mit Schritt 3 fort.
Algorithmus für die Entfernung von der Bézier-Kurve zur Bézier-Kurve
Diesmal haben wir zwei Bézier-Kurven, die von F(t)und parametriert werden G(t).
Lassen Sie SAMPLES = 10zum Beispiel
Beginnen Sie mit t0 = 0, t1 = 1, s0 = 0unds1 = 1
Lassen dt = (t1 - t0) / SAMPLES
Lassen ds = (s1 - s0) / SAMPLES
Wenn dt < 1e-10(oder eine andere Genauigkeitsbedingung, die Sie für richtig halten), ist der Algorithmus beendet und die Antwort lautetF(t0) .
WENN dies der erste Durchlauf der Schleife ist:
6.1. Berechnen Sie eine Liste von SAMPLES + 1Punkten auf F( siehe oben ).
6.2. Berechnen Sie eine Liste von SAMPLES + 1Punkten auf G.
6.3. Finden Sie heraus, welches Punktepaar am nächsten ist.
6.4. Update t0, t1, s0, s1wie oben zu sehen.
ELSE : alternativ eine Liste von Punkten berechnen auf Foder eine Liste von Punkten auf G, dann finden , welche auf den Punkt Fam nächsten ist , G(s0)und zu aktualisieren t0und t1, OR , welcher Punkt der Gam nächsten ist , F(t0)und zu aktualisieren s0und s1.
Fahren Sie mit Schritt 3 fort.
Probleme
Diese Algorithmen konvergieren konstruktionsbedingt immer auf ein lokales Minimum. Es gibt jedoch keine Garantie dafür, dass sie zur besten Lösung konvergieren. Insbesondere der Bézier-Kurvenalgorithmus ist überhaupt nicht sehr gut, und wenn zwei Kurven an vielen Stellen nahe beieinander liegen, kann es sein, dass Sie die Lösung bei weitem verpassen.
Aber wie gesagt, bevor Sie über robustere Lösungen nachdenken, sollten Sie zuerst mit diesen einfachen experimentieren.
1) Verschieben Sie alles auf eine Achse. Sie müssen also nicht die Länge eines Punktes berechnen, sondern beispielsweise die Y-Achse.
Bei einer Bézierkurve würde ich sagen, dass es an der Anzahl der Kontrollpunkte liegt.
Wenn es drei gibt (Anfang, "Kontrolle" und Ende), würde ich eine Art Scan durchführen (sagen wir jeweils ein paar Prozent) und dann zwischen den nächsten verfeinern (mit einem "binären" Ansatz).
Weitere Punkte würde ich das Paar ausprobieren, das der (übersetzten Y-Achse) am nächsten war.
Ich bin sicher, ein Mathematiker kann Ihnen die exakte Lösung geben (in Mathematik), aber wenn Sie die / eine Lösung in einem Videospiel finden möchten, sind Sie vielleicht besser dran mit einer etwas ok Lösung, da die echte Lösung mehrere Antworten enthalten könnte ( Ich spreche nicht einmal von Rechenleistung.
Für den Fall Bezier-Kurve - Gerade ist der genaueste Weg, die Antwort zu finden, der folgende:
Transformiere das Problem so, dass die Gerade bei Y = 0 immer horizontal ist. Dies erfolgt durch Multiplikation aller Kontrollpunkte mit einer geeigneten affinen Matrix. (Ich gehe davon aus, dass Sie mit der Darstellung affiner Transformationen der Ebene mit 3x3-Matrizen mit 3 festen Einträgen vertraut sind.)
Überprüfen Sie die Y-Koordinaten der Kontrollpunkte. Wenn nicht alle das gleiche Vorzeichen haben, kann es zu einem Schnittpunkt mit der Linie kommen. Berechnen Sie die Wurzeln des Y-Teils der Bezier-Kurve. Sie können jede Wurzelfindungsmethode für Polynome verwenden. In der Literatur gibt es viele davon. Zum Beispiel google "konvexes Rumpfmarschieren" - dies ist eine einigermaßen gute Methode für die in Bezier-Kurven verwendeten Polynome. Jede gefundene Wurzel ist ein Zeitwert eines Schnittpunkts mit der Linie, bei dem der Abstand Null ist - Ihre Arbeit ist erledigt.
Wenn alle Y-Koordinaten dasselbe Vorzeichen haben, berechnen Sie die Ableitung des Y-Teils der Bezier-Kurve. Sie können die X-Koordinaten von Punkten ignorieren, da sie keinen Unterschied machen - die Ziellinie ist horizontal. Finden Sie die Wurzeln dieses Derivats. Dies sind die Zeitwerte, bei denen die Kurve lokal der Linie am nächsten liegt.
Werten Sie die Bezier-Kurve explizit für alle Wurzeln aus, die Sie im vorherigen Schritt gefunden haben, und geben Sie die Wurzel an, die den geringsten Abstand von der Linie ergibt. Sie müssen auch die Endpunkte überprüfen - sie geben möglicherweise einen geringeren Abstand als jede Wurzel.
Antworten:
Hier ist mein Versuch. Die folgenden Algorithmen sind alles andere als perfekt , aber sie sind einfach, und ich glaube, Sie sollten damit beginnen, prüfen, ob sie in Ihrer Situation funktionieren, und später zu etwas Schnellerem und / oder Genauerem wechseln.
Die Idee ist die folgende:
Algorithmus für die Entfernung von der Bézier-Kurve zur Linie
Die Bézier-Kurve wird durch eine Funktion
F(t)
mit einer Reihe von Kontrollpunkten und einem variierenden Parameter parametrisiertt
. Die Anzahl der Erzeugungspunkte ist unwichtig.Die Linie wird durch zwei Punkte
A
und parametriertB
.Lassen Sie
SAMPLES = 10
zum BeispielBeginnen Sie mit
t0 = 0
undt1 = 1
Lassen
dt = (t1 - t0) / SAMPLES
Wenn
dt < 1e-10
(oder eine andere Genauigkeitsbedingung, die Sie für richtig halten), ist der Algorithmus beendet und die Antwort lautetF(t0)
.Berechnen Sie eine Liste von
SAMPLES + 1
Punkten auf der Bézier-Kurve:L[0] = F(t0)
L[1] = F(t0 + dt)
L[2] = F(t0 + 2 * dt)
L[SAMPLES] = F(t0 + SAMPLES * dt)
Finden Sie den Punkt
L
mit Indexi
, der der Linie am nächsten liegt. Verwenden Sie eine beliebige bekannte Punkt- / Linienentfernungsmethode , z. B. die Quadratentfernung,||AB^L[i]A||² / ||AB||²
bei der^
das Kreuzprodukt und||…||
die Entfernung angegeben sind.Wenn
i == 0
, setzei = 1
; wenni == SAMPLES
, setzei = SAMPLES - 1
Lass
t1 = t0 + (i + 1) * dt
undt0 = t0 + (i - 1) * dt
Fahren Sie mit Schritt 3 fort.
Algorithmus für die Entfernung von der Bézier-Kurve zur Bézier-Kurve
Diesmal haben wir zwei Bézier-Kurven, die von
F(t)
und parametriert werdenG(t)
.Lassen Sie
SAMPLES = 10
zum BeispielBeginnen Sie mit
t0 = 0
,t1 = 1
,s0 = 0
unds1 = 1
Lassen
dt = (t1 - t0) / SAMPLES
Lassen
ds = (s1 - s0) / SAMPLES
Wenn
dt < 1e-10
(oder eine andere Genauigkeitsbedingung, die Sie für richtig halten), ist der Algorithmus beendet und die Antwort lautetF(t0)
.WENN dies der erste Durchlauf der Schleife ist:
6.1. Berechnen Sie eine Liste von
SAMPLES + 1
Punkten aufF
( siehe oben ).6.2. Berechnen Sie eine Liste von
SAMPLES + 1
Punkten aufG
.6.3. Finden Sie heraus, welches Punktepaar am nächsten ist.
6.4. Update
t0
,t1
,s0
,s1
wie oben zu sehen.ELSE : alternativ eine Liste von Punkten berechnen auf
F
oder eine Liste von Punkten aufG
, dann finden , welche auf den PunktF
am nächsten ist ,G(s0)
und zu aktualisierent0
undt1
, OR , welcher Punkt derG
am nächsten ist ,F(t0)
und zu aktualisierens0
unds1
.Fahren Sie mit Schritt 3 fort.
Probleme
Diese Algorithmen konvergieren konstruktionsbedingt immer auf ein lokales Minimum. Es gibt jedoch keine Garantie dafür, dass sie zur besten Lösung konvergieren. Insbesondere der Bézier-Kurvenalgorithmus ist überhaupt nicht sehr gut, und wenn zwei Kurven an vielen Stellen nahe beieinander liegen, kann es sein, dass Sie die Lösung bei weitem verpassen.
Aber wie gesagt, bevor Sie über robustere Lösungen nachdenken, sollten Sie zuerst mit diesen einfachen experimentieren.
quelle
1) Verschieben Sie alles auf eine Achse. Sie müssen also nicht die Länge eines Punktes berechnen, sondern beispielsweise die Y-Achse.
Bei einer Bézierkurve würde ich sagen, dass es an der Anzahl der Kontrollpunkte liegt.
Wenn es drei gibt (Anfang, "Kontrolle" und Ende), würde ich eine Art Scan durchführen (sagen wir jeweils ein paar Prozent) und dann zwischen den nächsten verfeinern (mit einem "binären" Ansatz).
Weitere Punkte würde ich das Paar ausprobieren, das der (übersetzten Y-Achse) am nächsten war.
Ich bin sicher, ein Mathematiker kann Ihnen die exakte Lösung geben (in Mathematik), aber wenn Sie die / eine Lösung in einem Videospiel finden möchten, sind Sie vielleicht besser dran mit einer etwas ok Lösung, da die echte Lösung mehrere Antworten enthalten könnte ( Ich spreche nicht einmal von Rechenleistung.
quelle
Einige Antworten von der Algorithmist- Blogseite, die den nächstgelegenen Punkt auf der angegebenen quadratischen Bezierkurve korrekt findet.
Demo .
quelle
Für den Fall Bezier-Kurve - Gerade ist der genaueste Weg, die Antwort zu finden, der folgende:
quelle