четверг, 24 апреля 2014 г.

Яндекс.Карты API. Расстояние от МКАД до указанной точки: увеличиваем точность.


Если вы потыкаете пример из прошлого поста про вычисление расстояния от МКАД, то увидите, что ближайшая точка - не всегда точка нужного съезда, и маршрут рисуется от неё. И как бы правильно мы не расставляли точки съездов, всегда найдётся неправильная точка, которая ближайшая к кликнутой точке, но не является нужным съездом.
Для приблизительных расчётов это нормально, но для пользователей это будет выглядеть некрасиво. А мы хотим вот так
маршрут от мкада (без развязок)



Додумалась я вот до такого.
1. Обрисовываем полигон МКАД "с припуском", потом увидите для чего. Для этого я быстренько накатала скриптик, который по кликам отдаёт мне координаты. Вы найдёте его в скачивании внизу статьи.
МКАД "с припуском"
 2. Строим полигон по полученным координатам МКАД. Из центра полигона (я его приблизительно тыкнула на карте) рисуем маршрут до кликнутой точки.
3. Полученный маршрут делим на отрезки и смотрим какие из них:
     А. лежат внутри полигона
     Б. пересекаются с полигоном
     В. лежат снаружи полигона
4. Из коллекции отрезков убираем те, которые лежат внутри полигона. Граничные и наружние нам и нужны. Спрашиваем координаты первого граничного отрезка - вот и получаем точку пересечения с МКАД.

Маршрут до кликнутой точки

Песочница яндекса вообще очень полезная вещь - там есть много нужных и полезных примеров (правда, ещё больше там нет). Деление маршрута на отрезки и нахождение пересечений с полигоном в песочнице как раз чётко показано. Мы выкусываем оттуда те знания, которые нам нужны: граничные и наружние отрезки находятся быстрее всего нахождением внутренних отрезков и вычитания из всей кучи этих найденных внутренних отрезков.
пример из песочницы
Для этого мы и сделали полигон чуть побольше: чтобы спокойно включить граничные отрезки в маршрут и чтобы проезд по мкаду до съезда не включать в расчёты. Насколько больше зависит от того, надо ли вам включать развязки в маршрут =)

Сегменты маршрута

Замечу, что для расчётов маршрут приходится добавлять на карту, однако его можно сделать невидимым, что значительно облегчает внешний вид расчётов.
var routeObjects = ymaps.geoQuery(edges).setOptions('visible', false).addToMap(myMap);
   
//находим сегменты, попадающие внутрь мкад
var objectsInMoscow = routeObjects.searchInside(mkad_polygon),
 //объекты за пределами МКАД получим исключением полученных выборок из исходной (так проще!).
 objectsOutMoscow = routeObjects.remove(objectsInMoscow),
 //находим начальную точку полученной выборки
 start_coords = objectsOutMoscow.get(0).geometry.getCoordinates()[1];

Получаем нечто вроде вот такого

В общем, смотрим в код - так куча комментов =)

Скачать файлы из статьи

6 комментариев:

  1. Спасибо! Самое удачное решение из того что видел.)

    ОтветитьУдалить
    Ответы
    1. пожалуйста, рада что пригодилось. правда, кажется, код из статьи хочет оптимизации =)

      Удалить
  2. велосипед блин изобрели. нафига какие-то выемки делать, если можно просто определить ТОЧКУ пересечения полигона мкад и маршрута и построить роутинг до этой точки пересечения?
    например, здесь так и сделано:
    http://web-finder.ru/yandeks-karty-rasstoyanie-do-blizhajshego-poligona

    ОтветитьУдалить
    Ответы
    1. изначально самой большой проблемой было нахождение точного полигона "бесплатной доставки". термином "мкад" у нас называлась любая область (полигон) бесплатной доставки. центром такого "мкада" служили координаты центра-склада магазина.
      невозможность точного построения полигона операторами породила приблизительность расчётов.

      для определённых координат, да, пересечение точечное лучше.

      я этой темой не занимаюсь уже приличное время, возможно алгоритм и перерос бы во что-то большее.

      спасибо за содержательный комментарий!

      Удалить
  3. К сожалению файлы по ссылке больше не доступны(

    ОтветитьУдалить