Профиль высот представляет собой графическое отображение изменения высоты поверхности вдоль заданного маршрута. В геоинформационных системах профили используются для анализа рельефа, проектирования дорог и трубопроводов, оценки видимости объектов, расчёта уклонов и изучения особенностей местности.
В экосистеме CesiumJS профиль высот не является встроенным компонентом интерфейса, однако платформа предоставляет все необходимые инструменты для его построения: получение высот рельефа, выборку точек вдоль линии, интерполяцию маршрута и визуализацию результатов в сторонних графических библиотеках.
Профиль высот показывает зависимость расстояния от начальной точки маршрута и высоты поверхности в каждой точке пути.
Типичный профиль содержит:
Например, маршрут длиной 10 км может проходить через:
На профиле все эти особенности будут представлены в виде кривой изменения высот.
Процесс формирования профиля состоит из нескольких шагов:
Схема выглядит следующим образом:
Маршрут
↓
Промежуточные точки
↓
Высоты Terrain
↓
Расстояния
↓
Массив данных
↓
График профиля
Маршрут обычно задаётся набором координат.
const route = [
Cesium.Cartesian3.fromDegrees(30.5, 50.45),
Cesium.Cartesian3.fromDegrees(30.7, 50.50)
];
Для визуализации линии:
viewer.entities.add({
polyline: {
positions: route,
width: 3,
material: Cesium.Color.RED
}
});
Высоты необходимо получать не только в конечных точках, но и вдоль всей линии.
Для этого используется линейная интерполяция.
Сначала преобразуем координаты:
const start = Cesium.Cartographic.fromCartesian(route[0]);
const end = Cesium.Cartographic.fromCartesian(route[1]);
Создадим точки выборки:
const samples = [];
const count = 100;
for (let i = 0; i <= count; i++) {
const fraction = i / count;
const longitude = Cesium.Math.lerp(
start.longitude,
end.longitude,
fraction
);
const latitude = Cesium.Math.lerp(
start.latitude,
end.latitude,
fraction
);
samples.push(
new Cesium.Cartographic(
longitude,
latitude
)
);
}
Теперь массив содержит 101 точку вдоль маршрута.
После подготовки точек необходимо запросить высоты у активного Terrain Provider.
Для этого применяется функция:
Cesium.sampleTerrainMostDetailed()
Пример:
const terrainSamples =
await Cesium.sampleTerrainMostDetailed(
viewer.terrainProvider,
samples
);
После завершения запроса каждая точка будет содержать поле:
height
Например:
console.log(terrainSamples[0].height);
Результат:
178.4
Высота задаётся в метрах относительно эллипсоида или геоида в зависимости от источника данных.
Создадим структуру:
const profileData = [];
Расстояние между соседними точками вычисляется постепенно.
let distance = 0;
Добавление первой точки:
profileData.push({
distance: 0,
height: terrainSamples[0].height
});
Далее вычисляем накопленное расстояние.
for (let i = 1; i < terrainSamples.length; i++) {
const p1 =
Cesium.Cartesian3.fromRadians(
terrainSamples[i - 1].longitude,
terrainSamples[i - 1].latitude,
terrainSamples[i - 1].height
);
const p2 =
Cesium.Cartesian3.fromRadians(
terrainSamples[i].longitude,
terrainSamples[i].latitude,
terrainSamples[i].height
);
distance +=
Cesium.Cartesian3.distance(p1, p2);
profileData.push({
distance,
height: terrainSamples[i].height
});
}
Получаем структуру:
[
{
distance: 0,
height: 176
},
{
distance: 105,
height: 180
},
{
distance: 210,
height: 184
}
]
CesiumJS не содержит встроенных средств построения графиков, поэтому обычно используются сторонние библиотеки:
Пример подготовки данных для Chart.js:
const labels =
profileData.map(
p => p.distance.toFixed(0)
);
const heights =
profileData.map(
p => p.height
);
Создание графика:
new Chart(ctx, {
type: "line",
data: {
labels,
datasets: [{
label: "Высота",
data: heights
}]
}
});
Результатом станет классический профиль рельефа.
Маршрут редко состоит из двух точек.
Чаще используется полилиния с множеством вершин.
Например:
const route = [
[30.1, 50.1],
[30.3, 50.2],
[30.5, 50.35],
[30.7, 50.4]
];
В этом случае профиль строится по каждому сегменту отдельно.
Алгоритм:
Такой подход обеспечивает равномерную детализацию маршрута любой длины.
Фиксированное количество точек подходит не всегда.
Для длинных маршрутов профиль может оказаться слишком грубым.
Лучше определять число выборок автоматически.
Например:
const length =
Cesium.Cartesian3.distance(
startCartesian,
endCartesian
);
const count =
Math.max(
20,
Math.floor(length / 50)
);
Здесь одна точка создаётся примерно каждые 50 метров.
Часто требуется связь между графиком и сценой.
При наведении на график:
Создание маркера:
const marker =
viewer.entities.add({
position: routePoint,
point: {
pixelSize: 12,
color: Cesium.Color.YELLOW
}
});
Пользователь получает возможность видеть местоположение участка рельефа непосредственно на глобусе.
Полезной является и обратная схема взаимодействия.
При выборе точки на карте:
handler.setInputAction(
function(click) {
const picked =
viewer.scene.pick(
click.position
);
},
Cesium.ScreenSpaceEventType.LEFT_CLICK
);
Можно:
Такой механизм широко применяется в профессиональных геоинформационных системах.
После формирования профиля легко получить статистику.
Минимальная высота:
const minHeight =
Math.min(
...profileData.map(
p => p.height
)
);
Максимальная:
const maxHeight =
Math.max(
...profileData.map(
p => p.height
)
);
Средняя:
const averageHeight =
profileData.reduce(
(sum, point) =>
sum + point.height,
0
) / profileData.length;
Набор высоты показывает суммарный подъём по маршруту.
Алгоритм:
let ascent = 0;
for (let i = 1; i < profileData.length; i++) {
const delta =
profileData[i].height -
profileData[i - 1].height;
if (delta > 0) {
ascent += delta;
}
}
Полученный результат выражается в метрах.
Аналогичным образом вычисляется общий спуск.
let descent = 0;
for (let i = 1; i < profileData.length; i++) {
const delta =
profileData[i].height -
profileData[i - 1].height;
if (delta < 0) {
descent += Math.abs(delta);
}
}
Уклон определяется отношением перепада высот к расстоянию.
Формула:
i=%
Пример:
const slope =
(heightDiff / distance) * 100;
Если подъём составил:
10 м
на участке:
200 м
то уклон равен:
5 %
Для поиска опасных зон профиль можно анализировать автоматически.
Например:
const dangerousSections = [];
for (let i = 1; i < profileData.length; i++) {
const dh =
profileData[i].height -
profileData[i - 1].height;
const dd =
profileData[i].distance -
profileData[i - 1].distance;
const slope =
Math.abs(dh / dd);
if (slope > 0.15) {
dangerousSections.push(i);
}
}
Подобные алгоритмы применяются при проектировании:
Источником высоты может выступать не только Terrain.
Для 3D Tiles можно получать координаты непосредственно из объектов сцены.
Например:
const position =
viewer.scene.pickPosition(
screenPosition
);
После выборки множества точек возможно построение профиля:
Иногда требуется анализ не рельефа, а траектории движения.
Пример:
entity.position
Для каждой временной отметки можно получать:
const position =
entity.position.getValue(
currentTime
);
После чего формируется профиль:
Время → Высота
Такой подход используется для:
Построение профилей на больших расстояниях может требовать тысячи запросов высот.
Для повышения производительности применяются следующие методы:
const cache = new Map();
Высоты для уже обработанных координат не запрашиваются повторно.
const count = 300;
В большинстве случаев 300–500 точек достаточно для качественного профиля.
await Cesium.sampleTerrainMostDetailed(
terrainProvider,
positions
);
Запросы выполняются без блокировки интерфейса.
Лучше отправлять один большой запрос:
sampleTerrainMostDetailed(
provider,
positions
);
чем множество мелких запросов в цикле.
Если используется только эллипсоид Земли:
viewer.terrainProvider
может возвращать нулевые значения высот.
Результатом станет плоский профиль.
Малое количество точек приводит к потере деталей рельефа.
Особенно заметно это в горных районах.
Высокодетализированные модели рельефа могут содержать локальные скачки высот.
Для сглаживания применяются:
Использование прямолинейного расстояния между точками может давать небольшие погрешности на длинных маршрутах.
Для высокой точности рекомендуется вычислять расстояния по геодезическим линиям.
Полноценный модуль профилей обычно включает следующие компоненты:
Map Module
↓
Route Builder
↓
Sampling Engine
↓
Terrain Query
↓
Profile Processor
↓
Chart Renderer
Такое разделение позволяет независимо развивать:
В крупных приложениях CesiumJS профили высот становятся важным инструментом пространственного анализа, объединяющим возможности трёхмерной визуализации, цифровых моделей рельефа и инженерных расчётов в единую аналитическую систему.