Bearing между точками

Азимут (bearing) между двумя географическими точками представляет собой угол направления от одной точки к другой относительно северного направления. В контексте веб-картографии и Mapbox GL JS этот параметр используется для вычисления направления линии, поворота камеры, ориентации маркеров и построения маршрутов с корректной геометрией направления.

На сфере направление между двумя координатами не является прямой линией в декартовой системе координат. Оно определяется как начальный курс великого круга (initial bearing), который показывает, под каким углом относительно географического севера необходимо двигаться из точки A в точку B.

Основные особенности:

  • значение измеряется в градусах
  • диапазон обычно от 0° до 360°
  • 0° соответствует северу
  • 90° — востоку
  • 180° — югу
  • 270° — западу

Математическая основа вычисления

Для расчёта начального азимута между двумя точками на сфере используются тригонометрические преобразования с учётом широты и долготы.

Пусть:

  • φ₁ — широта первой точки
  • φ₂ — широта второй точки
  • λ₁ — долгота первой точки
  • λ₂ — долгота второй точки

Все углы переводятся в радианы.

Формула начального азимута:

= (()(_2),; (_1)(_2) - (_1)(_2)())

где:

  • Δλ = λ₂ − λ₁

Результат затем переводится из радиан в градусы и нормализуется в диапазон 0–360°:

  • если θ < 0°, то θ = θ + 360°

Преобразование координат

Mapbox GL JS работает с координатами в формате [longitude, latitude], однако тригонометрические функции требуют радианы.

function toRadians(deg) {
    return deg * Math.PI / 180;
}

function toDegrees(rad) {
    return rad * 180 / Math.PI;
}

Реализация вычисления bearing без сторонних библиотек

function calculateBearing([lon1, lat1], [lon2, lat2]) {
    const φ1 = toRadians(lat1);
    const φ2 = toRadians(lat2);
    const λ1 = toRadians(lon1);
    const λ2 = toRadians(lon2);

    const Δλ = λ2 - λ1;

    const y = Math.sin(Δλ) * Math.cos(φ2);
    const x = Math.cos(φ1) * Math.sin(φ2) -
              Math.sin(φ1) * Math.cos(φ2) * Math.cos(Δλ);

    let θ = Math.atan2(y, x);
    θ = toDegrees(θ);

    return (θ + 360) % 360;
}

Функция возвращает начальный азимут от первой точки ко второй.

Использование Turf.js

В экосистеме Mapbox часто применяется библиотека Turf.js, где уже реализованы геодезические вычисления.

import { bearing } from "@turf/turf";

const from = [37.6173, 55.7558]; // Москва
const to = [30.3351, 59.9343];   // Санкт-Петербург

const angle = bearing(from, to);

Особенности Turf.js:

  • автоматически нормализует координаты
  • учитывает сферическую модель Земли
  • возвращает значение в градусах

Применение в Mapbox GL JS

Поворот камеры по направлению между точками

Mapbox позволяет управлять углом поворота карты через параметр bearing.

map.setCenter([37.6173, 55.7558]);

const angle = calculateBearing(
    [37.6173, 55.7558],
    [30.3351, 59.9343]
);

map.setBearing(angle);

Это создаёт эффект ориентации карты по направлению движения между точками.

Ориентация маркера

Для визуального обозначения направления часто используется поворот символа:

map.addLayer({
    id: "arrow",
    type: "symbol",
    source: "route",
    layout: {
        "icon-image": "arrow-icon",
        "icon-rotate": [
            "get",
            "bearing"
        ],
        "icon-rotation-alignment": "map"
    }
});

Значение bearing можно заранее вычислить и добавить в GeoJSON:

const feature = {
    type: "Feature",
    geometry: {
        type: "Point",
        coordinates: [30.3351, 59.9343]
    },
    properties: {
        bearing: calculateBearing(
            [37.6173, 55.7558],
            [30.3351, 59.9343]
        )
    }
};

Построение направленных линий

При работе с маршрутами направление между сегментами часто вычисляется для каждого отрезка:

function addBearingsToLine(coordinates) {
    const result = [];

    for (let i = 0; i < coordinates.length - 1; i++) {
        const from = coordinates[i];
        const to = coordinates[i + 1];

        const angle = calculateBearing(from, to);

        result.push({
            from,
            to,
            bearing: angle
        });
    }

    return result;
}

Использование в анимации движения

При анимации объекта по маршруту направление помогает корректно поворачивать маркер:

function animateMarker(map, marker, path) {
    let index = 0;

    function step() {
        if (index >= path.length - 1) return;

        const current = path[index];
        const next = path[index + 1];

        const angle = calculateBearing(current, next);

        marker.setLngLat(current);
        marker.setRotation(angle);

        index++;
        requestAnimationFrame(step);
    }

    step();
}

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

Полюса

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

Антимеридиан

Если координаты пересекают ±180° долготы, необходимо учитывать корректную разницу долгот:

  • naive subtraction даёт ошибку
  • требуется нормализация Δλ в диапазон [-π, π]

Численная устойчивость

При очень близких точках значения sin и cos могут приводить к потере точности, что делает результат нестабильным. В таких случаях применяются пороговые проверки расстояния.

Интеграция с GeoJSON источниками

Mapbox GL JS часто работает с GeoJSON, где bearing добавляется как вычисляемое свойство:

const geojson = {
    type: "FeatureCollection",
    features: [
        {
            type: "Feature",
            geometry: {
                type: "LineString",
                coordinates: [
                    [37.6173, 55.7558],
                    [30.3351, 59.9343]
                ]
            },
            properties: {
                bearing: calculateBearing(
                    [37.6173, 55.7558],
                    [30.3351, 59.9343]
                )
            }
        }
    ]
};

Комбинация с углом наклона карты

В Mapbox GL JS параметр bearing часто используется совместно с pitch:

map.setBearing(45);
map.setPitch(60);

Это создаёт трёхмерное восприятие направления движения и усиливает визуальную глубину маршрутов.

Практическое значение в визуализации

Вектор направления между точками используется в следующих сценариях:

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