Für eine Zeichenanwendung speichere ich die Mausbewegungskoordinaten in einem Array und zeichne sie dann mit lineTo. Die resultierende Linie ist nicht glatt. Wie kann ich eine einzelne Kurve zwischen allen gesammelten Punkten erstellen?
Ich habe gegoogelt, aber ich habe nur 3 Funktionen zum Zeichnen von Linien gefunden: Verwenden Sie für 2 Beispielpunkte einfach lineTo
. Für 3 Abtastpunkte quadraticCurveTo
, für 4 Abtastpunkte , bezierCurveTo
.
(Ich habe versucht, bezierCurveTo
für jeweils 4 Punkte im Array ein zu zeichnen , aber dies führt zu Knicken alle 4 Abtastpunkte anstelle einer kontinuierlichen glatten Kurve.)
Wie schreibe ich eine Funktion zum Zeichnen einer glatten Kurve mit 5 Abtastpunkten und darüber hinaus?
Antworten:
Das Problem beim Verbinden nachfolgender Abtastpunkte mit disjunkten Funktionen vom Typ "CurveTo" besteht darin, dass das Zusammentreffen der Kurven nicht glatt ist. Dies liegt daran, dass die beiden Kurven einen Endpunkt gemeinsam haben, jedoch von vollständig getrennten Kontrollpunkten beeinflusst werden. Eine Lösung besteht darin, die Mittelpunkte zwischen den nächsten 2 nachfolgenden Abtastpunkten zu "krümmen". Das Verbinden der Kurven mit diesen neuen interpolierten Punkten ergibt einen reibungslosen Übergang an den Endpunkten (was ein Endpunkt für eine Iteration ist, wird zu einem Kontrollpunkt für die nächste Iteration.) Mit anderen Worten, die beiden nicht zusammenhängenden Kurven haben jetzt viel mehr gemeinsam.
Diese Lösung wurde aus dem Buch "Foundation ActionScript 3.0 Animation: Dinge in Bewegung bringen" extrahiert. S.95 - Rendering-Techniken: Erstellen mehrerer Kurven.
Hinweis: Diese Lösung zeichnet nicht durch jeden der Punkte, wie der Titel meiner Frage lautete (vielmehr nähert sie sich der Kurve durch die Stichprobenpunkte, geht aber nie durch die Stichprobenpunkte), sondern für meine Zwecke (eine Zeichenanwendung). es ist gut genug für mich und visuell kann man den Unterschied nicht erkennen. Es gibt eine Lösung, um alle Beispielpunkte durchzugehen, die jedoch viel komplizierter ist (siehe http://www.cartogrammar.com/blog/actionscript-curves-update/ ).
Hier ist der Zeichnungscode für die Approximationsmethode:
quelle
Ein bisschen spät, aber fürs Protokoll.
Sie können glatte Linien erzielen, indem Sie Kardinal-Splines verwenden (auch als kanonischer Spline bezeichnet) verwenden, um glatte Kurven zu zeichnen, die durch die Punkte verlaufen.
Ich habe diese Funktion für Leinwand erstellt - sie ist in drei Funktionen unterteilt, um die Vielseitigkeit zu erhöhen. Die Haupt-Wrapper-Funktion sieht folgendermaßen aus:
Um eine Kurve zu zeichnen, haben Sie ein Array mit x, y Punkten in der Reihenfolge:
x1,y1, x2,y2, ...xn,yn
.Verwenden Sie es so:
Die obige Funktion ruft zwei Unterfunktionen auf, eine zur Berechnung der geglätteten Punkte. Dies gibt ein Array mit neuen Punkten zurück - dies ist die Kernfunktion, die die geglätteten Punkte berechnet:
Und um die Punkte tatsächlich als geglättete Kurve (oder andere segmentierte Linien, solange Sie ein x, y-Array haben) zu zeichnen:
Code-Snippet anzeigen
Dies führt zu folgendem:
Sie können die Leinwand einfach erweitern, sodass Sie sie stattdessen so nennen können:
Fügen Sie dem Javascript Folgendes hinzu:
Eine optimierte Version finden Sie auf NPM (
npm i cardinal-spline-js
) oder auf GitLab .quelle
ptsa
sollte seinpts
, sonst würde es Fehler geben.Die erste Antwort wird nicht alle Punkte durchlaufen. Dieser Graph durchläuft genau alle Punkte und ist eine perfekte Kurve mit den Punkten als [{x :, y:}] n solchen Punkten.
quelle
Wie Daniel Howard betont , beschreibt Rob Spencer unter http://scaledinnovation.com/analytics/splines/aboutSplines.html, was Sie wollen .
Hier ist eine interaktive Demo: http://jsbin.com/ApitIxo/2/
Hier ist es als Ausschnitt für den Fall, dass jsbin nicht verfügbar ist.
quelle
Ich fand das gut
quelle
Ich entscheide mich, etwas hinzuzufügen, anstatt meine Lösung in einem anderen Beitrag zu veröffentlichen. Unten ist die Lösung, die ich baue, vielleicht nicht perfekt, aber bisher ist die Ausgabe gut.
Wichtig: Es werden alle Punkte durchlaufen!
Wenn Sie eine Idee haben, um sie zu verbessern , teilen Sie sie mir bitte mit. Vielen Dank.
Hier ist der Vergleich von vorher nachher:
Speichern Sie diesen Code in HTML, um ihn zu testen.
quelle
Probieren Sie KineticJS aus - Sie können einen Spline mit einer Reihe von Punkten definieren. Hier ist ein Beispiel:
Alte URL: http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-spline-tutorial/
Siehe Archiv-URL: https://web.archive.org/web/20141204030628/http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-spline-tutorial/
quelle
Unglaublich spät, aber inspiriert von Homans genial einfacher Antwort, erlauben Sie mir, eine allgemeinere Lösung zu veröffentlichen (allgemein in dem Sinne, dass Homans Lösung auf Arrays von Punkten mit weniger als 3 Eckpunkten abstürzt):
quelle
Um die Kardinal-Splines-Methode von K3N zu erweitern und möglicherweise die Bedenken von TJ Crowder bezüglich des Eintauchens von Kurven an irreführenden Stellen auszuräumen, habe ich
getCurvePoints()
kurz zuvor den folgenden Code in die Funktion eingefügtres.push(x);
Dies erzeugt effektiv einen (unsichtbaren) Begrenzungsrahmen zwischen jedem Paar aufeinanderfolgender Punkte und stellt sicher, dass die Kurve innerhalb dieses Begrenzungsrahmens bleibt - dh. Wenn sich ein Punkt auf der Kurve über / unter / links / rechts von beiden Punkten befindet, ändert sich seine Position so, dass er sich innerhalb des Felds befindet. Hier wird der Mittelpunkt verwendet, dies könnte jedoch verbessert werden, möglicherweise unter Verwendung einer linearen Interpolation.
quelle
Wenn Sie die Gleichung der Kurve durch n Punkte bestimmen möchten, gibt Ihnen der folgende Code die Koeffizienten des Polynoms vom Grad n-1 und speichert diese Koeffizienten im
coefficients[]
Array (beginnend mit dem konstanten Term). Die x-Koordinaten müssen nicht in Ordnung sein. Dies ist ein Beispiel für ein Lagrange-Polynom .quelle