Путевые анимации

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

В основе лежит SampledPositionProperty — структура, которая хранит набор временных меток и соответствующих им координат. Cesium интерполирует между этими значениями, создавая непрерывное движение.

const position = new Cesium.SampledPositionProperty();

position.addSample(
  Cesium.JulianDate.fromIso8601("2026-01-01T10:00:00Z"),
  Cesium.Cartesian3.fromDegrees(71.4304, 51.1282, 1000)
);

position.addSample(
  Cesium.JulianDate.fromIso8601("2026-01-01T10:10:00Z"),
  Cesium.Cartesian3.fromDegrees(71.5000, 51.1500, 1500)
);

Каждая добавленная точка формирует узел траектории, а интерполяция между узлами обеспечивает плавное перемещение объекта.


Временная модель и управление анимацией

Путевые анимации полностью зависят от системного времени сцены. Viewer.clock определяет текущее время, направление воспроизведения и скорость.

Ключевые параметры:

  • startTime — начало временного диапазона
  • stopTime — конец временного диапазона
  • currentTime — текущее значение времени
  • multiplier — скорость воспроизведения
  • shouldAnimate — флаг активности
const viewer = new Cesium.Viewer("cesiumContainer");

viewer.clock.startTime = Cesium.JulianDate.fromIso8601("2026-01-01T10:00:00Z");
viewer.clock.stopTime  = Cesium.JulianDate.fromIso8601("2026-01-01T10:30:00Z");
viewer.clock.currentTime = viewer.clock.startTime.clone();
viewer.clock.multiplier = 60;
viewer.clock.shouldAnimate = true;

Сцена начинает «проигрывать» временной интервал, а все объекты с временными свойствами автоматически обновляются.


Привязка пути к сущности

Путевая анимация обычно реализуется через Entity. Позиция, заданная как временная функция, привязывается к сущности через свойство position.

const entity = viewer.entities.add({
  availability: new Cesium.TimeIntervalCollection([
    new Cesium.TimeInterval({
      start: Cesium.JulianDate.fromIso8601("2026-01-01T10:00:00Z"),
      stop: Cesium.JulianDate.fromIso8601("2026-01-01T10:30:00Z")
    })
  ]),
  position: position,
  point: {
    pixelSize: 10,
    color: Cesium.Color.YELLOW
  }
});

availability ограничивает существование объекта во времени, что важно для корректной работы временной сцены и оптимизации отрисовки.


Интерполяция движения

Cesium поддерживает несколько стратегий интерполяции, влияющих на характер движения:

  • линейная интерполяция
  • лагранжева интерполяция
  • Hermite-интерполяция (с учетом скорости)
position.setInterpolationOptions({
  interpolationDegree: 2,
  interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
});

При недостаточном количестве точек движение становится угловатым, при увеличении степени интерполяции — более гладким, но потенциально менее предсказуемым.


Автоматическая ориентация вдоль траектории

Для динамических объектов важно не только положение, но и ориентация. VelocityOrientationProperty вычисляет направление движения на основе производной позиции.

entity.orientation = new Cesium.VelocityOrientationProperty(position);

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


Отрисовка траектории движения

Визуализация пути осуществляется через PathGraphics. Это создаёт след, который отображает историю перемещения объекта.

entity.path = {
  leadTime: 0,
  trailTime: 600,
  width: 3,
  material: Cesium.Color.CYAN
};
  • trailTime определяет длину отображаемого следа
  • leadTime отвечает за прогнозируемую часть пути
  • material задаёт визуальный стиль линии

Генерация траектории через массив координат

Часто путь формируется из заранее известных точек маршрута. В этом случае координаты преобразуются в временные узлы с равномерным распределением времени.

const coords = [
  [71.4304, 51.1282],
  [71.4500, 51.1350],
  [71.4700, 51.1400],
  [71.5000, 51.1500]
];

const start = Cesium.JulianDate.fromIso8601("2026-01-01T10:00:00Z");
const position = new Cesium.SampledPositionProperty();

coords.forEach((c, i) => {
  const time = Cesium.JulianDate.addSeconds(
    start,
    i * 300,
    new Cesium.JulianDate()
  );

  position.addSample(
    time,
    Cesium.Cartesian3.fromDegrees(c[0], c[1], 1000)
  );
});

Равномерное распределение временных меток создаёт стабильную скорость движения, которая при необходимости может быть модифицирована через изменение интервалов.


Камера и сопровождение движущегося объекта

Слежение камеры за объектом реализуется через привязку к сущности. Камера автоматически обновляет положение и ориентацию относительно текущего состояния объекта.

viewer.trackedEntity = entity;

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

Более гибкий вариант предполагает ручное управление:

viewer.scene.preUpdate.addEventListener(() => {
  const pos = entity.position.getValue(viewer.clock.currentTime);
  if (pos) {
    viewer.camera.lookAt(pos, new Cesium.HeadingPitchRange(0, -0.5, 2000));
  }
});

Использование Polyline для динамического следа

Альтернативный способ визуализации пути — обновляемая полилиния. Она строится на основе массива уже пройденных координат.

const positions = [];

viewer.entities.add({
  polyline: {
    positions: new Cesium.CallbackProperty(() => positions, false),
    width: 2,
    material: Cesium.Color.ORANGE
  }
});

При каждом обновлении времени можно добавлять новую точку:

viewer.clock.onTick.addEventListener(() => {
  const time = viewer.clock.currentTime;
  const pos = entity.position.getValue(time);

  if (pos) {
    positions.push(pos.clone());
  }
});

Такой подход используется для отображения реального трека без заранее заданной траектории.


Работа с высотой и режимами поверхности

Путевые анимации могут учитывать рельеф или игнорировать его в зависимости от режима привязки.

  • clampToGround — прижим к поверхности
  • фиксированная высота — независимое движение
  • геодезическая интерпретация координат
Cesium.Cartesian3.fromDegrees(longitude, latitude, height, undefined, result);

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


CZML и декларативные траектории

Для сложных сценариев применяется CZML — формат описания временных данных. Он позволяет задавать траектории без императивного кода.

const czml = [{
  id: "document",
  version: "1.0"
}, {
  id: "vehicle",
  position: {
    cartographicDegrees: [
      0, 71.4304, 51.1282, 1000,
      600, 71.5000, 51.1500, 1500
    ]
  },
  path: {
    material: { solidColor: { color: { rgba: [0, 255, 255, 255] } } },
    width: 3
  }
}];

viewer.dataSources.add(Cesium.CzmlDataSource.load(czml));

CZML особенно полезен при потоковой передаче траекторий из серверных систем.


Оптимизация путевых анимаций

При увеличении количества объектов возрастает нагрузка на интерполяцию и отрисовку. Основные методы оптимизации:

  • ограничение количества sample points
  • использование availability
  • отключение ненужных графических компонентов
  • упрощение интерполяции
  • использование батчинга сущностей

На уровне сцены важную роль играет requestRenderMode, уменьшающий количество кадров при отсутствии изменений:

const viewer = new Cesium.Viewer("cesiumContainer", {
  requestRenderMode: true,
  maximumRenderTimeChange: Infinity
});

Синхронизация нескольких объектов

Для групповых путевых анимаций важно синхронизировать временные шкалы. Все объекты используют общий clock, что позволяет строить координированные сценарии движения.

viewer.clock.multiplier = 120;
viewer.clock.shouldAnimate = true;

При одинаковом временном диапазоне разные SampledPositionProperty формируют согласованные траектории, даже при различной сложности маршрутов.


Поведение при выходе за пределы траектории

Если текущее время выходит за пределы доступных sample-данных, Cesium прекращает интерполяцию и возвращает undefined. Это состояние используется для скрытия объекта или его фиксации на последней известной позиции.

const pos = position.getValue(viewer.clock.currentTime);
if (!pos) {
  entity.show = false;
}

Комбинирование ориентации, следа и камеры

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

  • SampledPositionProperty задаёт движение
  • VelocityOrientationProperty формирует поворот
  • PathGraphics отображает след
  • Viewer.trackedEntity обеспечивает сопровождение

Эти элементы работают как единая система, где временная модель является центральным управляющим механизмом, а визуальные компоненты лишь интерпретируют её состояние в каждый момент времени.