Измерительные операции в картографических приложениях используются для вычисления расстояний, длин маршрутов, площадей полигонов, размеров объектов и координатных смещений. Несмотря на визуальную простоту подобных вычислений, точность результатов зависит от множества факторов:
При разработке профессиональных геоинформационных систем важно понимать ограничения каждой методики измерений и выбирать подходящие алгоритмы в зависимости от поставленной задачи.
MapLibre GL JS работает с координатами в системе WGS84, которая является мировым стандартом для GPS и веб-картографии.
Каждая точка задаётся двумя значениями:
[longitude, latitude]
Пример:
const point = [37.6176, 55.7558];
Здесь:
37.6176 — долгота;55.7558 — широта.Особенность географических координат заключается в том, что они выражаются в градусах, а не в метрах. Поэтому нельзя напрямую вычислять расстояние между двумя точками через обычную теорему Пифагора.
Неправильный подход:
const dx = lon2 - lon1;
const dy = lat2 - lat1;
const distance = Math.sqrt(dx * dx + dy * dy);
Подобный расчёт даёт результат в градусах и становится всё менее точным по мере удаления от экватора.
Для отображения карты MapLibre GL JS использует веб-проекцию Mercator.
Она обладает важным свойством:
Чем ближе объект расположен к полюсам, тем сильнее проявляются искажения.
Например:
Поэтому измерения непосредственно в экранных координатах практически всегда приводят к ошибкам.
Наиболее корректный способ измерения расстояния между двумя точками заключается в расчёте длины дуги на поверхности земного эллипсоида.
На практике часто используется сферическая модель Земли.
Радиус Земли:
const EARTH_RADIUS = 6371008.8;
Для вычислений применяется формула гаверсинусов.
Формула позволяет вычислить расстояние между двумя точками по их широте и долготе.
d=2R()
Где:
R — радиус Земли;φ — широта;λ — долгота.Пример реализации:
function haversineDistance(start, end) {
const R = 6371008.8;
const lat1 = start[1] * Math.PI / 180;
const lat2 = end[1] * Math.PI / 180;
const dLat = (end[1] - start[1]) * Math.PI / 180;
const dLon = (end[0] - start[0]) * Math.PI / 180;
const a =
Math.sin(dLat / 2) ** 2 +
Math.cos(lat1) *
Math.cos(lat2) *
Math.sin(dLon / 2) ** 2;
const c = 2 * Math.atan2(
Math.sqrt(a),
Math.sqrt(1 - a)
);
return R * c;
}
Использование:
const distance = haversineDistance(
[37.6176, 55.7558],
[30.3141, 59.9386]
);
console.log(distance);
Результат возвращается в метрах.
Наиболее распространённым инструментом для измерений совместно с MapLibre GL JS является библиотека Turf.js.
Подключение:
<script src="https://unpkg.com/@turf/turf@latest/turf.min.js"></script>
Расчёт расстояния:
const from = turf.point([37.6176, 55.7558]);
const to = turf.point([30.3141, 59.9386]);
const distance = turf.distance(
from,
to,
{ units: 'kilometers' }
);
console.log(distance);
Преимущества:
Линейные объекты редко состоят из двух точек.
Обычно маршрут представляет собой набор вершин:
const route = {
type: "Feature",
geometry: {
type: "LineString",
coordinates: [
[37.6176, 55.7558],
[37.5, 55.8],
[37.3, 55.9]
]
}
};
Длина вычисляется суммированием всех сегментов.
Через Turf.js:
const length = turf.length(
route,
{
units: 'kilometers'
}
);
console.log(length);
Библиотека автоматически учитывает геодезическую модель и выполняет вычисления значительно точнее простого суммирования экранных расстояний.
Точность длины линии зависит от количества промежуточных точек.
Маршрут:
A ----------- B
обычно оказывается менее точным, чем:
A --- C --- D --- E --- B
Причина заключается в том, что реальная дорога имеет изгибы.
При недостаточном количестве вершин линия начинает срезать повороты.
Следствие:
Для дорожных сетей и треков GPS рекомендуется использовать максимально подробную геометрию.
Площадь является одной из наиболее чувствительных к проекции характеристик.
Пример полигона:
const polygon = {
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [[
[37.6, 55.7],
[37.7, 55.7],
[37.7, 55.8],
[37.6, 55.8],
[37.6, 55.7]
]]
}
};
Расчёт площади:
const area = turf.area(polygon);
console.log(area);
Результат возвращается в квадратных метрах.
Для площади ошибка возрастает быстрее, чем для расстояния.
Причины:
Даже небольшая ошибка в координатах может привести к существенному отклонению итоговой площади.
Во многих приложениях измерения основаны на данных GPS.
Типичная точность:
| Условия | Погрешность |
|---|---|
| Открытая местность | 3–5 м |
| Городская среда | 5–15 м |
| Плотная застройка | 10–30 м |
| Помещение | десятки метров |
Полученная координата уже содержит некоторую ошибку.
Если измеряется расстояние между двумя GPS-точками:
navigator.geolocation.getCurrentPosition(
position => {
console.log(
position.coords.accuracy
);
}
);
Свойство:
position.coords.accuracy
указывает радиус возможной ошибки в метрах.
Особенно заметны ошибки при измерении небольших расстояний.
Пример:
Итоговая погрешность может оказаться больше самой измеряемой дистанции.
Поэтому для коротких расстояний желательно использовать:
MapLibre GL JS предоставляет методы преобразования между координатами карты и экраном.
Преобразование в пиксели:
const pixel =
map.project([37.6176, 55.7558]);
Обратное преобразование:
const lngLat =
map.unproject([200, 300]);
Однако расстояние между пикселями:
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
const pixels =
Math.sqrt(dx * dx + dy * dy);
не является реальным расстоянием на поверхности Земли.
Такой расчёт подходит лишь для:
На разных уровнях масштабирования один и тот же пиксель соответствует различному расстоянию.
Например:
| Zoom | Размер пикселя |
|---|---|
| 3 | километры |
| 10 | десятки метров |
| 18 | сантиметры |
Следовательно, фиксированное количество пикселей не может использоваться как универсальная единица измерения.
Для задач трёхмерной визуализации применяется класс:
maplibregl.MercatorCoordinate
Пример:
const mercator =
maplibregl.MercatorCoordinate
.fromLngLat(
[37.6176, 55.7558],
0
);
const scale =
mercator.meterInMercatorCoordinateUnits();
Метод возвращает коэффициент пересчёта метров в координаты Mercator.
Это особенно важно при работе с:
Каждый сегмент маршрута содержит небольшую погрешность.
Если длина маршрута составляет:
1000 сегментов
то суммарная ошибка может оказаться значительной.
Поэтому рекомендуется:
Пример удаления аномальных точек:
const filtered = points.filter(
point => point.speed < 50
);
Более сложные методы:
После обработки точность измерений длины маршрута обычно существенно возрастает.
Некорректная геометрия может приводить к ошибочным результатам измерения площади.
Пример проблемной фигуры:
X
\\
\\
/ /
/
X
При наличии самопересечений разные алгоритмы могут возвращать различные результаты.
Проверка:
const kinks = turf.kinks(polygon);
Если найдено пересечение:
kinks.features.length > 0
геометрию необходимо исправить до вычисления площади.
GeoJSON хранит координаты в виде чисел с плавающей запятой.
Полная запись:
37.617683123456
Округлённая запись:
37.6177
Для большинства веб-карт используется точность:
| Знаков после запятой | Точность |
|---|---|
| 3 | около 100 м |
| 4 | около 10 м |
| 5 | около 1 м |
| 6 | около 10 см |
| 7 | около 1 см |
Чрезмерное округление может заметно ухудшать результаты измерений.
Для измерения расстояний:
Для измерения площадей:
Для GPS-данных:
Для профессиональных ГИС-систем: