From e568d3f0bc0468fedc9879a22a5948c170f898c9 Mon Sep 17 00:00:00 2001 From: vng Date: Mon, 5 Sep 2011 20:49:01 +0300 Subject: [PATCH] Code for full world generation (World.mwm, WorldCoasts.mwm). --- defines.hpp | 1 + generator/coastlines_generator.cpp | 175 ++++++++++++++++++++ generator/coastlines_generator.hpp | 34 ++++ generator/feature_builder.cpp | 19 ++- generator/feature_builder.hpp | 4 + generator/feature_generator.cpp | 110 +++++++++--- generator/feature_merger.hpp | 1 - generator/generator.pro | 2 + generator/generator_tool/generator_tool.cpp | 7 +- generator/polygonizer.hpp | 10 +- generator/world_map_generator.hpp | 5 - 11 files changed, 330 insertions(+), 38 deletions(-) create mode 100644 generator/coastlines_generator.cpp create mode 100644 generator/coastlines_generator.hpp diff --git a/defines.hpp b/defines.hpp index 95b9aef2ab..cb98329964 100644 --- a/defines.hpp +++ b/defines.hpp @@ -20,6 +20,7 @@ #endif #define WORLD_FILE_NAME "World" +#define WORLD_COASTS_FILE_NAME "WorldCoasts" #define SETTINGS_FILE_NAME "settings.ini" diff --git a/generator/coastlines_generator.cpp b/generator/coastlines_generator.cpp new file mode 100644 index 0000000000..d07eb00a49 --- /dev/null +++ b/generator/coastlines_generator.cpp @@ -0,0 +1,175 @@ +#include "coastlines_generator.hpp" +#include "feature_builder.hpp" + +#include "../indexer/point_to_int64.hpp" + +#include "../geometry/region2d/binary_operators.hpp" + +#include "../std/bind.hpp" + + +typedef m2::RegionI RegionT; + + +CoastlineFeaturesGenerator::CoastlineFeaturesGenerator(uint32_t coastType, int level) + : m_merger(POINT_COORD_BITS), m_coastType(coastType), m_Level(level) +{ +} + +namespace +{ + m2::RectD GetLimitRect(RegionT const & rgn) + { + m2::RectI r = rgn.GetRect(); + return m2::RectD(r.minX(), r.minY(), r.maxX(), r.maxY()); + } + + inline m2::PointI D2I(m2::PointD const & p) + { + m2::PointU const pu = PointD2PointU(p, POINT_COORD_BITS); + return m2::PointI(static_cast(pu.x), + static_cast(pu.y)); + } + + class DoCreateRegion + { + RegionT m_rgn; + m2::PointD m_pt; + bool m_exist; + + public: + DoCreateRegion() : m_exist(false) {} + + bool operator()(m2::PointD const & p) + { + // This logic is to skip last polygon point (that is equal to first). + + if (m_exist) + { + // add previous point to region + m_rgn.AddPoint(D2I(m_pt)); + } + else + m_exist = true; + + // save current point + m_pt = p; + return true; + } + + template void Add(TreeT & tree) + { + tree.Add(m_rgn, GetLimitRect(m_rgn)); + } + }; +} + +void CoastlineFeaturesGenerator::AddRegionToTree(FeatureBuilder1 const & fb) +{ + ASSERT ( fb.IsGeometryClosed(), () ); + + DoCreateRegion createRgn; + fb.ForEachGeometryPoint(createRgn); + createRgn.Add(m_tree); +} + +void CoastlineFeaturesGenerator::operator()(FeatureBuilder1 const & fb) +{ + if (fb.IsGeometryClosed()) + AddRegionToTree(fb); + else + m_merger(fb); +} + +namespace +{ + class DoAddToTree : public FeatureEmitterIFace + { + CoastlineFeaturesGenerator & m_rMain; + public: + DoAddToTree(CoastlineFeaturesGenerator & rMain) : m_rMain(rMain) {} + + virtual void operator() (FeatureBuilder1 const & fb) + { + if (fb.IsGeometryClosed()) + m_rMain.AddRegionToTree(fb); + } + }; +} + +void CoastlineFeaturesGenerator::Finish() +{ + DoAddToTree doAdd(*this); + m_merger.DoMerge(doAdd); +} + +namespace +{ + class DoDifference + { + vector m_res; + vector m_points; + + public: + DoDifference(RegionT const & rgn) + { + m_res.push_back(rgn); + } + + void operator() (RegionT const & r) + { + vector local; + + for (size_t i = 0; i < m_res.size(); ++i) + m2::DiffRegions(m_res[i], r, local); + + local.swap(m_res); + } + + void operator() (m2::PointI const & p) + { + CoordPointT const c = PointU2PointD(m2::PointU( + static_cast(p.x), + static_cast(p.y)), POINT_COORD_BITS); + m_points.push_back(m2::PointD(c.first, c.second)); + } + + void AssignGeometry(FeatureBuilder1 & fb) + { + for (size_t i = 0; i < m_res.size(); ++i) + { + m_points.clear(); + m_points.reserve(m_res[i].Size() + 1); + + m_res[i].ForEachPoint(bind(ref(*this), _1)); + + fb.AddPolygon(m_points); + } + } + }; +} + +bool CoastlineFeaturesGenerator::GetFeature(size_t i, FeatureBuilder1 & fb) +{ + // get rect cell + CellIdT cell = CellIdT::FromBitsAndLevel(i, m_Level); + double minX, minY, maxX, maxY; + CellIdConverter::GetCellBounds(cell, minX, minY, maxX, maxY); + + // create rect region + typedef m2::PointD P; + m2::PointI arr[] = { D2I(P(minX, minY)), D2I(P(minX, maxY)), + D2I(P(maxX, maxY)), D2I(P(maxX, minY)) }; + RegionT rectR(arr, arr + ARRAY_SIZE(arr)); + + // substract all 'land' from this region + DoDifference doDiff(rectR); + m_tree.ForEachInRect(GetLimitRect(rectR), bind(ref(doDiff), _1)); + + // assign feature + doDiff.AssignGeometry(fb); + fb.SetArea(); + fb.AddType(m_coastType); + + return true; +} diff --git a/generator/coastlines_generator.hpp b/generator/coastlines_generator.hpp new file mode 100644 index 0000000000..1a5df28e96 --- /dev/null +++ b/generator/coastlines_generator.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "feature_merger.hpp" + +#include "../indexer/cell_id.hpp" + +#include "../geometry/tree4d.hpp" +#include "../geometry/region2d.hpp" + + +class FeatureBuilder1; + +class CoastlineFeaturesGenerator +{ + typedef RectId CellIdT; + + FeatureMergeProcessor m_merger; + + m4::Tree m_tree; + + uint32_t m_coastType; + int m_Level; + +public: + CoastlineFeaturesGenerator(uint32_t coastType, int level = 6); + + void AddRegionToTree(FeatureBuilder1 const & fb); + + void operator() (FeatureBuilder1 const & fb); + void Finish(); + + inline size_t GetFeaturesCount() const { return 1 << 2 * m_Level; } + bool GetFeature(size_t i, FeatureBuilder1 & fb); +}; diff --git a/generator/feature_builder.cpp b/generator/feature_builder.cpp index 36e4221733..6eaaa7bb20 100644 --- a/generator/feature_builder.cpp +++ b/generator/feature_builder.cpp @@ -59,6 +59,19 @@ void FeatureBuilder1::SetAreaAddHoles(list const & holes) } } +void FeatureBuilder1::AddPolygon(vector & poly) +{ + // check for closing + if (poly.size() < 3) return; + if (poly.front() != poly.back()) + poly.push_back(poly.front()); + + if (!m_Polygons.back().empty()) + m_Polygons.push_back(points_t()); + + m_Polygons.back().swap(poly); +} + FeatureBase FeatureBuilder1::GetFeatureBase() const { CHECK ( CheckValid(), () ); @@ -290,9 +303,9 @@ string debug_print(FeatureBuilder1 const & f) switch (f.GetGeomType()) { - case feature::GEOM_POINT: out << "(" << f.m_Center << ")"; break; - case feature::GEOM_LINE: out << "line with " << f.GetPointsCount() << "points"; break; - case feature::GEOM_AREA: out << "area with " << f.GetPointsCount() << "points"; break; + case GEOM_POINT: out << "(" << f.m_Center << ")"; break; + case GEOM_LINE: out << "line with " << f.GetPointsCount() << "points"; break; + case GEOM_AREA: out << "area with " << f.GetPointsCount() << "points"; break; default: out << "ERROR: unknown geometry type"; break; } diff --git a/generator/feature_builder.hpp b/generator/feature_builder.hpp index c80d8528d0..84195a56bd 100644 --- a/generator/feature_builder.hpp +++ b/generator/feature_builder.hpp @@ -30,15 +30,19 @@ public: /// Set that feature is linear type. void SetLinear() { m_Params.SetGeomType(feature::GEOM_LINE); } + void SetArea() { m_Params.SetGeomType(feature::GEOM_AREA); } /// Set that feature is area and get ownership of holes. void SetAreaAddHoles(list > const & holes); + + void AddPolygon(vector & poly); //@} inline feature::EGeomType GetGeomType() const { return m_Params.GetGeomType(); } inline void AddType(uint32_t type) { m_Params.AddType(type); } inline bool HasType(uint32_t t) const { return m_Params.IsTypeExist(t); } + inline bool PopExactType(uint32_t type) { return m_Params.PopExactType(type); } typedef vector buffer_t; diff --git a/generator/feature_generator.cpp b/generator/feature_generator.cpp index 863d302d86..aae1329129 100644 --- a/generator/feature_generator.cpp +++ b/generator/feature_generator.cpp @@ -4,6 +4,8 @@ #include "polygonizer.hpp" #include "osm_decl.hpp" #include "generate_info.hpp" +#include "coastlines_generator.hpp" +#include "world_map_generator.hpp" #include "../defines.hpp" @@ -165,6 +167,9 @@ void FeaturesCollector::operator() (FeatureBuilder1 const & fb) // Generate functions implementations. /////////////////////////////////////////////////////////////////////////////////////////////////// +namespace +{ + class points_in_file { #ifdef OMIM_OS_WINDOWS @@ -178,12 +183,15 @@ public: bool GetPoint(uint64_t id, double & lat, double & lng) const { -#ifdef OMIM_OS_WINDOWS + // I think, it's not good idea to write this ugly code. + // memcpy isn't to slow for that. +//#ifdef OMIM_OS_WINDOWS LatLon ll; m_file.Read(id * sizeof(ll), &ll, sizeof(ll)); -#else - LatLon const & ll = *reinterpret_cast(m_file.Data() + id * sizeof(ll)); -#endif +//#else +// LatLon const & ll = *reinterpret_cast(m_file.Data() + id * sizeof(ll)); +//#endif + // assume that valid coordinate is not (0, 0) if (ll.lat != 0.0 || ll.lon != 0.0) { @@ -222,15 +230,7 @@ public: LatLonPos ll; reader.Read(pos, &ll, sizeof(ll)); - pair ret = m_map.insert(make_pair(ll.pos, make_pair(ll.lat, ll.lon))); - if (ret.second == true) - { -#ifdef DEBUG - pair const & c = ret.first->second; - ASSERT ( equal_coord(c.first, ll.lat), () ); - ASSERT ( equal_coord(c.second, ll.lon), () ); -#endif - } + (void)m_map.insert(make_pair(ll.pos, make_pair(ll.lat, ll.lon))); pos += sizeof(ll); } @@ -249,6 +249,79 @@ public: } }; +class MainFeaturesEmitter +{ + Polygonizer m_countries; + + scoped_ptr > m_world; + scoped_ptr m_coasts; + scoped_ptr m_coastsHolder; + + uint32_t m_coastType; + +public: + MainFeaturesEmitter(GenerateInfo const & info) + : m_countries(info) + { + { + vector path; + path.push_back("natural"); + path.push_back("coastline"); + m_coastType = classif().GetTypeByPath(path); + } + + if (info.m_createWorld) + { + m_world.reset(new WorldMapGenerator(info)); + m_coasts.reset(new CoastlineFeaturesGenerator(m_coastType)); + m_coastsHolder.reset(new FeaturesCollector( + info.m_datFilePrefix + WORLD_COASTS_FILE_NAME + info.m_datFileSuffix)); + } + } + + void operator() (FeatureBuilder1 fb) + { + if (m_coasts) + { + if (fb.HasType(m_coastType)) + (*m_coasts)(fb); + } + + if (!fb.PopExactType(m_coastType)) + { + if (m_world) + (*m_world)(fb); + + m_countries(fb); + } + } + + void Finish() + { + if (m_world) + m_world->DoMerge(); + + if (m_coasts) + { + m_coasts->Finish(); + + size_t const count = m_coasts->GetFeaturesCount(); + for (size_t i = 0; i < count; ++i) + { + FeatureBuilder1 fb; + m_coasts->GetFeature(i, fb); + + (*m_coastsHolder)(fb); + m_countries(fb); + } + } + } + + inline vector const & GetNames() const { return m_countries.Names(); } +}; + +} + template class TParser> bool GenerateImpl(GenerateInfo & info) { @@ -258,15 +331,14 @@ bool GenerateImpl(GenerateInfo & info) typedef FileHolder holder_t; holder_t holder(nodes, info.m_tmpDir); - holder.LoadIndex(); - typedef Polygonizer PolygonizerT; - // prefix is data dir - PolygonizerT bucketer(info); - TParser parser(bucketer, holder); + MainFeaturesEmitter bucketer(info); + TParser parser(bucketer, holder); ParseXMLFromStdIn(parser); - info.m_bucketNames = bucketer.Names(); + + bucketer.Finish(); + info.m_bucketNames = bucketer.GetNames(); } catch (Reader::Exception const & e) { diff --git a/generator/feature_merger.hpp b/generator/feature_merger.hpp index 29d7f0f598..54030beaee 100644 --- a/generator/feature_merger.hpp +++ b/generator/feature_merger.hpp @@ -33,7 +33,6 @@ public: inline void SetType(uint32_t type) { m_Params.SetType(type); } inline bool PopAnyType(uint32_t & type) { return m_Params.PopAnyType(type); } - inline bool PopExactType(uint32_t type) { return m_Params.PopExactType(type); } template void ForEachChangeTypes(ToDo toDo) { diff --git a/generator/generator.pro b/generator/generator.pro index 424232ed2e..93d52a1365 100644 --- a/generator/generator.pro +++ b/generator/generator.pro @@ -29,6 +29,7 @@ SOURCES += \ feature_builder.cpp \ osm_id.cpp \ osm_decl.cpp \ + coastlines_generator.cpp \ HEADERS += \ feature_merger.hpp \ @@ -55,3 +56,4 @@ HEADERS += \ feature_builder.hpp \ osm_id.hpp \ osm_decl.hpp \ + coastlines_generator.hpp \ diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp index 5afabe2ab7..5b2692a9cb 100644 --- a/generator/generator_tool/generator_tool.cpp +++ b/generator/generator_tool/generator_tool.cpp @@ -138,7 +138,10 @@ int main(int argc, char ** argv) genInfo.m_bucketNames[i] = genInfo.m_datFilePrefix + genInfo.m_bucketNames[i] + genInfo.m_datFileSuffix; if (FLAGS_generate_world) + { genInfo.m_bucketNames.push_back(genInfo.m_datFilePrefix + WORLD_FILE_NAME + genInfo.m_datFileSuffix); + genInfo.m_bucketNames.push_back(genInfo.m_datFilePrefix + WORLD_COASTS_FILE_NAME + genInfo.m_datFileSuffix); + } } else { @@ -148,6 +151,7 @@ int main(int argc, char ** argv) // Enumerate over all dat files that were created. size_t const count = genInfo.m_bucketNames.size(); string const worldPath = path + WORLD_FILE_NAME + DATA_FILE_EXTENSION; + string const worldCoastsPath = path + WORLD_COASTS_FILE_NAME + DATA_FILE_EXTENSION; for (size_t i = 0; i < count; ++i) { @@ -156,7 +160,8 @@ int main(int argc, char ** argv) if (FLAGS_generate_geometry) { LOG(LINFO, ("Generating result features for ", datFile)); - if (!feature::GenerateFinalFeatures(datFile, datFile == worldPath)) + if (!feature::GenerateFinalFeatures(datFile, + datFile == worldPath || datFile == worldCoastsPath)) { // If error - move to next bucket without index generation continue; diff --git a/generator/polygonizer.hpp b/generator/polygonizer.hpp index 9edb8b07c5..34787e951b 100644 --- a/generator/polygonizer.hpp +++ b/generator/polygonizer.hpp @@ -1,7 +1,6 @@ #pragma once #include "borders_loader.hpp" -#include "world_map_generator.hpp" #include "../indexer/feature.hpp" #include "../indexer/feature_visibility.hpp" @@ -43,7 +42,6 @@ namespace feature vector m_Buckets; vector m_Names; borders::CountriesContainerT m_countries; - scoped_ptr > m_worldMap; #if PARALLEL_POLYGONIZER QThreadPool m_ThreadPool; @@ -63,9 +61,6 @@ namespace feature LOG(LINFO, ("Polygonizer thread pool threads:", m_ThreadPool.maxThreadCount())); #endif - if (info.m_createWorld) - m_worldMap.reset(new WorldMapGenerator(info)); - if (info.m_splitByPolygons) { CHECK(borders::LoadCountriesList(info.m_datFilePrefix, m_countries), @@ -122,9 +117,6 @@ namespace feature void operator () (FeatureBuilder1 const & fb) { - if (m_worldMap) - (*m_worldMap)(fb); - buffer_vector vec; m_countries.ForEachInRect(fb.GetLimitRect(), InsertCountriesPtr(vec)); @@ -171,7 +163,7 @@ namespace feature (*(m_Buckets[country->m_index]))(fb); } - vector const & Names() + vector const & Names() const { return m_Names; } diff --git a/generator/world_map_generator.hpp b/generator/world_map_generator.hpp index 63d4fcc3b5..eb7fb08870 100644 --- a/generator/world_map_generator.hpp +++ b/generator/world_map_generator.hpp @@ -57,11 +57,6 @@ public: m_typesCorrector.SetDontNormalizeType(arrDontNormalize[i]); } - ~WorldMapGenerator() - { - DoMerge(); - } - void operator()(FeatureBuilder1 const & fb) { if (m_worldBucket.NeedPushToWorld(fb))