4 #include <lanelet2_core/geometry/Lanelet.h>
5 #include <lanelet2_core/primitives/Lanelet.h>
8 #include <boost/graph/reverse_graph.hpp>
9 #include <unordered_map>
21 using internal::RouteGraph;
22 using internal::RouteVertexInfo;
24 using ConstLaneletPointMapIt = std::map<Id, Point2d>::iterator;
25 using DebugEdge = std::pair<Id, Id>;
33 ConstLaneletPointMapIt createAndAddPoint(std::map<Id, Point2d>& pointMap,
const RouteVertexInfo& element) {
34 ConstLanelet
lanelet{element.lanelet};
37 point.setAttribute(
"id",
lanelet.id());
38 point.setAttribute(
"lane_id", element.laneId);
39 boost::geometry::centroid(CompoundHybridPolygon2d(
lanelet.polygon2d()), point);
40 const auto emplace{pointMap.emplace(
lanelet.id(), point)};
49 void addRelation(std::map<DebugEdge, LineString3d>& edgeMap, std::map<Id, Point2d>& vertexMap,
50 const RouteVertexInfo& from,
const RouteVertexInfo& to,
RelationType relation) {
51 auto fromPointIt = vertexMap.find(from.lanelet.id());
52 if (fromPointIt == vertexMap.end()) {
53 fromPointIt = createAndAddPoint(vertexMap, from);
55 DebugEdge
orderedPair = std::minmax(from.lanelet.id(), to.lanelet.id());
56 auto lineStringMapIt = edgeMap.find(orderedPair);
57 if (lineStringMapIt == edgeMap.end()) {
58 auto toPointIt = vertexMap.find(to.lanelet.id());
59 if (toPointIt == vertexMap.end()) {
60 toPointIt = createAndAddPoint(vertexMap, to);
62 LineString2d lineString;
63 lineString.push_back(fromPointIt->second);
64 lineString.push_back(toPointIt->second);
65 lineStringMapIt = edgeMap.emplace(orderedPair, LineString3d(lineString)).first;
66 lineStringMapIt->second.setAttribute(
"relation_1",
relationToString(relation));
69 std::string direction =
70 lineStringMapIt->second.front().id() == fromPointIt->first ?
"relation_" :
"relation_reverse_";
71 for (
size_t it = 1; it >= 1; it++) {
72 auto attr = direction + std::to_string(it);
73 if (!lineStringMapIt->second.hasAttribute(attr)) {
85 auto outEdges = boost::out_edges(v, g);
86 if (std::distance(outEdges.first, outEdges.second) != 1) {
89 v = boost::target(*outEdges.first, g);
90 if (boost::in_degree(v, g) != 1) {
97 return LaneletSequence{std::move(lane)};
100 template <
bool Backwards = false>
102 auto out = internal::GetEdges<Backwards>{}(v, g);
104 return LaneletRelation{g[internal::GetTarget<Backwards>{}(e, g)].lanelet, g[e].relation};
107 template <
bool Backwards = false>
109 auto out = internal::GetEdges<Backwards>{}(v, g);
111 [&g](
auto e) { return g[internal::GetTarget<Backwards>{}(e, g)].lanelet; });
115 auto outEdges = boost::out_edges(v, g);
116 if (outEdges.first == outEdges.second) {
119 return LaneletRelation{g[boost::target(*outEdges.first, g)].lanelet, g[*outEdges.first].relation};
122 template <
bool Backwards = false>
124 auto out = internal::GetEdges<Backwards>{}(v, g);
125 if (out.first == out.second) {
128 return {internal::GetTarget<Backwards>{}(*out.first, g), g[*out.first].relation};
133 Route::Route() =
default;
134 Route::~Route() noexcept = default;
135 Route& Route::operator=(Route&&
other) noexcept = default;
136 Route::Route(Route&&
other) noexcept = default;
137 Route::Route(LaneletPath shortestPath,
std::unique_ptr<RouteGraph> graph,
LaneletSubmapConstPtr laneletSubmap) noexcept
138 :
graph_{std::move(graph)}, shortestPath_{std::move(shortestPath)}, laneletSubmap_{std::move(laneletSubmap)} {}
141 auto iter = std::find(shortestPath_.begin(), shortestPath_.end(),
ll);
142 if (iter == shortestPath_.end()) {
145 if (!shortestPath_.empty() && shortestPath_.front() == shortestPath_.back()) {
148 std::rotate(llts.begin(), llts.begin() + std::distance(shortestPath_.begin(), iter), llts.end());
161 auto g =
graph_->withoutLaneChanges();
164 auto inEdges = boost::in_edges(*v, g);
165 if (std::distance(inEdges.first, inEdges.second) != 1) {
168 auto next = boost::source(*inEdges.first, g);
169 if (boost::out_degree(
next, g) != 1) {
177 return remainingLaneImpl(*v, g);
185 return remainingLaneImpl(*v,
graph_->withoutLaneChanges());
188 double Route::length2d()
const {
189 return std::accumulate(shortestPath_.begin(), shortestPath_.end(), 0.,
190 [](
double num,
const ConstLanelet&
ll) { return num + geometry::length2d(ll); });
193 size_t Route::numLanes()
const {
194 std::set<LaneId> lanes;
195 const auto& g =
graph_->get();
196 for (
auto v : g.vertex_set()) {
197 lanes.emplace(g[v].laneId);
204 std::map<DebugEdge, LineString3d> edgeMap;
205 std::map<Id, Point2d> vertexMap;
206 const auto& g =
graph_->get();
207 auto addEdge = [&](RouteGraph::Edge e) {
208 addRelation(edgeMap, vertexMap, g[boost::source(e, g)], g[boost::target(e, g)], g[e].relation);
210 for (
auto v :
graph_->get().vertex_set()) {
211 auto outEdges = boost::out_edges(v,
graph_->get());
212 std::for_each(outEdges.first, outEdges.second, addEdge);
215 for (
const auto& el : shortestPath_) {
216 vertexMap[el.id()].setAttribute(
"shortest_path",
true);
218 auto map = utils::createMap(utils::transform(edgeMap, [](
auto& e) {
return e.second; }));
219 for (
const auto& it : vertexMap) {
220 map->add(utils::to3D(it.second));
225 size_t Route::size()
const {
return boost::num_vertices(
graph_->get()); }
232 return getRelations(*v,
graph_->withoutLaneChanges());
240 return getLanelets(*v,
graph_->withoutLaneChanges());
248 return getRelations<true>(*v,
graph_->withoutLaneChanges());
256 return getLanelets<true>(*v,
graph_->withoutLaneChanges());
264 return getSingleRelation(*v,
graph_->somehowLeft());
271 auto g =
graph_->somehowLeft();
272 std::tie(
next, type) = getNextVertex(*
next, g);
275 std::tie(
next, type) = getNextVertex(*
next, g);
285 return getSingleRelation(*v,
graph_->somehowRight());
292 auto g =
graph_->somehowRight();
293 std::tie(
next, type) = getNextVertex(*
next, g);
296 std::tie(
next, type) = getNextVertex(*
next, g);
306 auto g =
graph_->withLaneChanges();
319 auto g =
graph_->withLaneChanges();
320 auto gInv = boost::make_reverse_graph(g);
333 return getLanelets(*v,
graph_->conflicting());
341 return graph_->get()[*v].conflictingInMap;
345 const auto& g =
graph_->get();
347 auto& conf = g[v].conflictingInMap;
348 return std::make_pair(std::begin(conf), std::end(conf));
354 template <RelationType Expect>
357 auto sourceStr = std::to_string(source);
358 auto destStr = std::to_string(dest);
359 errors.emplace_back(
"Lanelet " + sourceStr +
" is " +
relationToString(sourceRel) +
"of/with " + destStr +
360 ", but " + destStr +
" is " +
relationToString(targetRel) +
" with/of if!");
368 errors.emplace_back(
"Lanelet " + std::to_string(
ll.id()) +
" of shortest path is not part of the route!");
372 const auto& g =
graph_->get();
373 auto edges = boost::edges(g);
378 std::tie(eRev, exists) = boost::edge(boost::target(e, g), boost::source(e, g), g);
379 auto sourceId = g[boost::source(e, g)].lanelet.id();
380 auto targetId = g[boost::target(e, g)].lanelet.id();
381 auto sourceRelation = g[e].relation;
383 if (g[e].relation != RelationType::Successor) {
384 errors.emplace_back(
"Lanelet " + std::to_string(sourceId) +
" is " + relationToString(sourceRelation) +
385 " of/with lanelet " + std::to_string(targetId) +
", but there is no relation back!");
389 auto targetRelation = g[eRev].relation;
390 switch (sourceRelation) {
392 checkRelationIs<RelationType::Conflicting>(errors, sourceId, targetId, sourceRelation, targetRelation);
396 checkRelationIs<RelationType::Right | RelationType::AdjacentRight>(errors, sourceId, targetId, sourceRelation,
401 checkRelationIs<RelationType::Left | RelationType::AdjacentLeft>(errors, sourceId, targetId, sourceRelation,
407 errors.emplace_back(
"Unsupported relation type found in graph for lanelet " + std::to_string(sourceId) +
": " +
412 if (throwOnError && !errors.empty()) {
413 std::stringstream ss;
414 ss <<
"Errors found in routing graph:";
415 for (
const auto& err : errors) {
416 ss <<
"\n\t- " << err;