[indexer] Allow feature visibility override
- read 3 extra scale indices - fallback to a nearest geometry if requested one doesn't exist Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
This commit is contained in:
parent
2e20ddd3d7
commit
2ddb4b86fb
4 changed files with 47 additions and 12 deletions
|
@ -58,14 +58,20 @@ public:
|
|||
|
||||
Points const & GetSourcePoints()
|
||||
{
|
||||
// For short lines keep simplifying the previous version to ensure points visibility is consistent.
|
||||
return !m_current.empty() ? m_current : m_fb.GetOuterGeometry();
|
||||
}
|
||||
|
||||
// Its important AddPoints is called sequentially from upper scales to lower.
|
||||
void AddPoints(Points const & points, int scaleIndex)
|
||||
{
|
||||
if (m_ptsInner && points.size() <= m_maxNumTriangles)
|
||||
{
|
||||
// Store small features inline and keep a mask for individual points scale visibility.
|
||||
if (m_buffer.m_innerPts.empty())
|
||||
// FIXME: if geometry is added for the most detailed scale 3 only
|
||||
// then the mask is never updated and left == 0,
|
||||
// which means the geometry could be used on any scale.
|
||||
m_buffer.m_innerPts = points;
|
||||
else
|
||||
FillInnerPointsMask(points, scaleIndex);
|
||||
|
|
|
@ -49,6 +49,10 @@ public:
|
|||
|
||||
// In case of WorldCoasts we should pass correct scale in ForEachInIntervalAndScale.
|
||||
auto const lastScale = header.GetLastScale();
|
||||
// Read 3 additional scale indices to allow visibility changes
|
||||
// for style designers and for custom style users.
|
||||
// TODO: add enable/disable flag and always keep disabled for the world map.
|
||||
scale += 3;
|
||||
if (scale > lastScale)
|
||||
scale = lastScale;
|
||||
|
||||
|
|
|
@ -345,6 +345,7 @@ void FeatureType::ParseHeader2()
|
|||
{
|
||||
ptsCount = bitSource.Read(4);
|
||||
if (ptsCount == 0)
|
||||
// A mask of outer geometry present.
|
||||
ptsMask = bitSource.Read(4);
|
||||
else
|
||||
ASSERT_GREATER(ptsCount, 1, ());
|
||||
|
@ -363,6 +364,7 @@ void FeatureType::ParseHeader2()
|
|||
{
|
||||
if (ptsCount > 0)
|
||||
{
|
||||
// Inner geometry.
|
||||
int const count = ((ptsCount - 2) + 4 - 1) / 4;
|
||||
ASSERT_LESS(count, 4, ());
|
||||
|
||||
|
@ -378,6 +380,7 @@ void FeatureType::ParseHeader2()
|
|||
}
|
||||
else
|
||||
{
|
||||
// Outer geometry: first point is stored in the header (coding params).
|
||||
m_points.emplace_back(serial::LoadPoint(src, cp));
|
||||
ReadOffsets(*m_loadInfo, src, ptsMask, m_offsets.m_pts);
|
||||
}
|
||||
|
@ -435,8 +438,12 @@ uint32_t FeatureType::ParseGeometry(int scale)
|
|||
{
|
||||
ASSERT_EQUAL(count, 1, ());
|
||||
|
||||
// outer geometry
|
||||
int const ind = GetScaleIndex(*m_loadInfo, scale, m_offsets.m_pts);
|
||||
// Outer geometry.
|
||||
int ind = GetScaleIndex(*m_loadInfo, scale, m_offsets.m_pts);
|
||||
// If there is no geometry for the requested scale, fallback to a closest available one.
|
||||
// TODO: add enable/disable flag and always keep disabled for the world map.
|
||||
if (ind == -1)
|
||||
ind = GetScaleIndex(*m_loadInfo, FeatureType::WORST_GEOMETRY, m_offsets.m_pts);
|
||||
if (ind != -1)
|
||||
{
|
||||
ReaderSource<FilesContainerR::TReader> src(m_loadInfo->GetGeometryReader(ind));
|
||||
|
@ -451,7 +458,7 @@ uint32_t FeatureType::ParseGeometry(int scale)
|
|||
}
|
||||
else
|
||||
{
|
||||
// filter inner geometry
|
||||
// Filter inner geometry.
|
||||
|
||||
FeatureType::Points points;
|
||||
points.reserve(count);
|
||||
|
@ -460,11 +467,25 @@ uint32_t FeatureType::ParseGeometry(int scale)
|
|||
ASSERT_LESS(scaleIndex, m_loadInfo->GetScalesCount(), ());
|
||||
|
||||
points.emplace_back(m_points.front());
|
||||
int minScale = m_loadInfo->GetScalesCount() - 1;
|
||||
int pointScale = 0;
|
||||
for (size_t i = 1; i + 1 < count; ++i)
|
||||
{
|
||||
// check for point visibility in needed scaleIndex
|
||||
if (static_cast<int>((m_ptsSimpMask >> (2 * (i - 1))) & 0x3) <= scaleIndex)
|
||||
// Check for point visibility in needed scaleIndex.
|
||||
pointScale = static_cast<int>((m_ptsSimpMask >> (2 * (i - 1))) & 0x3);
|
||||
if (pointScale <= scaleIndex)
|
||||
points.emplace_back(m_points[i]);
|
||||
else if (points.size() == 1 && minScale > pointScale)
|
||||
minScale = pointScale;
|
||||
}
|
||||
// Fallback to a closest available geometry.
|
||||
if (points.size() == 1)
|
||||
{
|
||||
for (size_t i = 1; i + 1 < count; ++i)
|
||||
{
|
||||
if (static_cast<int>((m_ptsSimpMask >> (2 * (i - 1))) & 0x3) == minScale)
|
||||
points.emplace_back(m_points[i]);
|
||||
}
|
||||
}
|
||||
points.emplace_back(m_points.back());
|
||||
|
||||
|
|
|
@ -47,6 +47,11 @@ public:
|
|||
m_cellsInBucket.resize(m_bucketsCount);
|
||||
}
|
||||
|
||||
// Every feature should be indexed at most once, namely for the smallest possible scale where
|
||||
// -- its geometry is non-empty;
|
||||
// -- it is visible;
|
||||
// -- it is allowed by the classificator.
|
||||
// If the feature is invisible at all scales, do not index it.
|
||||
template <class Feature>
|
||||
void operator()(Feature & ft, uint32_t index) const
|
||||
{
|
||||
|
@ -56,12 +61,15 @@ public:
|
|||
// The classificator won't allow this feature to be drawable for smaller
|
||||
// scales so the first buckets can be safely skipped.
|
||||
// todo(@pimenov) Parallelizing this loop may be helpful.
|
||||
// TODO: skip index building for scales [0,9] for country files and scales 10+ for the world file.
|
||||
for (uint32_t bucket = minScaleClassif; bucket < m_bucketsCount; ++bucket)
|
||||
{
|
||||
// There is a one-to-one correspondence between buckets and scales.
|
||||
// This is not immediately obvious and in fact there was an idea to map
|
||||
// a bucket to a contiguous range of scales.
|
||||
// todo(@pimenov): We probably should remove scale_index.hpp altogether.
|
||||
|
||||
// Check feature's geometry and visibility.
|
||||
if (!FeatureShouldBeIndexed(ft, static_cast<int>(bucket), bucket == minScaleClassif /* needReset */))
|
||||
{
|
||||
continue;
|
||||
|
@ -78,11 +86,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
// Every feature should be indexed at most once, namely for the smallest possible scale where
|
||||
// -- its geometry is non-empty;
|
||||
// -- it is visible;
|
||||
// -- it is allowed by the classificator.
|
||||
// If the feature is invisible at all scales, do not index it.
|
||||
template <class Feature>
|
||||
bool FeatureShouldBeIndexed(Feature & ft, int scale, bool needReset) const
|
||||
{
|
||||
|
@ -136,9 +139,10 @@ void IndexScales(feature::DataHeader const & header, FeaturesVector const & feat
|
|||
};
|
||||
using TDisplacementManager = DisplacementManager<decltype(PushCFT)>;
|
||||
|
||||
// Heuristically rearrange and filter single-point features to simplify
|
||||
// Single-point features are heuristically rearranged and filtered to simplify
|
||||
// the runtime decision of whether we should draw a feature
|
||||
// or sacrifice it for the sake of more important ones.
|
||||
// or sacrifice it for the sake of more important ones ("displacement").
|
||||
// Lines and areas are not displaceable and are just passed on to the index.
|
||||
TDisplacementManager manager(PushCFT);
|
||||
std::vector<uint32_t> featuresInBucket(bucketsCount);
|
||||
std::vector<uint32_t> cellsInBucket(bucketsCount);
|
||||
|
|
Reference in a new issue