---
metadata:
  - name: generator
    content: Diplodoc Platform v5.39.1
alternate:
  - https://yandex.com.tr/dev/jsapi-v2-1/doc/ru/v2-1/examples/cases/tracks_compare.md
---
> **Documentation Index:** Fetch the complete configuration index at https://yandex.com.tr/dev/jsapi-v2-1/doc/ru/llms.txt

# Сравнение маршрутов для GPX и KML

<iframe id="LIVE-EXAMPLE" style="width:100%;height: 400px;border-radius: 8px;border: 1px solid rgba(92, 94, 102, 0.14);" frameBorder="0" src="https://yastatic.net/s3/front-maps-static/maps-front-jsapi-v2-1/examples/2/out/s3-cases/ru/tracks_compare/index.html" allow="fullscreen"></iframe>

<a target="_blank" rel="noopener noreferrer" style="display: inline-block;margin-top: 10px;cursor: pointer;border-radius: 4px;padding: 9px 12px;background: #151515;color: white;text-decoration: none;font-weight: 500" href="https://codesandbox.io/p/sandbox/jws9v4?file=index.html">Open in CodeSandbox</a>

<div id="references">
    <a href="https://yandex.ru/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/ready">ready</a>,
    <a href="https://yandex.ru/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/Map">Map</a>,
    <a href="https://yandex.ru/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/map.GeoObjects">map.GeoObjects</a>,
    <a href="https://yandex.ru/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/GeoObjectCollection">GeoObjectCollection</a>,
    <a href="https://yandex.ru/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/geoXml.load">geoXml.load</a>,
    <a href="https://yandex.ru/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/vow">vow</a>
</div>
<p>
    В примере показано, как сравнить между собой два маршрута: найти их общие участки и отклонения.
</p>
<p>
    Первый маршрут будем считать эталонным, второй - пройденным по факту. Маршруты загружаются в формате KML или GPX.
</p>
<p>
    Для каждой точки пройденного маршрута вычисляется  расстояние до ближайшей точки эталонного маршрута(берутся точки, с помощью которых описан маршрут). Расстояние вычисляется с помощью <a href="https://yandex.ru/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/ILineStringGeometryAccess-docpage/#getClosest">getClosest()</a>.
</p>
<p>
    Если полученное расстояние больше заданной точности (точность задается в переменной diff), то считаем, что маршруты в этой точке не совпадают. В балуне будем выводить протяженность отклонения от эталонного маршрута.
</p>
<p>
    Отклонения от эталонного маршрута отображаются на карте красным цветом.
</p>
<p>
    Для загрузки данных используется функция <a href="https://yandex.ru/dev/jsapi-v2-1/doc/ru/v2-1/ref/reference/geoXml.load">geoXml.load</a>.
</p>

{% list tabs %}

-   index.html

    ```html
      <!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/
        -->
        
        
        
    </head>
    <body>
    <div id="map"></div>
    </body>
    </html>
    ```

-   tracks_compare.js

    ```js
    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);
                    }
                );
        }
    }
    ```

{% endlist %}
