Правда точки, расстояние между которыми меньше 1 метра, могут иметь разные ключи, поэтому мы проверяем контейнер не только по вычисленному ключу, но и по 8- ми соседним: std: :vector< size. И если оно меньше заданного, то считаем, что точки одинаковы и объединяем в одну вершину (на рисунке покрашены в один цвет), возвращая идентификатор подходящей вершины уже имеющейся в ячейке с ключом get. Key(x. Part, y. Part). В результате получаем, что соседние точки ближе заданного порога получают один идентификатор.
Теперь у нас есть список смежных вершин. Временная сложность получения такого списка линейно зависит от количества вершин, потому что каждую мы обрабатываем ровно 1 раз, а операции поиска и вставки в хэш- контейнер имеет асимптотически константную сложность. Как вы уже, должно быть, заметили, мы не обрабатываем промежуточные вершины ломаной уличного сегмента, так как на топологию графа они не влияют (в середине сегмента нельзя осуществить никакого маневра, во всяком случае у нас нет об этом данных). Если бы мы разбили ломаную на составляющие ее отрезки и каждый отрезок считали бы ребром, то в графе вместо примерно 1. Значительно возросло бы время поиска пути, в конце я покажу эту разницу в абсолютных значениях. Остался последний штрих. Ограничения, или запрещенные маневры.
Ограничение запрещает какой- либо маневр, например поворот налево на перекрестке. Исходно в данных представляет собой список сегментов, последовательное движение по которым запрещено. Приведу пример: Рис. Красные стрелки показывают запрещенный маневр, числа обозначают идентификаторы сегментов. Фактически в данных этот запрет выглядит как .
И через эти дублированные вершины провесили ребра так, чтобы создать разрешенные маневры, а для запрещенного маневра такой маршрут просто не создавать. При клонировании вершины ее геометрическое местоположение остается прежним (показанные на рисунке вершины v. Проиллюстрирую сказанное на примере перекрестка с запрещенным левым поворотом выше: Рис 3. Видно, что на графе с измененной топологией осуществить левый поворот по запрещенному пути на перекрестке больше нельзя, при этом все разрешенные маневры остались возможными. Ограничения из более чем 2- х ребер обрабатываются по тому же принципу, но порождают больше новых вершин и ребер, на размер графа эти трансформации влияют, но не значительно (рост числа ребер примерно на 5%). В наших данных порядка 5.
Вот иллюстрация того, как трансформируется граф под действием ограничения из 3- х ребер: Было: Рис 4. Стало: Рис 5. Надо сказать, что реализация алгоритма трансформации графа стала самым сложным этапом всей работы (на нее ушло около 3. Отчасти это связано с не самой хорошей проработкой структуры хранения данных.
Так что если что- то осталось непонятным — не страшно, это действительно было непросто, задавайте вопросы, постараюсь ответить. Об инструментах. И так теперь у нас был граф представленный в удобном виде с учетом всех ограничений, по которому можно было прокладывать маршруты. В качестве алгоритма решили попробовать классический алгоритм Дейкстры, хорошая реализация которого есть в библиотеке boost. Тут добавить особо нечего, по boost: :graph есть хорошая документация и даже книги, мы взяли код одного из примеров и с небольшими изменениями использовали его у нас.
Следующим этапом стала обработка запросов. Мы решили, что удобно, если сервис сможет прокладывать маршрут, имея только начальную и конечную точку, заданные координатами.
А значит надо быстро найти начальную и конечную вершину в графе, которые максимально близко расположены к соответствующим точкам запроса. Для этого нужно было быстро уметь находить ближайшую к заданной пользователем точку на уличной сети (пользователь может захотеть маршрут от точки находящейся вне дорожно- уличной сети). Тут уместно вспомнить о том, что сегменты дорожно- уличной сети в наших данных это ломаные, поэтому нам надо было найти ближайшую к заданной точку на ломаной (это может быть точка лежащая на ломаной, либо ее начальная или конечная вершина). Ломаных довольно много (1. Искать перебором всех сегментов слишком медленно. Тут на помощь пришла свежая версия библиотеки boost: :geometry, где появились пространственные индексы (boost: :geometry: :index) уже с поддержкой такого объекта как ломаная линия (linestring). С использованием этого индекса мы быстро находим несколько ближайших кандидатов, из них затем точным алгоритмом определяется сегмент, наиболее близко проходящий возле заданной точки.
Для чтения SHP файлов мы использовали библиотеку GDAL, для преобразования между географическими системами координат (мы работаем в локальной системе города, так исторически сложилось), а пользователю удобнее использовать GPS (WGS8. О деталях.— маршрут к середине ребра. Напомню что наш граф — топологическое представление дорожной сети, геометрические детали для работы алгоритма Дейкстры неважны. Но геометрический аспект важен для пользователя. Вспомним, что алгоритм Дейкстры строит кратчайшие маршруты от заданной вершины графа до всех остальных (включая искомую конечную вершину).
Значит начальную вершину мы должны определить, но поиск по индексу мы ведем среди ломаных, то есть фактически среди ребер. Как понять от какой вершины (в графе) нужно прокладывать маршрут, ведь промежуточных вершин сегмента там нет, а значит надо выбрать либо начальную, либо конечную вершину найденного сегмента.
Рис 6. Однако для пользователя такое решение не будет удобным, представьте длиннющее шоссе, без поворотов и разворотов (а такое случается нередко). Пользователю будет очень удивительно видеть как маршрут построился от точки, находящейся в километре от той, что он задал (потому что на ближайшем сегменте других вершин ближе не оказалось). Кроме того, как показано на рисунке 6 (красные пунктирные линии) выбор ближайшей вершины сегмента иногда будет означать более длинный путь до цели, что вовсе нехорошо. Значит нам надо было как- то создать видимость того, что вершин в нашем графе больше и расположены они чаще, но так, чтобы это не повлияло на время работы алгоритма поиска пути.
Файл с расширением . Чем открыть? Множество программ менеджеров закачки при загрузке из интернета какого- либо файла добавляют к имени файла расширение . Предположим, скачивается файл movie. Когда файл скачается полностью, из его имени пропадет расширение . Скорее всего, большой пользы из файла с расширением .
Придется дождаться полной загрузки файла или начать загрузку заново. Но если ситуация не позволяет этого сделать, можно удалить из имени файла расширение . Если вы не нашли ответ или нужную информацию.