Nächster Punkt auf einer kubischen Bezier-Kurve?
Wie finde ich den Punkt B(t) entlang einer kubischen Bézier-Kurve, der am nächsten ist zu einem beliebigen Punkt P in der Ebene?
InformationsquelleAutor der Frage Adrian Lopez | 2010-04-30
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nach viel suchen, fand ich ein Papier, das beschreibt eine Methode für das finden der nächstgelegenen Punkt auf einer Bezier-Kurve an einem bestimmten Punkt:
Außerdem fand ich Wikipedia und MathWorld ist Beschreibungen der Sturm-Sequenzen hilfreich, zum Verständnis der erste Teil der algoritm, als das Papier selbst ist nicht sehr klar in seiner eigenen Beschreibung.
InformationsquelleAutor der Antwort Adrian Lopez
Je nach Toleranzen. Brute-force-und akzeptieren Fehler. Dieser Algorithmus könnte falsch sein, für einige seltene Fälle. Aber, die Mehrheit von Ihnen findet es einen Punkt sehr nahe an der richtigen Antwort, und die Ergebnisse werden sich verbessern, je höher der Scheiben. Es versucht jeder Punkt entlang der Kurve in regelmäßigen Abständen und gibt das beste es gefunden.
Können Sie viel besser und schneller, indem Sie einfach das finden der nächstgelegenen Punkt und recursing um diesen Punkt.
In beiden Fällen können Sie die quad nur als leicht:
Durch den Wechsel aus der Gleichung gibt.
Während die akzeptierte Antwort richtig ist, und Sie wirklich herausfinden können, die Wurzeln und vergleichen Sie das Zeug. Wenn Sie wirklich brauchen nur zu finden der nächstgelegenen Punkt auf der Kurve, dies wird es tun.
In Bezug auf Ben in den Kommentaren. Sie können nicht kurzer hand die Formel, in die viele Hunderte von Steuerelement-Punkt-Bereich, wie ich für kubische und quad Formen. Denn die Menge verlangt von jeder neuen Zugabe von einer Bézier-Kurve bedeutet, dass Sie bauen eine Pythagoreische Pyramiden für Sie, und wir sind im Grunde der Umgang mit noch mehr und noch massig zahlen. Für die quad gehen Sie 1, 2, 1, für kubische Sie gehen 1, 3, 3, 1. Sie landen, die Gebäude größer und größer Pyramiden, und am Ende brechen Sie Sie unten mit Casteljau-Algorithmus, (ich schrieb dies für Feste Geschwindigkeit):
Im Grunde muss man den Algorithmus verwenden direkt, nicht nur für die Berechnung der x,y, die auftreten, auf der Kurve selbst, aber Sie müssen auch für die Durchführung der tatsächlichen und ordnungsgemäßen Bezier-subdivision Algorithmus (es gibt andere, aber das ist, was ich empfehlen würde), um zu berechnen, nicht nur eine Annäherung sein, wie ich durch die Aufteilung in Linien-Segmenten, sondern von den tatsächlichen Kurven. Oder eher die polygon-Rumpf ist sicher enthalten die Kurve.
Tun Sie dies, indem Sie den oben beschriebenen Algorithmus zur Unterteilung der Kurven auf der gegebenen t. Also ist T=0.5, schneiden Sie die Kurven in der Hälfte (Hinweis 0.2 geschnitten würde es 20% 80% über der Kurve). Dann index der verschiedenen Punkte an der Seite der Pyramide, und die andere Seite der Pyramide, gebaut von der Basis. So zum Beispiel im kubischen:
Sie füttern würde der Algorithmus 0 1 2 3 control points, dann würde index die beiden perfekt unterteilt Kurven bei 0, 4, 7, 9 und 9, 8, 6, 3. Machen Sie sich spezielle Notiz zu sehen, dass diese Kurven beginnen und enden am gleichen Punkt. und der Letzte index 9, das ist der Punkt auf der Kurve ist als die anderen neuen Ankerpunkt. Angesichts dieser Sie können perfekt zu unterteilen, eine bezier-Kurve.
Dann finden Sie den nächsten Punkt, den Sie wollen würde, um zu halten die Unterteilung der Kurve in verschiedenen teilen der Feststellung, dass es der Fall ist, dass die gesamte Kurve eine bezier-Kurve enthalten ist, die innerhalb der Hülle der Kontrollpunkte. Das ist zu sagen, wenn wir die Punkte 0, 1, 2, 3 in einen geschlossenen Pfad verbinden 0,3, die Kurve muss fallen vollständig innerhalb des Polygons Rumpf. Also, was wir tun zu definieren, die unseren gegebenen Punkt P, dann fahren wir weiter zu unterteilen Kurven bis zu dem Zeitpunkt, als wir wissen, dass die entferntesten Punkt einer Kurve ist näher als dem nächstgelegenen Punkt der anderen Kurve. Wir vergleichen einfach dieses Punktes P zu allen Kontroll-und Anker-Punkte der Kurven. Und zu verwerfen jede Kurve aus unserer aktiven Liste, deren nächste Stelle (ob Anker oder Kontrolle) weiter entfernt ist als der am weitesten entfernte Punkt der anderen Kurve. Dann unterteilen wir alle aktiven Kurven und dies wieder tun. Schließlich haben wir sehr unterteilt Kurven verwerfen, etwa die Hälfte jeder Schritt (Bedeutung sollte es werden O(n log n)), bis unsere Fehler ist im Grunde vernachlässigbar. An dieser Stelle nennen wir unsere aktive Kurven der nächste Punkt zu diesem Punkt (es könnte mehr als eine), und beachten Sie, dass der Fehler in der hoch unterteilt bisschen von Kurve ist im Grunde gleich zu einem Punkt. Oder einfach entscheiden, die Frage mit den Worten, welche der beiden Anker-Punkt am nächsten liegt ist der nächste Punkt zu unserem Ausgangspunkt P. Und wir wissen, dass der Fehler zu einem ganz bestimmten Grad.
Diesem, obwohl, erfordert, dass wir tatsächlich eine stabile Lösung und eine sicherlich richtige Algorithmus und richtig finden, den kleinen Teil der Kurve, dass wird sicher sein, den nächsten Punkt zu unserem Ausgangspunkt. Und es sollte relativ schnell sein noch.
InformationsquelleAutor der Antwort Tatarize
Ich geschrieben habe, einige quick-and-dirty-code, der schätzt diese für Bezier-Kurven beliebigen Grades. (Hinweis: dies ist pseudo-brute-force, nicht eine geschlossener form-Lösung.)
Demo: http://phrogz.net/svg/closest-point-on-bezier.html
Der obige code verwendet die vmath Bibliothek effizient lerp zwischen Vektoren (in 2D, 3D oder 4D), aber es wäre trivial zu ersetzen, die
lerp()
Anruf inbézierPoint()
mit Ihrem eigenen code.Tuning der Algorithmus
Den
closestPoint()
Funktion arbeitet in zwei Phasen:localMinimum()
Funktion zu jagen, die region rund um die kleinste Entfernung, die Verwendung einer binären Suche den t und zeigen, produziert der true kleinsten Abstand.Den Wert
scans
imclosestPoint()
bestimmt, wie viele samples für den ersten pass. Weniger scans schneller, erhöht aber die Chancen fehlen den wahren minimalen Punkt.Den
ε
Grenze an dielocalMinimum()
Funktion steuert, wie lange es geht weiter auf die Jagd nach den besten Wert. Ein Wert von1e-2
quantisiert die Kurve in ~100 Punkte, und damit Sie sehen können, die Punkte zurückgegeben, die vonclosestPoint()
knallen entlang der Linie. Jede weitere Dezimalstelle Genauigkeit—1e-3
1e-4
...—kostet etwa 6-8 zusätzliche AufrufebézierPoint()
.InformationsquelleAutor der Antwort Phrogz