1 #include "extractor/maneuver_override_relation_parser.hpp"
2 #include "extractor/maneuver_override.hpp"
3
4 #include <boost/optional/optional.hpp>
5 #include <boost/ref.hpp>
6
7 #include <osmium/osm.hpp>
8 #include <osmium/tags/filter.hpp>
9 #include <osmium/tags/taglist.hpp>
10
11 #include <algorithm>
12 #include <iterator>
13
14 namespace osrm
15 {
16 namespace extractor
17 {
18
ManeuverOverrideRelationParser()19 ManeuverOverrideRelationParser::ManeuverOverrideRelationParser() {}
20
21 /**
22 * Parses the `type=maneuver` relation. Reads the fields, and puts data
23 * into an InputManeuverOverride object, if the relation is considered
24 * valid (i.e. has the minimum tags we expect).
25 */
26 boost::optional<InputManeuverOverride>
TryParse(const osmium::Relation & relation) const27 ManeuverOverrideRelationParser::TryParse(const osmium::Relation &relation) const
28 {
29
30 // Support both American and British spellings of maneuver/manoeuvre
31 osmium::tags::KeyValueFilter filter{false};
32 filter.add(true, "type", "maneuver");
33 filter.add(true, "type", "manoeuvre");
34
35 const osmium::TagList &tag_list = relation.tags();
36
37 if (osmium::tags::match_none_of(tag_list, filter))
38 // if it's not a maneuver, continue;
39 {
40 return boost::none;
41 }
42
43 // we pretend every restriction is a conditional restriction. If we do not find any restriction,
44 // we can trim away the vector after parsing
45 InputManeuverOverride maneuver_override;
46
47 // Handle both spellings
48 if (relation.tags().has_key("manoeuvre"))
49 {
50 maneuver_override.maneuver = relation.tags().get_value_by_key("manoeuvre", "");
51 }
52 else
53 {
54 maneuver_override.maneuver = relation.tags().get_value_by_key("maneuver", "");
55 }
56
57 maneuver_override.direction = relation.tags().get_value_by_key("direction", "");
58
59 bool valid_relation = true;
60 OSMNodeID via_node = SPECIAL_OSM_NODEID;
61 OSMWayID from = SPECIAL_OSM_WAYID, to = SPECIAL_OSM_WAYID;
62 std::vector<OSMWayID> via_ways;
63
64 for (const auto &member : relation.members())
65 {
66 const char *role = member.role();
67 if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0)
68 {
69 continue;
70 }
71
72 switch (member.type())
73 {
74 case osmium::item_type::node:
75 {
76
77 // Make sure nodes appear only in the role if a via node
78 if (0 == strcmp("from", role) || 0 == strcmp("to", role))
79 {
80 continue;
81 }
82 BOOST_ASSERT(0 == strcmp("via", role));
83 // set via node id
84 valid_relation &= via_node == SPECIAL_OSM_NODEID;
85 via_node = OSMNodeID{static_cast<std::uint64_t>(member.ref())};
86 break;
87 }
88 case osmium::item_type::way:
89 BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) ||
90 0 == strcmp("via", role));
91 if (0 == strcmp("from", role))
92 {
93 valid_relation &= from == SPECIAL_OSM_WAYID;
94 from = OSMWayID{static_cast<std::uint64_t>(member.ref())};
95 }
96 else if (0 == strcmp("to", role))
97 {
98 valid_relation &= to == SPECIAL_OSM_WAYID;
99 to = OSMWayID{static_cast<std::uint64_t>(member.ref())};
100 }
101 else if (0 == strcmp("via", role))
102 {
103 via_ways.push_back(OSMWayID{static_cast<std::uint64_t>(member.ref())});
104 }
105 break;
106 case osmium::item_type::relation:
107 // not yet supported, but who knows what the future holds...
108 break;
109 default:
110 // shouldn't ever happen
111 break;
112 }
113 }
114
115 // Check required roles
116 valid_relation &= from != SPECIAL_OSM_WAYID;
117 valid_relation &= to != SPECIAL_OSM_WAYID;
118 valid_relation &= via_node != SPECIAL_OSM_NODEID;
119
120 if (valid_relation)
121 {
122 maneuver_override.via_ways.push_back(from);
123 std::copy(via_ways.begin(), via_ways.end(), std::back_inserter(maneuver_override.via_ways));
124 maneuver_override.via_ways.push_back(to);
125 maneuver_override.via_node = via_node;
126 }
127 else
128 {
129 return boost::none;
130 }
131 return maneuver_override;
132 }
133 } // namespace extractor
134 } // namespace osrm
135