Сравнение маршрутов для GPX и KML
В примере показано, как сравнить между собой два маршрута: найти их общие участки и отклонения.
Первый маршрут будем считать эталонным, второй - пройденным по факту. Маршруты загружаются в формате KML или GPX.
Для каждой точки пройденного маршрута вычисляется расстояние до ближайшей точки эталонного маршрута(берутся точки, с помощью которых описан маршрут). Расстояние вычисляется с помощью getClosest().
Если полученное расстояние больше заданной точности (точность задается в переменной diff), то считаем, что маршруты в этой точке не совпадают. В балуне будем выводить протяженность отклонения от эталонного маршрута.
Отклонения от эталонного маршрута отображаются на карте красным цветом.
Для загрузки данных используется функция geoXml.load.
<!DOCTYPE html>
<head>
<title>Сравнение маршрутов для GPX и KML</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!--
Укажите свой API-ключ. Тестовый ключ НЕ БУДЕТ работать на других сайтах.
Получить ключ можно в Кабинете разработчика: https://developer.tech.yandex.ru/keys/
-->
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU&load=package.full,vow&apikey=<ваш API-ключ>" type="text/javascript"></script>
<script src="tracks_compare.js" type="text/javascript"></script>
<style type="text/css">
html, body, #map {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<div id="map"></div>
</body>
</html>
ymaps.ready(init);
function init() {
var myMap = new ymaps.Map("map", {
center: [59.9567962610097, 30.264981955459618],
zoom: 9,
});
// Ссылка на запланированный путь в формате kml/gpx.
var originalTrackUrl = "original.gpx",
// Ссылка на путь в формате kml/gpx, который будем сравнивать с запланированным путем.
comparableTrackUrl = "comparable.gpx",
// Допустимая разница в метрах.
diff = 1;
// Сравним два пути.
compare(originalTrackUrl, comparableTrackUrl);
// Метод, который добавляет два пути на карту и сравнивает их.
function compare(originalTrackUrl, comparableTrackUrl) {
// Создадим коллекцию участков пути, которые не совпадают с запланированным путем.
var collection = new ymaps.GeoObjectCollection(
{},
{
strokeColor: "#FF0000",
strokeWidth: 3,
}
);
// Дожидаемся загрузки файлов.
ymaps.vow
.all([
ymaps.geoXml.load(originalTrackUrl),
ymaps.geoXml.load(comparableTrackUrl),
])
.then(
function (res) {
// Получаем запланированный путь.
var originalTrack = res[0].geoObjects.get(0),
// Получаем сравниваемый путь.
comparableTrack = res[1].geoObjects.get(0);
// Для kml есть ещё один уровень вложенности.
if (!originalTrack.geometry) {
originalTrack = originalTrack.get(0);
comparableTrack = comparableTrack.get(0);
}
// Получаем геометрию запланированного пути.
var originalGeometry = originalTrack.geometry,
// Получаем геометрию для сравниваемого пути.
comparableGeometry = comparableTrack.geometry,
// Счётчик количества точек, которые не совпали с запланированным маршрутом.
diffPoints = 0;
// Изменим толщину и цвет путей, после чего добавим их на карту.
originalTrack.options.set({
strokeWidth: 3,
strokeColor: "#4585E6",
});
comparableTrack.options.set({
strokeWidth: 3,
strokeColor: "#4585E6",
});
myMap.geoObjects
.add(originalTrack)
.add(comparableTrack);
// Выставим границы карты так, чтобы отобразились сравниваемые пути.
myMap.setBounds(myMap.geoObjects.getBounds());
for (
var i = 0, isNotEqual, isPreviousNotEqual = false;
i < comparableGeometry.getLength();
i++
) {
// Проверим, что от каждой точки сравниваемого пути расстояние до запланированного пути меньше допустимого.
isNotEqual =
originalGeometry.getClosest(
comparableGeometry.get(i)
).distance > diff;
if (isNotEqual) {
// Инкрементируем счетчик количества точек, которые не совпали с запланированным маршрутом.
diffPoints++;
// Сохраняем состояние для следующей итерации.
isPreviousNotEqual = true;
// Пропускаем одну итерацию в случае несовпадения начальных точек.
if (i === 0) continue;
// Добавим в коллекцию участок пути от предыдущей точки до текущей точки, которая не лежит
// на запланированном маршруте.
collection.add(
new ymaps.Polyline([
comparableGeometry.get(i - 1),
comparableGeometry.get(i),
])
);
} else if (isPreviousNotEqual) {
// Добавим в коллекцию участок пути от предыдущей точки, которая не лежит на запланированном маршруте,
// до текущей точки.
collection.add(
new ymaps.Polyline([
comparableGeometry.get(i - 1),
comparableGeometry.get(i),
])
);
// Сохраняем состояние для следующей итерации.
isPreviousNotEqual = false;
}
}
// Добавим коллекцию на карту.
myMap.geoObjects.add(collection);
// Получим протяженность отличающихся участков.
var diffDistance = 0;
collection.each(function (obj) {
diffDistance += obj.geometry.getDistance();
});
diffDistance = Math.round(diffDistance);
// Получим протяженность сравниваемого пути.
var comparableDistance =
comparableGeometry.getDistance(),
// Получим сколько процентов пройдено вне запланированного пути.
diffDistanceRatio = Math.abs(
(100 * diffDistance) / comparableDistance
).toFixed(1),
// Сформируем текст для балуна.
content =
"Красные участки - отклонения от запланированного пути. <br> Вне запланированного пути пройдено %k м (%m %).";
content = content
.replace("%k", diffDistance)
.replace("%m", diffDistanceRatio);
// Добавим новый текст для балунов всех путей.
originalTrack.properties.set("balloonContent", content);
comparableTrack.properties.set(
"balloonContent",
content
);
collection.each(function (obj) {
obj.properties.set("balloonContent", content);
});
// Откроем балун на запланированном пути.
originalTrack.balloon.open();
},
function (error) {
console.log("Ошибка: " + error);
}
);
}
}