Профиль маршрутизации — это набор правил, по которым вычисляется путь между точками на карте. В основе профиля лежит функция стоимости (cost function), определяющая, какой маршрут считается оптимальным. Оптимальность может означать минимальное время, минимальное расстояние, наименьший расход топлива или соблюдение специфических ограничений (например, избегание платных дорог или грунтовых участков).
В системах маршрутизации профиль формирует поведение алгоритма поиска пути на графе дорог. Один и тот же граф может давать разные маршруты в зависимости от выбранного профиля:
Профиль задаёт:
MapLibre GL JS не выполняет маршрутизацию самостоятельно. Его задача — визуализация:
Маршрутизация выполняется внешними сервисами:
MapLibre GL JS лишь:
Типичная схема:
Пример структуры ответа маршрутизатора:
{
"routes": [
{
"geometry": {
"type": "LineString",
"coordinates": [
[73.1, 49.8],
[73.2, 49.85]
]
},
"distance": 5230,
"duration": 620
}
]
}
Автомобильный профиль ориентирован на минимизацию времени или расстояния с учётом дорожной сети.
Ключевые параметры:
Пример запроса OSRM:
GET /route/v1/driving/73.1,49.8;73.2,49.85?overview=full&geometries=geojson
Параметр driving — это профиль маршрутизации.
Пешеходный профиль учитывает:
Он может отдавать предпочтение:
Пример:
GET /route/v1/foot/73.1,49.8;73.2,49.85
Велосипедные профили более сложны, чем пешеходные, поскольку учитывают:
В GraphHopper профиль может быть задан как:
profiles:
- name: bike
vehicle: bike
weighting: fastest
Профиль маршрутизации обычно включает:
Определяет стоимость ребра графа:
cost = time + penalties + restrictions
Где:
Каждому типу дороги назначается скорость:
| Тип дороги | Скорость (км/ч) |
|---|---|
| motorway | 110 |
| primary | 80 |
| residential | 40 |
| track | 20 |
Повороты могут увеличивать стоимость маршрута:
MapLibre GL JS работает с результатом маршрутизации как с GeoJSON-источником.
map.addSource('route', {
type: 'geojson',
data: {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: []
}
}
});
map.addLayer({
id: 'route-line',
type: 'line',
source: 'route',
paint: {
'line-color': '#3b82f6',
'line-width': 5
}
});
async function getRoute(start, end) {
const response = await fetch(
`https://router.example.com/route/v1/driving/${start};${end}?geometries=geojson`
);
const data = await response.json();
const route = data.routes[0].geometry;
map.getSource('route').setData({
type: 'Feature',
geometry: route
});
}
Одна из ключевых задач интерфейса — динамическая смена профиля.
Пример логики:
let currentProfile = 'driving';
function setProfile(profile) {
currentProfile = profile;
updateRoute();
}
Запрос:
fetch(`https://router.example.com/route/v1/${currentProfile}/${coords}`)
Один и тот же маршрут может существенно отличаться:
В интерфейсах часто реализуется:
Особенности:
Оптимизация:
Использует:
В GraphHopper и OSRM можно создавать собственные профили.
Пример логики кастомного профиля:
function edgeWeight(edge) {
let weight = edge.distance / edge.speed;
if (edge.roadType === 'residential') {
weight *= 1.2;
}
if (edge.isToll) {
weight += 30;
}
return weight;
}
Хотя обычно маршрутизация выполняется сервером, возможен гибридный подход:
Это применяется в:
MapLibre GL JS позволяет визуально различать профили:
Пример стилизации:
paint: {
'line-color': [
'match',
['get', 'profile'],
'driving', '#2563eb',
'walking', '#16a34a',
'cycling', '#f97316',
'#000000'
],
'line-width': 4
}
При большом количестве запросов профили маршрутизации становятся узким местом.
Используются оптимизации:
Частые проблемы:
Обычно интерфейс включает:
При этом карта остаётся чисто визуальным слоем, а вся логика маршрутизации вынесена в отдельный сервисный слой архитектуры.