@@ -7,31 +7,33 @@ namespace engine
77namespace routing_algorithms
88{
99
10- std::vector<TurnData>
11- getTileTurns (const datafacade::ContiguousInternalMemoryDataFacade<ch::Algorithm> &facade,
12- const std::vector<RTreeLeaf> &edges,
13- const std::vector<std::size_t > &sorted_edge_indexes)
10+ namespace
1411{
15- std::vector<TurnData> all_turn_data;
12+ // Struct to hold info on all the EdgeBasedNodes that are visible in our tile
13+ // When we create these, we insure that (source, target) and packed_geometry_id
14+ // are all pointed in the same direction.
15+ struct EdgeBasedNodeInfo
16+ {
17+ bool is_geometry_forward; // Is the geometry forward or reverse?
18+ unsigned packed_geometry_id;
19+ };
1620
17- // Struct to hold info on all the EdgeBasedNodes that are visible in our tile
18- // When we create these, we insure that (source, target) and packed_geometry_id
19- // are all pointed in the same direction.
20- struct EdgeBasedNodeInfo
21- {
22- bool is_geometry_forward; // Is the geometry forward or reverse?
23- unsigned packed_geometry_id;
24- };
21+ struct SegmentData
22+ {
23+ NodeID target_node;
24+ EdgeID edge_based_node_id;
25+ };
26+
27+ template <typename edge_extractor, typename datafacade>
28+ std::vector<TurnData> generateTurns (const datafacade &facade,
29+ const std::vector<RTreeLeaf> &edges,
30+ const std::vector<std::size_t > &sorted_edge_indexes,
31+ edge_extractor const &find_edge)
32+ {
2533 // Lookup table for edge-based-nodes
2634 std::unordered_map<NodeID, EdgeBasedNodeInfo> edge_based_node_info;
27-
28- struct SegmentData
29- {
30- NodeID target_node;
31- EdgeID edge_based_node_id;
32- };
33-
3435 std::unordered_map<NodeID, std::vector<SegmentData>> directed_graph;
36+
3537 // Reserve enough space for unique edge-based-nodes on every edge.
3638 // Only a tile with all unique edges will use this much, but
3739 // it saves us a bunch of re-allocations during iteration.
@@ -41,8 +43,10 @@ getTileTurns(const datafacade::ContiguousInternalMemoryDataFacade<ch::Algorithm>
4143 return facade.GetGeometryIndex (edge.forward_segment_id .id ).id ;
4244 };
4345
44- // Build an adjacency list for all the road segments visible in
45- // the tile
46+ // To build a tile, we can only rely on the r-tree to quickly find all data visible within the
47+ // tile itself. The Rtree returns a series of segments that may or may not offer turns
48+ // associated with them. To be able to extract turn penalties, we extract a node based graph
49+ // from our edge based representation.
4650 for (const auto &edge_index : sorted_edge_indexes)
4751 {
4852 const auto &edge = edges[edge_index];
@@ -79,28 +83,32 @@ getTileTurns(const datafacade::ContiguousInternalMemoryDataFacade<ch::Algorithm>
7983 }
8084 }
8185
86+ // Make sure we traverse the startnodes in a consistent order
87+ // to ensure identical PBF encoding on all platforms.
88+ std::vector<NodeID> sorted_startnodes;
89+ sorted_startnodes.reserve (directed_graph.size ());
90+ std::transform (directed_graph.begin (),
91+ directed_graph.end (),
92+ std::back_inserter (sorted_startnodes),
93+ [](auto const &node) { return node.first ; });
94+ std::sort (sorted_startnodes.begin (), sorted_startnodes.end ());
95+
96+ std::vector<TurnData> all_turn_data;
97+
8298 // Given a turn:
8399 // u---v
84100 // |
85101 // w
86102 // uv is the "approach"
87103 // vw is the "exit"
88- std::vector<contractor::QueryEdge::EdgeData> unpacked_shortcut;
89104 std::vector<EdgeWeight> approach_weight_vector;
90105 std::vector<EdgeWeight> approach_duration_vector;
91106
92- // Make sure we traverse the startnodes in a consistent order
93- // to ensure identical PBF encoding on all platforms.
94- std::vector<NodeID> sorted_startnodes;
95- sorted_startnodes.reserve (directed_graph.size ());
96- for (const auto &startnode : directed_graph)
97- sorted_startnodes.push_back (startnode.first );
98- std::sort (sorted_startnodes.begin (), sorted_startnodes.end ());
99-
100107 // Look at every node in the directed graph we created
101108 for (const auto &startnode : sorted_startnodes)
102109 {
103- const auto &nodedata = directed_graph[startnode];
110+ BOOST_ASSERT (directed_graph.find (startnode) != directed_graph.end ());
111+ const auto &nodedata = directed_graph.find (startnode)->second ;
104112 // For all the outgoing edges from the node
105113 for (const auto &approachedge : nodedata)
106114 {
@@ -110,7 +118,7 @@ getTileTurns(const datafacade::ContiguousInternalMemoryDataFacade<ch::Algorithm>
110118 continue ;
111119
112120 // For each of the outgoing edges from our target coordinate
113- for (const auto &exit_edge : directed_graph[ approachedge.target_node ] )
121+ for (const auto &exit_edge : directed_graph. find ( approachedge.target_node )-> second )
114122 {
115123 // If the next edge has the same edge_based_node_id, then it's
116124 // not a turn, so skip it
@@ -132,55 +140,32 @@ getTileTurns(const datafacade::ContiguousInternalMemoryDataFacade<ch::Algorithm>
132140 //
133141 // would offer a backward edge at `b` to `a` (due to the oneway from a to b)
134142 // but could also offer a shortcut (b-c-a) from `b` to `a` which is longer.
135- EdgeID smaller_edge_id =
136- facade.FindSmallestEdge (approachedge.edge_based_node_id ,
137- exit_edge.edge_based_node_id ,
138- [](const contractor::QueryEdge::EdgeData &data) {
139- return data.forward && !data.shortcut ;
140- });
141-
142- // Depending on how the graph is constructed, we might have to look for
143- // a backwards edge instead. They're equivalent, just one is available for
144- // a forward routing search, and one is used for the backwards dijkstra
145- // steps. Their weight should be the same, we can use either one.
146- // If we didn't find a forward edge, try for a backward one
147- if (SPECIAL_EDGEID == smaller_edge_id)
148- {
149- smaller_edge_id =
150- facade.FindSmallestEdge (exit_edge.edge_based_node_id ,
151- approachedge.edge_based_node_id ,
152- [](const contractor::QueryEdge::EdgeData &data) {
153- return data.backward && !data.shortcut ;
154- });
155- }
143+ EdgeID edge_based_edge_id =
144+ find_edge (approachedge.edge_based_node_id , exit_edge.edge_based_node_id );
156145
157- // If no edge was found, it means that there's no connection between these
158- // nodes, due to oneways or turn restrictions. Given the edge-based-nodes
159- // that we're examining here, we *should* only find directly-connected
160- // edges, not shortcuts
161- if (smaller_edge_id != SPECIAL_EDGEID)
146+ if (edge_based_edge_id != SPECIAL_EDGEID)
162147 {
163- const auto &data = facade.GetEdgeData (smaller_edge_id);
164- BOOST_ASSERT_MSG (!data.shortcut , " Connecting edge must not be a shortcut" );
148+ const auto &data = facade.GetEdgeData (edge_based_edge_id);
165149
166150 // Now, calculate the sum of the weight of all the segments.
167- if (edge_based_node_info[approachedge.edge_based_node_id ].is_geometry_forward )
151+ if (edge_based_node_info.find (approachedge.edge_based_node_id )
152+ ->second .is_geometry_forward )
168153 {
169154 approach_weight_vector = facade.GetUncompressedForwardWeights (
170- edge_based_node_info[ approachedge.edge_based_node_id ]
171- .packed_geometry_id );
155+ edge_based_node_info. find ( approachedge.edge_based_node_id )
156+ -> second .packed_geometry_id );
172157 approach_duration_vector = facade.GetUncompressedForwardDurations (
173- edge_based_node_info[ approachedge.edge_based_node_id ]
174- .packed_geometry_id );
158+ edge_based_node_info. find ( approachedge.edge_based_node_id )
159+ -> second .packed_geometry_id );
175160 }
176161 else
177162 {
178163 approach_weight_vector = facade.GetUncompressedReverseWeights (
179- edge_based_node_info[ approachedge.edge_based_node_id ]
180- .packed_geometry_id );
164+ edge_based_node_info. find ( approachedge.edge_based_node_id )
165+ -> second .packed_geometry_id );
181166 approach_duration_vector = facade.GetUncompressedReverseDurations (
182- edge_based_node_info[ approachedge.edge_based_node_id ]
183- .packed_geometry_id );
167+ edge_based_node_info. find ( approachedge.edge_based_node_id )
168+ -> second .packed_geometry_id );
184169 }
185170 const auto sum_node_weight = std::accumulate (approach_weight_vector.begin (),
186171 approach_weight_vector.end (),
@@ -239,6 +224,90 @@ getTileTurns(const datafacade::ContiguousInternalMemoryDataFacade<ch::Algorithm>
239224 return all_turn_data;
240225}
241226
227+ } // namespace
228+
229+ // CH Version of finding all turn penalties. Here is where the actual work is happening
230+ std::vector<TurnData>
231+ getTileTurns (const datafacade::ContiguousInternalMemoryDataFacade<ch::Algorithm> &facade,
232+ const std::vector<RTreeLeaf> &edges,
233+ const std::vector<std::size_t > &sorted_edge_indexes)
234+ {
235+ // Define how to find the representative edge between two edge based nodes for a CH
236+ struct EdgeFinderCH
237+ {
238+ EdgeFinderCH (const datafacade::ContiguousInternalMemoryDataFacade<ch::Algorithm> &facade)
239+ : facade(facade)
240+ {
241+ }
242+ const datafacade::ContiguousInternalMemoryDataFacade<ch::Algorithm> &facade;
243+
244+ EdgeID operator ()(const NodeID approach_node, const NodeID exit_node) const
245+ {
246+ // Find the connection between our source road and the target node
247+ // Since we only want to find direct edges, we cannot check shortcut edges here.
248+ // Otherwise we might find a forward edge even though a shorter backward edge
249+ // exists (due to oneways).
250+ //
251+ // a > - > - > - b
252+ // | |
253+ // |------ c ----|
254+ //
255+ // would offer a backward edge at `b` to `a` (due to the oneway from a to b)
256+ // but could also offer a shortcut (b-c-a) from `b` to `a` which is longer.
257+ EdgeID edge_id = facade.FindSmallestEdge (
258+ approach_node, exit_node, [](const contractor::QueryEdge::EdgeData &data) {
259+ return data.forward && !data.shortcut ;
260+ });
261+
262+ // Depending on how the graph is constructed, we might have to look for
263+ // a backwards edge instead. They're equivalent, just one is available for
264+ // a forward routing search, and one is used for the backwards dijkstra
265+ // steps. Their weight should be the same, we can use either one.
266+ // If we didn't find a forward edge, try for a backward one
267+ if (SPECIAL_EDGEID == edge_id)
268+ {
269+ edge_id = facade.FindSmallestEdge (
270+ exit_node, approach_node, [](const contractor::QueryEdge::EdgeData &data) {
271+ return data.backward && !data.shortcut ;
272+ });
273+ }
274+
275+ BOOST_ASSERT_MSG (edge_id == SPECIAL_EDGEID || !facade.GetEdgeData (edge_id).shortcut ,
276+ " Connecting edge must not be a shortcut" );
277+ return edge_id;
278+ }
279+ };
280+
281+ EdgeFinderCH edge_finder (facade);
282+ return generateTurns (facade, edges, sorted_edge_indexes, edge_finder);
283+ }
284+
285+ // MLD version to find all turns
286+ std::vector<TurnData>
287+ getTileTurns (const datafacade::ContiguousInternalMemoryDataFacade<mld::Algorithm> &facade,
288+ const std::vector<RTreeLeaf> &edges,
289+ const std::vector<std::size_t > &sorted_edge_indexes)
290+ {
291+ // Define how to find the representative edge between two edge-based-nodes for a MLD
292+ struct EdgeFinderMLD
293+ {
294+ EdgeFinderMLD (const datafacade::ContiguousInternalMemoryDataFacade<mld::Algorithm> &facade)
295+ : facade(facade)
296+ {
297+ }
298+ const datafacade::ContiguousInternalMemoryDataFacade<mld::Algorithm> &facade;
299+
300+ EdgeID operator ()(const NodeID approach_node, const NodeID exit_node) const
301+ {
302+ return facade.FindEdge (approach_node, exit_node);
303+ }
304+ };
305+
306+ EdgeFinderMLD edge_finder (facade);
307+
308+ return generateTurns (facade, edges, sorted_edge_indexes, edge_finder);
309+ }
310+
242311} // namespace routing_algorithms
243312} // namespace engine
244313} // namespace osrm
0 commit comments