Als ich heute das Buch „HTML5+Javascript Animation Basics“ studierte, sprach ich im dritten Abschnitt von Kapitel 8 darüber, wie man mit drei Federn drei Punkte verbindet, um Dehnbewegungen auszuführen.
Nachdem ich das Beispiel beendet hatte, dachte ich darüber nach, was wäre, wenn es vier oder fünf Punkte wären.
Ich habe den Code umgeschrieben und die Anzahl der Punkte variabel gemacht. Der Endeffekt besteht darin, die endgültige Streckbewegung jedes Punktes zum Ausgleich zu erreichen, aber die Verbindungen zwischen den Punkten sehen nicht sehr gut aus und einige sind gekreuzt.
Deshalb habe ich darüber nachgedacht, ob dieser Bereich optimiert werden könnte.
Drehen Sie die LinieDie Punkte im vorherigen Beispiel liegen alle an zufälligen Positionen, sodass die Verbindungen unkontrollierbar sind. Deshalb möchte ich zunächst damit beginnen.
Verwenden Sie zunächst einen bestimmten Punkt als Referenzpunkt, um die Winkel anderer Punkte relativ zu diesem Punkt zu ermitteln.
Verbinden Sie diese Punkte dann entsprechend dem Winkel von klein nach groß, sodass Sie ein normales Polygon zeichnen können.
Der ungefähre Implementierungscode lautet wie folgt:
let ball = [];let ballNum = 6;let firstBall = null;while(ballNum--) { let ball = new Ball(20, parseColor(Math.random() * 0xffffff)) ball.x = Math.random( ) * width; ball.y = Math.random() * height;balls.push(ball) if (!firstBall) { firstBall = ball ball.angle = 0 } else { const dx = ball.x - firstBall.x, dy = ball.y - firstBall.y; ball.angle = Math.atan2(dy, dx); }}// Versuchen Sie, die Verbindungslinie der Bälle zu einem regelmäßigen Polygon zu machen = Bälle .sort((ballA, ballB) => { return ballA.angle - ballB.angle})
Auf diese Weise kann beim endgültigen Zeichnen der Verbindung der Winkel durch Durchlaufen des Arrays von klein nach groß gezeichnet werden.
Der Effekt ist wie folgt:
Dadurch lässt sich die Zahl der sich kreuzenden Leitungen deutlich reduzieren, ganz vermeiden lässt sich dies jedoch nicht.
Als nächstes möchte ich versuchen, diese Lösung zu optimieren. Verwenden Sie beispielsweise Math.abs, um den Winkel zu korrigieren, oder finden Sie den Punkt mit dem kleinsten Winkel, um jeden Punkt zu verbinden. Aber das Ergebnis ist nicht gut, Grenzüberschreitungen lassen sich nicht vermeiden.
Basierend auf dem Mittelpunkt drehenDann kam mir eine andere Idee in den Sinn. Wenn der Mittelpunkt des Polygons bestimmt werden kann, können die Winkel aller Punkte relativ zum Mittelpunkt separat berechnet und diese Punkte im Uhrzeigersinn oder gegen den Uhrzeigersinn verbunden werden.
Nach langer Suche im Internet benötigen jedoch alle Punktalgorithmen eine Reihe von Punkten, die in einer bestimmten Reihenfolge im Uhrzeigersinn angeordnet sind.
Aber wenn ich diese Punkte habe, kann ich das Polygon schon zeichnen. Musste aufgeben
Zweipolige X-Achsen-SegmentierungIn meiner Verzweiflung musste ich bei Google suchen und dann auf Zhihu eine gute Antwort finden: Wie verbinde ich eine Gruppe ungeordneter Punkte auf der Ebene zu einem einfachen Polygon?
Für die spezifische Beschreibung des Algorithmus schauen Sie sich einfach die Antwort an und ich werde nicht auf Details eingehen.
Wenn Sie jedoch die obere Kette und die untere Kette verbinden, müssen Sie nur darauf achten, dass die obere Kette in absteigender Reihenfolge auf der X-Achse und die untere Kette in aufsteigender Reihenfolge auf der X-Achse verbunden wird (gezeichnet im Gegenuhrzeigersinn). . Bei Punkten mit gleicher X-Achse spielt es keine Rolle, ob die Y-Achse größer oder kleiner ist.
Bei der Implementierung erfolgt die Implementierung streng nach dem Algorithmus in der Antwort.
Bei der Beurteilung, ob ein Punkt zur oberen oder unteren Kette gehört, besteht die ursprüngliche Idee darin, die Funktionsgleichung der geraden Linie basierend auf zwei Punkten zu bestimmen und dann die Koordinaten der Punkte zur Berechnung einzuführen. Aber später dachte ich, dass alle Punkte den am weitesten links stehenden Pol verwenden, um den Schrägwinkel zu berechnen, und ihn dann entsprechend der Winkelgröße dividieren, was visuell einfacher zu verstehen ist.
Der ungefähre Code lautet wie folgt:
letballs = [];let tempBalls = [];let ballNum = 6;let isDragingBall = false;while(ballNum--) { let ball = new Ball(10, parseColor(Math.random() * 0xffffff)) ball. x = Math.random() * width; ball.y = Math.random() * heightBalls.push(ball)}// Lassen Sie die Punkte in aufsteigender Reihenfolge nach tempBalls.length -1] sortieren;let smallXBalls = tempBalls.filter(ball => ball.x === firstBall.x), bigXBalls = tempBalls.filter(ball => ball.x === lastBall.x)// Behandeln Sie die Situation, in der es mehrere linke und rechte Pole gibt, wenn (smallXBalls.length > 1) { smallXBalls.sort((ballA, ballB) => { return ballB.y - ballA.y })}if (bigXBalls.length > 1) { bigXBalls.sort((ballA, ballB) => { return ballB.y - ballA.y })}firstBall = smallXBalls[0]lastBall = bigXBalls[0]//Erhalte den Winkel der Polverbindung let splitLineAngle = Math.atan2(lastBall.y - firstBall.y, lastBall.x - firstBall.x);let UpperBalls = [], LowerBalls = [];//Alle anderen Punkte berechnen Winkel mit firstBall// Alles, was größer als „splitLineAngle“ ist, befindet sich in der unteren Kette // Andere befinden sich in der oberen Kette tempBalls.forEach(ball => { if (ball === firstBall || ball === lastBall) { return false } let angle = Math.atan2(ball.y - firstBall.y, ball.x - firstBall.x); if (angle > splitLineAngle) { LowerBalls.push(ball) } else { UpperBalls.push(ball) }})// Behandeln Sie die Sortierung derselben Situation auf der ballA.x - ballB.x } return ballB.y - ballA.y})upperBalls = UpperBalls.sort((ballA, ballB) => { if (ballA.x !== ballB.x) { return ballB.x - ballA.x } return ballB.y - ballB.x})// Alle Punkte gegen den Uhrzeigersinn verbindenballs = [firstBall].concat(lowerBalls, [lastBall], UpperBalls)balls = Bälle. map((ball, i) => { ball.text = i + 1; return ball})
Die schließlich zurückgegebenen Kugeln sind die gegen den Uhrzeigersinn sortierten Polygonpunkte.
Der Effekt ist wie folgt:
Der innere Zustand jeder Kugel ist wie folgt:
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er für das Studium aller hilfreich ist. Ich hoffe auch, dass jeder das VeVb Wulin Network unterstützt.