1 #include "guidance/turn_analysis.hpp"
2 #include "extractor/road_classification.hpp"
3 #include "guidance/constants.hpp"
4
5 #include "util/coordinate.hpp"
6 #include "util/coordinate_calculation.hpp"
7
8 #include <cstddef>
9 #include <set>
10 #include <unordered_set>
11 #include <utility>
12
13 using osrm::guidance::getTurnDirection;
14
15 namespace osrm
16 {
17 namespace guidance
18 {
19
20 using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
21
TurnAnalysis(const util::NodeBasedDynamicGraph & node_based_graph,const extractor::EdgeBasedNodeDataContainer & node_data_container,const std::vector<util::Coordinate> & node_coordinates,const extractor::CompressedEdgeContainer & compressed_edge_container,const extractor::RestrictionMap & restriction_map,const std::unordered_set<NodeID> & barrier_nodes,const extractor::TurnLanesIndexedArray & turn_lanes_data,const extractor::NameTable & name_table,const extractor::SuffixTable & street_name_suffix_table)22 TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
23 const extractor::EdgeBasedNodeDataContainer &node_data_container,
24 const std::vector<util::Coordinate> &node_coordinates,
25 const extractor::CompressedEdgeContainer &compressed_edge_container,
26 const extractor::RestrictionMap &restriction_map,
27 const std::unordered_set<NodeID> &barrier_nodes,
28 const extractor::TurnLanesIndexedArray &turn_lanes_data,
29 const extractor::NameTable &name_table,
30 const extractor::SuffixTable &street_name_suffix_table)
31 : node_based_graph(node_based_graph), roundabout_handler(node_based_graph,
32 node_data_container,
33 node_coordinates,
34 compressed_edge_container,
35 restriction_map,
36 barrier_nodes,
37 turn_lanes_data,
38 name_table,
39 street_name_suffix_table),
40 motorway_handler(node_based_graph,
41 node_data_container,
42 node_coordinates,
43 compressed_edge_container,
44 restriction_map,
45 barrier_nodes,
46 turn_lanes_data,
47 name_table,
48 street_name_suffix_table),
49 turn_handler(node_based_graph,
50 node_data_container,
51 node_coordinates,
52 compressed_edge_container,
53 restriction_map,
54 barrier_nodes,
55 turn_lanes_data,
56 name_table,
57 street_name_suffix_table),
58 sliproad_handler(node_based_graph,
59 node_data_container,
60 node_coordinates,
61 compressed_edge_container,
62 restriction_map,
63 barrier_nodes,
64 turn_lanes_data,
65 name_table,
66 street_name_suffix_table),
67 suppress_mode_handler(node_based_graph,
68 node_data_container,
69 node_coordinates,
70 compressed_edge_container,
71 restriction_map,
72 barrier_nodes,
73 turn_lanes_data,
74 name_table,
75 street_name_suffix_table),
76 driveway_handler(node_based_graph,
77 node_data_container,
78 node_coordinates,
79 compressed_edge_container,
80 restriction_map,
81 barrier_nodes,
82 turn_lanes_data,
83 name_table,
84 street_name_suffix_table),
85 statistics_handler(node_based_graph,
86 node_data_container,
87 node_coordinates,
88 compressed_edge_container,
89 restriction_map,
90 barrier_nodes,
91 turn_lanes_data,
92 name_table,
93 street_name_suffix_table)
94 {
95 }
96
AssignTurnTypes(const NodeID node_prior_to_intersection,const EdgeID entering_via_edge,const extractor::intersection::IntersectionView & intersection_view) const97 Intersection TurnAnalysis::AssignTurnTypes(
98 const NodeID node_prior_to_intersection,
99 const EdgeID entering_via_edge,
100 const extractor::intersection::IntersectionView &intersection_view) const
101 {
102 // Roundabouts are a main priority. If there is a roundabout instruction present, we process the
103 // turn as a roundabout
104
105 // the following lines create a partly invalid intersection object. We might want to refactor
106 // this at some point
107 Intersection intersection;
108 intersection.reserve(intersection_view.size());
109 std::transform(intersection_view.begin(),
110 intersection_view.end(),
111 std::back_inserter(intersection),
112 [&](const extractor::intersection::IntersectionViewData &data) {
113 return ConnectedRoad(data,
114 {TurnType::Invalid, DirectionModifier::UTurn},
115 INVALID_LANE_DATAID);
116 });
117
118 // Suppress turns on ways between mode types that do not need guidance, think ferry routes.
119 // This handler has to come first and when it triggers we're done with the intersection: there's
120 // nothing left to be done once we suppressed instructions on such routes. Exit early.
121 if (suppress_mode_handler.canProcess(
122 node_prior_to_intersection, entering_via_edge, intersection))
123 {
124 intersection = suppress_mode_handler(
125 node_prior_to_intersection, entering_via_edge, std::move(intersection));
126
127 return intersection;
128 }
129
130 if (roundabout_handler.canProcess(node_prior_to_intersection, entering_via_edge, intersection))
131 {
132 intersection = roundabout_handler(
133 node_prior_to_intersection, entering_via_edge, std::move(intersection));
134 }
135 else
136 {
137 // set initial defaults for normal turns and modifier based on angle
138 intersection =
139 setTurnTypes(node_prior_to_intersection, entering_via_edge, std::move(intersection));
140 if (driveway_handler.canProcess(
141 node_prior_to_intersection, entering_via_edge, intersection))
142 {
143 intersection = driveway_handler(
144 node_prior_to_intersection, entering_via_edge, std::move(intersection));
145 }
146 else if (motorway_handler.canProcess(
147 node_prior_to_intersection, entering_via_edge, intersection))
148 {
149 intersection = motorway_handler(
150 node_prior_to_intersection, entering_via_edge, std::move(intersection));
151 }
152 else
153 {
154 BOOST_ASSERT(turn_handler.canProcess(
155 node_prior_to_intersection, entering_via_edge, intersection));
156 intersection = turn_handler(
157 node_prior_to_intersection, entering_via_edge, std::move(intersection));
158 }
159 }
160 // Handle sliproads
161 if (sliproad_handler.canProcess(node_prior_to_intersection, entering_via_edge, intersection))
162 intersection = sliproad_handler(
163 node_prior_to_intersection, entering_via_edge, std::move(intersection));
164
165 // Turn On Ramps Into Off Ramps, if we come from a motorway-like road
166 if (node_based_graph.GetEdgeData(entering_via_edge).flags.road_classification.IsMotorwayClass())
167 {
168 std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) {
169 if (road.instruction.type == TurnType::OnRamp)
170 road.instruction.type = TurnType::OffRamp;
171 });
172 }
173
174 // After we ran all handlers and determined instruction type
175 // and direction modifier gather statistics about our decisions.
176 if (statistics_handler.canProcess(node_prior_to_intersection, entering_via_edge, intersection))
177 intersection = statistics_handler(
178 node_prior_to_intersection, entering_via_edge, std::move(intersection));
179
180 return intersection;
181 }
182
183 // Sets basic turn types as fallback for otherwise unhandled turns
setTurnTypes(const NodeID node_prior_to_intersection,const EdgeID,Intersection intersection) const184 Intersection TurnAnalysis::setTurnTypes(const NodeID node_prior_to_intersection,
185 const EdgeID,
186 Intersection intersection) const
187 {
188 for (auto &road : intersection)
189 {
190 if (!road.entry_allowed)
191 continue;
192
193 const EdgeID onto_edge = road.eid;
194 const NodeID to_nid = node_based_graph.GetTarget(onto_edge);
195
196 if (node_prior_to_intersection == to_nid)
197 road.instruction = {TurnType::Continue, DirectionModifier::UTurn};
198 else
199 road.instruction = {TurnType::Turn, getTurnDirection(road.angle)};
200 }
201 return intersection;
202 }
203
204 } // namespace guidance
205 } // namespace osrm
206