forked from organicmaps/organicmaps
Using kd-tree for select appropriate water polygons
This commit is contained in:
parent
388d0bcb02
commit
5d95ae6ed5
3 changed files with 57 additions and 53 deletions
|
@ -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);
|
||||
|
|
|
@ -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<m2::RegionD> m_waterRegions;
|
||||
deque<m2::RegionD> m_waterRegions;
|
||||
|
||||
m4::Tree<size_t> 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<FileReader> file(reader);
|
||||
|
||||
size_t total = 0;
|
||||
while (true)
|
||||
{
|
||||
uint64_t numGeometries = 0;
|
||||
file.read(reinterpret_cast<char *>(&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<char *>(&numPoints), sizeof(numPoints));
|
||||
file.Read(&numPoints, sizeof(numPoints));
|
||||
points.resize(numPoints);
|
||||
file.read(reinterpret_cast<char *>(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 <class TInfo>
|
||||
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 <class FeatureOutT>
|
||||
|
@ -201,7 +201,10 @@ class CountryMapGenerator
|
|||
|
||||
public:
|
||||
template <class TInfo>
|
||||
explicit CountryMapGenerator(TInfo const & info) : m_bucket(info) {}
|
||||
explicit CountryMapGenerator(TInfo const & info)
|
||||
: m_bucket(info)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(FeatureBuilder1 fb)
|
||||
{
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue