Синхронизация с реальным временем

CesiumJS использует собственную систему времени, основанную на астрономической модели и типе JulianDate. В отличие от стандартного JavaScript-времени (Date), где время выражается в миллисекундах от Unix-эпохи, здесь применяется непрерывная шкала, удобная для высокоточной симуляции и работы с орбитальной механикой.

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

  • скоростью течения времени;
  • направлением (вперёд/назад);
  • режимом паузы;
  • синхронизацией с внешними источниками данных.

JulianDate и высокоточное представление времени

JulianDate представляет момент времени как пару чисел двойной точности, что минимизирует накопление ошибок при длительных вычислениях.

Основные операции:

  • создание момента времени;
  • добавление интервалов;
  • вычисление разницы между датами;
  • преобразование в UTC.

Пример логики работы:

const now = Cesium.JulianDate.now();
const later = Cesium.JulianDate.addSeconds(now, 60, new Cesium.JulianDate());

const diff = Cesium.JulianDate.secondsDifference(later, now);

Использование JulianDate критично в задачах, где требуется согласованность координат во времени: спутниковые траектории, авиационные данные, морская навигация.


Clock как центральный механизм управления временем

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

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

  • startTime — начало временного интервала;
  • stopTime — конец интервала;
  • currentTime — текущее виртуальное время;
  • multiplier — коэффициент ускорения;
  • shouldAnimate — флаг анимации;
  • clockStep — режим шага времени;
  • clockRange — поведение при достижении границ.

Пример настройки:

const viewer = new Cesium.Viewer("cesiumContainer");

viewer.clock.startTime = Cesium.JulianDate.fromIso8601("2026-01-01T00:00:00Z");
viewer.clock.stopTime  = Cesium.JulianDate.fromIso8601("2026-01-02T00:00:00Z");
viewer.clock.currentTime = Cesium.JulianDate.now();

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

ClockStep и режимы дискретизации

ClockStep определяет, как именно изменяется время:

  • TICK_DEPENDENT — шаг зависит от времени кадра;
  • SYSTEM_CLOCK_MULTIPLIER — ускорение относительно реального времени;
  • SYSTEM_CLOCK — полная синхронизация с системными часами;
  • TICK — фиксированные шаги.

На практике выбор режима влияет на стабильность симуляции. Например, для потоковых GPS-данных чаще используется SYSTEM_CLOCK_MULTIPLIER.


Синхронизация с системным временем

Режим синхронизации с реальным временем применяется при визуализации живых данных: транспорта, IoT-устройств, дронов.

viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK;
viewer.clock.shouldAnimate = true;

При этом currentTime автоматически следует системному времени, но остаётся возможность смещения через clock.offset.

Использование смещения позволяет:

  • проигрывать исторические данные в реальном темпе;
  • сопоставлять архив и live-источник;
  • воспроизводить события с задержкой.

Динамические сущности и обновление позиций

Синхронизация с реальным временем особенно важна для Entity с временными координатами.

SampledPositionProperty хранит набор точек с временными метками:

const position = new Cesium.SampledPositionProperty();

position.addSample(
  Cesium.JulianDate.now(),
  Cesium.Cartesian3.fromDegrees(37.6173, 55.7558, 100)
);

position.addSample(
  Cesium.JulianDate.addSeconds(Cesium.JulianDate.now(), 10, new Cesium.JulianDate()),
  Cesium.Cartesian3.fromDegrees(37.6200, 55.7600, 100)
);

Система интерполирует положение между точками, обеспечивая плавное движение без ручного обновления координат в каждом кадре.


Потоковые данные и WebSocket интеграция

При работе с реальным временем часто используется поток данных через WebSocket или MQTT. Основная идея заключается в непрерывном добавлении новых временных сэмплов.

const socket = new WebSocket("wss://example.com/stream");

socket.onmess age = (event) => {
  const data = JSON.parse(event.data);

  const time = Cesium.JulianDate.fromIso8601(data.timestamp);
  const position = Cesium.Cartesian3.fromDegrees(
    data.lon,
    data.lat,
    data.alt
  );

  entity.position.addSample(time, position);
};

Такой подход формирует непрерывную временную траекторию, где каждый пакет данных автоматически интегрируется в модель движения.


Привязка визуализации к текущему времени

В Cesium существует разделение между:

  • system time — реальное время компьютера;
  • simulation time — время сцены.

Для синхронизации используется явное присваивание:

viewer.clock.currentTime = Cesium.JulianDate.now();
viewer.clock.multiplier = 1;

При этом визуализация становится аналогом «живого слоя», где сцена отражает текущую реальность.


Работа с интервалами и предсказанием движения

Для объектов, движущихся по предсказанной траектории, используется расширение временного диапазона:

  • добавление будущих сэмплов;
  • экстраполяция;
  • сглаживание скорости.
position.setInterpolationOptions({
  interpolationDegree: 2,
  interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
});

Это снижает рывки при редких обновлениях данных.


CZML и временные пакеты данных

CZML представляет собой формат, ориентированный на временные сцены. Каждый пакет данных содержит:

  • идентификатор объекта;
  • временные интервалы;
  • свойства (позиция, цвет, ориентация).

Пример структуры:

[
  {
    "id": "document",
    "version": "1.0"
  },
  {
    "id": "vehicle",
    "position": {
      "epoch": "2026-01-01T00:00:00Z",
      "cartographicDegrees": [
        0, 37.6173, 55.7558, 0,
        10, 37.6200, 55.7600, 0
      ]
    }
  }
]

Cesium автоматически связывает эти данные с Clock, обеспечивая временную навигацию без ручного обновления состояния.


Таймлайн и визуальное управление временем

Компонент Timeline предоставляет визуальную шкалу времени, синхронизированную с ClockViewModel. Он позволяет:

  • перемещаться по временной оси;
  • изменять масштаб времени;
  • фиксировать текущий момент.

ClockViewModel выступает промежуточным слоем между UI и логикой времени, обеспечивая реактивную синхронизацию.


Проблема дрейфа времени и компенсация

При длительной работе симуляции возможен дрейф из-за:

  • накопления ошибок floating point;
  • задержек рендеринга;
  • асинхронных обновлений данных.

Методы компенсации:

  • периодическая синхронизация с JulianDate.now();
  • использование SYSTEM_CLOCK_MULTIPLIER;
  • ограничение интерполяции на больших интервалах.

Производительность при реальном времени

Обработка потокового времени требует контроля нагрузки:

  • ограничение количества активных сэмплов;
  • удаление устаревших точек;
  • батчинг входящих данных;
  • использование CallbackProperty только при необходимости.
const position = new Cesium.CallbackProperty(() => {
  return computeLatestPosition();
}, false);

Однако чрезмерное использование callback-подхода увеличивает нагрузку на рендер-цикл.


Согласование времени между слоями данных

В сложных сценах одновременно присутствуют:

  • спутниковые орбиты;
  • транспортные потоки;
  • погодные модели;
  • 3D Tiles с временными метками.

Согласование достигается через единый Clock, который становится глобальным источником времени для всех слоёв сцены. Любое несоответствие приводит к визуальным рассинхронизациям, особенно при разной частоте обновления данных.


Управление направлением времени

Cesium поддерживает обратный ход времени:

viewer.clock.multiplier = -5;

Это используется при:

  • анализе событий задним числом;
  • отладке симуляций;
  • исследовании динамики процессов.

Обратный ход требует корректной интерполяции, иначе возможны артефакты движения.


Связь времени и кадрового цикла

Визуализация сцены выполняется в цикле рендеринга WebGL. На каждом кадре:

  1. вычисляется текущий Clock.currentTime;
  2. обновляются все time-dependent properties;
  3. пересчитываются позиции;
  4. выполняется отрисовка кадра.

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