From 99e1e6b7a80c724adb5aa56ac97ce51939bc4660 Mon Sep 17 00:00:00 2001 From: Alex Zolotarev Date: Wed, 19 Jan 2011 02:01:17 +0200 Subject: [PATCH] [indexer_tool] Added --simplify_countries_level Now country polygons which are enabled by --split_by_polygons parameter can be optionally simplified by giving simplificator level values --- indexer/indexer_tool/feature_generator.cpp | 2 +- indexer/indexer_tool/feature_generator.hpp | 4 +- indexer/indexer_tool/indexer_tool.cpp | 2 + indexer/indexer_tool/kml_parser.cpp | 74 ++++++++++++++++------ indexer/indexer_tool/kml_parser.hpp | 4 +- indexer/indexer_tool/polygonizer.hpp | 9 +-- 6 files changed, 67 insertions(+), 28 deletions(-) diff --git a/indexer/indexer_tool/feature_generator.cpp b/indexer/indexer_tool/feature_generator.cpp index 31c0d0a39c..074efbcd05 100644 --- a/indexer/indexer_tool/feature_generator.cpp +++ b/indexer/indexer_tool/feature_generator.cpp @@ -301,7 +301,7 @@ bool GenerateImpl(GenerateInfo & info) { typedef Polygonizer FeaturePolygonizerType; // prefix is data dir - FeaturePolygonizerType bucketer(info.datFilePrefix, collectorInitData); + FeaturePolygonizerType bucketer(info.datFilePrefix, collectorInitData, info.m_simplifyCountriesLevel); TParser parser(bucketer, holder); ParseXMLFromStdIn(parser); bucketer.GetBucketNames(MakeBackInsertFunctor(info.bucketNames)); diff --git a/indexer/indexer_tool/feature_generator.hpp b/indexer/indexer_tool/feature_generator.hpp index 23e95f0b90..7c78f881eb 100644 --- a/indexer/indexer_tool/feature_generator.hpp +++ b/indexer/indexer_tool/feature_generator.hpp @@ -16,7 +16,8 @@ namespace feature struct GenerateInfo { GenerateInfo() - : m_maxScaleForWorldFeatures(-1), m_worldOnly(false), m_splitByPolygons(false) {} + : m_maxScaleForWorldFeatures(-1), m_worldOnly(false), m_splitByPolygons(false), + m_simplifyCountriesLevel(-1) {} string dir, datFilePrefix, datFileSuffix; int cellBucketingLevel; vector bucketNames; @@ -26,6 +27,7 @@ namespace feature int m_maxScaleForWorldFeatures; bool m_worldOnly; bool m_splitByPolygons; + int m_simplifyCountriesLevel; }; bool GenerateFeatures(GenerateInfo & info, bool lightNodes); diff --git a/indexer/indexer_tool/indexer_tool.cpp b/indexer/indexer_tool/indexer_tool.cpp index 55a546b9ad..bef802cfc6 100644 --- a/indexer/indexer_tool/indexer_tool.cpp +++ b/indexer/indexer_tool/indexer_tool.cpp @@ -49,6 +49,7 @@ DEFINE_int32(worldmap_max_zoom, -1, "If specified, features for zoomlevels [0..t " which are enabled in classificator will be added to the separate world.map"); DEFINE_bool(world_only, false, "Generate only world features for given worldmap_max_zoom"); DEFINE_bool(split_by_polygons, false, "Use kml shape files to split planet by regions and countries"); +DEFINE_int32(simplify_countries_level, -1, "If positive, simplifies country polygons. Recommended values [10..15]"); string AddSlashIfNeeded(string const & str) { @@ -126,6 +127,7 @@ int main(int argc, char ** argv) // split data by countries polygons genInfo.m_splitByPolygons = FLAGS_split_by_polygons; + genInfo.m_simplifyCountriesLevel = FLAGS_simplify_countries_level; genInfo.cellBucketingLevel = FLAGS_bucketing_level; genInfo.m_maxScaleForWorldFeatures = FLAGS_worldmap_max_zoom; diff --git a/indexer/indexer_tool/kml_parser.cpp b/indexer/indexer_tool/kml_parser.cpp index 463198e8eb..69e7874d58 100644 --- a/indexer/indexer_tool/kml_parser.cpp +++ b/indexer/indexer_tool/kml_parser.cpp @@ -1,4 +1,5 @@ #include "kml_parser.hpp" +#include "feature_sorter.hpp" #include "../../base/string_utils.hpp" #include "../../base/logging.hpp" @@ -27,9 +28,10 @@ namespace kml string m_data; CountryPolygons & m_country; + int m_simplifyCountriesLevel; public: - KmlParser(CountryPolygons & country); + KmlParser(CountryPolygons & country, int simplifyCountriesLevel); bool Push(string const & element); void Pop(string const & element); @@ -37,7 +39,8 @@ namespace kml void CharData(string const & data); }; - KmlParser::KmlParser(CountryPolygons & country) : m_country(country) + KmlParser::KmlParser(CountryPolygons & country, int simplifyCountriesLevel) + : m_country(country), m_simplifyCountriesLevel(simplifyCountriesLevel) { } @@ -74,17 +77,20 @@ namespace kml double lat; CHECK(utils::to_double(latStr, lat), ("invalid lon", latStr)); // to mercator - double const x = MercatorBounds::LonToX(lon); - double const y = MercatorBounds::LatToY(lat); - m_rect.Add(m2::PointD(x, y)); - // convert points to uint32_t - typedef CellIdConverter CellIdConverterType; - uint32_t const ix = static_cast(CellIdConverterType::XToCellIdX(x)); - uint32_t const iy = static_cast(CellIdConverterType::YToCellIdY(y)); - m_container.push_back(Region::value_type(ix, iy)); + m2::PointD const mercPoint(MercatorBounds::LonToX(lon), MercatorBounds::LatToY(lat)); + m_rect.Add(mercPoint); + m_container.push_back(mercPoint); } }; + m2::PointU MercatorPointToPointU(m2::PointD const & pt) + { + typedef CellIdConverter CellIdConverterType; + uint32_t const ix = static_cast(CellIdConverterType::XToCellIdX(pt.x)); + uint32_t const iy = static_cast(CellIdConverterType::YToCellIdY(pt.y)); + return m2::PointU(ix, iy); + } + void KmlParser::Pop(string const & element) { if (element == "Placemark") @@ -98,17 +104,33 @@ namespace kml if (m_tags[size - 3] == "outerBoundaryIs") { - typedef vector ContainerT; - ContainerT points; + // first, collect points in Mercator + typedef vector MercPointsContainerT; + MercPointsContainerT points; m2::RectD rect; - PointsCollector collector(points, rect); + PointsCollector collector(points, rect); utils::TokenizeString(m_data, " \n\r\a", collector); size_t const numPoints = points.size(); if (numPoints > 3 && points[numPoints - 1] == points[0]) { // remove last point which is equal to first points.pop_back(); - m_country.m_regions.push_back(Region(points.begin(), points.end())); + + // second, simplify points if necessary + if (m_simplifyCountriesLevel > 0) + { + MercPointsContainerT simplifiedPoints; + feature::SimplifyPoints(points, simplifiedPoints, m_simplifyCountriesLevel); + LOG_SHORT(LINFO, (m_country.m_name, numPoints, "simplified to ", simplifiedPoints.size())); + points.swap(simplifiedPoints); + } + + // third, convert mercator doubles to uint points + Region region; + for (MercPointsContainerT::iterator it = points.begin(); it != points.end(); ++it) + region.AddPoint(MercatorPointToPointU(*it)); + + m_country.m_regions.push_back(region); m_country.m_rect.Add(rect); } else @@ -147,9 +169,10 @@ namespace kml } } - bool LoadPolygonsFromKml(string const & kmlFile, CountryPolygons & country) + bool LoadPolygonsFromKml(string const & kmlFile, CountryPolygons & country, + int simplifyCountriesLevel) { - KmlParser parser(country); + KmlParser parser(country, simplifyCountriesLevel); try { FileReader file(kmlFile); @@ -166,16 +189,19 @@ namespace kml { string m_baseDir; CountryPolygons & m_out; + int m_simplifyCountriesLevel; public: - PolygonLoader(string const & basePolygonsDir, CountryPolygons & polygons) - : m_baseDir(basePolygonsDir), m_out(polygons) {} + PolygonLoader(string const & basePolygonsDir, CountryPolygons & polygons, + int simplifyCountriesLevel) + : m_baseDir(basePolygonsDir), m_out(polygons), + m_simplifyCountriesLevel(simplifyCountriesLevel) {} void operator()(string const & name) { if (m_out.m_name.empty()) m_out.m_name = name; CountryPolygons current; - if (LoadPolygonsFromKml(m_baseDir + BORDERS_DIR + name + BORDERS_EXTENSION, current) + if (LoadPolygonsFromKml(m_baseDir + BORDERS_DIR + name + BORDERS_EXTENSION, current, m_simplifyCountriesLevel) && current.m_regions.size()) { m_out.m_regions.insert(m_out.m_regions.end(), @@ -185,8 +211,14 @@ namespace kml } }; - bool LoadCountriesList(string const & baseDir, CountriesContainerT & countries) + bool LoadCountriesList(string const & baseDir, CountriesContainerT & countries, + int simplifyCountriesLevel) { + if (simplifyCountriesLevel > 0) + { + LOG_SHORT(LINFO, ("Simplificator level for country polygons:", simplifyCountriesLevel)); + } + countries.clear(); ifstream stream((baseDir + POLYGONS_FILE).c_str()); std::string line; @@ -197,7 +229,7 @@ namespace kml if (line.empty()) continue; CountryPolygons country; - PolygonLoader loader(baseDir, country); + PolygonLoader loader(baseDir, country, simplifyCountriesLevel); utils::TokenizeString(line, ",", loader); if (!country.m_regions.empty()) countries.push_back(country); diff --git a/indexer/indexer_tool/kml_parser.hpp b/indexer/indexer_tool/kml_parser.hpp index d2b1a8a8e3..dcb326ff21 100644 --- a/indexer/indexer_tool/kml_parser.hpp +++ b/indexer/indexer_tool/kml_parser.hpp @@ -21,5 +21,7 @@ namespace kml typedef vector CountriesContainerT; - bool LoadCountriesList(string const & baseDir, CountriesContainerT & countries); + /// @param[in] simplifyCountriesLevel if positive, used as a level for simplificator + bool LoadCountriesList(string const & baseDir, CountriesContainerT & countries, + int simplifyCountriesLevel = -1); } diff --git a/indexer/indexer_tool/polygonizer.hpp b/indexer/indexer_tool/polygonizer.hpp index 5f4de80380..6bf1c377f4 100644 --- a/indexer/indexer_tool/polygonizer.hpp +++ b/indexer/indexer_tool/polygonizer.hpp @@ -23,14 +23,15 @@ namespace feature class Polygonizer { public: - Polygonizer(string const & dir, typename FeatureOutT::InitDataType const & featureOutInitData) + Polygonizer(string const & dir, typename FeatureOutT::InitDataType const & featureOutInitData, + int simplifyCountriesLevel) : m_FeatureOutInitData(featureOutInitData) { - CHECK(kml::LoadCountriesList(dir, m_countries), ("Error loading polygons")); - LOG(LINFO, ("Loaded polygons count for regions:")); + CHECK(kml::LoadCountriesList(dir, m_countries, simplifyCountriesLevel), ("Error loading polygons")); + LOG_SHORT(LINFO, ("Loaded polygons count for regions:")); for (size_t i = 0; i < m_countries.size(); ++i) { - LOG(LINFO, (m_countries[i].m_name, m_countries[i].m_regions.size())); + LOG_SHORT(LINFO, (m_countries[i].m_name, m_countries[i].m_regions.size())); } m_Buckets.resize(m_countries.size());