Indikator cakrawala buatan pada kanvas HTML5

Di bawah ini kami akan menyajikan implementasi melalui HTML5 dari salah satu ide yang tidak biasa untuk memvisualisasikan posisi spasial dari objek yang dikendalikan. Kode tersebut dapat digunakan dalam game browser yang mensimulasikan mengemudi dalam ruang tiga dimensi. Cara penyajian informasi difokuskan pada simulator subterin atau mesin fantastis lainnya.







Tujuan dan ruang lingkup cakrawala buatan



Horizon buatan dalam arti sempit yang dipertimbangkan di sini adalah visualisasi kemiringan suatu objek relatif terhadap vertikal lokal, yang digunakan untuk mengontrol pergerakannya. Kemiringan ditentukan oleh nilai dari dua sudut Euler, roll dan pitch . Pelaut lebih suka sinonim "trim" untuk istilah penerbangan "pitch".



Terkait dengan cakrawala buatan (tapi tidak sepenuhnya sama) istilah bahasa Rusia: "cakrawala buatan", "perangkat perintah penerbangan". Dalam bahasa Inggris, ungkapan "indikator sikap" , "cakrawala buatan" atau "cakrawala gyro" digunakan .



Teknik visualisasi yang dikenal



Sebagian besar pekerjaan untuk menemukan solusi yang berhasil di bidang indikasi pitch and roll telah dilakukan untuk kepentingan penerbangan. Ada penjelasan sederhana untuk ini: pilot harus membaca informasi dengan cepat, dan setiap kesalahan dalam persepsinya tentang ruang angkasa bisa berakibat fatal.



Sebagian besar solusi yang diketahui di bidang indikasi roll dan pitch didasarkan pada penggunaan siluet pesawat dan latar belakang khusus. Fitur umum:



  • latar belakang dibagi menjadi dua bagian, melambangkan langit dan bumi, dengan garis yang melambangkan cakrawala;
  • siluet pesawat adalah tampilan belakang yang disederhanakan, kontras warnanya dengan latar belakang;
  • sudut putar ditentukan oleh indikator sebagai sudut antara garis horizon simbolis dan garis yang menghubungkan ujung sayap siluet (biasanya skala referensi tersedia untuk pembacaan yang akurat);
  • Sudut nada diukur sepanjang skala tegak lurus dengan cakrawala bersyarat menurut posisi titik kontrol di tengah siluet.






Sistem yang diterapkan dalam produksi massal memiliki sejumlah solusi umum:



  • informasi diberikan oleh posisi relatif siluet dan latar belakang;
  • perubahan sudut putar dikaitkan dengan gerakan sudut siluet relatif terhadap latar belakang;
  • perubahan sudut pitch dikaitkan dengan perpindahan linier dari siluet relatif terhadap latar belakang.


Tetapi tidak sulit untuk menebak bahwa gerakan relatif yang diinginkan dapat diwujudkan dalam beberapa cara berbeda. Setelah banyak trial and error di abad terakhir, evolusi penerbangan telah meninggalkan dua kombinasi yang layak:



1. Siluet tetap, bergerak di latar belakang roll dan pitch. Nama yang digunakan: "indikasi langsung", "pemandangan dari pesawat ke darat", lebih jarang "indikasi egosentris".







2. Siluet hanya bergerak di sepanjang gulungan, latar belakang hanya bergerak di sepanjang lemparan. Nama yang digunakan: "indikasi terbalik" dan "pemandangan dari tanah ke pesawat", lebih jarang "indikasi geosentris".







Perhatikan bahwa nama klausul 2 berlaku untuk sistem secara keseluruhan, tetapi hanya mencerminkan prinsip indikasi sudut gulungan yang diterapkan di dalamnya. Indikasi sudut nada pada kedua sistem yang digunakan adalah "lurus" dan "egosentris".



Dalam simulator penerbangan yang ada, seperti Microsoft Flight Simulator dan Digital Combat Simulator , kedua jenis tampilan tersebut dapat dilihat beraksi.



Perlu dicatat bahwa tidak semua solusi yang diketahui cocok dengan pola di atas. Untuk contoh melampaui kerangka kerja yang ditentukan, mari kita pertimbangkan dua paten untuk penemuan: RU 2561311 dan RU 2331848.



Paten pertama dikhususkan untuk "Horizon buatan dengan indikator pitch dan roll berjarak tinggi", penulisnya: V. I. Putintsev dan N. A. Lituev. Diagram di bawah diambil dari paten.







Jika perlu, Anda dapat menemukan decoding sebutan dan deskripsi karya dalam teks sumber aslinya... Secara keseluruhan, konsep penemuan ini cukup sederhana: gagasan tentang "pemandangan dari tanah ke pesawat terbang" diwujudkan baik dalam bentuk roll dan pitch ("geosentrisme lengkap"), tetapi indikasi tersebut dibagi menjadi dua komponen independen.



Penemuan kedua memiliki nama yang lebih kompleks: "Perangkat perintah penerbangan untuk indikasi logis dari posisi dan kendali pesawat di luar angkasa." Penulis paten: A.P. Plentsov dan N.A. Zakonova Gagasan tentang indikasi pitch and roll agak tidak biasa di sini.







Penjelasan tentang penunjukan sirkuit, deskripsi perangkat, perbandingan dengan analog dan sirkuit tambahan dengan sedikit perbedaan dalam desain diberikan dalam paten .



Satu kesamaan dengan penemuan sebelumnya adalah konsep geosentrisme untuk kedua saluran. Pada saat yang sama, horizon buatan hanya memiliki satu "simbol pesawat", seperti pada model yang ada, tetapi ini bukan lagi siluet, tetapi model tiga dimensi - "model volumetrik". Jika gerakan menggulung ternyata serupa dengan yang diterapkan pada indikasi "mundur", maka melempar dan menyelam pada perangkat ini terlihat asli.







Ada sejumlah faktor yang menahan inovasi dalam desain sistem tampilan dunia nyata. Misalnya, salah satu alasan yang masuk akal untuk konservatisme adalah keinginan untuk menjaga kelangsungan keterampilan yang diperoleh operator, termasuk keterampilan memahami informasi. Permainan komputer dapat menghasilkan lebih banyak kreativitas, oleh karena itu, tanpa mempelajari analisis komparatif solusi, kami akan mengambil dasar penemuan yang terlihat paling efektif.



Persyaratan solusi



Sebelum mulai menulis kode, mari tentukan tugasnya:



1. Perlu menulis fungsi drawAttitude () yang menggambar indikator horizon buatan menggunakan kanvas berdasarkan penemuan A.P. Plentsov dan N.A. Zakonova



2. Fungsi tersebut mengambil konteks kanvas , koordinat bagian tengah indikator, nilai sudut roll dan pitch dalam derajat, jari-jari permukaan indikator.



3. Nilai sudut pitch dibatasi pada interval dari minus 30 hingga plus 30 derajat.



4. Nilai sudut putar dibatasi pada interval dari minus 45 hingga plus 45 derajat.



5. Jika nilai argumen melebihi yang ditentukan dalam p. Batas 3 dan 4 indikator menunjukkan nilai terdekat yang diizinkan.



Pembuatan fungsi



Kode fungsi mencakup bagian-bagian berikut:



1. Memeriksa nilai yang dimasukkan untuk melebihi batas.



2. Mengubah sudut menjadi radian.



3. Menskalakan ukuran karakteristik "tata letak" dan font dengan nilai radius indikator.



4. Menggambar komponen:

a) Badan indikator.

b) Tata Letak.

c) Timbangan pitch and roll.



Fungsi di bawah ini ditulis dalam urutan ini, dan bagian-bagiannya dipisahkan oleh komentar.



Kode lengkap
index.html:



<!DOCTYPE html>
<html>

<head>
  <title>Attitude</title>
  <script src="js/attitude.js"></script>
</head>

<body>
  <canvas id="drawingCanvas" width="640" height="480"></canvas>
</body>

</html>


attitude.js:



window.onload = function () {

    let canvas = document.getElementById("drawingCanvas");
    let context = canvas.getContext("2d");
    
    let run = function () {
        drawAttitude(context, 320, 240, 30 * Math.sin(performance.now() / 2000), 45 * Math.sin(performance.now() / 5000), 200);
    }

    let interval = setInterval(run, 1000 / 60);
};


drawAttitude = function (ctx, centreX, centreY, pitch, roll, radius = 100) {
    //   :
    if (pitch > 30) pitch = 30;
    if (pitch < -30) pitch = -30;

    if (roll > 45) roll = 45;
    if (roll < -45) roll = -45;
    //  :
    roll *= Math.PI / 180;
    pitch *= Math.PI / 180;
    // ""  :
    let vehicleSize = radius * 0.8;
    ctx.font = Math.round(radius / 8) + "px Arial";
    //    :
    ctx.lineWidth = 2;
    ctx.strokeStyle = "Black";
    // :
    ctx.beginPath();
    ctx.arc(centreX, centreY, radius, 0, Math.PI, false);
    ctx.fillStyle = "Maroon";
    ctx.stroke();
    ctx.fill();
    // :
    ctx.beginPath();
    ctx.arc(centreX, centreY, radius, 0, Math.PI, true);
    ctx.fillStyle = "SkyBlue";
    ctx.stroke();
    ctx.fill();
    //"":
    ctx.beginPath();
    //:
    let topSideIsVisible = (pitch >= 0);
    ctx.strokeStyle = topSideIsVisible ? "Orange" : "Brown";
    ctx.fillStyle = topSideIsVisible ? "Yellow" : "Red";
    ctx.lineWidth = 3;
    //
    //  4 ,       ,
    //  :
    ctx.moveTo(centreX, centreY - Math.sin(pitch) * vehicleSize / 2);
    ctx.lineTo(centreX + vehicleSize * Math.cos(roll), centreY + vehicleSize * Math.sin(roll) * Math.cos(pitch));
    ctx.lineTo(centreX, centreY - 2 * Math.sin(pitch) * vehicleSize);
    ctx.lineTo(centreX - vehicleSize * Math.cos(roll), centreY - vehicleSize * Math.sin(roll) * Math.cos(pitch));
    ctx.lineTo(centreX, centreY - Math.sin(pitch) * vehicleSize / 2);
    ctx.stroke();
    ctx.fill();
    // :
    // :
    ctx.beginPath();
    ctx.strokeStyle = "Black";
    ctx.fillStyle = "Black";
    ctx.lineWidth = 1;
    //:
    ctx.fillText(30, centreX - radius * 0.28, centreY - vehicleSize + radius / 20);
    ctx.fillText(20, centreX - radius * 0.28, centreY - vehicleSize * 0.684 + radius / 20);
    ctx.fillText(10, centreX - radius * 0.28, centreY - vehicleSize * 0.348 + radius / 20);
    // - :
    ctx.moveTo(centreX - radius / 10, centreY - vehicleSize);
    ctx.lineTo(centreX + radius / 10, centreY - vehicleSize);
    ctx.stroke();

    ctx.moveTo(centreX - radius / 10, centreY - vehicleSize * 0.684);
    ctx.lineTo(centreX + radius / 10, centreY - vehicleSize * 0.684);
    ctx.stroke();

    ctx.moveTo(centreX - radius / 10, centreY - vehicleSize * 0.348);
    ctx.lineTo(centreX + radius / 10, centreY - vehicleSize * 0.348);
    ctx.stroke();
    // :
    ctx.beginPath();
    ctx.strokeStyle = "White";
    ctx.fillStyle = "White";
    //:
    ctx.fillText(30, centreX - radius * 0.28, centreY + vehicleSize + radius / 20);
    ctx.fillText(20, centreX - radius * 0.28, centreY + vehicleSize * 0.684 + radius / 20);
    ctx.fillText(10, centreX - radius * 0.28, centreY + vehicleSize * 0.348 + radius / 20);
    // - :
    ctx.moveTo(centreX - radius / 10, centreY + vehicleSize);
    ctx.lineTo(centreX + radius / 10, centreY + vehicleSize);
    ctx.stroke();

    ctx.moveTo(centreX - radius / 10, centreY + vehicleSize * 0.684);
    ctx.lineTo(centreX + radius / 10, centreY + vehicleSize * 0.684);
    ctx.stroke();

    ctx.moveTo(centreX - radius / 10, centreY + vehicleSize * 0.348);
    ctx.lineTo(centreX + radius / 10, centreY + vehicleSize * 0.348);
    ctx.stroke();

    // :
    ctx.lineWidth = 2;

    //+-15 :
    ctx.fillText(15, centreX + radius * 0.6, centreY + radius * 0.22);
    ctx.moveTo(centreX + 0.966 * 0.8 * radius, centreY + 0.259 * 0.8 * radius);
    ctx.lineTo(centreX + 0.966 * 0.95 * radius, centreY + 0.259 * 0.95 * radius);

    ctx.fillText(15, centreX - radius * 0.75, centreY + radius * 0.22);
    ctx.moveTo(centreX - 0.966 * 0.8 * radius, centreY + 0.259 * 0.8 * radius);
    ctx.lineTo(centreX - 0.966 * 0.95 * radius, centreY + 0.259 * 0.95 * radius);

    //+-30 :
    ctx.moveTo(centreX + 0.866 * 0.8 * radius, centreY + 0.5 * 0.8 * radius);
    ctx.lineTo(centreX + 0.866 * 0.95 * radius, centreY + 0.5 * 0.95 * radius);

    ctx.moveTo(centreX - 0.866 * 0.8 * radius, centreY + 0.5 * 0.8 * radius);
    ctx.lineTo(centreX - 0.866 * 0.95 * radius, centreY + 0.5 * 0.95 * radius);

    //+-45 :
    ctx.moveTo(centreX + 0.707 * 0.8 * radius, centreY + 0.707 * 0.8 * radius);
    ctx.lineTo(centreX + 0.707 * 0.95 * radius, centreY + 0.707 * 0.95 * radius);

    ctx.moveTo(centreX - 0.707 * 0.8 * radius, centreY + 0.707 * 0.8 * radius);
    ctx.lineTo(centreX - 0.707 * 0.95 * radius, centreY + 0.707 * 0.95 * radius);

    ctx.stroke();
}






Yang paling sulit dipahami adalah kode untuk menggambar "layout". Mari kita pertimbangkan lebih detail. Sebagai tata letak, diputuskan untuk menggunakan sosok simetris datar berbentuk panah.







Permukaan atas dan bawah tata letak berbeda satu sama lain dalam garis besar dan warna isian. Memilih skema warna saat ini adalah bagian pertama dari kode.

Berikutnya adalah konstruksi kontur gambar.



Tugas yang paling sulit adalah menentukan koordinat proyeksi simpul gambar pada bidang YOZ . Inilah yang diselesaikan oleh ekspresi dengan fungsi trigonometri. Simpul dalam kode tersebut dilintasi sesuai urutan penomorannya pada gambar.



Bagian terbesar dari kode dikhususkan untuk skala dan tanda tangan. Tanda skala memiliki banyak perbedaan: atas dan bawah, kiri dan kanan, dengan dan tanpa label. Jumlah baris yang mengesankan adalah karena penulisan kode "individu" untuk setiap elemen.



Fungsi trigonometri dari sudut yang sesuai digunakan untuk menerapkan tanda gulung. Karena nilai sudut masing-masing label diketahui sebelumnya, nilai sinus dan cosinus yang sudah jadi ditulis dalam kode.



Lebih baik mengevaluasi penampilan indikator dalam dinamika. Kami menunjukkan dengan bantuan fungsi baru osilasi pitch and roll. Untuk variasi posisi maksimum, mari kita buat amplitudo osilasi sesuai dengan batas indikator, dan periode - berbeda dan sederhana satu sama lain.







Kesimpulan



Tegasnya, kode di atas untuk visualisasi roll dan pitch harus disebut indikasi "berdasarkan" penemuan A. P. Plentsov dan N. A. Zakonova. Beberapa penyimpangan dari skema asli dilakukan untuk menyederhanakan tugas, yang lain untuk meningkatkan implementasi.



Indikator yang disajikan jauh dari ideal dari segi desain. Batasan yang diterima dari nilai yang ditampilkan tidak optimal menurut kriteria obyektif apa pun. Meski demikian, tugas menciptakan demonstran teknologi yang menarik bisa dianggap terselesaikan.



All Articles