1 #ifndef EXTRACTION_RELATION_HPP 2 #define EXTRACTION_RELATION_HPP 3 4 #include "util/exception.hpp" 5 6 #include <osmium/osm/relation.hpp> 7 8 #include <boost/assert.hpp> 9 10 #include <string> 11 #include <unordered_map> 12 #include <vector> 13 14 namespace osrm 15 { 16 namespace extractor 17 { 18 19 struct ExtractionRelation 20 { 21 class OsmIDTyped 22 { 23 public: OsmIDTyped(osmium::object_id_type _id,osmium::item_type _type)24 OsmIDTyped(osmium::object_id_type _id, osmium::item_type _type) : id(_id), type(_type) {} 25 GetID() const26 std::uint64_t GetID() const { return std::uint64_t(id); } GetType() const27 osmium::item_type GetType() const { return type; } 28 Hash() const29 std::uint64_t Hash() const { return id ^ (static_cast<std::uint64_t>(type) << 56); } 30 31 private: 32 osmium::object_id_type id; 33 osmium::item_type type; 34 }; 35 36 using AttributesList = std::vector<std::pair<std::string, std::string>>; 37 using MembersRolesList = std::vector<std::pair<std::uint64_t, std::string>>; 38 ExtractionRelationosrm::extractor::ExtractionRelation39 explicit ExtractionRelation(const OsmIDTyped &_id) : id(_id) {} 40 Clearosrm::extractor::ExtractionRelation41 void Clear() 42 { 43 attributes.clear(); 44 members_role.clear(); 45 } 46 GetAttrosrm::extractor::ExtractionRelation47 const char *GetAttr(const std::string &attr) const 48 { 49 auto it = std::lower_bound( 50 attributes.begin(), attributes.end(), std::make_pair(attr, std::string())); 51 52 if (it != attributes.end() && (*it).first == attr) 53 return (*it).second.c_str(); 54 55 return nullptr; 56 } 57 Prepareosrm::extractor::ExtractionRelation58 void Prepare() 59 { 60 std::sort(attributes.begin(), attributes.end()); 61 std::sort(members_role.begin(), members_role.end()); 62 } 63 AddMemberosrm::extractor::ExtractionRelation64 void AddMember(const OsmIDTyped &member_id, const char *role) 65 { 66 members_role.emplace_back(std::make_pair(member_id.Hash(), std::string(role))); 67 } 68 GetRoleosrm::extractor::ExtractionRelation69 const char *GetRole(const OsmIDTyped &member_id) const 70 { 71 const auto hash = member_id.Hash(); 72 auto it = std::lower_bound( 73 members_role.begin(), members_role.end(), std::make_pair(hash, std::string())); 74 75 if (it != members_role.end() && (*it).first == hash) 76 return (*it).second.c_str(); 77 78 return nullptr; 79 } 80 81 OsmIDTyped id; 82 AttributesList attributes; 83 MembersRolesList members_role; 84 }; 85 86 // It contains data of all parsed relations for each node/way element 87 class ExtractionRelationContainer 88 { 89 public: 90 using AttributesMap = ExtractionRelation::AttributesList; 91 using OsmIDTyped = ExtractionRelation::OsmIDTyped; 92 using RelationList = std::vector<AttributesMap>; 93 using RelationIDList = std::vector<ExtractionRelation::OsmIDTyped>; 94 using RelationRefMap = std::unordered_map<std::uint64_t, RelationIDList>; 95 AddRelation(ExtractionRelation && rel)96 void AddRelation(ExtractionRelation &&rel) 97 { 98 rel.Prepare(); 99 100 BOOST_ASSERT(relations_data.find(rel.id.GetID()) == relations_data.end()); 101 relations_data.insert(std::make_pair(rel.id.GetID(), std::move(rel))); 102 } 103 AddRelationMember(const OsmIDTyped & relation_id,const OsmIDTyped & member_id)104 void AddRelationMember(const OsmIDTyped &relation_id, const OsmIDTyped &member_id) 105 { 106 switch (member_id.GetType()) 107 { 108 case osmium::item_type::node: 109 node_refs[member_id.GetID()].push_back(relation_id); 110 break; 111 112 case osmium::item_type::way: 113 way_refs[member_id.GetID()].push_back(relation_id); 114 break; 115 116 case osmium::item_type::relation: 117 rel_refs[member_id.GetID()].push_back(relation_id); 118 break; 119 120 default: 121 break; 122 }; 123 } 124 Merge(ExtractionRelationContainer && other)125 void Merge(ExtractionRelationContainer &&other) 126 { 127 for (auto it : other.relations_data) 128 { 129 const auto res = relations_data.insert(std::make_pair(it.first, std::move(it.second))); 130 BOOST_ASSERT(res.second); 131 (void)res; // prevent unused warning in release 132 } 133 134 auto MergeRefMap = [&](RelationRefMap &source, RelationRefMap &target) { 135 for (auto it : source) 136 { 137 auto &v = target[it.first]; 138 v.insert(v.end(), it.second.begin(), it.second.end()); 139 } 140 }; 141 142 MergeRefMap(other.way_refs, way_refs); 143 MergeRefMap(other.node_refs, node_refs); 144 MergeRefMap(other.rel_refs, rel_refs); 145 } 146 GetRelationsNum() const147 std::size_t GetRelationsNum() const { return relations_data.size(); } 148 GetRelations(const OsmIDTyped & member_id) const149 const RelationIDList &GetRelations(const OsmIDTyped &member_id) const 150 { 151 auto getFromMap = [this](std::uint64_t id, 152 const RelationRefMap &map) -> const RelationIDList & { 153 auto it = map.find(id); 154 if (it != map.end()) 155 return it->second; 156 157 return empty_rel_list; 158 }; 159 160 switch (member_id.GetType()) 161 { 162 case osmium::item_type::node: 163 return getFromMap(member_id.GetID(), node_refs); 164 165 case osmium::item_type::way: 166 return getFromMap(member_id.GetID(), way_refs); 167 168 case osmium::item_type::relation: 169 return getFromMap(member_id.GetID(), rel_refs); 170 171 default: 172 break; 173 } 174 175 return empty_rel_list; 176 } 177 GetRelationData(const ExtractionRelation::OsmIDTyped & rel_id) const178 const ExtractionRelation &GetRelationData(const ExtractionRelation::OsmIDTyped &rel_id) const 179 { 180 auto it = relations_data.find(rel_id.GetID()); 181 if (it == relations_data.end()) 182 throw osrm::util::exception("Can't find relation data for " + 183 std::to_string(rel_id.GetID())); 184 185 return it->second; 186 } 187 188 private: 189 RelationIDList empty_rel_list; 190 std::unordered_map<std::uint64_t, ExtractionRelation> relations_data; 191 192 // each map contains list of relation id's, that has keyed id as a member 193 RelationRefMap way_refs; 194 RelationRefMap node_refs; 195 RelationRefMap rel_refs; 196 }; 197 198 } // namespace extractor 199 } // namespace osrm 200 201 #endif // EXTRACTION_RELATION_HPP 202