Route.cpp
Go to the documentation of this file.
2 
4 #include <lanelet2_core/geometry/Lanelet.h>
5 #include <lanelet2_core/primitives/Lanelet.h>
7 
8 #include <boost/graph/reverse_graph.hpp>
9 #include <unordered_map>
10 
15 
16 namespace lanelet {
17 namespace routing {
18 
19 namespace {
21 using internal::RouteGraph;
22 using internal::RouteVertexInfo;
23 
24 using ConstLaneletPointMapIt = std::map<Id, Point2d>::iterator;
25 using DebugEdge = std::pair<Id, Id>;
26 
33 ConstLaneletPointMapIt createAndAddPoint(std::map<Id, Point2d>& pointMap, const RouteVertexInfo& element) {
34  ConstLanelet lanelet{element.lanelet};
35  Point2d point;
36  point.setId(lanelet.id());
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)};
41  return emplace.first;
42 }
43 
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);
54  }
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);
61  }
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));
67  return;
68  }
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)) {
74  lineStringMapIt->second.setAttribute(attr, relationToString(relation));
75  break;
76  }
77  }
78 }
79 
80 LaneletSequence remainingLaneImpl(RouteGraph::Vertex v, const FilteredRouteGraph& g) {
81  ConstLanelets lane;
82  auto start = v;
83  while (true) {
84  lane.push_back(g[v].lanelet);
85  auto outEdges = boost::out_edges(v, g);
86  if (std::distance(outEdges.first, outEdges.second) != 1) {
87  break; // lane splits
88  }
89  v = boost::target(*outEdges.first, g);
90  if (boost::in_degree(v, g) != 1) {
91  break; // other lane merges
92  }
93  if (v == start) {
94  break; // we are in a loop
95  }
96  }
97  return LaneletSequence{std::move(lane)};
98 }
99 
100 template <bool Backwards = false>
101 LaneletRelations getRelations(RouteGraph::Vertex v, const FilteredRouteGraph& g) {
102  auto out = internal::GetEdges<Backwards>{}(v, g);
103  return utils::transform(out.first, out.second, [&g](auto e) {
104  return LaneletRelation{g[internal::GetTarget<Backwards>{}(e, g)].lanelet, g[e].relation};
105  });
106 }
107 template <bool Backwards = false>
108 ConstLanelets getLanelets(RouteGraph::Vertex v, const FilteredRouteGraph& g) {
109  auto out = internal::GetEdges<Backwards>{}(v, g);
110  return utils::transform(out.first, out.second,
111  [&g](auto e) { return g[internal::GetTarget<Backwards>{}(e, g)].lanelet; });
112 }
113 
114 Optional<LaneletRelation> getSingleRelation(RouteGraph::Vertex v, const FilteredRouteGraph& g) {
115  auto outEdges = boost::out_edges(v, g);
116  if (outEdges.first == outEdges.second) {
117  return {};
118  }
119  return LaneletRelation{g[boost::target(*outEdges.first, g)].lanelet, g[*outEdges.first].relation};
120 }
121 
122 template <bool Backwards = false>
123 std::pair<Optional<RouteGraph::Vertex>, RelationType> getNextVertex(RouteGraph::Vertex v, const FilteredRouteGraph& g) {
124  auto out = internal::GetEdges<Backwards>{}(v, g);
125  if (out.first == out.second) {
126  return {};
127  }
128  return {internal::GetTarget<Backwards>{}(*out.first, g), g[*out.first].relation};
129 }
130 
131 } // anonymous namespace
132 
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)} {}
139 
140 LaneletPath Route::remainingShortestPath(const ConstLanelet& ll) const {
141  auto iter = std::find(shortestPath_.begin(), shortestPath_.end(), ll);
142  if (iter == shortestPath_.end()) {
143  return LaneletPath{};
144  }
145  if (!shortestPath_.empty() && shortestPath_.front() == shortestPath_.back()) { // circular
146  ConstLanelets llts{shortestPath_.begin(), shortestPath_.end()};
147  llts.pop_back();
148  std::rotate(llts.begin(), llts.begin() + std::distance(shortestPath_.begin(), iter), llts.end());
149  return LaneletPath{llts};
150  }
151  return LaneletPath{ConstLanelets{iter, shortestPath_.end()}};
152 }
153 
154 LaneletSequence Route::fullLane(const ConstLanelet& ll) const {
155  // go back to the first lanelet of the lane (ie the first lanelet that has not exactly one predecessor) and then call
156  // remaining lane on it
157  auto v = graph_->getVertex(ll);
158  if (!v) {
159  return LaneletSequence{};
160  }
161  auto g = graph_->withoutLaneChanges();
162  auto begin = *v;
163  while (true) {
164  auto inEdges = boost::in_edges(*v, g);
165  if (std::distance(inEdges.first, inEdges.second) != 1) {
166  break; // lanes merge
167  }
168  auto next = boost::source(*inEdges.first, g);
169  if (boost::out_degree(next, g) != 1) {
170  break; // other lane merges
171  }
172  v = next;
173  if (v == begin) {
174  break; // we are in a loop
175  }
176  }
177  return remainingLaneImpl(*v, g);
178 }
179 
180 LaneletSequence Route::remainingLane(const ConstLanelet& ll) const {
181  auto v = graph_->getVertex(ll);
182  if (!v) {
183  return LaneletSequence{};
184  }
185  return remainingLaneImpl(*v, graph_->withoutLaneChanges());
186 }
187 
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); });
191 }
192 
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);
198  }
199  return lanes.size();
200 }
201 
202 LaneletMapPtr Route::getDebugLaneletMap() const {
203  // we need std::map because of its iterator validity guarantee at insertion
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);
209  };
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);
213  }
214  // Mark shortest path
215  for (const auto& el : shortestPath_) {
216  vertexMap[el.id()].setAttribute("shortest_path", true);
217  }
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));
221  }
222  return map;
223 }
224 
225 size_t Route::size() const { return boost::num_vertices(graph_->get()); }
226 
227 LaneletRelations Route::followingRelations(const ConstLanelet& lanelet) const {
228  auto v = graph_->getVertex(lanelet);
229  if (!v) {
230  return {};
231  }
232  return getRelations(*v, graph_->withoutLaneChanges());
233 }
234 
235 ConstLanelets Route::following(const ConstLanelet& lanelet) const {
236  auto v = graph_->getVertex(lanelet);
237  if (!v) {
238  return {};
239  }
240  return getLanelets(*v, graph_->withoutLaneChanges());
241 }
242 
243 LaneletRelations Route::previousRelations(const ConstLanelet& lanelet) const {
244  auto v = graph_->getVertex(lanelet);
245  if (!v) {
246  return {};
247  }
248  return getRelations<true>(*v, graph_->withoutLaneChanges());
249 }
250 
251 ConstLanelets Route::previous(const ConstLanelet& lanelet) const {
252  auto v = graph_->getVertex(lanelet);
253  if (!v) {
254  return {};
255  }
256  return getLanelets<true>(*v, graph_->withoutLaneChanges());
257 }
258 
259 Optional<LaneletRelation> Route::leftRelation(const ConstLanelet& lanelet) const {
260  auto v = graph_->getVertex(lanelet);
261  if (!v) {
262  return {};
263  }
264  return getSingleRelation(*v, graph_->somehowLeft());
265 }
266 
267 LaneletRelations Route::leftRelations(const ConstLanelet& lanelet) const {
268  LaneletRelations result;
269  auto next = graph_->getVertex(lanelet);
270  RelationType type;
271  auto g = graph_->somehowLeft();
272  std::tie(next, type) = getNextVertex(*next, g);
273  while (!!next) {
274  result.emplace_back(LaneletRelation{g[*next].lanelet, type});
275  std::tie(next, type) = getNextVertex(*next, g);
276  }
277  return result;
278 }
279 
280 Optional<LaneletRelation> Route::rightRelation(const ConstLanelet& lanelet) const {
281  auto v = graph_->getVertex(lanelet);
282  if (!v) {
283  return {};
284  }
285  return getSingleRelation(*v, graph_->somehowRight());
286 }
287 
288 LaneletRelations Route::rightRelations(const ConstLanelet& lanelet) const {
289  LaneletRelations result;
290  auto next = graph_->getVertex(lanelet);
291  RelationType type;
292  auto g = graph_->somehowRight();
293  std::tie(next, type) = getNextVertex(*next, g);
294  while (!!next) {
295  result.emplace_back(LaneletRelation{g[*next].lanelet, type});
296  std::tie(next, type) = getNextVertex(*next, g);
297  }
298  return result;
299 }
300 
301 void Route::forEachSuccessor(const ConstLanelet& lanelet, const LaneletVisitFunction& f) const {
302  auto v = graph_->getVertex(lanelet);
303  if (!v) {
304  return;
305  }
306  auto g = graph_->withLaneChanges();
308  search.query(*v, [&](const internal::VertexVisitInformation& i) -> bool {
309  return f(LaneletVisitInformation{graph_->get()[i.vertex].lanelet, graph_->get()[i.predecessor].lanelet, i.cost,
310  i.length, i.numLaneChanges});
311  });
312 }
313 
314 void Route::forEachPredecessor(const ConstLanelet& lanelet, const LaneletVisitFunction& f) const {
315  auto v = graph_->getVertex(lanelet);
316  if (!v) {
317  return;
318  }
319  auto g = graph_->withLaneChanges();
320  auto gInv = boost::make_reverse_graph(g);
321  internal::DijkstraStyleSearch<decltype(gInv)> search(gInv);
322  search.query(*v, [&](const internal::VertexVisitInformation& i) -> bool {
323  return f(LaneletVisitInformation{graph_->get()[i.vertex].lanelet, graph_->get()[i.predecessor].lanelet, i.cost,
324  i.length, i.numLaneChanges});
325  });
326 }
327 
328 ConstLanelets Route::conflictingInRoute(const ConstLanelet& lanelet) const {
329  auto v = graph_->getVertex(lanelet);
330  if (!v) {
331  return {};
332  }
333  return getLanelets(*v, graph_->conflicting());
334 }
335 
336 ConstLaneletOrAreas Route::conflictingInMap(const ConstLanelet& lanelet) const {
337  auto v = graph_->getVertex(lanelet);
338  if (!v) {
339  return {};
340  }
341  return graph_->get()[*v].conflictingInMap;
342 }
343 
345  const auto& g = graph_->get();
346  return utils::concatenateRange(g.vertex_set(), [&](auto v) {
347  auto& conf = g[v].conflictingInMap;
348  return std::make_pair(std::begin(conf), std::end(conf));
349  });
350 }
351 
352 bool Route::contains(const ConstLanelet& lanelet) const { return !!graph_->getVertex(lanelet); }
353 
354 template <RelationType Expect>
355 void checkRelationIs(Route::Errors& errors, Id source, Id dest, RelationType sourceRel, RelationType targetRel) {
356  if ((Expect & targetRel) != RelationType::None) {
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!");
361  }
362 }
363 Route::Errors Route::checkValidity(bool throwOnError) const {
364  Errors errors;
365  // All elements of the shortest path are in the route
366  for (const auto& ll : shortestPath_) {
367  if (!contains(ll)) {
368  errors.emplace_back("Lanelet " + std::to_string(ll.id()) + " of shortest path is not part of the route!");
369  }
370  }
371  // Check if all relations are back and forth
372  const auto& g = graph_->get();
373  auto edges = boost::edges(g);
374  std::for_each(edges.first, edges.second, [&](internal::RouteGraph::Edge e) {
375  // get reverse edge
376  decltype(e) eRev;
377  bool exists = false;
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;
382  if (!exists) {
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!");
386  }
387  return;
388  }
389  auto targetRelation = g[eRev].relation;
390  switch (sourceRelation) {
392  checkRelationIs<RelationType::Conflicting>(errors, sourceId, targetId, sourceRelation, targetRelation);
393  break;
394  case RelationType::Left:
396  checkRelationIs<RelationType::Right | RelationType::AdjacentRight>(errors, sourceId, targetId, sourceRelation,
397  targetRelation);
398  break;
399  case RelationType::Right:
401  checkRelationIs<RelationType::Left | RelationType::AdjacentLeft>(errors, sourceId, targetId, sourceRelation,
402  targetRelation);
403  break;
404  case RelationType::Successor: // anything is ok here or already checked for the reverse edge
405  break;
406  default:
407  errors.emplace_back("Unsupported relation type found in graph for lanelet " + std::to_string(sourceId) + ": " +
408  std::to_string(static_cast<RelationUnderlyingType>(g[eRev].relation)));
409  }
410  });
411 
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;
417  }
418  throw RoutingGraphError(ss.str());
419  }
420  return errors;
421 }
422 
423 } // namespace routing
424 } // namespace lanelet
orderedPair
auto orderedPair(T1 &first, T2 &second)
lanelet::routing::LaneletPath::end
iterator end()
Definition: LaneletPath.h:22
lanelet::routing::Route::allConflictingInMap
ConstLaneletOrAreas allConflictingInMap() const
Provides all lanelets in the map that conflict with any lanelet in the route.
Definition: Route.cpp:344
lanelet::ConstLaneletOrAreas
std::vector< ConstLaneletOrArea > ConstLaneletOrAreas
lanelet::routing::internal::DijkstraStyleSearch::query
void query(VertexType start, Func &&func)
Definition: ShortestPath.h:117
LaneletMap.h
lanelet::LaneletMapPtr
std::shared_ptr< LaneletMap > LaneletMapPtr
lanelet
lanelet::LaneletSequence
lanelet::routing::internal::VertexVisitInformation::cost
double cost
Definition: ShortestPath.h:18
lanelet::routing::relationToString
std::string relationToString(RelationType type)
Definition: Forward.h:83
next
Optional< ConstLaneletOrArea > next
Definition: LaneletPath.cpp:83
lanelet::routing::internal::FilteredRouteGraph
FilteredGraphT< RouteGraphType > FilteredRouteGraph
Definition: Graph.h:60
lanelet::Id
int64_t Id
lanelet::routing::RelationType
RelationType
Definition: Forward.h:56
ShortestPath.h
lanelet::routing::RelationType::Successor
@ Successor
A (the only) direct, reachable successor. Not merging and not diverging.
lanelet::routing::LaneletVisitInformation
This object carries the required information for the graph neighbourhood search.
Definition: Types.h:22
lanelet::routing::internal::VertexVisitInformation::predecessor
RoutingGraphGraph::Vertex predecessor
Definition: ShortestPath.h:17
lanelet::routing::internal::VertexVisitInformation::length
size_t length
Definition: ShortestPath.h:19
lanelet::utils::concatenateRange
auto concatenateRange(ContainerT &&c, Func f)
lanelet::utils::transform
auto transform(Container &&c, Func f)
Optional
boost::optional< T > Optional
Route.h
lanelet::routing::Route::shortestPath_
LaneletPath shortestPath_
The underlying shortest path used to create the route.
Definition: Route.h:203
lanelet::routing::LaneletRelations
std::vector< LaneletRelation > LaneletRelations
Definition: Forward.h:34
lanelet::routing::Route::checkValidity
Errors checkValidity(bool throwOnError=false) const
Perform some sanity checks on the route.
Definition: Route.cpp:363
lanelet::routing::LaneletRelation
Represents the relation of a lanelet to another lanelet.
Definition: Types.h:34
lanelet::routing::Route::contains
bool contains(const ConstLanelet &lanelet) const
Checks if a specific lanelet is part of the route.
Definition: Route.cpp:352
lanelet::routing::RelationType::Conflicting
@ Conflicting
Unreachable but with overlapping shape.
lanelet::routing::internal::VertexVisitInformation
This object carries the required information for the graph neighbourhood search.
Definition: ShortestPath.h:15
lanelet::routing::Route::Errors
std::vector< std::string > Errors
Definition: Route.h:38
GraphUtils.h
lanelet::routing::RelationType::Left
@ Left
(the only) directly adjacent, reachable left neighbour
lanelet::routing::Route::graph_
std::unique_ptr< internal::RouteGraph > graph_
The internal graph.
Definition: Route.h:202
lanelet::routing::RelationUnderlyingType
std::underlying_type_t< RelationType > RelationUnderlyingType
Definition: Forward.h:67
lanelet::routing::RelationType::None
@ None
No relation.
other
lanelet::routing::checkRelationIs
void checkRelationIs(Route::Errors &errors, Id source, Id dest, RelationType sourceRel, RelationType targetRel)
Definition: Route.cpp:355
Graph.h
lanelet::routing::RelationType::AdjacentLeft
@ AdjacentLeft
directly adjacent, unreachable left neighbor
std
lanelet::RoutingGraphError
Thrown when an there's an error in the routing graph. It will feature further information.
Definition: Exceptions.h:19
lanelet::routing::internal::Graph< RouteGraphType >::Edge
typename boost::graph_traits< RouteGraphType >::edge_descriptor Edge
Definition: Graph.h:112
lanelet::routing::internal::DijkstraStyleSearch
Definition: ShortestPath.h:59
lanelet::routing::LaneletVisitFunction
std::function< bool(const LaneletVisitInformation &)> LaneletVisitFunction
Definition: Types.h:30
lanelet::routing::LaneletRelation::lanelet
ConstLanelet lanelet
the lanelet this relation refers to
Definition: Types.h:35
lanelet::routing::LaneletPath::begin
iterator begin()
Definition: LaneletPath.h:20
lanelet::routing::RelationType::AdjacentRight
@ AdjacentRight
directly adjacent, unreachable right neighbor
lanelet::routing::internal::VertexVisitInformation::numLaneChanges
size_t numLaneChanges
Definition: ShortestPath.h:20
LaneletSubmapConstPtr
std::shared_ptr< const LaneletSubmap > LaneletSubmapConstPtr
lanelet::ConstLanelet
ll
LaneletAdjacency ll
Definition: LaneletPath.cpp:88
Utilities.h
graph_
const OriginalGraph * graph_
Definition: RouteBuilder.cpp:366
lanelet::routing::RelationType::Right
@ Right
(the only) directly adjacent, reachable right neighbour
ConstLanelets
std::vector< ConstLanelet > ConstLanelets
Exceptions.h
lanelet::routing::LaneletPath
A lanelet path represents a set of lanelets that can be reached in order by either driving straight o...
Definition: LaneletPath.h:13
lanelet::routing::internal::VertexVisitInformation::vertex
RoutingGraphGraph::Vertex vertex
Definition: ShortestPath.h:16


lanelet2_routing
Author(s): Matthias Mayr
autogenerated on Sun Oct 27 2024 02:27:49