Индикатор размещен таким образом, что центр циферблата шкалы крена совпадает с началом мировой системы координат. При отсутствии тангажа и крена макет лежит в плоскости
XOZ, его продольная ось совпадает с осью
OZ, нос макета направлен в сторону отрицательных значений
z.
Плоскостью симметрии рабочего места оператора будем считать плоскость
YOZ. Взгляд оператора направлен в сторону отрицательных значений
z.
Основную часть кода класса
Attitude составляет его конструктор. Здесь определены геометрические свойства и дизайн всех элементов индикатора. Помимо параметров, указанных в требованиях, конструктору передаются камера и сцена.
constructor(camera, scene, radius, maxPitch, maxRoll){
Первая понадобится для проекции трехмерного положения текстовых отметок на экран (функция
to2D()), а вторая – для добавления к ней всех видимых компонентов индикатора через метод
add().
Установка пределов шкал выполняется довольно просто. Для шкалы тангажа дополнительно устанавливаются границы по условиям п. 3 требований.
if (maxPitch > 90) maxPitch = 90;
this.maxPitch = maxPitch;
maxPitch /= 30;
maxPitch = Math.ceil(maxPitch) * 30;
Шкала тангажа может иметь предел 30, 60 или 90 градусов. Для рационального использования пространства экрана пропорции макета-стрелки должны выбираться в соответствии с этими значениями.
let skeletonLength = radius / Math.sin(maxPitch * Math.PI / 180);
Если параметр radius однозначно определяет ширину макета, то длина
skeletonLength зависит от
maxPitch: чем выше максимальное значение тангажа, тем короче макет. Таким образом, пропорции самого индикатора не зависят от
maxPitch.
Строго говоря, для перспективной камеры пропорции индикатора сохраняются лишь на бесконечном удалении. Тем не менее, и в реальных условиях различия достаточно малы.
Контур макета строится по четырем точкам, начиная с ближней к оператору вершины на продольной оси макета.
let geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(0, 0, -skeletonLength / 4));
geometry.vertices.push(new THREE.Vector3(-radius, 0, 0));
geometry.vertices.push(new THREE.Vector3(0, 0, -skeletonLength));
geometry.vertices.push(new THREE.Vector3(radius, 0, 0));
geometry.vertices.push(new THREE.Vector3(0, 0, -skeletonLength / 4));
let material = new THREE.LineBasicMaterial({ color: 0x00ff00, linewidth: 1 });
this.skeleton = new THREE.Line(geometry, material);
scene.add(this.skeleton);
Обход силуэта осуществляется по часовой стрелке, если смотреть на него сверху. Повторение в коде первой точки замыкает контур фигуры.
Аналогичные средства
three.js используются для создания линий отметок шкал. Шкалы тангажа и крена имеют следующие различия:
1. Шкала тангажа неподвижна, положение ее элементов не меняется при вызове метода
update(), а все метки шкалы крена, кроме двух нулевых, вращаются по тангажу. Различие обусловлено природой самих углов. Вращение по тангажу осуществляется вокруг поперечной оси нормальной земной системы координат, а вращение по крену – вокруг продольной оси связанной системы координат.
2. Отметки шкалы тангажа расположены горизонтально, перпендикулярно плоскости шкалы (плоскости симметрии рабочего места оператора), а отметки шкалы крена находятся в ее плоскости и имеют радиальное направление.
Метод
update() после проверки значений тангажа и крена на соответствие установленным ограничениям осуществляет поворот всех подвижных компонентов:
- макет поворачивается на углы крена и тангажа;
- шкала крена поворачивается на угол тангажа.
Текстовые подписи числовых значений шкалы тангажа выполняются посредством создания тегов
html. Использование
3D шрифтов в этом случае лишено практического смысла.