В Google Maps JavaScript API работа с маршрутами через DirectionsService включает задачу упорядочивания промежуточных точек (waypoints) для минимизации общего расстояния или времени в пути. Эта задача относится к классу NP-трудных задач маршрутизации, и в реальных сценариях решается приближёнными методами — как на стороне API, так и в пользовательской логике.
Маршрут в Directions API задаётся через три ключевых компонента:
origin — начальная точкаdestination — конечная точкаwaypoints — промежуточные точкиКаждая промежуточная точка может быть фиксированной или оптимизируемой.
const request = {
origin: "Almaty, Kazakhstan",
destination: "Astana, Kazakhstan",
waypoints: [
{ location: "Karaganda, Kazakhstan", stopover: true },
{ location: "Balkhash, Kazakhstan", stopover: true }
],
travelMode: google.maps.TravelMode.DRIVING
};
Google Maps JavaScript API предоставляет параметр
optimizeWaypoints, который включает автоматическую
перестановку промежуточных точек для сокращения общего маршрута.
const request = {
origin: "Almaty",
destination: "Astana",
waypoints: [
{ location: "Balkhash", stopover: true },
{ location: "Karaganda", stopover: true }
],
optimizeWaypoints: true,
travelMode: google.maps.TravelMode.DRIVING
};
После выполнения запроса API возвращает:
directionsService.route(request, (result, status) => {
if (status === "OK") {
console.log(result.routes[0].waypoint_order);
}
});
waypoint_order — массив индексов, отражающий новый
порядок точек.
Внутри Google Maps JavaScript API используется эвристика, приближённая к задаче коммивояжёра (TSP). Алгоритм:
Особенность: оптимизация выполняется только для промежуточных точек, origin и destination остаются фиксированными.
Использование optimizeWaypoints имеет ряд
ограничений:
При большом количестве точек результат может быть субоптимальным.
Для кастомной оптимизации используется Distance Matrix Service:
const service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: points,
destinations: points,
travelMode: google.maps.TravelMode.DRIVING
}, callback);
Результат — матрица расстояний N × N, которая
используется для построения маршрута.
Один из базовых методов оптимизации порядка:
function nearestNeighbor(points, startIndex = 0) {
const visited = new Array(points.length).fill(false);
const order = [startIndex];
visited[startIndex] = true;
for (let i = 1; i < points.length; i++) {
const last = order[order.length - 1];
let nearest = -1;
let bestDist = Infinity;
for (let j = 0; j < points.length; j++) {
if (!visited[j] && distance[last][j] < bestDist) {
bestDist = distance[last][j];
nearest = j;
}
}
order.push(nearest);
visited[nearest] = true;
}
return order;
}
Характеристики:
После начального решения применяется локальная оптимизация:
function twoOpt(route) {
let improved = true;
while (improved) {
improved = false;
for (let i = 1; i < route.length - 2; i++) {
for (let k = i + 1; k < route.length - 1; k++) {
const newRoute = route.slice(0, i)
.concat(route.slice(i, k + 1).reverse())
.concat(route.slice(k + 1));
if (cost(newRoute) < cost(route)) {
route = newRoute;
improved = true;
}
}
}
}
return route;
}
Этот подход часто даёт более качественные маршруты, чем встроенная оптимизация.
Оптимизация порядка точек напрямую связана с экономией запросов к Google Maps JavaScript API:
Кластеризация может выполняться алгоритмами:
При большом наборе точек маршрут разбивается на подзадачи:
Такой подход уменьшает сложность с O(n²) до нескольких меньших задач.
Комбинированные стратегии:
function simulatedAnnealing(route, temp) {
while (temp > 1) {
const newRoute = swapRandom(route);
if (acceptanceProbability(cost(route), cost(newRoute), temp) > Math.random()) {
route = newRoute;
}
temp *= 0.99;
}
return route;
}
Оптимизация в Google Maps JavaScript API основана на:
Это приводит к особенностям:
При большом количестве точек применяется:
Это позволяет уменьшить задержки при построении маршрутов в интерфейсах реального времени.
Типичный pipeline:
После вычисления порядка точек важна оптимизация рендера:
google.maps.MarkerПри росте числа точек применяются ограничения:
В системах логистики маршрут часто пересчитывается динамически:
Это снижает нагрузку на Google Maps JavaScript API и улучшает отзывчивость интерфейса.