مؤشر الأفق الاصطناعي على قماش HTML5

أدناه سوف نقدم تطبيقًا عن طريق HTML5 لإحدى الأفكار غير العادية لتصور الموقع المكاني لكائن متحكم فيه. يمكن استخدام الكود في ألعاب المتصفح التي تحاكي قيادة مركبة في مساحة ثلاثية الأبعاد. تتركز طريقة عرض المعلومات على محاكيات السطوح أو الآلات الرائعة الأخرى.







الغرض ونطاق الأفق الاصطناعي



الأفق المصطنع بالمعنى الضيق المدروس هنا هو تصور إمالة كائن بالنسبة إلى الوضع الرأسي المحلي ، ويستخدم للتحكم في حركته. يتم تعريف المنحدر من قيم زاويتين يولر، لفة و الملعب . يفضل البحارة المرادف "تقليم" لمصطلح الطيران "الملعب".



تتعلق بالأفق الاصطناعي (ولكن ليس مرادفًا تمامًا) لمصطلحات اللغة الروسية: "الأفق الاصطناعي" ، "جهاز قيادة الطيران". في اللغة الإنجليزية ، يتم استخدام التعبيرات "مؤشر الموقف" أو "الأفق الاصطناعي" أو "الأفق الجيروسكوبي" .



تقنيات التصور المعروفة



تم تنفيذ معظم العمل على إيجاد حلول ناجحة في مجال إشارات الملعب واللف لمصلحة الطيران. هناك تفسير بسيط لذلك: يجب على الطيار قراءة المعلومات بسرعة ، وأي خطأ في إدراكه للفضاء يهدد بأن يصبح قاتلاً.



تعتمد معظم الحلول المعروفة في مجال بيان التدحرج والميل على استخدام صورة ظلية للطائرة وخلفية خاصة. الملامح العامة:



  • الخلفية مقسمة إلى جزأين يرمزان إلى السماء والأرض بخط يمثل الأفق ؛
  • صورة ظلية الطائرة عبارة عن منظر خلفي مبسط يتناقض في اللون مع الخلفية ؛
  • يتم تحديد زاوية اللف بواسطة المؤشر كزاوية بين خط الأفق الرمزي والخط الذي يربط بين رؤوس الأجنحة في الصورة الظلية (عادةً ما يكون مقياس مرجعي موجودًا لقراءة دقيقة) ؛
  • تُقاس زاوية الميل على طول مقياس عمودي على الأفق الشرطي وفقًا لموضع نقطة التحكم في مركز الصورة الظلية.






الأنظمة المطبقة في الإنتاج الضخم لها عدد من الحلول الشائعة:



  • يتم إعطاء المعلومات من خلال الموقع النسبي للصورة الظلية والخلفية ؛
  • يرتبط التغيير في زاوية اللف بالحركة الزاوية للصورة الظلية بالنسبة للخلفية ؛
  • يرتبط التغيير في زاوية الملعب بالإزاحة الخطية للصورة الظلية بالنسبة للخلفية.


لكن ليس من الصعب تخمين أن الحركة النسبية المرغوبة يمكن أن تتحقق بعدة طرق مختلفة. بعد الكثير من التجارب والخطأ في القرن الماضي ، ترك تطور الطيران مجموعتين قابلتين للتطبيق:



1. صورة ظلية ثابتة ، تتحرك بشكل متدرج وخلفية الملعب. الأسماء المستخدمة: "إشارة مباشرة" ، "رؤية من الطائرة إلى الأرض" ، وغالبًا ما تكون "إشارة متمركزة حول الذات".







2. صورة ظلية تتحرك فقط على طول لفة ، خلفية تتحرك فقط على طول الملعب. الأسماء المستخدمة: "إشارة عكسية" و "عرض من الأرض إلى المستوى" ، وغالبًا ما تكون "إشارة مركزية الأرض".







لاحظ أن أسماء الفقرة 2 تنطبق على النظام ككل ، ولكنها تعكس فقط مبدأ بيان زاوية اللف المعتمد فيه. مؤشر زاوية الملعب في كلا النظامين المستخدم هو "مستقيم" و "أناني".



في محاكيات الطيران الموجودة ، مثل Microsoft Flight Simulator و Digital Combat Simulator ، يمكن رؤية كلا النوعين من شاشات العرض أثناء العمل.



من الجدير بالذكر أنه ليست كل الحلول المعروفة تتناسب مع النمط أعلاه. للحصول على مثال لتجاوز الإطار المحدد ، دعونا ننظر في براءتي اختراع للاختراعات: RU 2561311 و RU 2331848.



أول براءة اختراع مخصصة لـ "الأفق الاصطناعي مع مؤشرات الانحدار والالتفاف المتباعدة" ، مؤلفوها: V.I. Putintsev و N. من براءة الاختراع.







إذا لزم الأمر ، يمكنك العثور على فك تشفير للتعيينات ووصف للعمل في نص المصدر الأصلي... بشكل عام ، فإن فكرة الاختراع بسيطة للغاية: يتم تحقيق فكرة "الرؤية من الأرض إلى الطائرة" في كل من التدحرج والميل ("مركزية الأرض" بالكامل) ، ولكن المؤشر ينقسم إلى مكونين مستقلين.



الاختراع الثاني له اسم أكثر تعقيدًا: "جهاز قيادة الطيران للإشارة المنطقية لموقع الطائرة والتحكم فيها في الفضاء." مؤلفو براءة الاختراع: A. P. Plentsov و N. A. Zakonova. إن فكرة بيان الملعب واللف غير مألوفة هنا.







يقدم براءة الاختراع شرحًا لتسميات الدائرة ، ووصفًا للجهاز ، ومقارنة مع نظائر ودوائر إضافية مع اختلافات طفيفة في التصميم .



شيء واحد مشترك مع الاختراع السابق هو مفهوم مركزية الأرض لكلا القناتين. في الوقت نفسه ، يحتوي الأفق الاصطناعي على "رمز طائرة" واحد فقط ، كما هو الحال في النماذج الحالية ، ولكن هذا لم يعد صورة ظلية ، بل نموذج ثلاثي الأبعاد - "نموذج حجمي". إذا اتضح أن حركة التدحرج مشابهة لتلك التي تم تنفيذها في الإشارة "العكسية" ، فإن التأرجح والغوص على هذا الجهاز سيبدو أصليًا.







هناك عدد من العوامل التي تعوق الابتكار في تصميم أنظمة العرض في العالم الحقيقي. على سبيل المثال ، أحد الأسس المعقولة للمحافظة هو الرغبة في الحفاظ على استمرارية المهارات التي يكتسبها المشغل ، بما في ذلك مهارات إدراك المعلومات. يمكن لألعاب الكمبيوتر أن توفر قدرًا أكبر من الإبداع ، لذلك ، دون الخوض في تحليل مقارن للحلول ، سنأخذ الاختراع الأكثر فاعلية كأساس.



متطلبات الحل



قبل البدء في كتابة الكود ، دعنا نحدد المهمة:



1. من الضروري كتابة دالة drawAttitude () ، التي ترسم مؤشر الأفق الاصطناعي عن طريق قماش يعتمد على اختراع A.P. Plentsov و N.A. Zakonova



2. تأخذ الوظيفة سياق اللوحة القماشية والإحداثيات مركز المؤشر ، قيم زوايا التدحرج والميل بالدرجات ، نصف قطر وجه المؤشر.



3. قيم زاوية الملعب محدودة بالفاصل الزمني من 30 إلى زائد 30 درجة.



4. قيم زاوية اللف مقيدة بالفاصل الزمني من 45 إلى زائد 45 درجة.



5. إذا كانت قيمة الوسيطة تتجاوز تلك المحددة في p. حدود 3 و 4 يظهر المؤشر أقرب قيمة مسموح بها.



خلق الوظيفة



يتضمن كود الوظيفة الأجزاء التالية:



1. فحص القيم المدخلة لتجاوز الحدود.



2. تحويل الزوايا إلى راديان.



3. قياس الحجم المميز لـ "التخطيط" والخط بقيمة نصف قطر المؤشر.



4. رسم المكونات:

أ) جسم المؤشر.

ب) التخطيط.

ج) موازين Pitch and Roll.



تمت كتابة الوظيفة أدناه بهذا الترتيب ، ويتم فصل أجزائها عن طريق التعليقات.



كود كامل
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();
}






أصعب فهم هو رمز لرسم "التخطيط". دعونا ننظر في الأمر بمزيد من التفصيل. كتخطيط ، تقرر استخدام شكل متناظر مسطح على شكل سهم.







تختلف الأسطح العلوية والسفلية للتخطيط عن بعضها البعض في ألوان المخطط التفصيلي والتعبئة. اختيار نظام الألوان الحالي هو الجزء الأول من الكود.

بعد ذلك ، تم بناء محيط الشكل.



أصعب مهمة هي تحديد إحداثيات إسقاطات رؤوس الشكل على مستوى YOZ . هذا ما تحله التعبيرات ذات الدوال المثلثية. يتم اجتياز الرؤوس في الكود بترتيب ترقيمها في الشكل.



الجزء الأكبر من الكود مخصص للمقاييس والتوقيعات. علامات المقياس لها العديد من الاختلافات: أعلى وأسفل ، يسار ويمين ، مع وبدون تسميات. يرجع العدد المذهل للأسطر إلى كتابة الرمز "الفردي" لكل عنصر.



تستخدم الدوال المثلثية للزوايا المتناظرة لتطبيق علامات التدحرج. نظرًا لأن قيم زوايا كل تسمية معروفة مسبقًا ، تتم كتابة القيم الجاهزة للجيب وجيب التمام في الكود.



من الأفضل تقييم نوع المؤشر في الديناميكيات. دعونا نظهر تذبذبات الدرجة واللف باستخدام الوظيفة الجديدة. للحصول على أقصى تنوع في المواضع ، دعونا نجعل اتساع التذبذب يتوافق مع حدود المؤشر ، والفترات - مختلفة وبسيطة بشكل متبادل.







خاتمة



بالمعنى الدقيق للكلمة ، يجب أن يُطلق على الكود أعلاه لتصور التدحرج والنغمة إشارة "بناءً على" اختراع A. P. Plentsov و N. A. Zakonova. تم إجراء بعض الانحرافات عن المخططات الأصلية لتبسيط المهمة ، والبعض الآخر لتحسين التنفيذ.



المؤشر المقدم بعيد كل البعد عن المثالية من حيث التصميم. القيود المقبولة للقيم المعروضة ليست مثالية بأي معيار موضوعي. ومع ذلك ، يمكن اعتبار مهمة إنشاء متظاهر لتقنية مثيرة للاهتمام محلولة.



All Articles