diff --git a/generator/feature_builder.hpp b/generator/feature_builder.hpp index a1862f97c8..c8251becb5 100644 --- a/generator/feature_builder.hpp +++ b/generator/feature_builder.hpp @@ -145,6 +145,8 @@ public: /// Set all the parameters, except geometry type (it's set by other functions). inline void SetParams(FeatureParams const & params) { m_params.SetParams(params); } + inline FeatureParams const & GetParams() const { return m_params; } + /// @name For OSM debugging, store original OSM id //@{ void AddOsmId(osm::Id id); diff --git a/generator/world_map_generator.hpp b/generator/world_map_generator.hpp index 42f187bad8..94b8f625a1 100644 --- a/generator/world_map_generator.hpp +++ b/generator/world_map_generator.hpp @@ -3,13 +3,16 @@ #include "generator/feature_merger.hpp" #include "generator/generate_info.hpp" +#include "geometry/tree4d.hpp" + #include "indexer/scales.hpp" +#include "coding/file_name_utils.hpp" + #include "base/logging.hpp" #include "defines.hpp" - /// Process FeatureBuilder1 for world map. Main functions: /// - check for visibility in world map /// - merge linear features @@ -20,32 +23,31 @@ class WorldMapGenerator { FeatureOutT m_output; uint32_t m_boundaryType; - list m_waterRegions; + deque m_waterRegions; + + m4::Tree m_tree; public: explicit EmitterImpl(feature::GenerateInfo const & info) : m_output(info.GetTmpFileName(WORLD_FILE_NAME)) { - m_boundaryType = classif().GetTypeByPath({ "boundary", "administrative"}); - LoadWatersRegionsDump(info.m_intermediateDir + WORLD_COASTS_FILE_NAME + ".rawdump"); + m_boundaryType = classif().GetTypeByPath({"boundary", "administrative"}); + LoadWaterGeometry(my::JoinFoldersToPath({info.m_intermediateDir}, + string(WORLD_COASTS_FILE_NAME) + ".rawdump")); LOG(LINFO, ("Output World file:", info.GetTmpFileName(WORLD_FILE_NAME))); } - - void LoadWatersRegionsDump(string const &dumpFileName) + void LoadWaterGeometry(string const & rawGeometryFileName) { - LOG(LINFO, ("Load water polygons:", dumpFileName)); - ifstream file; - file.exceptions(ifstream::badbit); - file.open(dumpFileName); - if (!file.is_open()) - LOG(LCRITICAL, ("Can't open water polygons")); + LOG(LINFO, ("Loading water geometry:", rawGeometryFileName)); + FileReader reader(rawGeometryFileName); + ReaderSource file(reader); size_t total = 0; while (true) { uint64_t numGeometries = 0; - file.read(reinterpret_cast(&numGeometries), sizeof(numGeometries)); + file.Read(&numGeometries, sizeof(numGeometries)); if (numGeometries == 0) break; @@ -56,67 +58,66 @@ class WorldMapGenerator for (size_t i = 0; i < numGeometries; ++i) { uint64_t numPoints = 0; - file.read(reinterpret_cast(&numPoints), sizeof(numPoints)); + file.Read(&numPoints, sizeof(numPoints)); points.resize(numPoints); - file.read(reinterpret_cast(points.data()), sizeof(m2::PointD) * numPoints); + file.Read(points.data(), sizeof(m2::PointD) * numPoints); m_waterRegions.push_back(m2::RegionD()); m_waterRegions.back().Assign(points.begin(), points.end()); + m_tree.Add(m_waterRegions.size() - 1, m_waterRegions.back().GetRect()); } } - LOG(LINFO, ("Load", total, "water polygons")); + LOG(LINFO, ("Load", total, "water geometries")); } /// This function is called after merging linear features. - virtual void operator() (FeatureBuilder1 const & fb) + virtual void operator()(FeatureBuilder1 const & fb) { // do additional check for suitable size of feature - if (NeedPushToWorld(fb) && scales::IsGoodForLevel(scales::GetUpperWorldScale(), fb.GetLimitRect())) + if (NeedPushToWorld(fb) && + scales::IsGoodForLevel(scales::GetUpperWorldScale(), fb.GetLimitRect())) PushSure(fb); } bool IsWaterBoundaries(FeatureBuilder1 const & fb) const { + return false; + if (fb.FindType(m_boundaryType, 2) == ftype::GetEmptyValue()) return false; m2::PointD pts[3] = {{0, 0}, {0, 0}, {0, 0}}; size_t hits[3] = {0, 0, 0}; - pts[0] = fb.GetGeometry().front().front(); - pts[1] = *(fb.GetGeometry().front().begin() + fb.GetGeometry().front().size()/2); - pts[2] = fb.GetGeometry().front().back(); + // For check we select first, last and middle point in line. + auto const & line = fb.GetGeometry().front(); + pts[0] = line.front(); + pts[1] = *(line.cbegin() + line.size() / 2); + pts[2] = line.back(); - for (m2::RegionD const & region : m_waterRegions) + m_tree.ForEachInRect(fb.GetLimitRect(), [&](size_t index) { - hits[0] += region.Contains(pts[0]) ? 1 : 0; - hits[1] += region.Contains(pts[1]) ? 1 : 0; - hits[2] += region.Contains(pts[2]) ? 1 : 0; - } + hits[0] += m_waterRegions[index].Contains(pts[0]) ? 1 : 0; + hits[1] += m_waterRegions[index].Contains(pts[1]) ? 1 : 0; + hits[2] += m_waterRegions[index].Contains(pts[2]) ? 1 : 0; + }); - size_t state = (hits[0] & 0x01) + (hits[1] & 0x01) + (hits[2] & 0x01); - - LOG(LINFO, ("hits:", hits, "Boundary state:", state, "Dump:", DebugPrint(fb))); - - // whole border on land - if (state == 0) - return false; + size_t const state = (hits[0] & 0x01) + (hits[1] & 0x01) + (hits[2] & 0x01); // whole border on water if (state == 3) + { + LOG(LINFO, ("Boundary", (state == 3 ? "deleted" : "kept"), "hits:", hits, + DebugPrint(fb.GetParams()), fb.GetOsmIdsString())); return true; + } - LOG(LINFO, ("Found partial boundary")); + // state == 0 whole border on land, else partial intersection return false; } bool NeedPushToWorld(FeatureBuilder1 const & fb) const { - if (IsWaterBoundaries(fb)) - { - LOG(LINFO, ("Skip boundary")); - return false; - } // GetMinFeatureDrawScale also checks suitable size for AREA features return (scales::GetUpperWorldScale() >= fb.GetMinFeatureDrawScale()); } @@ -131,21 +132,19 @@ class WorldMapGenerator public: template explicit WorldMapGenerator(TInfo const & info) - : m_worldBucket(info), - m_merger(POINT_COORD_BITS - (scales::GetUpperScale() - scales::GetUpperWorldScale()) / 2) + : m_worldBucket(info), + m_merger(POINT_COORD_BITS - (scales::GetUpperScale() - scales::GetUpperWorldScale()) / 2) { // Do not strip last types for given tags, // for example, do not cut 'admin_level' in 'boundary-administrative-XXX'. - char const * arr1[][3] = { - { "boundary", "administrative", "2" }, - { "boundary", "administrative", "3" }, - { "boundary", "administrative", "4" } - }; + char const * arr1[][3] = {{"boundary", "administrative", "2"}, + {"boundary", "administrative", "3"}, + {"boundary", "administrative", "4"}}; for (size_t i = 0; i < ARRAY_SIZE(arr1); ++i) m_typesCorrector.SetDontNormalizeType(arr1[i]); - char const * arr2[] = { "boundary", "administrative", "4", "state" }; + char const * arr2[] = {"boundary", "administrative", "4", "state"}; m_typesCorrector.SetDontNormalizeType(arr2); /// @todo It's not obvious to integrate link->way conversion. @@ -174,6 +173,10 @@ public: { if (m_worldBucket.NeedPushToWorld(fb)) { + // skip visible water boundary + if (m_worldBucket.IsWaterBoundaries(fb)) + return; + if (fb.GetGeomType() == feature::GEOM_LINE) { MergedFeatureBuilder1 * p = m_typesCorrector(fb); @@ -188,10 +191,7 @@ public: } } - void DoMerge() - { - m_merger.DoMerge(m_worldBucket); - } + void DoMerge() { m_merger.DoMerge(m_worldBucket); } }; template @@ -201,7 +201,10 @@ class CountryMapGenerator public: template - explicit CountryMapGenerator(TInfo const & info) : m_bucket(info) {} + explicit CountryMapGenerator(TInfo const & info) + : m_bucket(info) + { + } void operator()(FeatureBuilder1 fb) { diff --git a/indexer/feature_data.cpp b/indexer/feature_data.cpp index 0d9d4fe439..1ab7c98018 100644 --- a/indexer/feature_data.cpp +++ b/indexer/feature_data.cpp @@ -431,7 +431,6 @@ string DebugPrint(FeatureParams const & p) string res = "Types"; for (size_t i = 0; i < p.m_Types.size(); ++i) res += (" : " + c.GetReadableObjectName(p.m_Types[i])); - res += "\n"; return (res + p.DebugString()); }