forked from organicmaps/organicmaps
Move places handling from translator to MainFratureEmitter.
This commit is contained in:
parent
30a47a10c3
commit
80d669896f
2 changed files with 143 additions and 133 deletions
|
@ -18,6 +18,7 @@
|
|||
#include "platform/platform.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
#include "geometry/tree4d.hpp"
|
||||
|
||||
#include "coding/parse_xml.hpp"
|
||||
|
||||
|
@ -183,6 +184,78 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// TODO(mgsergio): comment
|
||||
class Place
|
||||
{
|
||||
FeatureBuilder1 m_ft;
|
||||
m2::PointD m_pt;
|
||||
uint32_t m_type;
|
||||
double m_thresholdM;
|
||||
|
||||
bool IsPoint() const { return (m_ft.GetGeomType() == feature::GEOM_POINT); }
|
||||
static bool IsEqualTypes(uint32_t t1, uint32_t t2)
|
||||
{
|
||||
// Use 2-arity places comparison for filtering.
|
||||
// ("place-city-capital-2" is equal to "place-city")
|
||||
ftype::TruncValue(t1, 2);
|
||||
ftype::TruncValue(t2, 2);
|
||||
return (t1 == t2);
|
||||
}
|
||||
|
||||
public:
|
||||
Place(FeatureBuilder1 const & ft, uint32_t type) : m_ft(ft), m_pt(ft.GetKeyPoint()), m_type(type)
|
||||
{
|
||||
using namespace ftypes;
|
||||
|
||||
switch (IsLocalityChecker::Instance().GetType(m_type))
|
||||
{
|
||||
case COUNTRY: m_thresholdM = 300000.0; break;
|
||||
case STATE: m_thresholdM = 100000.0; break;
|
||||
case CITY: m_thresholdM = 30000.0; break;
|
||||
case TOWN: m_thresholdM = 20000.0; break;
|
||||
case VILLAGE: m_thresholdM = 10000.0; break;
|
||||
default: m_thresholdM = 10000.0; break;
|
||||
}
|
||||
}
|
||||
|
||||
FeatureBuilder1 const & GetFeature() const { return m_ft; }
|
||||
|
||||
m2::RectD GetLimitRect() const
|
||||
{
|
||||
return MercatorBounds::RectByCenterXYAndSizeInMeters(m_pt, m_thresholdM);
|
||||
}
|
||||
|
||||
bool IsEqual(Place const & r) const
|
||||
{
|
||||
return (IsEqualTypes(m_type, r.m_type) &&
|
||||
m_ft.GetName() == r.m_ft.GetName() &&
|
||||
(IsPoint() || r.IsPoint()) &&
|
||||
MercatorBounds::DistanceOnEarth(m_pt, r.m_pt) < m_thresholdM);
|
||||
}
|
||||
|
||||
/// Check whether we need to replace place @r with place @this.
|
||||
bool IsBetterThan(Place const & r) const
|
||||
{
|
||||
// Check ranks.
|
||||
uint8_t const r1 = m_ft.GetRank();
|
||||
uint8_t const r2 = r.m_ft.GetRank();
|
||||
if (r1 != r2)
|
||||
return (r2 < r1);
|
||||
|
||||
// Check types length.
|
||||
// ("place-city-capital-2" is better than "place-city").
|
||||
uint8_t const l1 = ftype::GetLevel(m_type);
|
||||
uint8_t const l2 = ftype::GetLevel(r.m_type);
|
||||
if (l1 != l2)
|
||||
return (l2 < l1);
|
||||
|
||||
// Assume that area places has better priority than point places at the very end ...
|
||||
/// @todo It was usefull when place=XXX type has any area fill style.
|
||||
/// Need to review priority logic here (leave the native osm label).
|
||||
return !IsPoint();
|
||||
}
|
||||
};
|
||||
|
||||
class MainFeaturesEmitter
|
||||
{
|
||||
using TWorldGenerator = WorldMapGenerator<feature::FeaturesCollector>;
|
||||
|
@ -196,6 +269,9 @@ class MainFeaturesEmitter
|
|||
string m_srcCoastsFile;
|
||||
bool m_failOnCoasts;
|
||||
|
||||
// TODO(mgsergio): comment.
|
||||
m4::Tree<Place> m_places;
|
||||
|
||||
enum TypeIndex
|
||||
{
|
||||
NATURAL_COASTLINE,
|
||||
|
@ -248,47 +324,33 @@ public:
|
|||
m_world.reset(new TWorldGenerator(info));
|
||||
}
|
||||
|
||||
void operator()(FeatureBuilder1 fb)
|
||||
void operator()(FeatureBuilder1 & fb)
|
||||
{
|
||||
uint32_t const coastType = Type(NATURAL_COASTLINE);
|
||||
bool const hasCoast = fb.HasType(coastType);
|
||||
static uint32_t const placeType = classif().GetTypeByPath({"place"});
|
||||
uint32_t const type = fb.GetParams().FindType(placeType, 1);
|
||||
|
||||
if (m_coasts)
|
||||
if (type != ftype::GetEmptyValue() && !fb.GetName().empty())
|
||||
{
|
||||
if (hasCoast)
|
||||
{
|
||||
CHECK(fb.GetGeomType() != feature::GEOM_POINT, ());
|
||||
// leave only coastline type
|
||||
fb.SetType(coastType);
|
||||
(*m_coasts)(fb);
|
||||
}
|
||||
return;
|
||||
m_places.ReplaceEqualInRect(
|
||||
Place(fb, type),
|
||||
[](Place const & p1, Place const & p2) { return p1.IsEqual(p2); },
|
||||
[](Place const & p1, Place const & p2) { return p1.IsBetterThan(p2); });
|
||||
}
|
||||
|
||||
if (hasCoast)
|
||||
else
|
||||
{
|
||||
fb.PopExactType(Type(NATURAL_LAND));
|
||||
fb.PopExactType(coastType);
|
||||
Emit(fb);
|
||||
}
|
||||
else if ((fb.HasType(Type(PLACE_ISLAND)) || fb.HasType(Type(PLACE_ISLET))) &&
|
||||
fb.GetGeomType() == feature::GEOM_AREA)
|
||||
{
|
||||
fb.AddType(Type(NATURAL_LAND));
|
||||
}
|
||||
|
||||
if (!fb.RemoveInvalidTypes())
|
||||
return;
|
||||
|
||||
if (m_world)
|
||||
(*m_world)(fb);
|
||||
|
||||
if (m_countries)
|
||||
(*m_countries)(fb);
|
||||
}
|
||||
|
||||
/// @return false if coasts are not merged and FLAG_fail_on_coasts is set
|
||||
bool Finish()
|
||||
{
|
||||
m_places.ForEach([this](Place const & p)
|
||||
{
|
||||
// m_places are no longer used after this point.
|
||||
Emit(const_cast<FeatureBuilder1 &>(p.GetFeature()));
|
||||
});
|
||||
|
||||
if (m_world)
|
||||
m_world->DoMerge();
|
||||
|
||||
|
@ -347,6 +409,45 @@ public:
|
|||
else
|
||||
names.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
void Emit(FeatureBuilder1 & fb)
|
||||
{
|
||||
uint32_t const coastType = Type(NATURAL_COASTLINE);
|
||||
bool const hasCoast = fb.HasType(coastType);
|
||||
|
||||
if (m_coasts)
|
||||
{
|
||||
if (hasCoast)
|
||||
{
|
||||
CHECK(fb.GetGeomType() != feature::GEOM_POINT, ());
|
||||
// leave only coastline type
|
||||
fb.SetType(coastType);
|
||||
(*m_coasts)(fb);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasCoast)
|
||||
{
|
||||
fb.PopExactType(Type(NATURAL_LAND));
|
||||
fb.PopExactType(coastType);
|
||||
}
|
||||
else if ((fb.HasType(Type(PLACE_ISLAND)) || fb.HasType(Type(PLACE_ISLET))) &&
|
||||
fb.GetGeomType() == feature::GEOM_AREA)
|
||||
{
|
||||
fb.AddType(Type(NATURAL_LAND));
|
||||
}
|
||||
|
||||
if (!fb.RemoveInvalidTypes())
|
||||
return;
|
||||
|
||||
if (m_world)
|
||||
(*m_world)(fb);
|
||||
|
||||
if (m_countries)
|
||||
(*m_countries)(fb);
|
||||
}
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
|
@ -521,7 +622,7 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info)
|
|||
info.m_bookingReferenceDir);
|
||||
|
||||
stringstream skippedElements;
|
||||
|
||||
|
||||
// Here we can add new tags to element!!!
|
||||
auto const fn = [&](OsmElement * e)
|
||||
{
|
||||
|
@ -534,7 +635,7 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info)
|
|||
skippedElements << e->id << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
parser.EmitElement(e);
|
||||
};
|
||||
|
||||
|
@ -567,8 +668,6 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info)
|
|||
LOG(LERROR, ("Can't output into", skippedElementsPath));
|
||||
}
|
||||
}
|
||||
|
||||
parser.Finish();
|
||||
|
||||
// Stop if coasts are not merged and FLAG_fail_on_coasts is set
|
||||
if (!bucketer.Finish())
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
#include "indexer/feature_visibility.hpp"
|
||||
#include "indexer/ftypes_matcher.hpp"
|
||||
|
||||
#include "geometry/tree4d.hpp"
|
||||
|
||||
#include "coding/file_writer.hpp"
|
||||
|
||||
#include "base/cache.hpp"
|
||||
|
@ -24,77 +22,6 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
class Place
|
||||
{
|
||||
FeatureBuilder1 m_ft;
|
||||
m2::PointD m_pt;
|
||||
uint32_t m_type;
|
||||
double m_thresholdM;
|
||||
|
||||
bool IsPoint() const { return (m_ft.GetGeomType() == feature::GEOM_POINT); }
|
||||
static bool IsEqualTypes(uint32_t t1, uint32_t t2)
|
||||
{
|
||||
// Use 2-arity places comparison for filtering.
|
||||
// ("place-city-capital-2" is equal to "place-city")
|
||||
ftype::TruncValue(t1, 2);
|
||||
ftype::TruncValue(t2, 2);
|
||||
return (t1 == t2);
|
||||
}
|
||||
|
||||
public:
|
||||
Place(FeatureBuilder1 const & ft, uint32_t type) : m_ft(ft), m_pt(ft.GetKeyPoint()), m_type(type)
|
||||
{
|
||||
using namespace ftypes;
|
||||
|
||||
switch (IsLocalityChecker::Instance().GetType(m_type))
|
||||
{
|
||||
case COUNTRY: m_thresholdM = 300000.0; break;
|
||||
case STATE: m_thresholdM = 100000.0; break;
|
||||
case CITY: m_thresholdM = 30000.0; break;
|
||||
case TOWN: m_thresholdM = 20000.0; break;
|
||||
case VILLAGE: m_thresholdM = 10000.0; break;
|
||||
default: m_thresholdM = 10000.0; break;
|
||||
}
|
||||
}
|
||||
|
||||
FeatureBuilder1 const & GetFeature() const { return m_ft; }
|
||||
|
||||
m2::RectD GetLimitRect() const
|
||||
{
|
||||
return MercatorBounds::RectByCenterXYAndSizeInMeters(m_pt, m_thresholdM);
|
||||
}
|
||||
|
||||
bool IsEqual(Place const & r) const
|
||||
{
|
||||
return (IsEqualTypes(m_type, r.m_type) &&
|
||||
m_ft.GetName() == r.m_ft.GetName() &&
|
||||
(IsPoint() || r.IsPoint()) &&
|
||||
MercatorBounds::DistanceOnEarth(m_pt, r.m_pt) < m_thresholdM);
|
||||
}
|
||||
|
||||
/// Check whether we need to replace place @r with place @this.
|
||||
bool IsBetterThan(Place const & r) const
|
||||
{
|
||||
// Check ranks.
|
||||
uint8_t const r1 = m_ft.GetRank();
|
||||
uint8_t const r2 = r.m_ft.GetRank();
|
||||
if (r1 != r2)
|
||||
return (r2 < r1);
|
||||
|
||||
// Check types length.
|
||||
// ("place-city-capital-2" is better than "place-city").
|
||||
uint8_t const l1 = ftype::GetLevel(m_type);
|
||||
uint8_t const l2 = ftype::GetLevel(r.m_type);
|
||||
if (l1 != l2)
|
||||
return (l2 < l1);
|
||||
|
||||
// Assume that area places has better priority than point places at the very end ...
|
||||
/// @todo It was usefull when place=XXX type has any area fill style.
|
||||
/// Need to review priority logic here (leave the native osm label).
|
||||
return !IsPoint();
|
||||
}
|
||||
};
|
||||
|
||||
/// Generated features should include parent relation tags to make
|
||||
/// full types matching and storing any additional info.
|
||||
class RelationTagsBase
|
||||
|
@ -243,7 +170,6 @@ protected:
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/// @param TEmitter Feature accumulating policy
|
||||
|
@ -255,7 +181,7 @@ class OsmToFeatureTranslator
|
|||
TCache & m_holder;
|
||||
uint32_t m_coastType;
|
||||
unique_ptr<FileWriter> m_addrWriter;
|
||||
m4::Tree<Place> m_places;
|
||||
|
||||
RelationTagsNode m_nodeRelations;
|
||||
RelationTagsWay m_wayRelations;
|
||||
|
||||
|
@ -334,32 +260,25 @@ class OsmToFeatureTranslator
|
|||
return params.IsValid();
|
||||
}
|
||||
|
||||
void EmitFeatureBase(FeatureBuilder1 & ft, FeatureParams const & params)
|
||||
void EmitFeatureBase(FeatureBuilder1 & ft, FeatureParams const & params) const
|
||||
{
|
||||
ft.SetParams(params);
|
||||
if (ft.PreSerialize())
|
||||
{
|
||||
string addr;
|
||||
if (m_addrWriter && ftypes::IsBuildingChecker::Instance()(params.m_Types) && ft.FormatFullAddress(addr))
|
||||
m_addrWriter->Write(addr.c_str(), addr.size());
|
||||
|
||||
static uint32_t const placeType = classif().GetTypeByPath({"place"});
|
||||
uint32_t const type = params.FindType(placeType, 1);
|
||||
|
||||
if (type != ftype::GetEmptyValue() && !ft.GetName().empty())
|
||||
if (m_addrWriter && ftypes::IsBuildingChecker::Instance()(params.m_Types) &&
|
||||
ft.FormatFullAddress(addr))
|
||||
{
|
||||
m_places.ReplaceEqualInRect(Place(ft, type),
|
||||
[](Place const & p1, Place const & p2) { return p1.IsEqual(p2); },
|
||||
[](Place const & p1, Place const & p2) { return p1.IsBetterThan(p2); });
|
||||
m_addrWriter->Write(addr.c_str(), addr.size());
|
||||
}
|
||||
else
|
||||
m_emitter(ft);
|
||||
|
||||
m_emitter(ft);
|
||||
}
|
||||
}
|
||||
|
||||
/// @param[in] params Pass by value because it can be modified.
|
||||
//@{
|
||||
void EmitPoint(m2::PointD const & pt, FeatureParams params, osm::Id id)
|
||||
void EmitPoint(m2::PointD const & pt, FeatureParams params, osm::Id id) const
|
||||
{
|
||||
if (feature::RemoveNoDrawableTypes(params.m_Types, feature::GEOM_POINT))
|
||||
{
|
||||
|
@ -370,7 +289,7 @@ class OsmToFeatureTranslator
|
|||
}
|
||||
}
|
||||
|
||||
void EmitLine(FeatureBuilder1 & ft, FeatureParams params, bool isCoastLine)
|
||||
void EmitLine(FeatureBuilder1 & ft, FeatureParams params, bool isCoastLine) const
|
||||
{
|
||||
if (isCoastLine || feature::RemoveNoDrawableTypes(params.m_Types, feature::GEOM_LINE))
|
||||
{
|
||||
|
@ -380,7 +299,7 @@ class OsmToFeatureTranslator
|
|||
}
|
||||
|
||||
template <class MakeFnT>
|
||||
void EmitArea(FeatureBuilder1 & ft, FeatureParams params, MakeFnT makeFn)
|
||||
void EmitArea(FeatureBuilder1 & ft, FeatureParams params, MakeFnT makeFn) const
|
||||
{
|
||||
using namespace feature;
|
||||
|
||||
|
@ -571,12 +490,4 @@ public:
|
|||
if (!addrFilePath.empty())
|
||||
m_addrWriter.reset(new FileWriter(addrFilePath));
|
||||
}
|
||||
|
||||
void Finish()
|
||||
{
|
||||
m_places.ForEach([this] (Place const & p)
|
||||
{
|
||||
m_emitter(p.GetFeature());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue