[indexer_tool] Added --merge_coastlines flag

It tries to merge all coastlines when building World file
This commit is contained in:
Alex Zolotarev 2011-02-06 19:30:28 +02:00 committed by Alex Zolotarev
parent ebcd7f9736
commit a48d4d5575
10 changed files with 144 additions and 11 deletions

View file

@ -20,6 +20,9 @@ class FeatureBase;
/// Used for serialization\deserialization of features during --generate_features.
class FeatureBuilder1
{
// needed for hacky coastlines merging
friend class FeatureBuilder1Merger;
public:
FeatureBuilder1();

View file

@ -0,0 +1,50 @@
#include "feature_merger.hpp"
#include "../base/logging.hpp"
FeatureBuilder1Merger::FeatureBuilder1Merger(FeatureBuilder1 const & fb)
: FeatureBuilder1(fb)
{
}
bool FeatureBuilder1Merger::MergeWith(FeatureBuilder1 const & fb)
{
// check that both features are of linear type
if (!fb.m_bLinear || !m_bLinear)
return false;
// check that classificator types are the same
if (fb.m_Types != m_Types)
return false;
// check last-first points equality
//if (m2::AlmostEqual(m_Geometry.back(), fb.m_Geometry.front()))
if (m_Geometry.back() == fb.m_Geometry.front())
{
// merge fb at the end
for (size_t i = 1; i < fb.m_Geometry.size(); ++i)
{
m_Geometry.push_back(fb.m_Geometry[i]);
m_LimitRect.Add(m_Geometry.back());
}
}
// check first-last points equality
//else if (m2::AlmostEqual(m_Geometry.front(), fb.m_Geometry.back()))
else if (m_Geometry.front() == fb.m_Geometry.back())
{
// merge fb in the beginning
m_Geometry.insert(m_Geometry.begin(), fb.m_Geometry.begin(), fb.m_Geometry.end());
for (size_t i = 0; i < fb.m_Geometry.size() - 1; ++i)
m_LimitRect.Add(fb.m_Geometry[i]);
}
else
return false; // no common points were found...
static int counter = 0;
// @TODO check if we got AREA feature after merging, this can be useful for coastlines
LOG(LINFO, (++counter, "features were merged!"));
return true;
}

View file

@ -0,0 +1,10 @@
#pragma once
#include "feature.hpp"
class FeatureBuilder1Merger : public FeatureBuilder1
{
public:
FeatureBuilder1Merger(FeatureBuilder1 const & fb);
bool MergeWith(FeatureBuilder1 const & fb);
};

View file

@ -31,6 +31,7 @@ SOURCES += \
geometry_coding.cpp \
geometry_serialization.cpp \
tesselator.cpp \
feature_merger.cpp \
HEADERS += \
feature.hpp \
@ -66,3 +67,4 @@ HEADERS += \
point_to_int64.hpp \
tesselator.hpp \
tesselator_decl.hpp \
feature_merger.hpp \

View file

@ -38,14 +38,14 @@ public:
template <class TInfo>
explicit CellFeatureBucketer(TInfo & info)
: m_Level(info.cellBucketingLevel), m_FeatureOutInitData(info.datFilePrefix, info.datFileSuffix),
m_worldMap(info.maxScaleForWorldFeatures, m_FeatureOutInitData)
m_worldMap(info.maxScaleForWorldFeatures, info.mergeCoastlines, m_FeatureOutInitData)
{
Init();
}
/// @note this constructor doesn't support world file generation
CellFeatureBucketer(int level, typename FeatureOutT::InitDataType const & initData)
: m_Level(level), m_FeatureOutInitData(initData), m_worldMap(-1, initData)
: m_Level(level), m_FeatureOutInitData(initData), m_worldMap(-1, false, initData)
{
Init();
}

View file

@ -17,7 +17,7 @@ namespace feature
{
GenerateInfo()
: maxScaleForWorldFeatures(-1), splitByPolygons(false),
simplifyCountriesLevel(-1) {}
simplifyCountriesLevel(-1), mergeCoastlines(false) {}
string tmpDir, datFilePrefix, datFileSuffix;
/// If not -1, world will be split by buckets with specified level
int cellBucketingLevel;
@ -28,6 +28,7 @@ namespace feature
int maxScaleForWorldFeatures;
bool splitByPolygons;
int simplifyCountriesLevel;
bool mergeCoastlines;
};
bool GenerateFeatures(GenerateInfo & info, bool lightNodes);

View file

@ -49,6 +49,7 @@ DEFINE_int32(generate_world_scale, -1, "If specified, features for zoomlevels [0
"which are enabled in classificator will be MOVED to the separate world file");
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]");
DEFINE_bool(merge_coastlines, true, "If defined, tries to merge coastlines when renerating World file");
string AddSlashIfNeeded(string const & str)
{
@ -130,6 +131,7 @@ int main(int argc, char ** argv)
genInfo.cellBucketingLevel = FLAGS_bucketing_level;
genInfo.maxScaleForWorldFeatures = FLAGS_generate_world_scale;
genInfo.mergeCoastlines = FLAGS_merge_coastlines;
if (!feature::GenerateFeatures(genInfo, FLAGS_use_light_nodes))
return -1;

View file

@ -24,7 +24,7 @@ SOURCES += \
update_generator.cpp \
grid_generator.cpp \
statistics.cpp \
kml_parser.cpp
kml_parser.cpp \
HEADERS += \
osm_element.hpp \
@ -39,4 +39,4 @@ HEADERS += \
statistics.hpp \
kml_parser.hpp \
polygonizer.hpp \
world_map_generator.hpp
world_map_generator.hpp \

View file

@ -28,7 +28,7 @@ namespace feature
public:
template <class TInfo>
Polygonizer(TInfo & info) : m_FeatureOutInitData(info.datFilePrefix, info.datFileSuffix),
m_worldMap(info.maxScaleForWorldFeatures, m_FeatureOutInitData)
m_worldMap(info.maxScaleForWorldFeatures, info.mergeCoastlines, m_FeatureOutInitData)
{
CHECK(kml::LoadCountriesList(info.datFilePrefix, m_countries, info.simplifyCountriesLevel),
("Error loading country polygons files"));

View file

@ -3,8 +3,11 @@
#include "../../defines.hpp"
#include "../../indexer/feature.hpp"
#include "../../indexer/feature_merger.hpp"
#include "../../indexer/feature_visibility.hpp"
#include "../../std/list.hpp"
#include <boost/scoped_ptr.hpp>
template <class FeatureOutT>
@ -14,25 +17,87 @@ class WorldMapGenerator
boost::scoped_ptr<FeatureOutT> m_worldBucket;
/// features visible before or at this scale level will go to World map
int m_maxWorldScale;
bool m_mergeCoastlines;
typedef list<FeatureBuilder1Merger> FeaturesContainerT;
FeaturesContainerT m_features;
private:
/// scans all features and tries to merge them with each other
/// @return true if one feature was merged
bool ReMergeFeatures()
{
bool merged = false;
for (FeaturesContainerT::iterator base = m_features.begin(); base != m_features.end(); ++base)
{
FeaturesContainerT::iterator ft = base;
for (++ft; ft != m_features.end();)
{
if (base->MergeWith(*ft))
{
m_features.erase(ft++);
merged = true;
}
else
++ft;
}
}
return merged;
}
void TryToMerge(FeatureBuilder1 const & fb)
{
// @TODO group features by types (use map of lists?)
for (FeaturesContainerT::iterator it = m_features.begin(); it != m_features.end(); ++it)
{
if (it->MergeWith(fb))
return;
}
// do not loose feature if it wasn't merged
m_features.push_back(fb);
}
public:
WorldMapGenerator(int maxWorldScale, typename FeatureOutT::InitDataType featureOutInitData)
: m_maxWorldScale(maxWorldScale)
WorldMapGenerator(int maxWorldScale, bool mergeCoastlines,
typename FeatureOutT::InitDataType featureOutInitData)
: m_maxWorldScale(maxWorldScale), m_mergeCoastlines(mergeCoastlines)
{
if (maxWorldScale >= 0)
m_worldBucket.reset(new FeatureOutT(WORLD_FILE_NAME, featureOutInitData));
}
~WorldMapGenerator()
{
// try to merge all merged features with each other
while (ReMergeFeatures())
{
}
// emit all merged features
for (FeaturesContainerT::iterator it = m_features.begin(); it != m_features.end(); ++it)
(*m_worldBucket)(*it);
}
bool operator()(FeatureBuilder1 const & fb)
{
if (m_worldBucket)
{
int minScale = feature::MinDrawableScaleForFeature(fb.GetFeatureBase());
FeatureBase fBase = fb.GetFeatureBase();
int minScale = feature::MinDrawableScaleForFeature(fBase);
CHECK_GREATER(minScale, -1, ("Non-drawable feature found!?"));
// separately store features needed for world map
if (m_maxWorldScale >= minScale)
{
(*m_worldBucket)(fb);
if (m_mergeCoastlines)
{
// we're merging only linear features,
// areas and points are written immediately
if (fBase.GetFeatureType() != FeatureBase::FEATURE_TYPE_LINE)
(*m_worldBucket)(fb);
else
TryToMerge(fb);
}
else
(*m_worldBucket)(fb);
return true;
}
}