VorwortDie Erzeugung glatter Kurven ist eine sehr praktische Technologie Oft müssen wir einige Polylinien zeichnen und sie dann vom Computer reibungslos verbinden lassen. Schauen wir uns zunächst den endgültigen Effekt an (die rote Linie ist die gerade Linie, die wir eingegeben haben, und die blaue Linie ist die Kurve nach der Anpassung). Der Anfang und das Ende können speziell bearbeitet werden, damit das Diagramm besser aussieht:) Die Idee ist, die Bezier-Kurve zur Anpassung zu verwenden Einführung in BézierkurvenDie Bézierkurve ist eine sehr wichtige parametrische Kurve in der Computergrafik. Quadratische Bézier-KurveDer Verlauf einer quadratischen Bézierkurve wird durch die Funktion B(t) bei gegebenen Punkten P0, P1 und P2 beschrieben: Kubische BézierkurveBei einer kubischen Kurve kann sie durch die Zwischenpunkte Q0, Q1, Q2, die durch die lineare Bézierkurve beschrieben werden, und die Punkte R0 und R1, die durch die quadratische Kurve beschrieben werden, konstruiert werden. Bézierkurven-BerechnungsfunktionNach der obigen Formel erhalten wir die Berechnungsfunktion Zweite Ordnung /** * * * @param {Zahl} p0 * @param {Zahl} p1 * @param {Zahl} p2 * @param {Zahl} t * @zurückkehren {*} * @memberof Pfad */ bezier2P(p0: Zahl, p1: Zahl, p2: Zahl, t: Zahl) { const P0 = p0 * Math.pow(1 - t, 2); Konstante P1 = p1 * 2 * t * (1 - t); Konstante P2 = p2 * t * t; gib P0 + P1 + P2 zurück; } /** * * * @param {Punkt} p0 * @param {Punkt} p1 * @param {Punkt} p2 * @param {number} Zahl * @param {Zahl} Häkchen * @return {*} {Punkt} * @memberof Pfad */ getBezierNowPoint2P( p0: Punkt, p1: Punkt, p2: Punkt, num: Zahl, Häkchen: Zahl, ): Punkt { zurückkehren { x: this.bezier2P(p0.x, p1.x, p2.x, num * tick), y: this.bezier2P(p0.y, p1.y, p2.y, Num * Tick), }; } /** * Generieren Sie quadratische Bézierkurven-Scheitelpunktdaten* * @param {Punkt} p0 * @param {Punkt} p1 * @param {Punkt} p2 * @param {Zahl} [Zahl=100] * @param {Zahl} [Häkchen=1] * @zurückkehren {*} * @memberof Pfad */ erstelle2PBezier( p0: Punkt, p1: Punkt, p2: Punkt, num: Zahl = 100, Häkchen: Zahl = 1, ) { const t = Tick / (Zahl - 1); const Punkte = []; für (sei i = 0; i < num; i++) { const Punkt = this.getBezierNowPoint2P(p0, p1, p2, i, t); Punkte.push({x: Punkt.x, y: Punkt.y}); } Rückgabepunkte; } Dritte Ebene /** * Formel für die kubische Searl-Kurve* * @param {Zahl} p0 * @param {Zahl} p1 * @param {Zahl} p2 * @param {Zahl} p3 * @param {Zahl} t * @zurückkehren {*} * @memberof Pfad */ bezier3P(p0: Zahl, p1: Zahl, p2: Zahl, p3: Zahl, t: Zahl) { const P0 = p0 * Math.pow(1 - t, 3); const P1 = 3 * p1 * t * Math.pow(1 - t, 2); const P2 = 3 * p2 * Math.pow(t, 2) * (1 - t); const P3 = p3 * Math.pow(t, 3); gebe P0 + P1 + P2 + P3 zurück; } /** * Koordinaten abrufen * * @param {Punkt} p0 * @param {Punkt} p1 * @param {Punkt} p2 * @param {Punkt} p3 * @param {number} Zahl * @param {Zahl} Häkchen * @zurückkehren {*} * @memberof Pfad */ getBezierNowPoint3P( p0: Punkt, p1: Punkt, p2: Punkt, p3: Punkt, num: Zahl, Häkchen: Zahl, ) { zurückkehren { x: this.bezier3P(p0.x, p1.x, p2.x, p3.x, num * tick), y: this.bezier3P(p0.y, p1.y, p2.y, p3.y, Num * Tick), }; } /** * Kubische Bézierkurven-Scheitelpunktdaten generieren* * @param {Point} p0 Startpunkt {x: Zahl, y: Zahl} * @param {Punkt} p1 Kontrollpunkt 1 { x : Zahl, y : Zahl} * @param {Punkt} p2 Kontrollpunkt 2 { x : Zahl, y : Zahl} * @param {Punkt} p3 Endpunkt {x: Zahl, y: Zahl} * @param {Zahl} [Zahl=100] * @param {Zahl} [Häkchen=1] * @return {Punkt[]} * @memberof Pfad */ erstelle3PBezier( p0: Punkt, p1: Punkt, p2: Punkt, p3: Punkt, num: Zahl = 100, Häkchen: Zahl = 1, ) { const PunktMum = Num; const _tick = ticken; const t = _tick / (pointMum - 1); const Punkte = []; für (sei i = 0; i < pointMum; i++) { const Punkt = this.getBezierNowPoint3P(p0, p1, p2, p3, i, t); Punkte.push({x: Punkt.x, y: Punkt.y}); } Rückgabepunkte; } AnpassungsalgorithmusDas Problem ist, wie man die Kontrollpunkte erhält. Wir verwenden eine relativ einfache Methode Nehmen Sie die Winkelhalbierende c1c2 von p1-pt-p2, die senkrecht zur Winkelhalbierenden c2 steht. Nehmen Sie die kurze Seite als Länge von c1-pt c2-pt. Skalieren Sie die Länge. Diese Länge kann grob als Krümmung der Kurve verstanden werden. Das ab-Liniensegment wird hier einfach verarbeitet und verwendet nur die Kurvengenerierung zweiter Ordnung -> 🌈 Sie können es nach Ihren persönlichen Vorstellungen verarbeiten Das bc-Liniensegment verwendet den von abc berechneten Kontrollpunkt c2 und den von bcd berechneten Kontrollpunkt c3 und so weiter. /** * Kontrollpunkte, die zur Erzeugung einer glatten Kurve erforderlich sind * * @param {Vector2D} p1 * @param {Vector2D} pt * @param {Vector2D} p2 * @param {Zahl} [Verhältnis=0,3] * @zurückkehren {*} * @memberof Pfad */ erstelleSmoothLineControlPoint( p1: Vektor2D, pt: Vektor2D, p2: Vektor2D, Verhältnis: Zahl = 0,3, ) { const vec1T: Vektor2D = Vektor2dMinus(p1, pt); const vecT2: Vektor2D = Vektor2dMinus(p1, pt); const len1: Zahl = vec1T.Länge; const len2: Zahl = vecT2.Länge; const v: Zahl = Länge1 / Länge2; sei Delta; wenn (v > 1) { delta = Vektor2dMinus( Seite 1, Vektor2dPlus(pt, Vektor2dMinus(p2, pt).Skala(1 / v)), ); } anders { delta = Vektor2dMinus( Vektor2dPlus(pt, Vektor2dMinus(p1, pt).Skala(v)), Seite 2, ); } delta = delta.scale(Verhältnis); const control1: Punkt = { x: Vektor2dPlus(pt, delta).x, y: Vektor2dPlus(pt, delta).y, }; const control2: Punkt = { x: Vektor2dMinus(pt, delta).x, y: Vektor2dMinus(pt, delta).y, }; gebe {Steuerung1, Steuerung2} zurück; } /** * Sanfte Kurvengenerierung * * @param {Point[]} Punkte * @param {number} Verhältnis * @zurückkehren {*} * @memberof Pfad */ createSmoothLine(Punkte: Punkt[], Verhältnis: Zahl = 0,3) { const len = Punkte.Länge; let resultPoints = []; const Kontrollpunkte = []; wenn (Länge < 3) return; für (sei i = 0; i < len - 2; i++) { const {Kontrolle1, Kontrolle2} = this.createSmoothLineControlPoint( neuer Vector2D(Punkte[i].x, Punkte[i].y), neuer Vector2D(Punkte[i + 1].x, Punkte[i + 1].y), neuer Vektor2D(Punkte[i + 2].x, Punkte[i + 2].y), Verhältnis, ); Kontrollpunkte.push(Kontrolle1); Kontrollpunkte.push(Kontrolle2); lass Punkte1; lass Punkte2; // Der erste Kontrollpunkt verwendet nur einen if (i === 0) { Punkte1 = this.create2PBezier(Punkte[i], Kontrolle1, Punkte[i + 1], 50); } anders { console.log(Kontrollpunkte); Punkte1 = this.create3PBezier( Punkte[i], Kontrollpunkte[2 * i - 1], Steuerung1, Punkte[i + 1], 50, ); } // Endteil if (i + 2 === len - 1) { Punkte2 = this.create2PBezier( Punkte[i + 1], Steuerung2, Punkte[i + 2], 50, ); } wenn (i + 2 === Länge - 1) { ErgebnisPunkte = [...ErgebnisPunkte, ...Punkte1, ...Punkte2]; } anders { ErgebnisPunkte = [...ErgebnisPunkte, ...Punkte1]; } } gib Ergebnispunkte zurück; } Beispielcode const Eingabe = [ { x: 0, y: 0 }, { x: 150, y: 150 }, { x: 300, y: 0 }, { x: 400, y: 150 }, { x: 500, y: 0 }, { x: 650, y: 150 }, ] const s = Pfad.createSmoothLine(Eingabe); Lassen Sie ctx = document.getElementById('cv').getContext('2d'); ctx.strokeStyle = "blau"; ctx.beginPath(); ctx.moveTo(0, 0); für (sei i = 0; i < s.Länge; i++) { ctx.lineTo(s[i].x, s[i].y); } ctx.stroke(); ctx.beginPath(); ctx.moveTo(0, 0); für (lass i = 0; i < Eingabelänge; i++) { ctx.lineTo(Eingabe[i].x, Eingabe[i].y); } ctx.strokeStyle = "rot"; ctx.stroke(); document.getElementById('btn').addEventListener('klicken', () => { let app = document.getElementById('app'); lass Index = 0; lass bewegen = () => { wenn (Index < s.Länge) { app.style.left = s[index].x - 10 + 'px'; app.style.top = s[index].y - 10 + 'px'; Index++; requestAnimationFrame(verschieben) } } bewegen() }) Anhang: Vector2D-bezogener Code/** * * * @Klasse Vector2D * @extends {Array} */ Klasse Vector2D erweitert Array { /** * Erstellt eine Instanz von Vector2D. * @param {Zahl} [x=1] * @param {Zahl} [y=0] * @Mitglied von Vector2D * */ Konstruktor(x: Zahl = 1, y: Zahl = 0) { super(); dies.x = x; dies.y = y; } /** * * @param {Zahl} v * @Mitglied von Vector2D */ Menge x(v) { dies[0] = v; } /** * * @param {Zahl} v * @Mitglied von Vector2D */ setze y(v) { dies[1] = v; } /** * * * @readonly * @Mitglied von Vector2D */ erhalte x() { gib dies zurück[0]; } /** * * * @readonly * @Mitglied von Vector2D */ bekomme y() { gib dies zurück[1]; } /** * * * @readonly * @Mitglied von Vector2D */ Länge abrufen() { gibt Math.hypot(dieses.x, dies.y) zurück; } /** * * * @readonly * @Mitglied von Vector2D */ hol dir() { gibt Math.atan2(dieses.y, dieses.x) zurück; } /** * * * @zurückkehren {*} * @Mitglied von Vector2D */ kopieren() { gib einen neuen Vector2D (dieses.x, dieses.y) zurück; } /** * * * @param {*} v * @zurückkehren {*} * @Mitglied von Vector2D */ hinzufügen(v) { dies.x += vx; dies.y += vy; gib dies zurück; } /** * * * @param {*} v * @zurückkehren {*} * @Mitglied von Vector2D */ unter(v) { dies.x -= vx; dies.y -= vy; gib dies zurück; } /** * * * @param {*} ein * @return {Vector2D} * @Mitglied von Vector2D */ Skala(a) { dies.x *= a; dies.y *= a; gib dies zurück; } /** * * * @param {*} rad * @zurückkehren {*} * @Mitglied von Vector2D */ drehen(rad) { const c = Math.cos(rad); const s = Math.sin(rad); const [x, y] = dies; dies.x = x * c + y * -s; dies.y = x * s + y * c; gib dies zurück; } /** * * * @param {*} v * @zurückkehren {*} * @Mitglied von Vector2D */ Kreuz(v) { gib dies.x * vy - vx * dies.y zurück; } /** * * * @param {*} v * @zurückkehren {*} * @Mitglied von Vector2D */ Punkt(v) { gib dies.x * vx + vy * dies.y zurück; } /** * Normalisierung* * @zurückkehren {*} * @Mitglied von Vector2D */ normalisieren() { gib diesen Maßstab zurück (1 / diese Länge); } } /** * Vektoraddition * * @param {*} vec1 * @param {*} vec2 * @return {Vector2D} */ Funktion Vektor2dPlus(vec1, vec2) { gibt einen neuen Vector2D zurück (vec1.x + vec2.x, vec1.y + vec2.y); } /** * Vektorsubtraktion * * @param {*} vec1 * @param {*} vec2 * @return {Vector2D} */ Funktion Vektor2dMinus(vec1, vec2) { gibt einen neuen Vector2D zurück (vec1.x – vec2.x, vec1.y – vec2.y); } exportiere {Vector2D, vector2dPlus, vector2dMinus}; ZusammenfassenDies ist das Ende dieses Artikels zur Verwendung von Javascript zum Generieren glatter Kurven. Weitere Informationen zum Generieren glatter Kurven mit Javascript finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen! |
<<: Leitfaden zur effizienten Nutzung von MySQL-Indizes
>>: Implementierungscode für die Dateimontage von DockerToolBox
Hier konzentrieren wir uns nur auf die Installati...
Frage Beim Schreiben von Datenbank-SQL ist mir ge...
1: Verstehen Sie die Bedeutung von Adressumschrei...
In diesem Artikelbeispiel wird der spezifische Co...
Dieser Artikel veranschaulicht anhand von Beispie...
Im vorherigen Artikel „Änderungen der MySQL-Tabel...
In diesem Artikel werden MySQL-Funktionen zum Abf...
Finden Sie das Problem Als ich mich kürzlich über...
Routenplanung vue-router4 behält den Großteil der...
<br />Ursprünglicher Link: http://www.dudo.o...
Vorwort Tipp: Hier können Sie den ungefähren Inha...
Warum optimieren: Beim Start des eigentlichen Pro...
Vorwort Dieser Artikel stellt hauptsächlich den r...
Einführung in das Schlüsselwort void Zunächst ein...
Ich habe eine Weile nicht mit Servern gearbeitet....