Азимуты и направления

В веб-графике глобальных сцен библиотека CesiumJS оперирует не только координатами, но и ориентацией объектов в пространстве. Любое направление на глобусе задаётся через комбинацию географических и локальных систем координат, где ключевую роль играют азимуты, углы поворота камеры и преобразования между системами отсчёта.

Азимут как базовая геометрическая величина

Азимут представляет собой угол между направлением на север и проекцией направления объекта на горизонтальную плоскость.

В контексте CesiumJS азимут чаще всего связан с понятием heading — угла поворота относительно северного направления в локальной касательной плоскости Earth-Centered, Earth-Fixed (ECEF).

Формально:

  • 0° — направление на географический север
  • 90° — восток
  • 180° — юг
  • 270° — запад

В CesiumJS азимут выражается в радианах, а не в градусах, что требует постоянных преобразований:

const headingRad = Cesium.Math.toRadians(90);
const headingDeg = Cesium.Math.toDegrees(headingRad);

Геодезическая система координат и локальная плоскость

Работа с направлениями в CesiumJS невозможна без понимания локальной системы координат:

  • East-North-Up (ENU) — локальная система, ориентированная на поверхность Земли
  • Earth-Centered Earth-Fixed (ECEF) — глобальная декартова система
  • Cartographic coordinates — широта, долгота, высота

Преобразование между ними является основой для вычисления азимута:

const cartographic = Cesium.Cartographic.fromCartesian(position);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);

Heading, Pitch, Roll и ориентация объектов

В CesiumJS направление объекта задаётся через структуру HeadingPitchRoll, которая определяет вращение относительно локальной системы координат.

  • Heading — поворот вокруг оси Z (азимут)
  • Pitch — наклон вверх/вниз
  • Roll — крен вокруг продольной оси
const hpr = new Cesium.HeadingPitchRoll(
    Cesium.Math.toRadians(45),  // heading
    Cesium.Math.toRadians(-10), // pitch
    Cesium.Math.toRadians(0)    // roll
);

Для применения ориентации к объекту используется преобразование к кватерниону:

const quaternion = Cesium.Transforms.headingPitchRollQuaternion(
    position,
    hpr
);

Азимут между двумя точками

Одной из ключевых задач является вычисление направления от одной точки на поверхности Земли к другой.

Алгоритм основан на геодезической формуле начального курса (initial bearing):

const start = Cesium.Cartographic.fromDegrees(lon1, lat1);
const end = Cesium.Cartographic.fromDegrees(lon2, lat2);

const geodesic = new Cesium.EllipsoidGeodesic(start, end);

const heading = geodesic.startHeading;

Значение startHeading возвращается в радианах и соответствует азимуту от начальной точки к конечной.

Камера и направление обзора

Камера в CesiumJS имеет собственную систему ориентации, где азимут напрямую влияет на вращение сцены.

viewer.camera.setView({
    destination: Cesium.Cartesian3.fromDegrees(30, 50, 10000),
    orientation: {
        heading: Cesium.Math.toRadians(120),
        pitch: Cesium.Math.toRadians(-30),
        roll: 0
    }
});

Здесь:

  • heading определяет поворот вокруг вертикальной оси
  • pitch задаёт наклон камеры к поверхности Земли
  • roll изменяет горизонт камеры

Связь азимута с локальными осями

В CesiumJS локальные направления определяются относительно точки наблюдения:

  • X — восток
  • Y — север
  • Z — вверх

Азимут (heading) фактически является углом между осью Y (север) и проекцией направления на плоскость X–Y.

Вектор направления камеры можно получить через матрицу преобразования:

const transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
const rotation = Cesium.Matrix4.getMatrix3(transform, new Cesium.Matrix3());

Нормализация углов и диапазоны значений

CesiumJS работает в радианах, но при расчётах часто возникает необходимость нормализации:

  • диапазон heading: от -π до π или от 0 до 2π (в зависимости от метода)
  • отрицательные значения интерпретируются как поворот против часовой стрелки
const normalized = Cesium.Math.zeroToTwoPi(angle);

Или приведение к стандартному диапазону:

const wrapped = Cesium.Math.TWO_PI - Cesium.Math.zeroToTwoPi(angle);

Компасная интерпретация направлений

Для перевода математического угла в географический азимут используется соответствие:

Угол (градусы) Направление
0 Север
90 Восток
180 Юг
270 Запад

CesiumJS использует математическую систему координат, где положительное направление вращения — против часовой стрелки, что важно при интерпретации азимута.

Азимут в контексте 3D-объектов

При работе с моделями (3D Tiles, glTF) направление объекта определяется не только heading, но и исходной ориентацией модели.

const modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
    position,
    hpr
);

Любое изменение heading изменяет ориентацию модели относительно глобального севера.

Вычисление направления векторным способом

Азимут можно вычислить через вектор направления между двумя Cartesian3 точками:

const direction = Cesium.Cartesian3.subtract(
    target,
    origin,
    new Cesium.Cartesian3()
);

Cesium.Cartesian3.normalize(direction, direction);

Далее проекция на плоскость ENU позволяет получить угол:

const enu = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
const inverse = Cesium.Matrix4.inverse(enu, new Cesium.Matrix4());
const localDir = Cesium.Matrix4.multiplyByPoint(inverse, direction, new Cesium.Cartesian3());

Азимут вычисляется как:

const heading = Math.atan2(localDir.x, localDir.y);

Использование heading в навигации и трекинге

В задачах навигации heading применяется для:

  • построения маршрутов на поверхности Земли
  • ориентации объектов по траектории движения
  • синхронизации камеры с направлением транспорта

Пример привязки ориентации к скорости движения:

const heading = Cesium.Math.toRadians(velocityBearing);
const hpr = new Cesium.HeadingPitchRoll(heading, 0, 0);
entity.orientation = Cesium.Transforms.headingPitchRollQuaternion(
    position,
    hpr
);

Особенности численной точности

При вычислениях азимута в глобальных координатах возникают погрешности:

  • приближение эллипсоида сферой на малых расстояниях
  • потеря точности при работе с большими координатами ECEF
  • необходимость нормализации углов при накоплении трансформаций

CesiumJS компенсирует эти эффекты через использование эллипсоида WGS84 и встроенных геодезических функций.

Итоговая связка направлений в CesiumJS

Азимут в CesiumJS является связующим элементом между:

  • географическими координатами (широта, долгота)
  • локальной системой ENU
  • ориентацией камеры и объектов
  • векторной математикой 3D пространства

Через heading формируется единая модель направления, применимая к камере, моделям, траекториям и геодезическим вычислениям в глобальной сцене.