Hari ini ketika saya mempelajari buku "Dasar-Dasar Animasi HTML5+Javascript", di bagian ketiga Bab 8, saya berbicara tentang cara menggunakan tiga pegas untuk menghubungkan tiga titik untuk melakukan gerakan peregangan.
Setelah menyelesaikan contoh, saya memikirkan bagaimana jika itu empat poin atau lima poin.
Saya menulis ulang kode dan membuat jumlah poin menjadi variabel. Efek akhirnya adalah mencapai keseimbangan gerakan peregangan akhir setiap titik, tetapi hubungan antar titik tidak terlalu bagus, dan ada pula yang bersilangan.
Jadi saya memikirkan apakah area ini bisa dioptimalkan.
Putar garisnyaTitik-titik pada contoh sebelumnya semuanya berada pada posisi acak, sehingga koneksinya tidak dapat dikontrol. Jadi saya ingin memulainya dulu.
Pertama, gunakan titik tertentu sebagai titik acuan untuk mendapatkan sudut titik lain relatif terhadap titik tersebut.
Kemudian hubungkan titik-titik tersebut sesuai sudut dari kecil ke besar, sehingga diperoleh poligon normal.
Perkiraan kode implementasinya adalah sebagai berikut:
biarkan bola = [];biarkan ballNum = 6;biarkan firstBall = null;sementara(ballNum--) { biarkan bola = Bola baru(20, parseColor(Math.random() * 0xffffff)) ball.x = Math.random( ) * lebar; bola.y = Matematika.acak() * tinggi; bola.push(bola) if (!firstBall) { firstBall = bola ball.angle = 0 } else { const dx = ball.x - firstBall.x, dy = ball.y - firstBall.y; ball.angle = Math.atan2(dy, dx); = bola .sort((bolaA, bolaB) => { kembalikan bolaA.sudut - bolaB.sudut})
Dengan cara ini, ketika sambungan akhirnya dibuat, sudut dapat ditarik dari kecil ke besar dengan melintasi larik.
Efeknya adalah sebagai berikut:
Hal ini dapat sangat mengurangi jumlah garis yang bersilangan, namun tetap tidak dapat sepenuhnya dihindari.
Selanjutnya saya ingin mencoba mengoptimalkan solusi ini. Misalnya menggunakan Math.abs untuk mengoreksi sudut, atau mencari titik dengan sudut terkecil untuk menghubungkan setiap titik. Namun hasilnya kurang bagus, persilangan garis tidak bisa dihindari.
Putar berdasarkan titik pusatKemudian muncul ide lain. Jika titik pusat poligon dapat ditentukan, maka sudut semua titik terhadap titik pusat dapat dihitung secara terpisah, dan titik-titik tersebut dapat dihubungkan searah jarum jam atau berlawanan arah jarum jam.
Namun setelah lama mencari di Internet, semua algoritma titik memerlukan serangkaian titik yang disusun searah jarum jam tertentu.
Tapi kalau saya punya titik-titik ini, saya sudah bisa menggambar poligonnya. Harus menyerah
Segmentasi dua kutub sumbu XDalam keputusasaan, saya harus mencari di Google, dan kemudian saya menemukan jawaban yang bagus di Zhihu: Bagaimana cara menghubungkan sekelompok titik tak beraturan pada bidang menjadi poligon sederhana?
Untuk deskripsi algoritma spesifiknya, lihat saja jawabannya dan saya tidak akan menjelaskan secara detail.
Namun saat menghubungkan rantai atas dan rantai bawah, Anda hanya perlu memastikan bahwa rantai atas terhubung dalam urutan menurun pada sumbu X dan rantai bawah terhubung dalam urutan menaik pada sumbu X (digambar berlawanan arah jarum jam) . Sedangkan untuk titik-titik yang sumbu Xnya sama, tidak menjadi soal apakah sumbu Y lebih besar atau lebih kecil.
Ketika diimplementasikan, ini diterapkan secara ketat sesuai dengan algoritma dalam jawabannya.
Saat menilai apakah suatu titik termasuk dalam rantai atas atau rantai bawah, ide awalnya adalah menentukan persamaan fungsi garis lurus berdasarkan dua titik, dan kemudian memperkenalkan koordinat titik-titik tersebut untuk perhitungan. Namun belakangan saya terpikir bahwa semua titik menggunakan kutub paling kiri untuk menghitung sudut miring, lalu membaginya menurut besar sudutnya, agar lebih mudah dipahami secara visual.
Perkiraan kodenya adalah sebagai berikut:
biarkan bola = [];biarkan tempBalls = [];biarkan ballNum = 6;biarkan isDragingBall = false;sementara(ballNum--) { biarkan bola = Bola baru(10, parseColor(Math.random() * 0xffffff)) bola. x = Matematika.acak() * lebar; bola.y = Matematika.acak() * tinggi; tempBalls.push(bola)}// Biarkan poin diurutkan dalam urutan menaik pada tempBalls.length -1];let smallXBalls = tempBalls.filter(ball => ball.x === firstBall.x), bigXBalls = tempBalls.filter(ball => ball.x === lastBall.x)// Menangani situasi di mana terdapat beberapa kutub kiri dan kanan if (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]//Dapatkan sudut sambungan tiang let splitLineAngle = Math.atan2(lastBall.y - firstBall.y, lastBall.x - firstBall.x);biarkan upperBalls = [], lowerBalls = [];//Semua titik lainnya menghitung sudut dengan firstBall// Apa pun yang lebih besar dari splitLineAngle adalah rantai bawah // Lainnya adalah rantai atas tempBalls.forEach(ball => { if (ball === firstBall || ball === lastBall) { return false } let angle = Math.atan2(ball.y - firstBall.y, ball.x - firstBall.x); if (sudut > splitLineAngle) { lowerBalls.push(bola) } else { upperBalls.push(ball) }})// Menangani pengurutan situasi yang sama pada sumbu X lowerBalls = lowerBalls.sort((ballA, ballB) => { if (ballA.x !== ballB.x) { return ballA.x - ballB.x } kembalikan ballB.y - ballA.y})upperBalls = upperBalls.sort((ballA, ballB) => { if (ballA.x !== ballB.x) { return ballB.x - ballA.x } return ballB.y - ballB.x})// Hubungkan semua titik berlawanan arah jarum jam bola = [firstBall].concat(lowerBalls, [lastBall], upperBalls)balls = bola. map((bola, i) => { bola.teks = i + 1; mengembalikan bola})
Bola yang akhirnya dikembalikan adalah titik poligon yang diurutkan berlawanan arah jarum jam.
Efeknya adalah sebagai berikut:
Keadaan internal masing-masing bola adalah sebagai berikut:
Di atas adalah keseluruhan isi artikel ini, saya harap dapat bermanfaat untuk pembelajaran semua orang. Saya juga berharap semua orang mendukung VeVb Wulin Network.