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?

Bildbeschreibung hier eingeben

Robinicks
quelle
2
Ich glaube, diese Frage ist ein guter Anfang.
Sam Hocevar

Antworten:

3

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.

  1. Lassen Sie SAMPLES = 10zum Beispiel

  2. Beginnen Sie mit t0 = 0undt1 = 1

  3. Lassen dt = (t1 - t0) / SAMPLES

  4. Wenn dt < 1e-10(oder eine andere Genauigkeitsbedingung, die Sie für richtig halten), ist der Algorithmus beendet und die Antwort lautetF(t0) .

  5. 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)
  6. 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.

  7. Wenn i == 0, setze i = 1; wenn i == SAMPLES, setzei = SAMPLES - 1

  8. Lass t1 = t0 + (i + 1) * dtundt0 = t0 + (i - 1) * dt

  9. 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).

  1. Lassen Sie SAMPLES = 10zum Beispiel

  2. Beginnen Sie mit t0 = 0, t1 = 1, s0 = 0unds1 = 1

  3. Lassen dt = (t1 - t0) / SAMPLES

  4. Lassen ds = (s1 - s0) / SAMPLES

  5. Wenn dt < 1e-10(oder eine andere Genauigkeitsbedingung, die Sie für richtig halten), ist der Algorithmus beendet und die Antwort lautetF(t0) .

  6. 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.

  7. ELSE : alternativ eine Liste von Punkten berechnen auf F oder 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.

  8. 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.

sam hocevar
quelle
0

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.

Valmond
quelle
ps. 2 Kurven, denken Sie nicht einmal darüber nach (je nach Anzahl der Kontrollpunkte erhalten Sie möglicherweise etwas (zumindest so oft wie))
Valmond
0

Für den Fall Bezier-Kurve - Gerade ist der genaueste Weg, die Antwort zu finden, der folgende:

  1. 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.)
  2. Ü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.
  3. 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.
  4. 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.
Krzysztof Kosiński
quelle