Расчет расстояний

В веб-картах координаты всегда задаются в географической системе WGS84: долгота (lng) и широта (lat). В контексте Mapbox GL JS расчёт расстояний опирается не на плоскую евклидову геометрию, а на сферическую модель Земли.

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

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


LngLat и встроенный расчёт расстояний

Базовый объект координат в Mapbox GL JS — mapboxgl.LngLat.

Он предоставляет метод:

const a = new mapboxgl.LngLat(30.3141, 59.9386);
const b = new mapboxgl.LngLat(37.6173, 55.7558);

const distance = a.distanceTo(b);
console.log(distance);

Особенности distanceTo

  • возвращает расстояние в метрах
  • использует геодезическую модель Земли
  • учитывает кривизну эллипсоида
  • подходит для большинства прикладных задач (логистика, UI, аналитика)

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


Формула гаверсинуса как основа геодезических вычислений

Для понимания механики расчёта используется классическая формула:

d = 2R ()

где:

  • φ — широта
  • λ — долгота
  • R — радиус Земли (≈ 6371000 м)

Эта формула устойчива к численным ошибкам на малых расстояниях и широко используется в GIS-системах.


Когда использовать Turf.js вместо встроенных методов

В экосистеме Mapbox часто применяется библиотека Turf.js для геоаналитики.

Пример расчёта расстояния:

import distance from '@turf/distance';

const from = [30.3141, 59.9386];
const to = [37.6173, 55.7558];

const result = distance(from, to, { units: 'kilometers' });
console.log(result);

Отличия подходов

LngLat.distanceTo

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

Turf.js

  • поддержка множества единиц измерения
  • расширенные геооперации (полигоны, буферы, пересечения)
  • удобен для аналитики

Евклидово расстояние в экранных координатах

Mapbox GL JS работает с двумя системами координат:

  • географические (lng/lat)
  • экранные (pixel coordinates)

Для UI-задач часто требуется расстояние в пикселях:

const p1 = map.project([30.3141, 59.9386]);
const p2 = map.project([37.6173, 55.7558]);

const dx = p2.x - p1.x;
const dy = p2.y - p1.y;

const pixelDistance = Math.sqrt(dx * dx + dy * dy);

Этот расчёт не геодезический, а плоский, и используется для:

  • кластеризации маркеров
  • hover-интеракций
  • drag-событий
  • collision detection в слоях

Искажения проекции Mercator

Mapbox GL JS использует проекцию Web Mercator.

Следствия:

  • расстояния искажаются на высоких широтах
  • площадь объектов визуально увеличивается к полюсам
  • прямые линии на карте не всегда являются геодезическими

Поэтому важно различать:

Тип расстояния Где применяется Точность
Геодезическое аналитика, маршруты высокая
Экранное UI, события условная

Антиподальные точки и пересечение 180° меридиана

Особая проблема возникает при пересечении антимеридиана:

const a = new mapboxgl.LngLat(179, 10);
const b = new mapboxgl.LngLat(-179, 10);

console.log(a.distanceTo(b));

Хотя визуально точки рядом, численно долготы сильно отличаются.

Решение внутри Mapbox GL JS:

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

Расчёт расстояния для маршрутов

В задачах маршрутизации расстояние между двумя точками — лишь базовый элемент.

Типичный пайплайн:

  1. получение координат
  2. расчёт геодезического расстояния
  3. построение графа дорог
  4. оптимизация пути

Пример предварительной оценки:

function roughDistance(a, b) {
  return a.distanceTo(b);
}

Это используется как heuristic в A* и Dijkstra.


Работа с большим количеством точек

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

Пример:

const points = [
  [30.1, 59.9],
  [30.2, 59.8],
  [30.3, 59.7]
];

let total = 0;

for (let i = 1; i < points.length; i++) {
  const a = new mapboxgl.LngLat(...points[i - 1]);
  const b = new mapboxgl.LngLat(...points[i]);
  total += a.distanceTo(b);
}

Оптимизация

  • избегать постоянного создания объектов LngLat
  • использовать кэширование координат
  • применять batch-обработку в аналитике

Геодезические ограничения и точность

Любой расчёт расстояний в Mapbox GL JS имеет ограничения:

  • Земля моделируется как сфера/эллипсоид
  • локальные погрешности до нескольких метров
  • на больших расстояниях возможны отклонения

Для высокоточной геодезии применяются:

  • PROJ4
  • специализированные GIS-библиотеки
  • серверные геодезические движки

Комбинирование расстояний с визуализацией

Расстояния часто используются для динамических эффектов:

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

Пример фильтрации:

const center = new mapboxgl.LngLat(30.3141, 59.9386);

const filtered = points.filter(p => {
  const d = center.distanceTo(new mapboxgl.LngLat(...p));
  return d < 5000;
});

Радиусы и визуальные зоны

При построении зон влияния часто используется приближение окружности в географических координатах:

const radius = 1000; // метров

Дальнейшее преобразование требует:

  • пересчёта метров в градусы
  • учёта широты
  • компенсации искажений Mercator

В аналитических задачах чаще применяется Turf.js buffer, который учитывает геодезию корректнее, чем ручные расчёты.


Сравнение методов расчёта расстояний

Метод Точность Производительность Применение
LngLat.distanceTo высокая высокая базовые вычисления
Turf.js distance высокая средняя аналитика
Евклидово (pixels) условная очень высокая UI

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

  • UI события → экранные координаты
  • фильтрация объектов → LngLat.distanceTo
  • аналитика и геообработка → Turf.js
  • сложные геометрии → специализированные GIS-инструменты