11#ifndef EXTRACTION_RELATION_HPP
22#define EXTRACTION_RELATION_HPP
33
4+ #include " util/exception.hpp"
5+
46#include < osmium/osm/relation.hpp>
57
68#include < boost/assert.hpp>
@@ -16,63 +18,197 @@ namespace extractor
1618
1719struct ExtractionRelation
1820{
19- using AttributesMap = std::unordered_map<std::string, std::string>;
20- using OsmIDTyped = std::pair<osmium::object_id_type, osmium::item_type>;
21-
22- struct OsmIDTypedHash
21+ class OsmIDTyped
2322 {
24- std::size_t operator ()(const OsmIDTyped &id) const
23+ public:
24+ OsmIDTyped (osmium::object_id_type _id, osmium::item_type _type)
25+ : id(_id), type(_type)
2526 {
26- return id.first ^ (static_cast <std::uint64_t >(id.second ) << 56 );
2727 }
28+
29+ std::uint64_t GetID () const { return std::uint64_t (id); }
30+ osmium::item_type GetType () const { return type; }
31+
32+ std::uint64_t Hash () const
33+ {
34+ return id ^ (static_cast <std::uint64_t >(type) << 56 );
35+ }
36+
37+ private:
38+ osmium::object_id_type id;
39+ osmium::item_type type;
2840 };
2941
30- ExtractionRelation () : is_restriction(false ) {}
42+ using AttributesList = std::vector<std::pair<std::string, std::string>>;
43+ using MembersRolesList = std::vector<std::pair<std::uint64_t , std::string>>;
3144
32- void clear ()
45+ explicit ExtractionRelation (const OsmIDTyped & _id)
46+ : id(_id)
3347 {
34- is_restriction = false ;
35- values.clear ();
3648 }
3749
38- bool IsRestriction () const { return is_restriction; }
50+ void Clear ()
51+ {
52+ attributes.clear ();
53+ members_role.clear ();
54+ }
55+
56+ const char * GetAttr (const std::string & attr) const
57+ {
58+ auto it = std::lower_bound (
59+ attributes.begin (),
60+ attributes.end (),
61+ std::make_pair (attr, std::string ()));
62+
63+ if (it != attributes.end () && (*it).first == attr)
64+ return (*it).second .c_str ();
65+
66+ return nullptr ;
67+ }
3968
40- AttributesMap & GetMember ( const osmium::RelationMember &member )
69+ void Prepare ( )
4170 {
42- return values[OsmIDTyped (member.ref (), member.type ())];
71+ std::sort (attributes.begin (), attributes.end ());
72+ std::sort (members_role.begin (), members_role.end ());
4373 }
4474
45- bool is_restriction;
46- std::unordered_map<OsmIDTyped, AttributesMap, OsmIDTypedHash> values;
75+ void AddMember (const OsmIDTyped & member_id, const char * role)
76+ {
77+ members_role.emplace_back (std::make_pair (member_id.Hash (), std::string (role)));
78+ }
79+
80+ const char * GetRole (const OsmIDTyped & member_id) const
81+ {
82+ const auto hash = member_id.Hash ();
83+ auto it = std::lower_bound (
84+ members_role.begin (),
85+ members_role.end (),
86+ std::make_pair (hash, std::string ()));
87+
88+ if (it != members_role.end () && (*it).first == hash)
89+ return (*it).second .c_str ();
90+
91+ return nullptr ;
92+ }
93+
94+ OsmIDTyped id;
95+ AttributesList attributes;
96+ MembersRolesList members_role;
4797};
4898
4999// It contains data of all parsed relations for each node/way element
50100class ExtractionRelationContainer
51101{
52102 public:
53- using AttributesMap = ExtractionRelation::AttributesMap ;
103+ using AttributesMap = ExtractionRelation::AttributesList ;
54104 using OsmIDTyped = ExtractionRelation::OsmIDTyped;
55105 using RelationList = std::vector<AttributesMap>;
106+ using RelationIDList = std::vector<ExtractionRelation::OsmIDTyped>;
107+ using RelationRefMap = std::unordered_map<std::uint64_t , RelationIDList>;
56108
57- void AddRelation (const ExtractionRelation &rel)
109+ void AddRelation (ExtractionRelation && rel)
58110 {
59- BOOST_ASSERT (!rel.is_restriction );
60- for (auto it : rel.values )
61- data[it.first ].push_back (it.second );
111+ rel.Prepare ();
112+
113+ BOOST_ASSERT (relations_data.find (rel.id .GetID ()) == relations_data.end ());
114+ relations_data.insert (std::make_pair (rel.id .GetID (), std::move (rel)));
62115 }
63116
64- const RelationList & Get ( const OsmIDTyped &id) const
117+ void AddRelationMember ( const OsmIDTyped & relation_id, const OsmIDTyped & member_id)
65118 {
66- const auto it = data.find (id);
67- if (it != data.end ())
68- return it->second ;
119+ switch (member_id.GetType ())
120+ {
121+ case osmium::item_type::node:
122+ node_refs[member_id.GetID ()].push_back (relation_id);
123+ break ;
69124
70- static RelationList empty;
71- return empty;
125+ case osmium::item_type::way:
126+ way_refs[member_id.GetID ()].push_back (relation_id);
127+ break ;
128+
129+ case osmium::item_type::relation:
130+ rel_refs[member_id.GetID ()].push_back (relation_id);
131+ break ;
132+
133+ default :
134+ break ;
135+ };
136+ }
137+
138+ void Merge (ExtractionRelationContainer && other)
139+ {
140+ for (auto it : other.relations_data )
141+ {
142+ const auto res = relations_data.insert (std::make_pair (it.first , std::move (it.second )));
143+ BOOST_ASSERT (res.second );
144+ (void )res; // prevent unused warning in release
145+ }
146+
147+ auto MergeRefMap = [&](RelationRefMap & source, RelationRefMap & target)
148+ {
149+ for (auto it : source)
150+ {
151+ auto & v = target[it.first ];
152+ v.insert (v.end (), it.second .begin (), it.second .end ());
153+ }
154+ };
155+
156+ MergeRefMap (other.way_refs , way_refs);
157+ MergeRefMap (other.node_refs , node_refs);
158+ MergeRefMap (other.rel_refs , rel_refs);
159+ }
160+
161+ std::size_t GetRelationsNum () const
162+ {
163+ return relations_data.size ();
164+ }
165+
166+ const RelationIDList & GetRelations (const OsmIDTyped & member_id) const
167+ {
168+ auto getFromMap = [this ](std::uint64_t id, const RelationRefMap & map) -> const RelationIDList &
169+ {
170+ auto it = map.find (id);
171+ if (it != map.end ())
172+ return it->second ;
173+
174+ return empty_rel_list;
175+ };
176+
177+ switch (member_id.GetType ())
178+ {
179+ case osmium::item_type::node:
180+ return getFromMap (member_id.GetID (), node_refs);
181+
182+ case osmium::item_type::way:
183+ return getFromMap (member_id.GetID (), way_refs);
184+
185+ case osmium::item_type::relation:
186+ return getFromMap (member_id.GetID (), rel_refs);
187+
188+ default :
189+ break ;
190+ }
191+
192+ return empty_rel_list;
193+ }
194+
195+ const ExtractionRelation & GetRelationData (const ExtractionRelation::OsmIDTyped & rel_id) const
196+ {
197+ auto it = relations_data.find (rel_id.GetID ());
198+ if (it == relations_data.end ())
199+ throw osrm::util::exception (" Can't find relation data for " + std::to_string (rel_id.GetID ()));
200+
201+ return it->second ;
72202 }
73203
74204 private:
75- std::unordered_map<OsmIDTyped, RelationList, ExtractionRelation::OsmIDTypedHash> data;
205+ RelationIDList empty_rel_list;
206+ std::unordered_map<std::uint64_t , ExtractionRelation> relations_data;
207+
208+ // each map contains list of relation id's, that has keyed id as a member
209+ RelationRefMap way_refs;
210+ RelationRefMap node_refs;
211+ RelationRefMap rel_refs;
76212};
77213
78214} // namespace extractor
0 commit comments