6 #include <lanelet2_core/geometry/Lanelet.h>
7 #include <lanelet2_core/primitives/Area.h>
8 #include <lanelet2_core/primitives/Point.h>
12 #include <boost/graph/reverse_graph.hpp>
32 #if __cplusplus < 201703L
38 using internal::DijkstraStyleSearch;
42 using internal::RoutingGraphGraph;
43 using internal::VertexVisitInformation;
46 T reservedVector(
size_t size) {
53 struct PossibleRoutesInfo;
54 using PossibleRoutesInfoUPtr = std::unique_ptr<PossibleRoutesInfo>;
55 struct PossibleRoutesInfo {
60 explicit PossibleRoutesInfo(uint32_t startVertex,
const ConstLaneletOrArea& startLanelet) :
vertexId(startVertex) {
66 struct MoreLaneChanges {
67 bool operator()(
const PossibleRoutesInfo& lhs,
const PossibleRoutesInfo& rhs)
const {
68 if (lhs.numLaneChanges == rhs.numLaneChanges) {
69 return lhs.totalDistance > rhs.totalDistance;
71 return lhs.numLaneChanges > rhs.numLaneChanges;
76 template <
typename T,
typename U>
77 bool addToPath(T& path,
const Optional<U>& newElements) {
79 path.insert(path.end(), ++newElements->begin(), newElements->end());
86 template <
typename Po
intT>
87 PointT createPoint(
const ConstLaneletOrArea&
ll) {
90 p.setAttribute(
"id", Attribute(
ll.id()));
92 boost::geometry::centroid(utils::toHybrid(
ll.lanelet()->polygon2d()), p);
95 boost::geometry::centroid(utils::toHybrid(utils::to2D(
ll.area()->outerBoundPolygon())), p);
108 auto outEdges = boost::out_edges(vertex, graph);
109 if (throwOnError && std::distance(outEdges.first, outEdges.second) > 1) {
111 std::for_each(outEdges.first, outEdges.second, [&graph, &ids](
const auto& edge) {
112 ids +=
" " + std::to_string(graph[boost::target(edge, graph)].laneletOrArea.id());
114 throw RoutingGraphError(
"More than one neighboring lanelet to " + std::to_string(graph[vertex].laneletOrArea.id()) +
115 " with this relation:" + ids);
117 if (outEdges.first != outEdges.second) {
118 return graph[boost::target(*(outEdges.first), graph)].laneletOrArea;
125 auto value = neighboringImpl(vertex, graph, throwOnError);
126 if (!!value && value->isLanelet()) {
127 return value->lanelet();
132 template <
typename Func>
134 auto vertex = g.getVertex(llt);
141 template <
typename Func>
143 auto laneletVertex = g.getVertex(llt);
144 if (!laneletVertex) {
147 return f(*laneletVertex);
150 template <
typename Func>
152 auto result = reservedVector<ConstLanelets>(3);
154 while (!!(current =
next(*current))) {
155 result.emplace_back(*current);
161 const ConstLaneletOrArea& laneletOrArea,
bool edgesOut) {
163 auto laneletVertex = graph.getVertex(laneletOrArea);
164 if (!laneletVertex) {
167 auto processEdges = [&](
auto edgeRange) {
168 result.reserve(
size_t(std::distance(edgeRange.first, edgeRange.second)));
169 for (; edgeRange.first != edgeRange.second; edgeRange.first++) {
171 edgesOut ? boost::target(*edgeRange.first, graph.get()) :
boost::source(*edgeRange.first, graph.
get());
172 result.emplace_back(graph.get()[node].laneletOrArea);
176 return edgesOut ? processEdges(boost::out_edges(*laneletVertex, subgraph))
177 : processEdges(
boost::in_edges(*laneletVertex, subgraph));
181 const ConstLanelet&
lanelet,
bool edgesOut) {
183 auto allEdges = getAllEdgesFromGraph(graph, subgraph,
lanelet, edgesOut);
184 result = reservedVector<ConstLanelets>(allEdges.size());
185 for (
auto& edge : allEdges) {
186 if (edge.isLanelet()) {
187 result.push_back(*edge.lanelet());
193 template <
bool Backw>
196 struct GetGraph<true> {
197 template <
typename G>
198 auto operator()(
const G& g) {
199 return boost::make_reverse_graph(g);
203 struct GetGraph<false> {
204 template <
typename G>
205 auto operator()(
const G& g) {
210 template <
bool Backw,
typename OutVertexT,
typename GraphT>
211 std::vector<OutVertexT> buildPath(
const DijkstraSearchMap<LaneletVertexId>& map,
LaneletVertexId vertex, GraphT g) {
212 const auto* currInfo = &map.at(vertex);
213 auto size = currInfo->length;
214 std::vector<OutVertexT> path(size);
216 auto idx = Backw ? size - currInfo->length : currInfo->length - 1;
217 path[idx] =
static_cast<OutVertexT
>(g[vertex].laneletOrArea);
218 if (currInfo->predecessor == vertex) {
221 vertex = currInfo->predecessor;
222 currInfo = &map.at(vertex);
227 template <
typename Cost1,
typename Cost2>
228 struct CombinedCost {
229 CombinedCost(
const Cost1&
c1,
const Cost2&
c2) :
c1{
c1},
c2{
c2} {}
230 template <
typename T>
231 inline bool operator()(
const T& v)
const {
232 return c1(v) &&
c2(v);
238 template <
bool Eq = false>
239 struct StopIfLaneletsMoreThan {
240 explicit StopIfLaneletsMoreThan(
size_t n) :
n{
n} {}
241 template <
typename T>
242 inline bool operator()(
const T& v)
const {
243 return Eq ? v.length <=
n : v.length <
n;
248 template <
bool Eq = false>
249 struct StopIfCostMoreThan {
250 explicit StopIfCostMoreThan(
double c) :
c{
c} {}
251 template <
typename T>
252 inline bool operator()(
const T& v)
const {
253 return Eq ? v.cost <=
c : v.cost <
c;
256 template <
typename Other>
257 CombinedCost<StopIfCostMoreThan, Other> operator&&(
const Other& o) {
263 template <
bool Backw,
bool KeepShorter,
typename OutVertexT,
typename OutContainerT,
typename Func>
264 std::vector<OutContainerT> possiblePathsImpl(
const GraphType::vertex_descriptor& start,
266 auto g = GetGraph<Backw>{}(graph);
267 DijkstraStyleSearch<decltype(g)> search(g);
268 search.query(start, stopCriterion);
269 auto keepPath = [&](
auto& vertex) {
return vertex.second.isLeaf && (KeepShorter || !vertex.second.predicate); };
270 auto numPaths = size_t(std::count_if(search.getMap().begin(), search.getMap().end(), keepPath));
271 std::vector<OutContainerT> result;
272 result.reserve(numPaths);
273 for (
auto& vertex : search.getMap()) {
274 if (!keepPath(vertex)) {
277 result.emplace_back(buildPath<Backw, OutVertexT>(search.getMap(), vertex.first, graph));
282 template <
bool Backw,
typename OutVertexT,
typename OutContainerT>
283 std::vector<OutContainerT> possiblePathsImpl(
const GraphType::vertex_descriptor& start,
285 if (params.routingCostLimit && !params.elementLimit && !params.includeShorterPaths) {
286 return possiblePathsImpl<Backw, false, OutVertexT, OutContainerT>(start, graph,
287 StopIfCostMoreThan<>(*params.routingCostLimit));
289 if (params.routingCostLimit && !params.elementLimit && params.includeShorterPaths) {
290 return possiblePathsImpl<Backw, true, OutVertexT, OutContainerT>(start, graph,
291 StopIfCostMoreThan<>(*params.routingCostLimit));
293 if (!params.routingCostLimit && params.elementLimit && !params.includeShorterPaths) {
294 return possiblePathsImpl<Backw, false, OutVertexT, OutContainerT>(start, graph,
295 StopIfLaneletsMoreThan<>(*params.elementLimit));
297 if (!params.routingCostLimit && params.elementLimit && params.includeShorterPaths) {
298 return possiblePathsImpl<Backw, true, OutVertexT, OutContainerT>(start, graph,
299 StopIfLaneletsMoreThan<>(*params.elementLimit));
301 if (params.routingCostLimit && params.elementLimit && !params.includeShorterPaths) {
302 return possiblePathsImpl<Backw, false, OutVertexT, OutContainerT>(
303 start, graph, StopIfCostMoreThan<>(*params.routingCostLimit) && StopIfLaneletsMoreThan<>(*params.elementLimit));
305 if (params.routingCostLimit && params.elementLimit && params.includeShorterPaths) {
306 return possiblePathsImpl<Backw, true, OutVertexT, OutContainerT>(
307 start, graph, StopIfCostMoreThan<>(*params.routingCostLimit) && StopIfLaneletsMoreThan<>(*params.elementLimit));
309 throw InvalidInputError(
"Possible paths called with invalid cost limit AND invalid element limit!");
312 template <
bool Backw,
typename OutVertexT,
typename Func>
313 std::vector<OutVertexT> reachableSetImpl(
const GraphType::vertex_descriptor& start,
const FilteredRoutingGraph& graph,
314 Func stopCriterion) {
315 auto g = GetGraph<Backw>{}(graph);
316 DijkstraStyleSearch<decltype(g)> search(g);
317 search.query(start, stopCriterion);
318 std::vector<OutVertexT> result;
319 result.reserve(search.getMap().size());
320 for (
auto& vertex : search.getMap()) {
321 if (vertex.second.predicate) {
322 result.emplace_back(
static_cast<OutVertexT
>(graph[vertex.first].laneletOrArea));
328 template <
typename PathT,
typename PrimT>
330 bool withAreas,
const internal::RoutingGraphGraph& graph) {
331 auto startVertex = graph.getVertex(from);
332 auto endVertex = graph.getVertex(to);
333 if (!startVertex || !endVertex) {
338 ? withAreas ? graph.withAreasAndLaneChanges(routingCostId) : graph.withLaneChanges(routingCostId)
339 : withAreas ? graph.withAreasWithoutLaneChanges(routingCostId) : graph.withoutLaneChanges(routingCostId);
340 DijkstraStyleSearch<FilteredRoutingGraph> search(filteredGraph);
341 class DestinationReached {};
343 search.query(*startVertex, [endVertex](
const internal::VertexVisitInformation& i) {
344 if (i.vertex == *endVertex) {
345 throw DestinationReached{};
349 }
catch (DestinationReached) {
350 return PathT{buildPath<false, PrimT>(search.getMap(), *endVertex, filteredGraph)};
355 template <
typename RetT,
typename Primitives,
typename ShortestPathFunc>
356 Optional<RetT> shortestPathViaImpl(Primitives routePoints, ShortestPathFunc&& shortestPath) {
358 for (
size_t it = 0; it < routePoints.size() - 1; it++) {
359 auto results = shortestPath(routePoints[it], routePoints[it + 1]);
360 if (!!results && !results->empty() && path.empty()) {
361 path.push_back(results->front());
363 if (!addToPath(path, results)) {
371 RoutingGraph::RoutingGraph(RoutingGraph&& ) noexcept = default;
372 RoutingGraph& RoutingGraph::operator=(RoutingGraph&& ) noexcept = default;
373 RoutingGraph::~RoutingGraph() = default;
387 bool withLaneChanges)
const {
388 auto optPath{shortestPath(from, to, routingCostId, withLaneChanges)};
397 auto optPath{shortestPathVia(from, via, to, routingCostId, withLaneChanges)};
406 return shortestPathImpl<LaneletPath, ConstLanelet>(from, to, routingCostId, withLaneChanges,
false, *
graph_);
412 bool withLaneChanges)
const {
413 return shortestPathImpl<LaneletOrAreaPath, ConstLaneletOrArea>(from, to, routingCostId, withLaneChanges,
true,
419 bool withLaneChanges)
const {
421 return shortestPathViaImpl<LaneletPath>(
422 routePoints, [&](
auto& from,
auto& to) {
return this->shortestPath(from, to, routingCostId, withLaneChanges); });
429 bool withLaneChanges)
const {
431 return shortestPathViaImpl<LaneletOrAreaPath>(routePoints, [&](
auto& from,
auto& to) {
432 return this->shortestPathIncludingAreas(from, to, routingCostId, withLaneChanges);
437 bool includeConflicting)
const {
438 auto edgeInfo = includeConflicting ?
graph_->getEdgeInfo(from, to)
439 :
graph_->getEdgeInfoFor(from, to,
graph_->withoutConflicting());
441 return edgeInfo->relation;
447 auto subgraph = withLaneChanges ?
graph_->withLaneChanges() :
graph_->withoutLaneChanges();
448 return getLaneletEdgesFromGraph(*
graph_, subgraph,
lanelet,
true);
454 for (
auto const& it : foll) {
461 auto subgraph = withLaneChanges ?
graph_->withLaneChanges(0) :
graph_->withoutLaneChanges(0);
462 return getLaneletEdgesFromGraph(*
graph_, subgraph,
lanelet,
false);
468 result.reserve(prev.size());
469 for (
auto const& it : prev) {
474 assert(
false &&
"Two Lanelets in a route are not connected. This shouldn't happen.");
481 auto move = [](
auto it) {
return std::make_move_iterator(it); };
485 result.reserve(
left.size() +
right.size() + 1);
486 result.insert(std::end(result), move(
left.rbegin()), move(
left.rend()));
488 result.insert(std::end(result), move(std::begin(
right)), move(std::end(
right)));
494 [&](
auto& vertex) {
return neighboringLaneletImpl(vertex,
graph_->left(routingCostId)); });
498 return ifLaneletInGraph(*
graph_,
lanelet, [&](
auto& vertex) {
499 return neighboringLaneletImpl(vertex,
graph_->adjacentLeft(routingCostId));
505 [&](
auto& vertex) {
return neighboringLaneletImpl(vertex,
graph_->right(routingCostId)); });
509 return ifLaneletInGraph(*
graph_,
lanelet, [&](
auto& vertex) {
510 return neighboringLaneletImpl(vertex,
graph_->adjacentRight(routingCostId));
519 return getUntilEnd(
lanelet, [&](
const ConstLanelet& llt) {
return adjacentLeft(llt, routingCostId); });
523 bool leftReached{
false};
526 while (!leftReached) {
528 for (
auto const& it :
leftOf) {
532 const ConstLanelets adjacentLeftOf{adjacentLefts(current, routingCostId)};
533 for (
auto const& it : adjacentLeftOf) {
537 leftReached = (
leftOf.empty() && adjacentLeftOf.empty());
547 return getUntilEnd(
lanelet, [&](
const ConstLanelet& llt) {
return adjacentRight(llt, routingCostId); });
551 bool rightReached{
false};
553 auto result = reservedVector<LaneletRelations>(3);
554 while (!rightReached) {
556 for (
auto const& it :
rightOf) {
560 const ConstLanelets adjacentRightOf{adjacentRights(current, routingCostId)};
561 for (
auto const& it : adjacentRightOf) {
565 rightReached = (
rightOf.empty() && adjacentRightOf.empty());
571 return getAllEdgesFromGraph(*
graph_,
graph_->conflicting(), laneletOrArea,
true);
580 auto graph = allowLaneChanges ?
graph_->withLaneChanges(routingCostId) :
graph_->withoutLaneChanges(routingCostId);
581 return reachableSetImpl<false, ConstLanelet>(*start, graph, StopIfCostMoreThan<true>{maxRoutingCost});
586 auto start =
graph_->getVertex(llOrAr);
590 auto graph =
graph_->withAreasAndLaneChanges(routingCostId);
591 return reachableSetImpl<false, ConstLaneletOrArea>(*start, graph, StopIfCostMoreThan<true>{maxRoutingCost});
600 auto graph = allowLaneChanges ?
graph_->withLaneChanges(routingCostId) :
graph_->withoutLaneChanges(routingCostId);
601 return reachableSetImpl<true, ConstLanelet>(*start, graph, StopIfCostMoreThan<true>{maxRoutingCost});
605 auto start =
graph_->getVertex(startPoint);
611 return possiblePathsImpl<false, ConstLanelet, LaneletPath>(*start, graph, params);
616 return possiblePaths(startPoint,
PossiblePathsParams{minRoutingCost, {}, routingCostId, allowLaneChanges,
false});
621 return possiblePaths(startPoint,
PossiblePathsParams{{}, minLanelets, routingCostId, allowLaneChanges,
false});
626 auto start =
graph_->getVertex(targetLanelet);
632 return possiblePathsImpl<true, ConstLanelet, LaneletPath>(*start, graph, params);
637 return possiblePathsTowards(targetLanelet,
643 return possiblePathsTowards(targetLanelet,
649 auto start =
graph_->getVertex(startPoint);
655 return possiblePathsImpl<false, ConstLaneletOrArea, LaneletOrAreaPath>(*start, graph, params);
660 bool allowLaneChanges)
const {
661 return possiblePathsIncludingAreas(startPoint,
667 return possiblePathsIncludingAreas(startPoint,
677 auto graph = allowLaneChanges ?
graph_->withLaneChanges(routingCostId) :
graph_->withoutLaneChanges(routingCostId);
678 DijkstraStyleSearch<FilteredRoutingGraph> search(graph);
679 search.query(*start, [&](
const VertexVisitInformation& i) ->
bool {
681 i.length, i.numLaneChanges});
692 auto graph = allowLaneChanges ?
graph_->withAreasAndLaneChanges(routingCostId)
693 :
graph_->withAreasWithoutLaneChanges(routingCostId);
694 DijkstraStyleSearch<FilteredRoutingGraph> search(graph);
695 search.query(*start, [&](
const VertexVisitInformation& i) ->
bool {
697 graph_->get()[i.predecessor].laneletOrArea, i.cost, i.length,
709 allowLaneChanges ?
graph_->withLaneChanges(routingCostId) :
graph_->withoutLaneChanges(routingCostId);
710 auto graph = boost::make_reverse_graph(forwGraph);
712 search.
query(*start, [&](
const VertexVisitInformation& i) ->
bool {
714 i.length, i.numLaneChanges});
725 auto forwGraph = allowLaneChanges ?
graph_->withAreasAndLaneChanges(routingCostId)
726 :
graph_->withAreasWithoutLaneChanges(routingCostId);
727 auto graph = boost::make_reverse_graph(forwGraph);
729 search.
query(*start, [&](
const VertexVisitInformation& i) ->
bool {
731 graph_->get()[i.predecessor].laneletOrArea, i.cost, i.length,
736 void RoutingGraph::exportGraphML(
const std::string& filename,
const RelationType& edgeTypesToExclude,
738 if (filename.empty()) {
741 if (routingCostId >=
graph_->numRoutingCosts()) {
742 throw InvalidInputError(
"Routing Cost ID is higher than the number of routing modules.");
745 internal::exportGraphMLImpl<GraphType>(filename,
graph_->get(), relations, routingCostId);
748 void RoutingGraph::exportGraphViz(
const std::string& filename,
const RelationType& edgeTypesToExclude,
750 if (filename.empty()) {
753 if (routingCostId >=
graph_->numRoutingCosts()) {
754 throw InvalidInputError(
"Routing Cost ID is higher than the number of routing modules.");
757 internal::exportGraphVizImpl<GraphType>(filename,
graph_->get(), relations, routingCostId);
762 RelationType allowedRelations{RelationType::Successor | RelationType::Left | RelationType::Right |
764 if (includeAdjacent) {
765 allowedRelations |= RelationType::AdjacentLeft;
766 allowedRelations |= RelationType::AdjacentRight;
768 if (includeConflicting) {
769 allowedRelations |= RelationType::Conflicting;
771 return allowedRelations;
790 for (
const auto& vertex : loa) {
793 auto lineStrings =
utils::transform(lineStringMap_, [](
auto& mapLs) {
return mapLs.second; });
795 for (
auto&
p : pointMap_) {
796 map->add(utils::to3D(
p.second));
802 void visitVertex(
const internal::LaneletOrAreaToVertex::value_type& vertex) {
803 addPoint(vertex.first);
804 auto edges = boost::out_edges(vertex.second,
graph_);
805 for (
auto edge = edges.first; edge != edges.second; ++edge) {
806 const auto& target =
graph_[boost::target(*edge,
graph_)].laneletOrArea;
808 const auto& edgeInfo =
graph_[*edge];
809 addEdge(vertex.first, target, edgeInfo);
818 auto inMap = pointMap_.find(point);
819 if (inMap == pointMap_.end()) {
820 pointMap_.emplace(point, createPoint<Point2d>(point));
825 auto pair = getPair(from, to);
826 auto inMap = lineStringMap_.find(pair);
827 if (inMap != lineStringMap_.end()) {
829 inMap->second.setAttribute(
"routing_cost_reverse", std::to_string(edge.
routingCost));
832 auto pFrom = pointMap_.at(from);
833 auto pTo = pointMap_.at(to);
835 lineStringMap_.emplace(pair, lineString3d);
841 std::unordered_map<ConstLaneletOrArea, Point2d>
pointMap_;
845 bool includeConflicting)
const {
846 if (routingCostId >=
graph_->numRoutingCosts()) {
847 throw InvalidInputError(
"Routing Cost ID is higher than the number of routing modules.");
857 for (
const auto& laWithVertex :
graph_->vertexLookup()) {
858 const auto& la = laWithVertex.first;
859 auto ll = laWithVertex.first.lanelet();
860 const auto& vertex = laWithVertex.second;
865 left = neighboringLaneletImpl(vertex,
graph_->left(),
true);
868 errors.emplace_back(std::string(
"Left: ") + e.what());
872 adjacentLeft = neighboringLaneletImpl(vertex,
graph_->adjacentLeft(),
true);
874 errors.emplace_back(std::string(
"Adjacent left: ") + e.what());
876 if (
left && adjacentLeft) {
877 errors.emplace_back(
"Lanelet " + std::to_string(
id) +
" has both 'left' (id: " + std::to_string(
left->id()) +
878 ") and 'adjancent_left' (id: " + std::to_string(adjacentLeft->id()) +
") lanelet");
883 errors.emplace_back(
"There is a 'left' relation from " + std::to_string(
id) +
" to " +
884 std::to_string(
left->id()) +
" but no relation back");
885 }
else if (rel.front().lanelet !=
ll) {
886 errors.emplace_back(
"There is a 'left' relation from " + std::to_string(
id) +
" to " +
887 std::to_string(
left->id()) +
", but " + std::to_string(
id) +
888 " isn't the closest lanelet the other way round");
894 errors.emplace_back(
"There is a 'adjacentLeft' relation from " + std::to_string(
id) +
" to " +
895 std::to_string(adjacentLeft->id()) +
" but no relation back");
896 }
else if (rel.front().lanelet !=
ll) {
897 errors.emplace_back(
"There is a 'adjacentLeft' relation from " + std::to_string(
id) +
" to " +
898 std::to_string(adjacentLeft->id()) +
", but " + std::to_string(
id) +
899 " isn't the closest lanelet the other way round");
905 right = neighboringLaneletImpl(vertex,
graph_->right(),
true);
907 errors.emplace_back(std::string(
"Right: ") + e.what());
911 adjacentRight = neighboringLaneletImpl(vertex,
graph_->adjacentRight(),
true);
913 errors.emplace_back(std::string(
"Adjacent right: ") + e.what());
915 if (
right && adjacentRight) {
916 errors.emplace_back(
"Lanelet " + std::to_string(
id) +
" has both 'right' (id: " + std::to_string(
right->id()) +
917 ") and 'adjancent_right' (id: " + std::to_string(adjacentRight->id()) +
") lanelet");
922 errors.emplace_back(
"There is a 'right' relation from " + std::to_string(
id) +
" to " +
923 std::to_string(
right->id()) +
" but no relation back");
924 }
else if (rel.front().lanelet !=
ll) {
925 errors.emplace_back(
"There is a 'right' relation from " + std::to_string(
id) +
" to " +
926 std::to_string(
right->id()) +
", but " + std::to_string(
id) +
927 " isn't the closest lanelet the other way round");
933 errors.emplace_back(
"There is a 'adjacentRight' relation from " + std::to_string(
id) +
" to " +
934 std::to_string(adjacentRight->id()) +
" but no relation back");
935 }
else if (rel.front().lanelet !=
ll) {
936 errors.emplace_back(
"There is a 'adjacentRight' relation from " + std::to_string(
id) +
" to " +
937 std::to_string(adjacentRight->id()) +
", but " + std::to_string(
id) +
938 " isn't the closest lanelet the other way round");
942 if (throwOnError && !errors.empty()) {
943 std::stringstream ss;
944 ss <<
"Errors found in routing graph:";
945 for (
const auto& err : errors) {
946 ss <<
"\n\t- " << err;
953 RoutingGraph::RoutingGraph(std::unique_ptr<RoutingGraphGraph>&& graph,
LaneletSubmapConstPtr&& passableMap)
954 :
graph_{std::move(graph)}, passableLaneletSubmap_{std::move(passableMap)} {}