From 80d669896ffcd3fbefc7d539e14108c94757dd77 Mon Sep 17 00:00:00 2001 From: Sergey Magidovich Date: Thu, 21 Jul 2016 13:31:16 +0300 Subject: [PATCH] Move places handling from translator to MainFratureEmitter. --- generator/osm_source.cpp | 167 ++++++++++++++++++++++++++++------- generator/osm_translator.hpp | 109 +++-------------------- 2 files changed, 143 insertions(+), 133 deletions(-) diff --git a/generator/osm_source.cpp b/generator/osm_source.cpp index b3bfdf13ea..03371b029f 100644 --- a/generator/osm_source.cpp +++ b/generator/osm_source.cpp @@ -18,6 +18,7 @@ #include "platform/platform.hpp" #include "geometry/mercator.hpp" +#include "geometry/tree4d.hpp" #include "coding/parse_xml.hpp" @@ -183,6 +184,78 @@ public: } }; +// TODO(mgsergio): comment +class Place +{ + FeatureBuilder1 m_ft; + m2::PointD m_pt; + uint32_t m_type; + double m_thresholdM; + + bool IsPoint() const { return (m_ft.GetGeomType() == feature::GEOM_POINT); } + static bool IsEqualTypes(uint32_t t1, uint32_t t2) + { + // Use 2-arity places comparison for filtering. + // ("place-city-capital-2" is equal to "place-city") + ftype::TruncValue(t1, 2); + ftype::TruncValue(t2, 2); + return (t1 == t2); + } + +public: + Place(FeatureBuilder1 const & ft, uint32_t type) : m_ft(ft), m_pt(ft.GetKeyPoint()), m_type(type) + { + using namespace ftypes; + + switch (IsLocalityChecker::Instance().GetType(m_type)) + { + case COUNTRY: m_thresholdM = 300000.0; break; + case STATE: m_thresholdM = 100000.0; break; + case CITY: m_thresholdM = 30000.0; break; + case TOWN: m_thresholdM = 20000.0; break; + case VILLAGE: m_thresholdM = 10000.0; break; + default: m_thresholdM = 10000.0; break; + } + } + + FeatureBuilder1 const & GetFeature() const { return m_ft; } + + m2::RectD GetLimitRect() const + { + return MercatorBounds::RectByCenterXYAndSizeInMeters(m_pt, m_thresholdM); + } + + bool IsEqual(Place const & r) const + { + return (IsEqualTypes(m_type, r.m_type) && + m_ft.GetName() == r.m_ft.GetName() && + (IsPoint() || r.IsPoint()) && + MercatorBounds::DistanceOnEarth(m_pt, r.m_pt) < m_thresholdM); + } + + /// Check whether we need to replace place @r with place @this. + bool IsBetterThan(Place const & r) const + { + // Check ranks. + uint8_t const r1 = m_ft.GetRank(); + uint8_t const r2 = r.m_ft.GetRank(); + if (r1 != r2) + return (r2 < r1); + + // Check types length. + // ("place-city-capital-2" is better than "place-city"). + uint8_t const l1 = ftype::GetLevel(m_type); + uint8_t const l2 = ftype::GetLevel(r.m_type); + if (l1 != l2) + return (l2 < l1); + + // Assume that area places has better priority than point places at the very end ... + /// @todo It was usefull when place=XXX type has any area fill style. + /// Need to review priority logic here (leave the native osm label). + return !IsPoint(); + } +}; + class MainFeaturesEmitter { using TWorldGenerator = WorldMapGenerator; @@ -196,6 +269,9 @@ class MainFeaturesEmitter string m_srcCoastsFile; bool m_failOnCoasts; + // TODO(mgsergio): comment. + m4::Tree m_places; + enum TypeIndex { NATURAL_COASTLINE, @@ -248,47 +324,33 @@ public: m_world.reset(new TWorldGenerator(info)); } - void operator()(FeatureBuilder1 fb) + void operator()(FeatureBuilder1 & fb) { - uint32_t const coastType = Type(NATURAL_COASTLINE); - bool const hasCoast = fb.HasType(coastType); + static uint32_t const placeType = classif().GetTypeByPath({"place"}); + uint32_t const type = fb.GetParams().FindType(placeType, 1); - if (m_coasts) + if (type != ftype::GetEmptyValue() && !fb.GetName().empty()) { - if (hasCoast) - { - CHECK(fb.GetGeomType() != feature::GEOM_POINT, ()); - // leave only coastline type - fb.SetType(coastType); - (*m_coasts)(fb); - } - return; + m_places.ReplaceEqualInRect( + Place(fb, type), + [](Place const & p1, Place const & p2) { return p1.IsEqual(p2); }, + [](Place const & p1, Place const & p2) { return p1.IsBetterThan(p2); }); } - - if (hasCoast) + else { - fb.PopExactType(Type(NATURAL_LAND)); - fb.PopExactType(coastType); + Emit(fb); } - else if ((fb.HasType(Type(PLACE_ISLAND)) || fb.HasType(Type(PLACE_ISLET))) && - fb.GetGeomType() == feature::GEOM_AREA) - { - fb.AddType(Type(NATURAL_LAND)); - } - - if (!fb.RemoveInvalidTypes()) - return; - - if (m_world) - (*m_world)(fb); - - if (m_countries) - (*m_countries)(fb); } /// @return false if coasts are not merged and FLAG_fail_on_coasts is set bool Finish() { + m_places.ForEach([this](Place const & p) + { + // m_places are no longer used after this point. + Emit(const_cast(p.GetFeature())); + }); + if (m_world) m_world->DoMerge(); @@ -347,6 +409,45 @@ public: else names.clear(); } + +private: + void Emit(FeatureBuilder1 & fb) + { + uint32_t const coastType = Type(NATURAL_COASTLINE); + bool const hasCoast = fb.HasType(coastType); + + if (m_coasts) + { + if (hasCoast) + { + CHECK(fb.GetGeomType() != feature::GEOM_POINT, ()); + // leave only coastline type + fb.SetType(coastType); + (*m_coasts)(fb); + } + return; + } + + if (hasCoast) + { + fb.PopExactType(Type(NATURAL_LAND)); + fb.PopExactType(coastType); + } + else if ((fb.HasType(Type(PLACE_ISLAND)) || fb.HasType(Type(PLACE_ISLET))) && + fb.GetGeomType() == feature::GEOM_AREA) + { + fb.AddType(Type(NATURAL_LAND)); + } + + if (!fb.RemoveInvalidTypes()) + return; + + if (m_world) + (*m_world)(fb); + + if (m_countries) + (*m_countries)(fb); + } }; } // anonymous namespace @@ -521,7 +622,7 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info) info.m_bookingReferenceDir); stringstream skippedElements; - + // Here we can add new tags to element!!! auto const fn = [&](OsmElement * e) { @@ -534,7 +635,7 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info) skippedElements << e->id << endl; return; } - + parser.EmitElement(e); }; @@ -567,8 +668,6 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info) LOG(LERROR, ("Can't output into", skippedElementsPath)); } } - - parser.Finish(); // Stop if coasts are not merged and FLAG_fail_on_coasts is set if (!bucketer.Finish()) diff --git a/generator/osm_translator.hpp b/generator/osm_translator.hpp index f312752518..5f2e49992d 100644 --- a/generator/osm_translator.hpp +++ b/generator/osm_translator.hpp @@ -9,8 +9,6 @@ #include "indexer/feature_visibility.hpp" #include "indexer/ftypes_matcher.hpp" -#include "geometry/tree4d.hpp" - #include "coding/file_writer.hpp" #include "base/cache.hpp" @@ -24,77 +22,6 @@ namespace { -class Place -{ - FeatureBuilder1 m_ft; - m2::PointD m_pt; - uint32_t m_type; - double m_thresholdM; - - bool IsPoint() const { return (m_ft.GetGeomType() == feature::GEOM_POINT); } - static bool IsEqualTypes(uint32_t t1, uint32_t t2) - { - // Use 2-arity places comparison for filtering. - // ("place-city-capital-2" is equal to "place-city") - ftype::TruncValue(t1, 2); - ftype::TruncValue(t2, 2); - return (t1 == t2); - } - -public: - Place(FeatureBuilder1 const & ft, uint32_t type) : m_ft(ft), m_pt(ft.GetKeyPoint()), m_type(type) - { - using namespace ftypes; - - switch (IsLocalityChecker::Instance().GetType(m_type)) - { - case COUNTRY: m_thresholdM = 300000.0; break; - case STATE: m_thresholdM = 100000.0; break; - case CITY: m_thresholdM = 30000.0; break; - case TOWN: m_thresholdM = 20000.0; break; - case VILLAGE: m_thresholdM = 10000.0; break; - default: m_thresholdM = 10000.0; break; - } - } - - FeatureBuilder1 const & GetFeature() const { return m_ft; } - - m2::RectD GetLimitRect() const - { - return MercatorBounds::RectByCenterXYAndSizeInMeters(m_pt, m_thresholdM); - } - - bool IsEqual(Place const & r) const - { - return (IsEqualTypes(m_type, r.m_type) && - m_ft.GetName() == r.m_ft.GetName() && - (IsPoint() || r.IsPoint()) && - MercatorBounds::DistanceOnEarth(m_pt, r.m_pt) < m_thresholdM); - } - - /// Check whether we need to replace place @r with place @this. - bool IsBetterThan(Place const & r) const - { - // Check ranks. - uint8_t const r1 = m_ft.GetRank(); - uint8_t const r2 = r.m_ft.GetRank(); - if (r1 != r2) - return (r2 < r1); - - // Check types length. - // ("place-city-capital-2" is better than "place-city"). - uint8_t const l1 = ftype::GetLevel(m_type); - uint8_t const l2 = ftype::GetLevel(r.m_type); - if (l1 != l2) - return (l2 < l1); - - // Assume that area places has better priority than point places at the very end ... - /// @todo It was usefull when place=XXX type has any area fill style. - /// Need to review priority logic here (leave the native osm label). - return !IsPoint(); - } -}; - /// Generated features should include parent relation tags to make /// full types matching and storing any additional info. class RelationTagsBase @@ -243,7 +170,6 @@ protected: } } }; - } // namespace /// @param TEmitter Feature accumulating policy @@ -255,7 +181,7 @@ class OsmToFeatureTranslator TCache & m_holder; uint32_t m_coastType; unique_ptr m_addrWriter; - m4::Tree m_places; + RelationTagsNode m_nodeRelations; RelationTagsWay m_wayRelations; @@ -334,32 +260,25 @@ class OsmToFeatureTranslator return params.IsValid(); } - void EmitFeatureBase(FeatureBuilder1 & ft, FeatureParams const & params) + void EmitFeatureBase(FeatureBuilder1 & ft, FeatureParams const & params) const { ft.SetParams(params); if (ft.PreSerialize()) { string addr; - if (m_addrWriter && ftypes::IsBuildingChecker::Instance()(params.m_Types) && ft.FormatFullAddress(addr)) - m_addrWriter->Write(addr.c_str(), addr.size()); - - static uint32_t const placeType = classif().GetTypeByPath({"place"}); - uint32_t const type = params.FindType(placeType, 1); - - if (type != ftype::GetEmptyValue() && !ft.GetName().empty()) + if (m_addrWriter && ftypes::IsBuildingChecker::Instance()(params.m_Types) && + ft.FormatFullAddress(addr)) { - m_places.ReplaceEqualInRect(Place(ft, type), - [](Place const & p1, Place const & p2) { return p1.IsEqual(p2); }, - [](Place const & p1, Place const & p2) { return p1.IsBetterThan(p2); }); + m_addrWriter->Write(addr.c_str(), addr.size()); } - else - m_emitter(ft); + + m_emitter(ft); } } /// @param[in] params Pass by value because it can be modified. //@{ - void EmitPoint(m2::PointD const & pt, FeatureParams params, osm::Id id) + void EmitPoint(m2::PointD const & pt, FeatureParams params, osm::Id id) const { if (feature::RemoveNoDrawableTypes(params.m_Types, feature::GEOM_POINT)) { @@ -370,7 +289,7 @@ class OsmToFeatureTranslator } } - void EmitLine(FeatureBuilder1 & ft, FeatureParams params, bool isCoastLine) + void EmitLine(FeatureBuilder1 & ft, FeatureParams params, bool isCoastLine) const { if (isCoastLine || feature::RemoveNoDrawableTypes(params.m_Types, feature::GEOM_LINE)) { @@ -380,7 +299,7 @@ class OsmToFeatureTranslator } template - void EmitArea(FeatureBuilder1 & ft, FeatureParams params, MakeFnT makeFn) + void EmitArea(FeatureBuilder1 & ft, FeatureParams params, MakeFnT makeFn) const { using namespace feature; @@ -571,12 +490,4 @@ public: if (!addrFilePath.empty()) m_addrWriter.reset(new FileWriter(addrFilePath)); } - - void Finish() - { - m_places.ForEach([this] (Place const & p) - { - m_emitter(p.GetFeature()); - }); - } };