forked from organicmaps/organicmaps-tmp
[indexer_tool] Added --merge_coastlines flag
It tries to merge all coastlines when building World file
This commit is contained in:
parent
ebcd7f9736
commit
a48d4d5575
10 changed files with 144 additions and 11 deletions
|
@ -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();
|
||||
|
||||
|
|
50
indexer/feature_merger.cpp
Normal file
50
indexer/feature_merger.cpp
Normal 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;
|
||||
}
|
||||
|
10
indexer/feature_merger.hpp
Normal file
10
indexer/feature_merger.hpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "feature.hpp"
|
||||
|
||||
class FeatureBuilder1Merger : public FeatureBuilder1
|
||||
{
|
||||
public:
|
||||
FeatureBuilder1Merger(FeatureBuilder1 const & fb);
|
||||
bool MergeWith(FeatureBuilder1 const & fb);
|
||||
};
|
|
@ -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 \
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue