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