[generator] World lines: adjust short lines filtering, merge motorways into trunks #5655
5 changed files with 53 additions and 14 deletions
|
@ -109,14 +109,14 @@ size_t MergedFeatureBuilder::GetKeyPointsCount() const
|
|||
return m_roundBounds[0].size() + m_roundBounds[1].size() + 2;
|
||||
}
|
||||
|
||||
double MergedFeatureBuilder::GetPriority() const
|
||||
double MergedFeatureBuilder::GetSquaredLength() const
|
||||
{
|
||||
PointSeq const & poly = GetOuterGeometry();
|
||||
|
||||
double pr = 0.0;
|
||||
double sqLen = 0.0;
|
||||
for (size_t i = 1; i < poly.size(); ++i)
|
||||
pr += poly[i-1].SquaredLength(poly[i]);
|
||||
return pr;
|
||||
sqLen += poly[i-1].SquaredLength(poly[i]);
|
||||
return sqLen;
|
||||
}
|
||||
|
||||
|
||||
|
@ -145,6 +145,8 @@ void FeatureMergeProcessor::operator() (MergedFeatureBuilder * p)
|
|||
m_map[k2].push_back(p);
|
||||
else
|
||||
{
|
||||
// All of roundabout's points are considered for possible continuation of the line.
|
||||
// Effectively a roundabout itself is discarded and is used only for merging adjoining lines together.
|
||||
///@ todo Do it only for small round features!
|
||||
p->SetRound();
|
||||
|
||||
|
@ -207,6 +209,7 @@ void FeatureMergeProcessor::DoMerge(FeatureEmitterIFace & emitter)
|
|||
curr.SetType(type);
|
||||
|
||||
// Iterate through key points while merging.
|
||||
// Key points are either ends of the line or any point on the "roundabout" if the line ends with it.
|
||||
size_t ind = 0;
|
||||
while (ind < curr.GetKeyPointsCount()) // GetKeyPointsCount() can be different on each iteration
|
||||
{
|
||||
|
@ -216,17 +219,19 @@ void FeatureMergeProcessor::DoMerge(FeatureEmitterIFace & emitter)
|
|||
MergedFeatureBuilder * pp = 0;
|
||||
if (it != m_map.end())
|
||||
{
|
||||
// Find best feature to continue.
|
||||
double bestPr = -1.0;
|
||||
// Find the shortest connected line feature to continue,
|
||||
// it helps to spread points more evenly between the features and to avoid producing too long lines.
|
||||
double bestPr = std::numeric_limits<double>::max();
|
||||
for (size_t i = 0; i < it->second.size(); ++i)
|
||||
{
|
||||
MergedFeatureBuilder * pTest = it->second[i];
|
||||
if (pTest->HasType(type))
|
||||
{
|
||||
double const pr = pTest->GetPriority();
|
||||
double const pr = pTest->GetSquaredLength();
|
||||
// It's not necessery assert, because it's possible in source data
|
||||
// ASSERT_GREATER ( pr, 0.0, () );
|
||||
if (pr > bestPr)
|
||||
// TODO(pastk) : likely caused by degenerate closed lines.
|
||||
// ASSERT_GREATER(pr, 0.0, ());
|
||||
if (pr < bestPr)
|
||||
{
|
||||
pp = pTest;
|
||||
bestPr = pr;
|
||||
|
@ -234,7 +239,7 @@ void FeatureMergeProcessor::DoMerge(FeatureEmitterIFace & emitter)
|
|||
}
|
||||
}
|
||||
|
||||
// Merge current feature with best feature.
|
||||
// Merge the current feature with the best connected feature.
|
||||
if (pp)
|
||||
{
|
||||
bool const toBack = pt.second;
|
||||
|
|
|
@ -51,7 +51,8 @@ public:
|
|||
std::pair<m2::PointD, bool> GetKeyPoint(size_t i) const;
|
||||
size_t GetKeyPointsCount() const;
|
||||
|
||||
double GetPriority() const;
|
||||
// Used to determine which connected line to merge.
|
||||
double GetSquaredLength() const;
|
||||
};
|
||||
|
||||
/// Feature merger.
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include "generator/feature_builder.hpp"
|
||||
#include "generator/final_processor_utils.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
namespace generator
|
||||
|
@ -23,9 +25,11 @@ void WorldFinalProcessor::Process()
|
|||
auto fbs = ReadAllDatRawFormat<serialization_policy::MaxAccuracy>(m_worldTmpFilename);
|
||||
Order(fbs);
|
||||
WorldGenerator generator(m_worldTmpFilename, m_coastlineGeomFilename, m_popularPlacesFilename);
|
||||
LOG(LINFO, ("Process World features"));
|
||||
for (auto & fb : fbs)
|
||||
generator.Process(fb);
|
||||
|
||||
LOG(LINFO, ("Merge World lines"));
|
||||
generator.DoMerge();
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,10 @@ public:
|
|||
Earth
|
||||
};
|
||||
|
||||
// TODO(pastk): boundaries along the coast are being "torn" into small pieces instead of being discarded completely.
|
||||
// Likely it happens because an already simplified coastline is used, while boundary lines are not simplified yet.
|
||||
// It causes these lines to intersect each other often.
|
||||
// https://github.com/organicmaps/organicmaps/issues/6445
|
||||
void ProcessBoundary(feature::FeatureBuilder const & boundary, std::vector<feature::FeatureBuilder> & parts)
|
||||
{
|
||||
double constexpr kExtension = 0.01;
|
||||
|
|
|
@ -53,8 +53,27 @@ class WorldMapGenerator
|
|||
// This functor is called by m_merger after merging linear features.
|
||||
void operator()(feature::FeatureBuilder const & fb) override
|
||||
{
|
||||
// Skip small ways. This check is enough, because classifier types check was made in m_typesCorrector.
|
||||
if (scales::IsGoodForLevel(scales::GetUpperWorldScale(), fb.GetLimitRect()))
|
||||
static const uint32_t ferryType = classif().GetTypeByPath({"route", "ferry"});
|
||||
static const uint32_t boundaryType = classif().GetTypeByPath({"boundary", "administrative"});
|
||||
static const uint32_t highwayType = classif().GetTypeByPath({"highway"});
|
||||
pastk
commented
GetTypeByPath() is not constexpr GetTypeByPath() is not constexpr
![]() Right! It would be great to make these expressions constexpr in the future... Right! It would be great to make these expressions constexpr in the future...
|
||||
|
||||
int thresholdLevel = scales::GetUpperWorldScale();
|
||||
if (fb.HasType(ferryType) || fb.HasType(boundaryType, 2))
|
||||
{
|
||||
// Discard too short ferry and boundary lines
|
||||
// (boundaries along the coast are being "torn" into small pieces
|
||||
// by the coastline in WaterBoundaryChecker::ProcessBoundary()).
|
||||
thresholdLevel = scales::GetUpperWorldScale() - 2;
|
||||
}
|
||||
else if (fb.HasType(highwayType, 1))
|
||||
{
|
||||
// Discard too short roads incl. V-like approaches to roundabouts / other roads
|
||||
// and small roundabouts that were not merged into longer roads for some reason.
|
||||
thresholdLevel = scales::GetUpperWorldScale() + 2;
|
||||
}
|
||||
|
||||
// TODO(pastk): there seems to be two area size checks: here and in PushFeature().
|
||||
if (scales::IsGoodForLevel(thresholdLevel, fb.GetLimitRect()))
|
||||
PushSure(fb);
|
||||
}
|
||||
|
||||
|
@ -88,7 +107,7 @@ public:
|
|||
WorldMapGenerator(std::string const & worldFilename, std::string const & coastGeomFilename,
|
||||
std::string const & popularPlacesFilename)
|
||||
: m_worldBucket(worldFilename)
|
||||
, m_merger(kPointCoordBits - (scales::GetUpperScale() - scales::GetUpperWorldScale()) / 2)
|
||||
, m_merger(kFeatureSorterPointCoordBits - (scales::GetUpperScale() - scales::GetUpperWorldScale()) / 2)
|
||||
, m_popularPlacesFilename(popularPlacesFilename)
|
||||
{
|
||||
// Do not strip last types for given tags,
|
||||
|
@ -100,6 +119,12 @@ public:
|
|||
for (size_t i = 0; i < ARRAY_SIZE(arr1); ++i)
|
||||
m_typesCorrector.SetDontNormalizeType(arr1[i]);
|
||||
|
||||
// Merge motorways into trunks.
|
||||
// TODO : merge e.g. highway-trunk_link into highway-trunk?
|
||||
char const * marr1[2] = {"highway", "motorway"},
|
||||
* marr2[2] = {"highway", "trunk"};
|
||||
m_typesCorrector.SetMappingTypes(marr1, marr2);
|
||||
|
||||
if (popularPlacesFilename.empty())
|
||||
LOG(LWARNING, ("popular_places_data option not set. Popular attractions will not be added to World.mwm"));
|
||||
|
||||
|
|
Reference in a new issue
constexpr