Позиционирование и ориентация

В ядре CesiumJS используется несколько взаимосвязанных систем координат, каждая из которых решает конкретный класс задач: от отображения точек на эллипсоиде до расчёта ориентации 3D-моделей в локальных и глобальных пространствах.

Основные типы представлений:

  • Cartographic (географические координаты) — долгота, широта, высота.
  • Cartesian3 (декартовы координаты) — координаты в мировом трёхмерном пространстве.
  • WGS84 эллипсоид — базовая модель Земли.

Конвертация между ними выполняется через утилиты Cesium.Cartesian3 и Cesium.Cartographic.

const cartesian = Cesium.Cartesian3.fromDegrees(69.6, 42.3, 1000);
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);

const lon = Cesium.Math.toDegrees(cartographic.longitude);
const lat = Cesium.Math.toDegrees(cartographic.latitude);

Ключевой момент: внутренняя сцена всегда работает в Cartesian3, а географические координаты используются только на уровне API.


Преобразование координат и высотная модель

При работе с поверхностью Земли необходимо учитывать рельеф, который задаётся через terrain-provider. Прямое использование fromDegrees игнорирует высоту поверхности, поэтому применяется уточнение через выборку высот.

const position = Cesium.Cartesian3.fromDegrees(69.6, 42.3);

const updatedPosition = Cesium.Cartesian3.fromDegrees(
  69.6,
  42.3,
  0
);

const terrainPosition = Cesium.Cartesian3.fromDegrees(
  69.6,
  42.3,
  Cesium.sampleTerrainMostDetailed
);

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

const positions = [Cesium.Cartographic.fromDegrees(69.6, 42.3)];

Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, positions)
  .then((updated) => {
    console.log(updated[0].height);
  });

Локальные системы координат: East-North-Up

Для ориентации объектов в локальном пространстве используется система ENU (East-North-Up). Она формирует локальную базу осей относительно точки на поверхности эллипсоида.

const origin = Cesium.Cartesian3.fromDegrees(69.6, 42.3);

const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);

Эта матрица преобразует локальные координаты (X — восток, Y — север, Z — вверх) в глобальные Cartesian3.

Применение:

const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);

viewer.entities.add({
  position: origin,
  model: {
    uri: "model.glb",
    modelMatrix: modelMatrix
  }
});

Ключевой момент: ENU используется для «привязки» объектов к поверхности с сохранением локальной логики движения.


Ориентация через heading, pitch и roll

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

  • Heading — поворот вокруг оси Z (курс)
  • Pitch — наклон вверх/вниз
  • Roll — крен

Эта система широко используется в авиационной и навигационной визуализации.

const heading = Cesium.Math.toRadians(90);
const pitch = Cesium.Math.toRadians(0);
const roll = Cesium.Math.toRadians(0);

const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);

const orientation = Cesium.Transforms.headingPitchRollQuaternion(
  Cesium.Cartesian3.fromDegrees(69.6, 42.3),
  hpr
);

Применение в сущностях:

viewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(69.6, 42.3),
  orientation: orientation,
  model: {
    uri: "aircraft.glb"
  }
});

Кватернионы как основа ориентации

Внутренне Cesium использует кватернионы для представления вращений, что устраняет проблему gimbal lock и обеспечивает стабильную интерполяцию.

Создание кватерниона напрямую:

const hpr = Cesium.HeadingPitchRoll.fromDegrees(45, 10, 0);
const quaternion = Cesium.Quaternion.fromHeadingPitchRoll(hpr);

Кватернионы используются в:

  • анимации камеры
  • ориентации моделей
  • интерполяции движения

Матрицы преобразований и модельные пространства

Полное управление положением объекта часто требует использования Matrix4.

const translation = Cesium.Cartesian3.fromDegrees(69.6, 42.3, 0);
const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(translation);

Для кастомных преобразований:

const scale = Cesium.Matrix4.fromScale(new Cesium.Cartesian3(2.0, 2.0, 2.0));

Cesium.Matrix4.multiply(modelMatrix, scale, modelMatrix);

Матричная цепочка обычно включает:

  • локальный масштаб
  • поворот
  • перенос
  • привязку к глобальной системе

Камера как объект ориентации

Камера в Cesium — полноценный объект с позиционированием и ориентацией в 3D пространстве.

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

Методы управления:

  • lookAt — привязка камеры к точке
  • flyTo — анимированный переход
  • setView — мгновенная установка

Пример привязки:

const target = Cesium.Cartesian3.fromDegrees(69.6, 42.3);

viewer.camera.lookAt(
  target,
  new Cesium.HeadingPitchRange(
    Cesium.Math.toRadians(0),
    Cesium.Math.toRadians(-20),
    5000
  )
);

Система фиксированных и локальных референсных фреймов

Cesium поддерживает различные системы отсчёта:

  • Fixed Frame (WGS84)
  • East-North-Up frame
  • Inertial frames (для астрономических данных)

Преобразование:

const fixedFrame = Cesium.Transforms.eastNorthUpToFixedFrame(
  Cesium.Cartesian3.fromDegrees(69.6, 42.3)
);

И обратное преобразование:

const inverse = Cesium.Matrix4.inverseTransformation(fixedFrame, new Cesium.Matrix4());

Это позволяет строить иерархические сцены: объекты внутри объектов.


Entity API и автоматическое управление ориентацией

Entity-система автоматически вычисляет модельные матрицы при наличии position и orientation.

viewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(69.6, 42.3),
  orientation: Cesium.Transforms.headingPitchRollQuaternion(
    Cesium.Cartesian3.fromDegrees(69.6, 42.3),
    new Cesium.HeadingPitchRoll(0, 0, 0)
  ),
  box: {
    dimensions: new Cesium.Cartesian3(100, 100, 100)
  }
});

Если orientation не задана, объект ориентируется по глобальной системе координат без вращения.


Интерактивное обновление позиции и ориентации

Для динамических объектов используются функции обновления на каждом кадре:

viewer.clock.onTick.addEventListener(() => {
  const time = viewer.clock.currentTime;

  const position = Cesium.Cartesian3.fromDegrees(
    69.6 + Math.sin(Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime)) * 0.1,
    42.3
  );

  viewer.entities.getById("moving").position = position;
});

Ориентация может обновляться синхронно с движением:

entity.orientation = Cesium.Transforms.headingPitchRollQuaternion(
  position,
  new Cesium.HeadingPitchRoll(angle, 0, 0)
);

Привязка ориентации к поверхности и нормалям

Для сложных сценариев, например следования рельефу, используется нормаль поверхности.

const position = Cesium.Cartesian3.fromDegrees(69.6, 42.3);

const surfaceNormal = viewer.scene.globe.ellipsoid.geodeticSurfaceNormal(
  position,
  new Cesium.Cartesian3()
);

Это позволяет ориентировать объект вдоль поверхности Земли.


Иерархия преобразований в сцене

Типичная цепочка трансформаций объекта в Cesium:

  1. Локальные координаты модели
  2. Model matrix (масштаб, вращение)
  3. ENU frame
  4. Fixed frame (WGS84)
  5. Проекционная матрица камеры

Каждый слой влияет на итоговую визуализацию и может быть переопределён вручную через Matrix4 или автоматически через Entity API.


Практика комбинирования позиционирования и ориентации

Комбинированные сценарии часто требуют явного разделения:

  • позиция отвечает за размещение
  • ориентация — за направление
  • модельная матрица — за финальное преобразование
const position = Cesium.Cartesian3.fromDegrees(69.6, 42.3);

const hpr = new Cesium.HeadingPitchRoll(
  Cesium.Math.toRadians(120),
  0,
  0
);

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

viewer.entities.add({
  position,
  orientation,
  model: { uri: "vehicle.glb" }
});