Азимут (bearing) между двумя географическими точками представляет собой угол направления от одной точки к другой относительно северного направления. В контексте веб-картографии и Mapbox GL JS этот параметр используется для вычисления направления линии, поворота камеры, ориентации маркеров и построения маршрутов с корректной геометрией направления.
На сфере направление между двумя координатами не является прямой линией в декартовой системе координат. Оно определяется как начальный курс великого круга (initial bearing), который показывает, под каким углом относительно географического севера необходимо двигаться из точки A в точку B.
Основные особенности:
Для расчёта начального азимута между двумя точками на сфере используются тригонометрические преобразования с учётом широты и долготы.
Пусть:
Все углы переводятся в радианы.
Формула начального азимута:
= (()(_2),; (_1)(_2) - (_1)(_2)())
где:
Результат затем переводится из радиан в градусы и нормализуется в диапазон 0–360°:
Mapbox GL JS работает с координатами в формате
[longitude, latitude], однако тригонометрические функции
требуют радианы.
function toRadians(deg) {
return deg * Math.PI / 180;
}
function toDegrees(rad) {
return rad * 180 / Math.PI;
}
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;
}
Функция возвращает начальный азимут от первой точки ко второй.
В экосистеме 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 позволяет управлять углом поворота карты через параметр
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° долготы, необходимо учитывать корректную разницу долгот:
При очень близких точках значения sin и cos могут приводить к потере точности, что делает результат нестабильным. В таких случаях применяются пороговые проверки расстояния.
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);
Это создаёт трёхмерное восприятие направления движения и усиливает визуальную глубину маршрутов.
Вектор направления между точками используется в следующих сценариях: