diff options
author | vng <viktor.govako@gmail.com> | 2014-11-14 16:34:00 +0300 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 02:33:19 +0300 |
commit | 48ecb3a58742404f15d9e78eff75109f388ffd3a (patch) | |
tree | 6d6828c35040c338a0cfa2aee7d117b8e110c0d9 /generator | |
parent | 50035f452fee699254c84d3608b1a98e54bebe64 (diff) |
[generator] Better process of parent relation tags for generated feature.
Diffstat (limited to 'generator')
-rw-r--r-- | generator/feature_generator.cpp | 9 | ||||
-rw-r--r-- | generator/osm_element.hpp | 169 |
2 files changed, 76 insertions, 102 deletions
diff --git a/generator/feature_generator.cpp b/generator/feature_generator.cpp index 5d602fa4ec..b75a45164e 100644 --- a/generator/feature_generator.cpp +++ b/generator/feature_generator.cpp @@ -41,8 +41,8 @@ class FileHolder : public cache::BaseFileHolder<TNodesHolder, cache::DataFileRea template <class TElement, class ToDo> struct process_base { - reader_t & m_reader; protected: + reader_t & m_reader; ToDo & m_toDo; public: process_base(reader_t & reader, ToDo & toDo) : m_reader(reader), m_toDo(toDo) {} @@ -73,12 +73,7 @@ class FileHolder : public cache::BaseFileHolder<TNodesHolder, cache::DataFileRea bool operator() (uint64_t id) { - switch (this->m_toDo(id)) - { - case 1: return true; - case -1: return false; - default: return base_type::operator()(id); - } + return this->m_toDo(id, this->m_reader); } }; diff --git a/generator/osm_element.hpp b/generator/osm_element.hpp index 4b60a02987..b69bf578f5 100644 --- a/generator/osm_element.hpp +++ b/generator/osm_element.hpp @@ -11,6 +11,7 @@ #include "../base/string_utils.hpp" #include "../base/logging.hpp" #include "../base/stl_add.hpp" +#include "../base/cache.hpp" #include "../std/unordered_map.hpp" #include "../std/list.hpp" @@ -98,144 +99,122 @@ class SecondPassParser : public BaseOSMParser holes_list_t & GetHoles() { return m_holes.GetHoles(); } }; - /// Feature types processor. - class type_processor + /// Generated features should include parent relation tags to make + /// full types matching and storing any additional info. + class RelationTagsProcessor { - static void MakeXMLElement(RelationElement const & rel, XMLElement & out) - { - for (auto i = rel.tags.begin(); i != rel.tags.end(); ++i) - if (i->first != "type") - out.AddKV(i->first, i->second); - } - - /// @param[in] ID of processing feature. uint64_t m_featureID; + XMLElement * m_current; - /// @param[out] Feature value as result. - FeatureParams * m_val; + my::Cache<uint64_t, RelationElement> m_cache; - /// Cache: relation id -> feature value (for fast feature parsing) - struct RelationValue - { - FeatureParams m_p; - RelationElement * m_e; - - RelationValue() : m_e(0) {} - }; - - typedef unordered_map<uint64_t, RelationValue> RelationCacheT; - RelationCacheT m_typeCache; - - bool IsAcceptBoundaryTypes(RelationElement const & rel) const + bool IsAcceptBoundary(RelationElement const & e) const { string role; - if (!rel.FindWay(m_featureID, role)) - { - // This case is possible when we found the relation by node (just skip it). - CHECK ( rel.FindNode(m_featureID, role), (m_featureID) ); - return false; - } + CHECK(e.FindWay(m_featureID, role), (m_featureID)); - // Do not accumulate boundary types (boundary-administrative-*) for inner polygons. + // 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). return (role != "inner"); } - uint32_t const m_boundaryType; - uint32_t GetSkipBoundaryType(RelationElement const * rel) const - { - return ((rel == 0 || IsAcceptBoundaryTypes(*rel)) ? 0 : m_boundaryType); - } - - public: - type_processor() : m_boundaryType(ftype::GetBoundaryType2()) + bool HasName() const { - } + for (auto p : m_current->childs) + { + if (p.name == "tag") + for (auto a : p.attrs) + if (strings::StartsWith(a.first, "name")) + return true; + } - ~type_processor() - { - for (auto & r : m_typeCache) - delete r.second.m_e; + return false; } - /// Start process new feature. - void Reset(uint64_t fID, FeatureParams * val) + void Process(RelationElement const & e) { - m_featureID = fID; - m_val = val; - } + string const type = e.GetType(); - /// 1. "initial relation" process - int operator() (uint64_t id) - { - auto const i = m_typeCache.find(id); - if (i != m_typeCache.end()) + /// @todo Skip special relation types. + if (type == "multipolygon" || + type == "route" || + type == "bridge" || + type == "restriction") { - m_val->AddTypes(i->second.m_p, GetSkipBoundaryType(i->second.m_e)); - return -1; // continue process relations + return; } - return 0; // read relation from file (see next operator) - } - /// 2. "relation from file" process - /// param[in] rel Get non-const reference to Swap inner data - bool operator() (uint64_t id, RelationElement & rel) - { - string const type = rel.GetType(); - if (type == "multipolygon") + bool const isWay = (m_current->name == "way"); + bool const isBoundary = isWay && (type == "boundary") && IsAcceptBoundary(e); + bool const hasName = HasName(); + + for (auto p : e.tags) { - // we will process multipolygons later - return false; - } - bool const isBoundary = (type == "boundary"); + /// @todo Skip common key tags. + if (p.first == "type" || p.first == "route") + continue; - // make XMLElement struct from relation's tags for GetNameAndType function. - XMLElement e; - MakeXMLElement(rel, e); + if (hasName && strings::StartsWith(p.first, "name")) + continue; - // process types of relation and add them to m_val - RelationValue val; - ftype::GetNameAndType(&e, val.m_p); - if (val.m_p.IsValid()) - { - m_val->AddTypes(val.m_p, GetSkipBoundaryType(isBoundary ? &rel : 0)); + if (!isBoundary && p.first == "boundary") + continue; - if (isBoundary) - { - val.m_e = new RelationElement(); - val.m_e->Swap(rel); - } + if (isWay && p.first == "place") + continue; + + m_current->AddKV(p.first, p.second); } + } + + public: + RelationTagsProcessor() + : m_cache(14) + { + } - m_typeCache[id] = val; + void Reset(uint64_t fID, XMLElement * p) + { + m_featureID = fID; + m_current = p; + } - // continue process relations + 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_typeProcessor; + } m_relationsProcess; bool ParseType(XMLElement * p, uint64_t & id, FeatureParams & params) { - CHECK ( strings::to_uint64(p->attrs["id"], id), (p->attrs["id"]) ); - - // try to get type from element tags - ftype::GetNameAndType(p, params); + CHECK(strings::to_uint64(p->attrs["id"], id), (p->attrs["id"])); - // try to get type from relations tags - m_typeProcessor.Reset(id, ¶ms); + // Get tags from parent relations. + m_relationsProcess.Reset(id, p); - if (p->name == "node" && !params.IsValid()) + if (p->name == "node") { // additional process of nodes ONLY if there is no native types - m_holder.ForEachRelationByNodeCached(id, m_typeProcessor); + FeatureParams fp; + ftype::GetNameAndType(p, fp); + if (!ftype::IsValidTypes(fp)) + m_holder.ForEachRelationByNodeCached(id, m_relationsProcess); } else if (p->name == "way") { // always make additional process of ways - m_holder.ForEachRelationByWayCached(id, m_typeProcessor); + m_holder.ForEachRelationByWayCached(id, m_relationsProcess); } + // Get params from element tags. + ftype::GetNameAndType(p, params); params.FinishAddingTypes(); return ftype::IsValidTypes(params); } |