diff --git a/generator/feature_generator.cpp b/generator/feature_generator.cpp index 74c9f51792..94c0608979 100644 --- a/generator/feature_generator.cpp +++ b/generator/feature_generator.cpp @@ -314,6 +314,7 @@ public: { if (m_coasts) { + CHECK ( fb.GetGeomType() != feature::GEOM_POINT, () ); if (fb.HasType(m_coastType)) { // leave only coastline type diff --git a/generator/osm_decl.cpp b/generator/osm_decl.cpp index c0d345d400..de1e71eb13 100644 --- a/generator/osm_decl.cpp +++ b/generator/osm_decl.cpp @@ -35,13 +35,27 @@ string RelationElement::GetType() const return ((i != tags.end()) ? i->second : string()); } +namespace +{ + bool FindRoleImpl(vector > const & cnt, + uint64_t id, string & role) + { + for (size_t i = 0; i < cnt.size(); ++i) + if (cnt[i].first == id) + { + role = cnt[i].second; + return true; + } + return false; + } +} + bool RelationElement::FindWay(uint64_t id, string & role) const { - for (size_t i = 0; i < ways.size(); ++i) - if (ways[i].first == id) - { - role = ways[i].second; - return true; - } - return false; + return FindRoleImpl(ways, id, role); +} + +bool RelationElement::FindNode(uint64_t id, string & role) const +{ + return FindRoleImpl(nodes, id, role); } diff --git a/generator/osm_decl.hpp b/generator/osm_decl.hpp index 6c63948ccc..1bd3ba7e81 100644 --- a/generator/osm_decl.hpp +++ b/generator/osm_decl.hpp @@ -93,6 +93,7 @@ struct RelationElement string GetType() const; bool FindWay(uint64_t id, string & role) const; + bool FindNode(uint64_t id, string & role) const; template void ForEachWay(ToDo & toDo) const { diff --git a/generator/osm_element.hpp b/generator/osm_element.hpp index e48ef776f7..5db33a2360 100644 --- a/generator/osm_element.hpp +++ b/generator/osm_element.hpp @@ -222,7 +222,12 @@ protected: bool IsAcceptBoundaryTypes(RelationElement const & rel) const { string role; - VERIFY ( rel.FindWay(m_featureID, role), (m_featureID) ); + 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; + } // 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). @@ -359,6 +364,8 @@ class SecondPassParserUsual : public SecondPassParserBase protected: virtual void EmitElement(XMLElement * p) { + using namespace feature; + uint64_t id; FeatureParams fValue; if (!base_type::ParseType(p, id, fValue)) @@ -369,7 +376,7 @@ protected: if (p->name == "node") { - if (!feature::IsDrawableLike(fValue.m_Types, feature::FEATURE_TYPE_POINT)) + if (!feature::RemoveNoDrawableTypes(fValue.m_Types, FEATURE_TYPE_POINT)) return; m2::PointD pt; @@ -380,13 +387,7 @@ protected: } else if (p->name == "way") { - bool const isLine = feature::IsDrawableLike(fValue.m_Types, feature::FEATURE_TYPE_LINE) || - // this is important fix: we need to process all coastlines even without linear drawing rules - (m_coastType != 0 && fValue.IsTypeExist(m_coastType)); - - bool const isArea = feature::IsDrawableLike(fValue.m_Types, feature::FEATURE_TYPE_AREA); - - if (!isLine && !isArea) + if (!feature::RemoveNoDrawableTypes(fValue.m_Types, FEATURE_TYPE_LINE_AREA)) return; // geometry of feature @@ -395,8 +396,7 @@ protected: if (p->childs[i].name == "nd") { uint64_t nodeID; - VERIFY ( strings::to_uint64(p->childs[i].attrs["ref"], nodeID), - ("Bad node ref in way : ", p->childs[i].attrs["ref"]) ); + CHECK ( strings::to_uint64(p->childs[i].attrs["ref"], nodeID), (p->childs[i].attrs["ref"]) ); m2::PointD pt; if (!base_type::GetPoint(nodeID, pt)) @@ -410,13 +410,25 @@ protected: if (count < 2) return; - if (isLine) - ft.SetLinear(); - - // Get the tesselation for an area object (only if it has area drawing rules, - // otherwise it will stay a linear object). - if (isArea && count > 2 && ft.IsGeometryClosed()) + // Try to set area feature (linear types are also suitable for this) + if (feature::IsDrawableLike(fValue.m_Types, FEATURE_TYPE_AREA) && + (count > 2) && ft.IsGeometryClosed()) + { base_type::FinishAreaFeature(id, ft); + } + else + { + // Try to set linear feature: + // - it's a coastline, OR + // - has linear types (remove others) + if ((m_coastType != 0 && fValue.IsTypeExist(m_coastType)) || + feature::RemoveNoDrawableTypes(fValue.m_Types, FEATURE_TYPE_LINE)) + { + ft.SetLinear(); + } + else + return; + } } else if (p->name == "relation") { @@ -438,16 +450,13 @@ protected: } // 2. Relation should have visible area types. - if (!feature::IsDrawableLike(fValue.m_Types, feature::FEATURE_TYPE_AREA)) - { - LOG(LWARNING, ("Polygon relation without area types:", id)); + if (!feature::IsDrawableLike(fValue.m_Types, FEATURE_TYPE_AREA)) return; - } typename base_type::holes_accumulator holes(this); typename base_type::way_map_t wayMap; - // 2. Iterate ways to get 'outer' and 'inner' geometries + // 3. Iterate ways to get 'outer' and 'inner' geometries for (size_t i = 0; i < p->childs.size(); ++i) { if (p->childs[i].name == "member" && @@ -455,8 +464,7 @@ protected: { string const & role = p->childs[i].attrs["role"]; uint64_t wayID; - VERIFY ( strings::to_uint64(p->childs[i].attrs["ref"], wayID), - ("Bad way ref in relation : ", p->childs[i].attrs["ref"]) ); + CHECK ( strings::to_uint64(p->childs[i].attrs["ref"], wayID), (p->childs[i].attrs["ref"]) ); if (role == "outer") { @@ -466,10 +474,6 @@ protected: { holes(wayID); } - else if (role.empty()) - { - LOG(LWARNING, ("Way", wayID, "in relation", id, "with empty role")); - } } } diff --git a/indexer/feature_visibility.cpp b/indexer/feature_visibility.cpp index ee96d55a33..db0c5cc953 100644 --- a/indexer/feature_visibility.cpp +++ b/indexer/feature_visibility.cpp @@ -254,6 +254,47 @@ bool IsDrawableForIndex(FeatureBase const & f, int level) return false; } +namespace +{ + class CheckNonDrawableType + { + Classificator & m_c; + FeatureGeoType m_arr[3]; + size_t m_count; + + public: + CheckNonDrawableType(FeatureGeoType ft) + : m_c(classif()), m_count(0) + { + if (ft < FEATURE_TYPE_LINE_AREA) + m_arr[m_count++] = ft; + else + { + ASSERT_EQUAL ( ft, FEATURE_TYPE_LINE_AREA, () ); + m_arr[m_count++] = FEATURE_TYPE_LINE; + m_arr[m_count++] = FEATURE_TYPE_AREA; + } + } + + bool operator() (uint32_t t) + { + for (size_t i = 0; i < m_count; ++i) + { + IsDrawableLikeChecker doCheck(m_arr[i]); + if (m_c.ProcessObjects(t, doCheck)) + return false; + } + return true; + } + }; +} + +bool RemoveNoDrawableTypes(vector & types, FeatureGeoType ft) +{ + types.erase(remove_if(types.begin(), types.end(), CheckNonDrawableType(ft)), types.end()); + return !types.empty(); +} + int GetMinDrawableScale(FeatureBase const & f) { int const upBound = scales::GetUpperScale(); diff --git a/indexer/feature_visibility.hpp b/indexer/feature_visibility.hpp index b4ba4c5f77..6f3fea925c 100644 --- a/indexer/feature_visibility.hpp +++ b/indexer/feature_visibility.hpp @@ -19,13 +19,16 @@ namespace feature enum FeatureGeoType { FEATURE_TYPE_POINT = 0, FEATURE_TYPE_LINE = 1, - FEATURE_TYPE_AREA = 2 + FEATURE_TYPE_AREA = 2, + FEATURE_TYPE_LINE_AREA = 3 }; bool IsDrawableAny(uint32_t type); - bool IsDrawableLike(vector const & type, FeatureGeoType ft); + bool IsDrawableLike(vector const & types, FeatureGeoType ft); bool IsDrawableForIndex(FeatureBase const & f, int level); + bool RemoveNoDrawableTypes(vector & types, FeatureGeoType ft); + int GetMinDrawableScale(FeatureBase const & f); /// @return [-1, -1] if no any text exists