Correct processing of closed linear features (highway's roundabouts) during merging.

This commit is contained in:
vng 2011-05-29 17:33:44 +03:00 committed by Alex Zolotarev
parent ca58f00beb
commit 9020980cfc
4 changed files with 154 additions and 57 deletions

View file

@ -4,40 +4,53 @@
#include "../indexer/classificator.hpp"
MergedFeatureBuilder1::MergedFeatureBuilder1(FeatureBuilder1 const & fb, bool isOK)
: FeatureBuilder1(fb), m_isOK(isOK)
MergedFeatureBuilder1::MergedFeatureBuilder1(FeatureBuilder1 const & fb)
: FeatureBuilder1(fb), m_isRound(false)
{
m_Params.FinishAddingTypes();
}
void MergedFeatureBuilder1::AppendFeature(MergedFeatureBuilder1 const & fb, bool toBack)
void MergedFeatureBuilder1::SetRound()
{
if (fb.m_isOK)
m_isOK = true;
m_isRound = true;
m_roundBounds[0] = m_roundBounds[1] = m_Geometry;
}
m2::PointD const pt = toBack ? LastPoint() : FirstPoint();
void MergedFeatureBuilder1::AppendFeature(MergedFeatureBuilder1 const & fb, bool fromBegin, bool toBack)
{
if (fb.m_isRound)
{
if (toBack)
m_roundBounds[1] = fb.m_Geometry;
else
m_roundBounds[0] = fb.m_Geometry;
return;
}
bool fromEnd = false;
if ((pt.SquareLength(fb.FirstPoint()) > pt.SquareLength(fb.LastPoint())) == toBack)
fromEnd = true;
if (toBack)
m_roundBounds[1].clear();
else
m_roundBounds[0].clear();
m_isRound = false;
for (size_t i = 0; i < fb.m_Geometry.size(); ++i)
m_LimitRect.Add(fb.m_Geometry[i]);
if (fromEnd)
{
if (toBack)
m_Geometry.insert(m_Geometry.end(), fb.m_Geometry.rbegin() + 1, fb.m_Geometry.rend());
else
m_Geometry.insert(m_Geometry.begin(), fb.m_Geometry.rbegin(), fb.m_Geometry.rend() - 1);
}
else
if (fromBegin)
{
if (toBack)
m_Geometry.insert(m_Geometry.end(), fb.m_Geometry.begin() + 1, fb.m_Geometry.end());
else
m_Geometry.insert(m_Geometry.begin(), fb.m_Geometry.begin(), fb.m_Geometry.end() - 1);
}
else
{
if (toBack)
m_Geometry.insert(m_Geometry.end(), fb.m_Geometry.rbegin() + 1, fb.m_Geometry.rend());
else
m_Geometry.insert(m_Geometry.begin(), fb.m_Geometry.rbegin(), fb.m_Geometry.rend() - 1);
}
}
bool MergedFeatureBuilder1::EqualGeometry(MergedFeatureBuilder1 const & fb) const
@ -45,6 +58,36 @@ bool MergedFeatureBuilder1::EqualGeometry(MergedFeatureBuilder1 const & fb) cons
return (m_Geometry == fb.m_Geometry);
}
pair<m2::PointD, bool> MergedFeatureBuilder1::GetKeyPoint(size_t i) const
{
size_t sz = m_roundBounds[0].size();
if (i < sz) return make_pair(m_roundBounds[0][i], false);
i -= sz;
if (i == 0) return make_pair(FirstPoint(), false);
sz = m_roundBounds[1].size();
if (i < sz) return make_pair(m_roundBounds[1][i], true);
i -= sz;
ASSERT_EQUAL ( i, 1, () );
return make_pair(LastPoint(), true);
}
size_t MergedFeatureBuilder1::GetKeyPointsCount() const
{
return m_roundBounds[0].size() + m_roundBounds[1].size() + 2;
}
double MergedFeatureBuilder1::GetPriority() const
{
double pr = 0.0;
for (size_t i = 1; i < m_Geometry.size(); ++i)
pr += m_Geometry[i-1].SquareLength(m_Geometry[i]);
return pr;
}
FeatureMergeProcessor::key_t FeatureMergeProcessor::get_key(m2::PointD const & p)
{
@ -58,7 +101,7 @@ FeatureMergeProcessor::FeatureMergeProcessor(uint32_t coordBits)
void FeatureMergeProcessor::operator() (FeatureBuilder1 const & fb)
{
this->operator() (new MergedFeatureBuilder1(fb, true));
this->operator() (new MergedFeatureBuilder1(fb));
}
void FeatureMergeProcessor::operator() (MergedFeatureBuilder1 * p)
@ -69,16 +112,29 @@ void FeatureMergeProcessor::operator() (MergedFeatureBuilder1 * p)
m_map[k1].push_back(p);
if (k1 != k2)
m_map[k2].push_back(p);
else
{
///@ todo Do it only for small round features!
p->SetRound();
p->ForEachMiddlePoints(bind(&FeatureMergeProcessor::Insert, this, _1, p));
}
}
void FeatureMergeProcessor::Insert(m2::PointD const & pt, MergedFeatureBuilder1 * p)
{
m_map[get_key(pt)].push_back(p);
}
void FeatureMergeProcessor::Remove(key_t key, MergedFeatureBuilder1 const * p)
{
map_t::iterator i = m_map.find(key);
CHECK(i != m_map.end(), ());
vector_t & v = i->second;
v.erase(remove(v.begin(), v.end(), p), v.end());
if (v.empty()) m_map.erase(i);
if (i != m_map.end())
{
vector_t & v = i->second;
v.erase(remove(v.begin(), v.end(), p), v.end());
if (v.empty()) m_map.erase(i);
}
}
void FeatureMergeProcessor::Remove(MergedFeatureBuilder1 const * p)
@ -89,6 +145,12 @@ void FeatureMergeProcessor::Remove(MergedFeatureBuilder1 const * p)
Remove(k1, p);
if (k1 != k2)
Remove(k2, p);
else
{
ASSERT ( p->IsRound(), () );
p->ForEachMiddlePoints(bind(&FeatureMergeProcessor::Remove1, this, _1, p));
}
}
void FeatureMergeProcessor::DoMerge(FeatureEmitterIFace & emitter)
@ -113,53 +175,65 @@ void FeatureMergeProcessor::DoMerge(FeatureEmitterIFace & emitter)
MergedFeatureBuilder1 curr(*p);
curr.SetType(type);
// Cycle while merging.
while (true)
// Iterate through key points while merging.
size_t ind = 0;
while (ind < curr.GetKeyPointsCount()) // GetKeyPointsCount() can be different on each iteration
{
bool isMerged = false;
bool toBack = true;
map_t::iterator it = m_map.find(get_key(curr.LastPoint()));
if (it == m_map.end())
{
it = m_map.find(get_key(curr.FirstPoint()));
toBack = false;
}
pair<m2::PointD, bool> const pt = curr.GetKeyPoint(ind++);
map_t::const_iterator it = m_map.find(get_key(pt.first));
MergedFeatureBuilder1 * pp = 0;
if (it != m_map.end())
{
// Find best feature to continue.
double bestPr = -1.0;
for (size_t i = 0; i < it->second.size(); ++i)
{
MergedFeatureBuilder1 * pp = it->second[i];
if (pp->HasType(type))
MergedFeatureBuilder1 * pTest = it->second[i];
if (pTest->HasType(type))
{
isMerged = true;
curr.AppendFeature(*pp, toBack);
if (pp->PopExactType(type))
double const pr = pTest->GetPriority();
ASSERT_GREATER ( pr, 0.0, () );
if (pr > bestPr)
{
Remove(pp);
delete pp;
pp = pTest;
bestPr = pr;
}
break;
}
}
}
if (!isMerged)
break;
// Merge current feature with best feature.
if (pp)
{
bool const toBack = pt.second;
bool fromBegin = true;
if ((pt.first.SquareLength(pp->FirstPoint()) > pt.first.SquareLength(pp->LastPoint())) == toBack)
fromBegin = false;
curr.AppendFeature(*pp, fromBegin, toBack);
if (pp->PopExactType(type))
{
Remove(pp);
delete pp;
}
// start from the beginning if we have a successful merge
ind = 0;
}
}
}
// Push feature p to output.
if (m_last.NotEmpty() && m_last.EqualGeometry(curr))
{
// curr is equal with m_last by geometry - just add new type to m_last
m_last.AddType(type);
}
else
{
// emit m_last and set curr as last processed feature (m_last)
if (m_last.NotEmpty())
emitter(m_last);
m_last = curr;
}
@ -204,7 +278,7 @@ void FeatureTypesProcessor::SetMappingTypes(char const * arr1[2], char const * a
MergedFeatureBuilder1 * FeatureTypesProcessor::operator() (FeatureBuilder1 const & fb)
{
MergedFeatureBuilder1 * p = new MergedFeatureBuilder1(fb, true);
MergedFeatureBuilder1 * p = new MergedFeatureBuilder1(fb);
p->ForEachChangeTypes(do_change_types(*this));

View file

@ -10,13 +10,18 @@
/// Feature builder class that used while feature type processing and merging.
class MergedFeatureBuilder1 : public FeatureBuilder1
{
bool m_isOK;
bool m_isRound;
points_t m_roundBounds[2];
public:
MergedFeatureBuilder1() : m_isOK(false) {}
MergedFeatureBuilder1(FeatureBuilder1 const & fb, bool isOK);
MergedFeatureBuilder1() : m_isRound(false) {}
MergedFeatureBuilder1(FeatureBuilder1 const & fb);
void AppendFeature(MergedFeatureBuilder1 const & fb, bool toBack);
void SetRound();
bool IsRound() const { return m_isRound; }
void AppendFeature(MergedFeatureBuilder1 const & fb, bool fromBegin, bool toBack);
bool EqualGeometry(MergedFeatureBuilder1 const & fb) const;
@ -34,6 +39,17 @@ public:
for_each(m_Params.m_Types.begin(), m_Params.m_Types.end(), toDo);
m_Params.FinishAddingTypes();
}
template <class ToDo> void ForEachMiddlePoints(ToDo toDo) const
{
for (size_t i = 1; i < m_Geometry.size()-1; ++i)
toDo(m_Geometry[i]);
}
pair<m2::PointD, bool> GetKeyPoint(size_t i) const;
size_t GetKeyPointsCount() const;
double GetPriority() const;
};
/// Feature merger.
@ -48,7 +64,13 @@ class FeatureMergeProcessor
typedef map<key_t, vector_t> map_t;
map_t m_map;
void Insert(m2::PointD const & pt, MergedFeatureBuilder1 * p);
void Remove(key_t key, MergedFeatureBuilder1 const * p);
inline void Remove1(m2::PointD const & pt, MergedFeatureBuilder1 const * p)
{
Remove(get_key(pt), p);
}
void Remove(MergedFeatureBuilder1 const * p);
uint32_t m_coordBits;

View file

@ -130,5 +130,5 @@ UNIT_TEST(FeatureMerger_Branches)
VectorEmitter emitter;
processor.DoMerge(emitter);
TEST_EQUAL(emitter.GetSize(), 1, ());
TEST_LESS_OR_EQUAL(emitter.GetSize(), 2, ());
}

View file

@ -12,8 +12,9 @@ inline int GetMinFeatureDrawScale(FeatureBuilder1 const & fb)
{
FeatureBase fBase = fb.GetFeatureBase();
int const minScale = feature::MinDrawableScaleForFeature(fBase);
CHECK_GREATER(minScale, -1, ("Non-drawable feature found!?"));
return minScale;
// some features become invisible after merge processing, so -1 is possible
return (minScale == -1 ? 1000 : minScale);
}