Маршрутизация карты, а-ля Google Maps?

Меня всегда заинтриговала Map Routing, но я никогда не находил по ней хороших руководств начального (или даже продвинутого!) Уровня. Есть ли у кого-нибудь указатели, подсказки и т. Д.?

Обновление: в первую очередь я ищу указатели на то, как реализована система карт (структуры данных, алгоритмы и т. Д.).

Ответов (9)

Решение

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

Несколько лет назад ребята участвовали в этом довольно легко и ответили на множество моих вопросов, так что я не вижу причин, по которым они все еще не очень хорошие люди.

A * на самом деле намного ближе к алгоритмам отображения продукции. По сравнению с исходным алгоритмом Диджикстры, он требует немного меньше исследований.

С концептуальной точки зрения представьте, что вы бросаете камень в пруд и наблюдаете за рябью. Маршруты будут представлять пруд, а камень - вашу исходную позицию.

Конечно, алгоритм должен будет искать некоторую долю путей из n ^ 2 по мере увеличения расстояния n. Вы бы заняли свою исходную позицию и проверили все доступные пути с этой точки. Затем рекурсивно вызовите точки в конце этих путей и так далее.

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

Альтернативный способ - использовать подход с феромонами муравьев, когда муравьи беспорядочно ползают от начальной точки и оставляют след запаха, который накапливается по мере того, как больше муравьев пересекает заданный путь. Если вы отправите (достаточное количество) муравьев как из начальной, так и из конечной точек, в конечном итоге путь с самым сильным запахом будет самым коротким. Это связано с тем, что кратчайший путь будет посещаться больше раз за заданный период времени, учитывая, что муравьи идут с одинаковой скоростью.

ИЗМЕНИТЬ @ Spikie

В качестве дополнительного объяснения того, как реализовать алгоритм пруда, выделены потенциальные необходимые структуры данных:

Вам нужно будет сохранить карту как сеть. Это просто набор nodes и edges между ними. Набор из nodes архива route . Ребро соединяет два узла (возможно, оба являются одним и тем же узлом) и имеет связанный, cost например, distance или time для пересечения ребра. Ребро может быть двунаправленным или однонаправленным. Вероятно, проще всего иметь однонаправленные и удвоить для двухстороннего перемещения между узлами (то есть одно ребро от A до B и другое для B к A).

В качестве примера представьте себе три железнодорожные станции, расположенные в равностороннем треугольнике, направленном вверх. На полпути между ними есть еще три станции. Ребра соединяют все соседние станции вместе, итоговая диаграмма будет иметь перевернутый треугольник, расположенный внутри большего треугольника.

Обозначьте узлы, начиная снизу слева, слева направо и вверх, как A, B, C, D, E, F (F вверху).

Предположим, что края можно перемещать в любом направлении. Каждое ребро имеет стоимость 1 км.

Итак, мы хотим пройти от левого нижнего угла A до верхней станции F. Есть много возможных маршрутов, в том числе те, которые дублируют друг друга, например ABCEBDEF.

У нас есть процедура, скажем,, NextNode которая принимает a node и a cost и вызывает себя для каждого узла , к которому он может перемещаться.

Очевидно, что если мы позволим этой подпрограмме работать, она в конечном итоге обнаружит все маршруты, включая потенциально бесконечные по длине (например, ABABABAB и т. Д.). Чтобы этого не произошло, мы проверим файл cost . Каждый раз, когда мы посещаем узел, который ранее не посещался, мы помещаем стоимость и узел, из которого мы пришли, против этого узла. Если узел был посещен до того, как мы сверим с существующей стоимостью, и если мы дешевле, мы обновляем узел и продолжаем (рекурсивно). Если мы дороже, то пропускаем узел. Если все узлы пропущены, мы выходим из процедуры.

Если мы попадаем в наш целевой узел, мы также выходим из процедуры.

Таким образом проверяются все жизнеспособные маршруты, но, что особенно важно, только те, которые имеют наименьшую стоимость. К концу процесса каждый узел будет иметь наименьшую стоимость доступа к этому узлу, включая наш целевой узел.

Чтобы получить маршрут, мы работаем в обратном направлении от нашего целевого узла. Поскольку мы сохранили узел, из которого пришли, вместе со стоимостью, мы просто перескакиваем назад, строя маршрут. В нашем примере мы получим что-то вроде:

Узел A - (Общая) Стоимость 0 - От узла Нет
Узел B - Стоимость 1 - От узла A
Узел C - Стоимость 2 - От узла B
Узел D - Стоимость 1 - От узла A
Узел E - Стоимость 2 - От узла D / Стоимость 2 - От узла B (это исключение, поскольку там равная стоимость)
Узел F - Стоимость 2 - От узла D

Итак, самый короткий маршрут - ADF.

Судя по моему опыту работы в этой области, A * очень хорошо справляется со своей задачей. Он (как упоминалось выше) быстрее, чем алгоритм Дейкстры, но все же достаточно прост для реализации и понимания обычным компетентным программистом.

Создание сети маршрутов - самая сложная часть, но ее можно разбить на ряд простых шагов: проложить все дороги; отсортировать точки по порядку; объединять группы одинаковых точек на разных дорогах в перекрестки (узлы); добавьте дуги в обоих направлениях, где соединяются узлы (или в одном направлении только для дороги с односторонним движением).

Сам алгоритм A * хорошо документирован в Википедии . Ключевым моментом для оптимизации является выбор лучшего узла из открытого списка, для которого вам нужна высокопроизводительная приоритетная очередь. Если вы используете C++, вы можете использовать адаптер STL priority_queue.

Настроить алгоритм для маршрутизации по различным частям сети (например, пешеход, автомобиль, общественный транспорт и т. Д.) В зависимости от скорости, расстояния или других критериев довольно просто. Вы делаете это, создавая фильтры, чтобы контролировать, какие сегменты маршрута доступны при построении сети и какой вес назначается каждому из них.

Вместо того, чтобы изучать API для каждого поставщика картографических сервисов (например, Gmaps, Ymaps api), полезно изучить Mapstraction.

«Mapstraction - это библиотека, которая предоставляет общий API для различных API-интерфейсов сопоставления javascript»

Я предлагаю вам перейти по URL-адресу и изучить общий API. Также есть много How-Tos.

Под маршрутизацией по карте вы имеете в виду поиск кратчайшего пути по уличной сети?

Алгоритм кратчайшего пути Дейкстры является наиболее известным. В Википедии неплохое вступление: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm

Здесь есть Java-апплет, где вы можете увидеть его в действии: http://www.dgp.toronto.edu/people/JamesStewart/270/9798s/Laffra/DijkstraApplet.html, а в Google вы найдете исходный код практически в любом язык.

Любая реальная реализация для создания маршрутов движения будет включать в себя довольно много данных об уличной сети, которые описывают затраты, связанные с пересекающими звеньями и узлами - иерархия дорожной сети, средняя скорость, приоритет перекрестка, подключение светофоров, запрещенные повороты и т. Д.

Мне еще не удалось найти хороший учебник по маршрутизации, но есть много кода, который нужно прочитать:

Существуют приложения маршрутизации GPL, которые используют данные Openstreetmap, например Gosmore, который работает в Windows (+ mobile) и Linux. Существует ряд интересных приложений, использующих одни и те же данные, но у gosmore есть несколько интересных применений, например, интерфейс с веб-сайтами .

Самая большая проблема с маршрутизацией - это плохие данные, и вы никогда не получите достаточно хороших данных. Поэтому, если вы хотите попробовать, держите свой тест очень локальным, чтобы вы могли лучше контролировать данные.

Барри Брумитт, один из разработчиков функции поиска маршрута на картах Google, написал сообщение по теме, которая может представлять интерес:

Путь к лучшему поиску пути 06.11.2007 15:47:00

Мне приходит в голову еще одна мысль относительно стоимости каждого обхода, но это увеличит время и вычислительную мощность, необходимые для вычислений.

Пример. Согласно GoogleMaps, я могу (там, где я живу) добраться из точки А в точку Б тремя способами. Устройства Garmin предлагают каждый из этих трех путей при Quickest расчете маршрута. После многократного прохождения каждого из этих маршрутов и усреднения (очевидно, будут ошибки в зависимости от времени суток, количества кофеина и т. Д.), Я чувствую, что алгоритмы могут учитывать количество поворотов дороги для высокого уровня точности. , например , прямая дорога на 1 милю будет быстрее , чем 1 миля дорога с крутыми поворотами в нем . Не практическое предложение, но, безусловно, я использую его, чтобы улучшить результат моей ежедневной поездки на работу.