diff options
author | vng <viktor.govako@gmail.com> | 2015-08-19 16:58:20 +0300 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 03:03:08 +0300 |
commit | cc4562035c7da5f61c3f82d9a3414deb225f3d6b (patch) | |
tree | a2049a48977b202a7aaa4ed5e6da3089f961d480 /generator | |
parent | f80125b9d0829b83636806621475aa0c147e1d72 (diff) |
[generator] Process railway-station-subway for some special cities.
Diffstat (limited to 'generator')
-rw-r--r-- | generator/generator_tests/osm_type_test.cpp | 83 | ||||
-rw-r--r-- | generator/osm2type.cpp | 52 | ||||
-rw-r--r-- | generator/osm_element.hpp | 129 | ||||
-rw-r--r-- | generator/osm_source.cpp | 3 | ||||
-rw-r--r-- | generator/osm_source.hpp | 2 |
5 files changed, 213 insertions, 56 deletions
diff --git a/generator/generator_tests/osm_type_test.cpp b/generator/generator_tests/osm_type_test.cpp index 813fe22f33..2a4d520bb7 100644 --- a/generator/generator_tests/osm_type_test.cpp +++ b/generator/generator_tests/osm_type_test.cpp @@ -643,3 +643,86 @@ UNIT_TEST(OsmType_Dibrugarh) TEST(params.name.GetString(StringUtf8Multilang::DEFAULT_CODE, name), (params)); TEST_EQUAL(name, "Dibrugarh", (params)); } + +UNIT_TEST(OsmType_Subway) +{ + { + char const * arr[][2] = { + { "network", "Московский метрополитен" }, + { "operator", "ГУП «Московский метрополитен»" }, + { "railway", "station" }, + { "station", "subway" }, + { "transport", "subway" }, + }; + + XMLElement e; + FillXmlElement(arr, ARRAY_SIZE(arr), &e); + + FeatureParams params; + ftype::GetNameAndType(&e, params); + + TEST_EQUAL(params.m_Types.size(), 1, (params)); + TEST(params.IsTypeExist(GetType({"railway", "station", "subway", "moscow"})), (params)); + } + + { + char const * arr[][2] = { + { "name", "14th Street-8th Avenue (A,C,E,L)" }, + { "network", "New York City Subway" }, + { "railway", "station" }, + { "wheelchair", "yes" }, + { "route", "subway" }, + }; + + XMLElement e; + FillXmlElement(arr, ARRAY_SIZE(arr), &e); + + FeatureParams params; + ftype::GetNameAndType(&e, params); + + TEST_EQUAL(params.m_Types.size(), 1, (params)); + TEST(params.IsTypeExist(GetType({"railway", "station", "subway", "newyork"})), (params)); + } + + { + char const * arr[][2] = { + { "name", "S Landsberger Allee" }, + { "phone", "030 29743333" }, + { "public_transport", "stop_position" }, + { "railway", "station" }, + { "network", "New York City Subway" }, + { "station", "light_rail" }, + }; + + XMLElement e; + FillXmlElement(arr, ARRAY_SIZE(arr), &e); + + FeatureParams params; + ftype::GetNameAndType(&e, params); + + TEST_EQUAL(params.m_Types.size(), 1, (params)); + TEST(params.IsTypeExist(GetType({"railway", "station", "light_rail"})), (params)); + } + + { + char const * arr[][2] = { + { "monorail", "yes" }, + { "name", "Улица Академика Королёва" }, + { "network", "Московский метрополитен" }, + { "operator", "ГУП «Московский метрополитен»" }, + { "public_transport", "stop_position" }, + { "railway", "station" }, + { "station", "monorail" }, + { "transport", "monorail" }, + }; + + XMLElement e; + FillXmlElement(arr, ARRAY_SIZE(arr), &e); + + FeatureParams params; + ftype::GetNameAndType(&e, params); + + TEST_EQUAL(params.m_Types.size(), 1, (params)); + TEST(params.IsTypeExist(GetType({"railway", "station", "monorail"})), (params)); + } +} diff --git a/generator/osm2type.cpp b/generator/osm2type.cpp index b2bc46818b..33c02114f5 100644 --- a/generator/osm2type.cpp +++ b/generator/osm2type.cpp @@ -383,7 +383,8 @@ namespace ftype buffer_vector<uint32_t, 16> m_types; public: - enum EType { ENTRANCE, HIGHWAY, ADDRESS, ONEWAY, PRIVATE, LIT, NOFOOT, YESFOOT }; + enum EType { ENTRANCE, HIGHWAY, ADDRESS, ONEWAY, PRIVATE, LIT, NOFOOT, YESFOOT, + RW_STATION_SUBWAY }; CachedTypes() { @@ -399,6 +400,8 @@ namespace ftype }; for (auto const & e : arr) m_types.push_back(c.GetTypeByPath(e)); + + m_types.push_back(c.GetTypeByPath({ "railway", "station", "subway" })); } uint32_t Get(EType t) const { return m_types[t]; } @@ -407,6 +410,12 @@ namespace ftype ftype::TruncValue(t, 1); return t == Get(HIGHWAY); } + bool IsRwStation(uint32_t t) const + { + // check the exact match with possible types + ftype::TruncValue(t, 3); + return t == Get(RW_STATION_SUBWAY); + } }; void GetNameAndType(XMLElement * p, FeatureParams & params) @@ -483,15 +492,23 @@ namespace ftype } } - for (size_t i = 0; i < params.m_Types.size(); ++i) - if (types.IsHighway(params.m_Types[i])) + bool highwayDone = false; + bool subwayDone = false; + + // Get a copy of source types, because we will modify params in the loop; + FeatureParams::TTypes const vTypes = params.m_Types; + for (size_t i = 0; i < vTypes.size(); ++i) + { + if (!highwayDone && types.IsHighway(vTypes[i])) { TagProcessor(p).ApplyRules( { { "oneway", "yes", [¶ms]() { params.AddType(types.Get(CachedTypes::ONEWAY)); }}, { "oneway", "1", [¶ms]() { params.AddType(types.Get(CachedTypes::ONEWAY)); }}, { "oneway", "-1", [¶ms]() { params.AddType(types.Get(CachedTypes::ONEWAY)); params.m_reverseGeometry = true; }}, + { "access", "private", [¶ms]() { params.AddType(types.Get(CachedTypes::PRIVATE)); }}, + { "lit", "~", [¶ms]() { params.AddType(types.Get(CachedTypes::LIT)); }}, { "foot", "!", [¶ms]() { params.AddType(types.Get(CachedTypes::NOFOOT)); }}, @@ -499,9 +516,36 @@ namespace ftype { "foot", "~", [¶ms]() { params.AddType(types.Get(CachedTypes::YESFOOT)); }}, { "sidewalk", "~", [¶ms]() { params.AddType(types.Get(CachedTypes::YESFOOT)); }}, }); - break; + + highwayDone = true; } + if (!subwayDone && types.IsRwStation(vTypes[i])) + { + TagProcessor(p).ApplyRules( + { + { "network", "London Underground", [¶ms]() { params.SetRwStationType("london"); }}, + { "network", "New York City Subway", [¶ms]() { params.SetRwStationType("newyork"); }}, + { "network", "Московский метрополитен", [¶ms]() { params.SetRwStationType("moscow"); }}, + { "network", "Verkehrsverbund Berlin-Brandenburg", [¶ms]() { params.SetRwStationType("berlin"); }}, + { "network", "Минский метрополитен", [¶ms]() { params.SetRwStationType("minsk"); }}, + + { "network", "Київський метрополітен", [¶ms]() { params.SetRwStationType("kiev"); }}, + { "operator", "КП «Київський метрополітен»", [¶ms]() { params.SetRwStationType("kiev"); }}, + + { "network", "RATP", [¶ms]() { params.SetRwStationType("paris"); }}, + { "network", "Metro de Barcelona", [¶ms]() { params.SetRwStationType("barcelona"); }}, + + { "network", "Metro de Madrid", [¶ms]() { params.SetRwStationType("madrid"); }}, + { "operator", "Metro de Madrid", [¶ms]() { params.SetRwStationType("madrid"); }}, + + { "network", "Metropolitana di Roma", [¶ms]() { params.SetRwStationType("roma"); }}, + }); + + subwayDone = true; + } + } + params.FinishAddingTypes(); // Collect addidtional information about feature such as diff --git a/generator/osm_element.hpp b/generator/osm_element.hpp index 5260d08733..2ae4457169 100644 --- a/generator/osm_element.hpp +++ b/generator/osm_element.hpp @@ -104,17 +104,81 @@ class SecondPassParser /// Generated features should include parent relation tags to make /// full types matching and storing any additional info. - class RelationTagsProcessor + class RelationTagsBase { + public: + RelationTagsBase() : m_cache(14) {} + + void Reset(uint64_t fID, XMLElement * p) + { + m_featureID = fID; + m_current = p; + } + + template <class ReaderT> bool operator() (uint64_t id, ReaderT & reader) + { + bool exists = false; + RelationElement & e = m_cache.Find(id, exists); + if (!exists) + CHECK(reader.Read(id, e), (id)); + + Process(e); + return false; + } + + protected: + static bool IsSkipRelation(string const & type) + { + /// @todo Skip special relation types. + return (type == "multipolygon" || type == "bridge" || type == "restriction"); + } + + bool IsKeyTagExists(string const & key) const + { + for (auto const & p : m_current->m_tags) + if (p.key == key) + return true; + return false; + } + + virtual void Process(RelationElement const & e) = 0; + + protected: uint64_t m_featureID; XMLElement * m_current; + private: my::Cache<uint64_t, RelationElement> m_cache; + }; + + class RelationTagsNode : public RelationTagsBase + { + typedef RelationTagsBase TBase; + + protected: + void Process(RelationElement const & e) override + { + if (TBase::IsSkipRelation(e.GetType())) + return; + + for (auto const & p : e.tags) + { + // Store only this tags to use it in railway stations processing for the particular city. + if (p.first == "network" || p.first == "operator" || p.first == "route") + if (!TBase::IsKeyTagExists(p.first)) + TBase::m_current->AddTag(p.first, p.second); + } + } + } m_nodeRelations; + + class RelationTagsWay : public RelationTagsBase + { + typedef RelationTagsBase TBase; bool IsAcceptBoundary(RelationElement const & e) const { string role; - CHECK(e.FindWay(m_featureID, role), (m_featureID)); + CHECK(e.FindWay(TBase::m_featureID, role), (TBase::m_featureID)); // Do not accumulate boundary types (boundary=administrative) for inner polygons. // Example: Minsk city border (admin_level=8) is inner for Minsk area border (admin_level=4). @@ -124,25 +188,21 @@ class SecondPassParser typedef unordered_set<string> NameKeysT; void GetNameKeys(NameKeysT & keys) const { - for (auto const & p : m_current->m_tags) + for (auto const & p : TBase::m_current->m_tags) if (strings::StartsWith(p.key, "name")) keys.insert(p.key); } - void Process(RelationElement const & e) + protected: + void Process(RelationElement const & e) override { + /// @todo Review route relations in future. + /// Actually, now they give a lot of dummy tags. string const type = e.GetType(); - - /// @todo Skip special relation types. - if (type == "multipolygon" || - type == "route" || - type == "bridge" || - type == "restriction") - { + if (TBase::IsSkipRelation(type) || type == "route") return; - } - bool const isWay = (m_current->type == XMLElement::EntityType::Way); + bool const isWay = (TBase::m_current->type == XMLElement::EntityType::Way); bool const isBoundary = isWay && (type == "boundary") && IsAcceptBoundary(e); NameKeysT nameKeys; @@ -154,7 +214,7 @@ class SecondPassParser if (p.first == "type" || p.first == "route") continue; - /// Skip already existing "name" tags. + // Skip already existing "name" tags. if (nameKeys.count(p.first) != 0) continue; @@ -164,52 +224,23 @@ class SecondPassParser if (isWay && p.first == "place") continue; - m_current->AddTag(p.first, p.second); + TBase::m_current->AddTag(p.first, p.second); } } - - public: - RelationTagsProcessor() - : m_cache(14) - { - } - - void Reset(uint64_t fID, XMLElement * p) - { - m_featureID = fID; - m_current = p; - } - - template <class ReaderT> bool operator() (uint64_t id, ReaderT & reader) - { - bool exists = false; - RelationElement & e = m_cache.Find(id, exists); - if (!exists) - CHECK(reader.Read(id, e), (id)); - - Process(e); - return false; - } - - } m_relationsProcess; + } m_wayRelations; bool ParseType(XMLElement * p, FeatureParams & params) { // Get tags from parent relations. - m_relationsProcess.Reset(p->id, p); - if (p->type == XMLElement::EntityType::Node) { - // additional process of nodes ONLY if there is no native types - FeatureParams fp; - ftype::GetNameAndType(p, fp); - if (!ftype::IsValidTypes(fp)) - m_holder.ForEachRelationByNodeCached(p->id, m_relationsProcess); + m_nodeRelations.Reset(p->id, p); + m_holder.ForEachRelationByNodeCached(p->id, m_nodeRelations); } else if (p->type == XMLElement::EntityType::Way) { - // always make additional process of ways - m_holder.ForEachRelationByWayCached(p->id, m_relationsProcess); + m_wayRelations.Reset(p->id, p); + m_holder.ForEachRelationByWayCached(p->id, m_wayRelations); } // Get params from element tags. diff --git a/generator/osm_source.cpp b/generator/osm_source.cpp index 245adb7640..207ef7387e 100644 --- a/generator/osm_source.cpp +++ b/generator/osm_source.cpp @@ -20,14 +20,13 @@ #include "defines.hpp" SourceReader::SourceReader() -: m_file(unique_ptr<istream,Deleter>(&cin, Deleter(false))) +: m_file(unique_ptr<istream, Deleter>(&cin, Deleter(false))) { LOG_SHORT(LINFO, ("Reading OSM data from stdin")); } SourceReader::SourceReader(string const & filename) { - CHECK(!filename.empty() , ("Filename can't be empty")); m_file = unique_ptr<istream, Deleter>(new ifstream(filename), Deleter()); CHECK(static_cast<ifstream *>(m_file.get())->is_open() , ("Can't open file:", filename)); LOG_SHORT(LINFO, ("Reading OSM data from", filename)); diff --git a/generator/osm_source.hpp b/generator/osm_source.hpp index 9a12daacb0..e3b5b07894 100644 --- a/generator/osm_source.hpp +++ b/generator/osm_source.hpp @@ -24,7 +24,7 @@ class SourceReader public: SourceReader(); - SourceReader(string const & filename); + explicit SourceReader(string const & filename); explicit SourceReader(istringstream & stream); uint64_t Read(char * buffer, uint64_t bufferSize); |