forked from organicmaps/organicmaps-tmp
Added tile tree
This commit is contained in:
parent
0e6a372c05
commit
8cb22bf52d
13 changed files with 676 additions and 139 deletions
2
drape_frontend/drape_frontend.pro
Normal file → Executable file
2
drape_frontend/drape_frontend.pro
Normal file → Executable file
|
@ -36,6 +36,7 @@ SOURCES += \
|
|||
threads_commutator.cpp \
|
||||
tile_info.cpp \
|
||||
tile_key.cpp \
|
||||
tile_tree.cpp \
|
||||
tile_utils.cpp \
|
||||
user_mark_shapes.cpp \
|
||||
user_marks_provider.cpp \
|
||||
|
@ -76,6 +77,7 @@ HEADERS += \
|
|||
threads_commutator.hpp \
|
||||
tile_info.hpp \
|
||||
tile_key.hpp \
|
||||
tile_tree.hpp \
|
||||
tile_utils.hpp \
|
||||
user_mark_shapes.hpp \
|
||||
user_marks_provider.hpp \
|
||||
|
|
224
drape_frontend/frontend_renderer.cpp
Normal file → Executable file
224
drape_frontend/frontend_renderer.cpp
Normal file → Executable file
|
@ -79,8 +79,8 @@ void FrontendRenderer::AfterDrawFrame()
|
|||
|
||||
m_tpf = accumulate(m_tpfs.begin(), m_tpfs.end(), 0.0) / m_tpfs.size();
|
||||
|
||||
LOG(LINFO, ("Average Fps : ", m_fps));
|
||||
LOG(LINFO, ("Average Tpf : ", m_tpf));
|
||||
//LOG(LINFO, ("Average Fps : ", m_fps));
|
||||
//LOG(LINFO, ("Average Tpf : ", m_tpf));
|
||||
|
||||
#if defined(TRACK_GPU_MEM)
|
||||
string report = dp::GPUMemTracker::Inst().Report();
|
||||
|
@ -94,27 +94,27 @@ void FrontendRenderer::AfterDrawFrame()
|
|||
}
|
||||
#endif
|
||||
|
||||
UserMarkRenderGroup * FrontendRenderer::FindUserMarkRenderGroup(TileKey const & tileKey, bool createIfNeed)
|
||||
unique_ptr<UserMarkRenderGroup> & FrontendRenderer::FindUserMarkRenderGroup(TileKey const & tileKey, bool createIfNeed)
|
||||
{
|
||||
auto it = find_if(m_userMarkRenderGroups.begin(), m_userMarkRenderGroups.end(), [&tileKey](UserMarkRenderGroup * g)
|
||||
auto it = find_if(m_userMarkRenderGroups.begin(), m_userMarkRenderGroups.end(), [&tileKey](unique_ptr<UserMarkRenderGroup> const & g)
|
||||
{
|
||||
return g->GetTileKey() == tileKey;
|
||||
});
|
||||
|
||||
if (it != m_userMarkRenderGroups.end())
|
||||
{
|
||||
ASSERT((*it) != nullptr, ());
|
||||
ASSERT((*it).get() != nullptr, ());
|
||||
return *it;
|
||||
}
|
||||
|
||||
if (createIfNeed)
|
||||
{
|
||||
UserMarkRenderGroup * group = new UserMarkRenderGroup(dp::GLState(0, dp::GLState::UserMarkLayer), tileKey);
|
||||
m_userMarkRenderGroups.push_back(group);
|
||||
return group;
|
||||
m_userMarkRenderGroups.emplace_back(new UserMarkRenderGroup(dp::GLState(0, dp::GLState::UserMarkLayer), tileKey));
|
||||
return m_userMarkRenderGroups.back();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
static unique_ptr<UserMarkRenderGroup> emptyRenderGroup;
|
||||
return emptyRenderGroup;
|
||||
}
|
||||
|
||||
void FrontendRenderer::AcceptMessage(dp::RefPointer<Message> message)
|
||||
|
@ -134,8 +134,8 @@ void FrontendRenderer::AcceptMessage(dp::RefPointer<Message> message)
|
|||
CreateTileRenderGroup(state, bucket, key);
|
||||
else
|
||||
{
|
||||
UserMarkRenderGroup * group = FindUserMarkRenderGroup(key, true);
|
||||
ASSERT(group != nullptr, ());
|
||||
unique_ptr<UserMarkRenderGroup> & group = FindUserMarkRenderGroup(key, true);
|
||||
ASSERT(group.get() != nullptr, ());
|
||||
group->SetRenderBucket(state, bucket.Move());
|
||||
}
|
||||
break;
|
||||
|
@ -151,11 +151,15 @@ void FrontendRenderer::AcceptMessage(dp::RefPointer<Message> message)
|
|||
RefreshProjection();
|
||||
RefreshModelView();
|
||||
ResolveTileKeys();
|
||||
|
||||
TTilesCollection tiles;
|
||||
m_tileTree.GetRequestedTiles(tiles);
|
||||
|
||||
m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
|
||||
dp::MovePointer<Message>(new ResizeMessage(m_viewport)),
|
||||
MessagePriority::Normal);
|
||||
m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
|
||||
dp::MovePointer<Message>(new UpdateReadManagerMessage(m_view, m_tiles)),
|
||||
dp::MovePointer<Message>(new UpdateReadManagerMessage(m_view, tiles)),
|
||||
MessagePriority::Normal);
|
||||
break;
|
||||
}
|
||||
|
@ -169,8 +173,7 @@ void FrontendRenderer::AcceptMessage(dp::RefPointer<Message> message)
|
|||
InvalidateRectMessage * m = df::CastMessage<InvalidateRectMessage>(message);
|
||||
|
||||
TTilesCollection keyStorage;
|
||||
ResolveTileKeys(keyStorage, m->GetRect());
|
||||
InvalidateRenderGroups(keyStorage);
|
||||
// TODO: implement invalidation
|
||||
|
||||
Message * msgToBackend = new InvalidateReadManagerRectMessage(keyStorage);
|
||||
m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
|
||||
|
@ -182,17 +185,16 @@ void FrontendRenderer::AcceptMessage(dp::RefPointer<Message> message)
|
|||
case Message::ClearUserMarkLayer:
|
||||
{
|
||||
TileKey const & tileKey = df::CastMessage<ClearUserMarkLayerMessage>(message)->GetKey();
|
||||
auto it = find_if(m_userMarkRenderGroups.begin(), m_userMarkRenderGroups.end(), [&tileKey](UserMarkRenderGroup * g)
|
||||
auto it = find_if(m_userMarkRenderGroups.begin(), m_userMarkRenderGroups.end(), [&tileKey](unique_ptr<UserMarkRenderGroup> const & g)
|
||||
{
|
||||
return g->GetTileKey() == tileKey;
|
||||
});
|
||||
|
||||
if (it != m_userMarkRenderGroups.end())
|
||||
{
|
||||
UserMarkRenderGroup * group = *it;
|
||||
ASSERT(group != nullptr, ());
|
||||
unique_ptr<UserMarkRenderGroup> & group = *it;
|
||||
ASSERT(group.get() != nullptr, ());
|
||||
m_userMarkRenderGroups.erase(it);
|
||||
delete group;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -200,8 +202,8 @@ void FrontendRenderer::AcceptMessage(dp::RefPointer<Message> message)
|
|||
case Message::ChangeUserMarkLayerVisibility:
|
||||
{
|
||||
ChangeUserMarkLayerVisibilityMessage * m = df::CastMessage<ChangeUserMarkLayerVisibilityMessage>(message);
|
||||
UserMarkRenderGroup * group = FindUserMarkRenderGroup(m->GetKey(), true);
|
||||
ASSERT(group != nullptr, ());
|
||||
unique_ptr<UserMarkRenderGroup> & group = FindUserMarkRenderGroup(m->GetKey(), true);
|
||||
ASSERT(group.get() != nullptr, ());
|
||||
group->SetIsVisible(m->IsVisible());
|
||||
break;
|
||||
}
|
||||
|
@ -231,47 +233,90 @@ void FrontendRenderer::CreateTileRenderGroup(dp::GLState const & state,
|
|||
dp::MasterPointer<dp::RenderBucket> & renderBucket,
|
||||
TileKey const & newTile)
|
||||
{
|
||||
TTilesCollection & tiles = GetTileKeyStorage();
|
||||
auto const & tileIt = tiles.find(newTile);
|
||||
// adding tiles to render
|
||||
auto onAddTile = [&state, &renderBucket, this](TileKey const & tileKey, TileStatus tileStatus)
|
||||
{
|
||||
if (tileStatus == TileStatus::Rendered)
|
||||
{
|
||||
AddToRenderGroup(m_renderGroups, state, renderBucket, tileKey);
|
||||
LOG(LINFO, ("Render tile", tileKey, tileStatus));
|
||||
}
|
||||
else if (tileStatus == TileStatus::Deferred)
|
||||
OnAddDeferredTile(tileKey, tileStatus);
|
||||
else
|
||||
ASSERT(false, ());
|
||||
};
|
||||
|
||||
// skip obsolete tiles
|
||||
if (tileIt == tiles.end() || df::GetTileScaleBase(m_view) != newTile.m_zoomLevel)
|
||||
// deferring tiles
|
||||
auto onDeferTile = [&state, &renderBucket, this](TileKey const & tileKey, TileStatus tileStatus)
|
||||
{
|
||||
AddToRenderGroup(m_deferredRenderGroups, state, renderBucket, tileKey);
|
||||
LOG(LINFO, ("Defer tile", tileKey, tileStatus));
|
||||
};
|
||||
|
||||
// removing tiles
|
||||
auto onRemoveTile = [this](TileKey const & tileKey, TileStatus tileStatus)
|
||||
{
|
||||
OnRemoveTile(tileKey, tileStatus);
|
||||
LOG(LINFO, ("Remove tile", tileKey, tileStatus));
|
||||
};
|
||||
|
||||
bool const result = m_tileTree.ProcessTile(newTile, onAddTile, onRemoveTile, onDeferTile);
|
||||
if (!result)
|
||||
{
|
||||
renderBucket.Destroy();
|
||||
return;
|
||||
LOG(LINFO, ("Skip tile", newTile));
|
||||
}
|
||||
|
||||
// clip tiles below loaded one
|
||||
for (auto it = tiles.begin(); it != tiles.end(); ++it)
|
||||
if (it->second == TileStatus::Rendered && IsTileBelow(newTile, it->first))
|
||||
it->second = TileStatus::Clipped;
|
||||
|
||||
// clip tiles above loaded one
|
||||
for (auto it = tiles.begin(); it != tiles.end(); ++it)
|
||||
if (it->second == TileStatus::Rendered && IsTileAbove(newTile, it->first))
|
||||
it->second = TileStatus::Clipped;
|
||||
|
||||
// create a render group for visible tiles
|
||||
if (tileIt->second != TileStatus::Clipped)
|
||||
LOG(LINFO, ("Deferred count = ", m_deferredRenderGroups.size()));
|
||||
if (m_deferredRenderGroups.size() != 0)
|
||||
{
|
||||
RenderGroup * group = new RenderGroup(state, newTile);
|
||||
group->AddBucket(renderBucket.Move());
|
||||
m_renderGroups.push_back(group);
|
||||
tileIt->second = TileStatus::Rendered;
|
||||
LOG(LINFO, ("Zoom level: ", df::GetTileScaleBase(m_view)));
|
||||
LOG(LINFO, ("Tile tree: ", m_tileTree));
|
||||
LOG(LINFO, ("Rendered tiles: ", m_renderGroups));
|
||||
LOG(LINFO, ("Deferred tiles: ", m_deferredRenderGroups));
|
||||
}
|
||||
else
|
||||
renderBucket.Destroy();
|
||||
|
||||
// clean storage from clipped tiles
|
||||
CleanKeyStorage(tiles);
|
||||
}
|
||||
|
||||
void FrontendRenderer::CleanKeyStorage(TTilesCollection & keyStorage)
|
||||
void FrontendRenderer::AddToRenderGroup(vector<unique_ptr<RenderGroup>> & groups,
|
||||
dp::GLState const & state,
|
||||
dp::MasterPointer<dp::RenderBucket> & renderBucket,
|
||||
TileKey const & newTile)
|
||||
{
|
||||
for(auto it = keyStorage.begin(); it != keyStorage.end();)
|
||||
unique_ptr<RenderGroup> group(new RenderGroup(state, newTile));
|
||||
group->AddBucket(renderBucket.Move());
|
||||
groups.emplace_back(move(group));
|
||||
}
|
||||
|
||||
void FrontendRenderer::OnAddDeferredTile(TileKey const & tileKey, TileStatus tileStatus)
|
||||
{
|
||||
ASSERT(tileStatus == TileStatus::Deferred, ());
|
||||
for(auto it = m_deferredRenderGroups.begin(); it != m_deferredRenderGroups.end();)
|
||||
{
|
||||
if (it->second == TileStatus::Clipped)
|
||||
it = keyStorage.erase(it);
|
||||
if ((*it)->GetTileKey() == tileKey)
|
||||
{
|
||||
m_renderGroups.emplace_back(move(*it));
|
||||
it = m_deferredRenderGroups.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
LOG(LINFO, ("Add deferred tile", tileKey, tileStatus));
|
||||
}
|
||||
|
||||
void FrontendRenderer::OnRemoveTile(TileKey const & tileKey, TileStatus tileStatus)
|
||||
{
|
||||
for(auto it = m_renderGroups.begin(); it != m_renderGroups.end(); ++it)
|
||||
{
|
||||
if ((*it)->GetTileKey() == tileKey)
|
||||
(*it)->DeleteLater();
|
||||
}
|
||||
|
||||
for(auto it = m_deferredRenderGroups.begin(); it != m_deferredRenderGroups.end();)
|
||||
{
|
||||
if ((*it)->GetTileKey() == tileKey)
|
||||
it = m_deferredRenderGroups.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
@ -283,20 +328,20 @@ void FrontendRenderer::RenderScene()
|
|||
BeforeDrawFrame();
|
||||
#endif
|
||||
|
||||
RenderGroupComparator comparator(GetTileKeyStorage());
|
||||
RenderGroupComparator comparator;
|
||||
sort(m_renderGroups.begin(), m_renderGroups.end(), bind(&RenderGroupComparator::operator (), &comparator, _1, _2));
|
||||
|
||||
m_overlayTree.StartOverlayPlacing(m_view);
|
||||
size_t eraseCount = 0;
|
||||
for (size_t i = 0; i < m_renderGroups.size(); ++i)
|
||||
{
|
||||
RenderGroup * group = m_renderGroups[i];
|
||||
unique_ptr<RenderGroup> & group = m_renderGroups[i];
|
||||
if (group->IsEmpty())
|
||||
continue;
|
||||
|
||||
if (group->IsPendingOnDelete())
|
||||
{
|
||||
delete group;
|
||||
group.reset();
|
||||
++eraseCount;
|
||||
continue;
|
||||
}
|
||||
|
@ -322,7 +367,7 @@ void FrontendRenderer::RenderScene()
|
|||
dp::GLState::DepthLayer prevLayer = dp::GLState::GeometryLayer;
|
||||
for (size_t i = 0; i < m_renderGroups.size(); ++i)
|
||||
{
|
||||
RenderGroup * group = m_renderGroups[i];
|
||||
unique_ptr<RenderGroup> & group = m_renderGroups[i];
|
||||
dp::GLState const & state = group->GetState();
|
||||
dp::GLState::DepthLayer layer = state.GetDepthLayer();
|
||||
if (prevLayer != layer && layer == dp::GLState::OverlayLayer)
|
||||
|
@ -345,9 +390,9 @@ void FrontendRenderer::RenderScene()
|
|||
|
||||
GLFunctions::glClearDepth();
|
||||
|
||||
for (UserMarkRenderGroup * group : m_userMarkRenderGroups)
|
||||
for (unique_ptr<UserMarkRenderGroup> & group : m_userMarkRenderGroups)
|
||||
{
|
||||
ASSERT(group != nullptr, ());
|
||||
ASSERT(group.get() != nullptr, ());
|
||||
if (group->IsVisible())
|
||||
{
|
||||
dp::GLState const & state = group->GetState();
|
||||
|
@ -393,15 +438,15 @@ void FrontendRenderer::RefreshModelView()
|
|||
|
||||
void FrontendRenderer::ResolveTileKeys()
|
||||
{
|
||||
ResolveTileKeys(GetTileKeyStorage(), df::GetTileScaleBase(m_view));
|
||||
ResolveTileKeys(df::GetTileScaleBase(m_view));
|
||||
}
|
||||
|
||||
void FrontendRenderer::ResolveTileKeys(TTilesCollection & keyStorage, m2::RectD const & rect)
|
||||
void FrontendRenderer::ResolveTileKeys(m2::RectD const & rect)
|
||||
{
|
||||
ResolveTileKeys(keyStorage, df::GetTileScaleBase(rect));
|
||||
ResolveTileKeys(df::GetTileScaleBase(rect));
|
||||
}
|
||||
|
||||
void FrontendRenderer::ResolveTileKeys(TTilesCollection & keyStorage, int tileScale)
|
||||
void FrontendRenderer::ResolveTileKeys(int tileScale)
|
||||
{
|
||||
// equal for x and y
|
||||
double const range = MercatorBounds::maxX - MercatorBounds::minX;
|
||||
|
@ -415,38 +460,29 @@ void FrontendRenderer::ResolveTileKeys(TTilesCollection & keyStorage, int tileSc
|
|||
int const maxTileY = static_cast<int>(ceil(clipRect.maxY() / rectSize));
|
||||
|
||||
// clip all tiles which are out of viewport
|
||||
for (auto it = keyStorage.begin(); it != keyStorage.end(); ++it)
|
||||
if (!clipRect.IsIntersect(it->first.GetGlobalRect()))
|
||||
it->second = TileStatus::Clipped;
|
||||
auto onRemoveTile = [this](TileKey const & tileKey, TileStatus tileStatus)
|
||||
{
|
||||
OnRemoveTile(tileKey, tileStatus);
|
||||
LOG(LINFO, ("Clip tile", tileKey, tileStatus));
|
||||
};
|
||||
|
||||
m_tileTree.ClipByRect(clipRect, bind(&FrontendRenderer::OnAddDeferredTile, this, _1, _2),
|
||||
onRemoveTile);
|
||||
|
||||
// request new tiles
|
||||
m_tileTree.BeginRequesting(tileScale);
|
||||
for (int tileY = minTileY; tileY < maxTileY; ++tileY)
|
||||
{
|
||||
for (int tileX = minTileX; tileX < maxTileX; ++tileX)
|
||||
{
|
||||
// request new tile
|
||||
TileKey key(tileX, tileY, tileScale);
|
||||
if (clipRect.IsIntersect(key.GetGlobalRect()) && keyStorage.find(key) == keyStorage.end())
|
||||
keyStorage.insert(make_pair(key, TileStatus::Requested));
|
||||
if (clipRect.IsIntersect(key.GetGlobalRect()))
|
||||
m_tileTree.RequestTile(key);
|
||||
}
|
||||
}
|
||||
m_tileTree.EndRequesting();
|
||||
|
||||
// clean storage from clipped tiles
|
||||
CleanKeyStorage(keyStorage);
|
||||
}
|
||||
|
||||
void FrontendRenderer::InvalidateRenderGroups(TTilesCollection & keyStorage)
|
||||
{
|
||||
for (size_t i = 0; i < m_renderGroups.size(); ++i)
|
||||
{
|
||||
RenderGroup * group = m_renderGroups[i];
|
||||
if (keyStorage.find(group->GetTileKey()) != keyStorage.end())
|
||||
group->DeleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
TTilesCollection & FrontendRenderer::GetTileKeyStorage()
|
||||
{
|
||||
return m_tiles;
|
||||
//LOG(LINFO, (m_tileTree));
|
||||
}
|
||||
|
||||
void FrontendRenderer::StartThread()
|
||||
|
@ -523,8 +559,10 @@ void FrontendRenderer::ReleaseResources()
|
|||
|
||||
void FrontendRenderer::DeleteRenderData()
|
||||
{
|
||||
DeleteRange(m_renderGroups, DeleteFunctor());
|
||||
DeleteRange(m_userMarkRenderGroups, DeleteFunctor());
|
||||
m_renderGroups.clear();
|
||||
m_deferredRenderGroups.clear();
|
||||
m_userMarkRenderGroups.clear();
|
||||
m_tileTree.Clear();
|
||||
}
|
||||
|
||||
void FrontendRenderer::SetModelView(ScreenBase const & screen)
|
||||
|
@ -541,10 +579,24 @@ void FrontendRenderer::UpdateScene()
|
|||
m_view = m_newView;
|
||||
RefreshModelView();
|
||||
ResolveTileKeys();
|
||||
|
||||
TTilesCollection tiles;
|
||||
m_tileTree.GetRequestedTiles(tiles);
|
||||
|
||||
m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
|
||||
dp::MovePointer<Message>(new UpdateReadManagerMessage(m_view, m_tiles)),
|
||||
dp::MovePointer<Message>(new UpdateReadManagerMessage(m_view, tiles)),
|
||||
MessagePriority::Normal);
|
||||
}
|
||||
}
|
||||
|
||||
string DebugPrint(vector<unique_ptr<RenderGroup>> const & groups)
|
||||
{
|
||||
ostringstream out;
|
||||
out << "\n{\n";
|
||||
for (auto it = groups.begin(); it != groups.end(); ++it)
|
||||
out << DebugPrint((*it)->GetTileKey()) << "\n";
|
||||
out << "}\n";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
|
|
28
drape_frontend/frontend_renderer.hpp
Normal file → Executable file
28
drape_frontend/frontend_renderer.hpp
Normal file → Executable file
|
@ -11,6 +11,7 @@
|
|||
#include "drape_frontend/base_renderer.hpp"
|
||||
#include "drape_frontend/threads_commutator.hpp"
|
||||
#include "drape_frontend/tile_info.hpp"
|
||||
#include "drape_frontend/tile_tree.hpp"
|
||||
#include "drape_frontend/backend_renderer.hpp"
|
||||
#include "drape_frontend/render_group.hpp"
|
||||
#include "drape_frontend/my_position.hpp"
|
||||
|
@ -67,12 +68,10 @@ private:
|
|||
void RefreshModelView();
|
||||
|
||||
void ResolveTileKeys();
|
||||
void ResolveTileKeys(TTilesCollection & keyStorage, m2::RectD const & rect);
|
||||
void ResolveTileKeys(TTilesCollection & keyStorage, int tileScale);
|
||||
TTilesCollection & GetTileKeyStorage();
|
||||
void ResolveTileKeys(m2::RectD const & rect);
|
||||
void ResolveTileKeys(int tileScale);
|
||||
|
||||
void InvalidateRenderGroups(TTilesCollection & keyStorage);
|
||||
UserMarkRenderGroup * FindUserMarkRenderGroup(TileKey const & tileKey, bool createIfNeed);
|
||||
unique_ptr<UserMarkRenderGroup> & FindUserMarkRenderGroup(TileKey const & tileKey, bool createIfNeed);
|
||||
|
||||
private:
|
||||
class Routine : public threads::IRoutine
|
||||
|
@ -100,15 +99,22 @@ private:
|
|||
void CreateTileRenderGroup(dp::GLState const & state,
|
||||
dp::MasterPointer<dp::RenderBucket> & renderBucket,
|
||||
TileKey const & newTile);
|
||||
void CleanKeyStorage(TTilesCollection & keyStorage);
|
||||
void AddToRenderGroup(vector<unique_ptr<RenderGroup>> & groups,
|
||||
dp::GLState const & state,
|
||||
dp::MasterPointer<dp::RenderBucket> & renderBucket,
|
||||
TileKey const & newTile);
|
||||
|
||||
void OnAddDeferredTile(TileKey const & tileKey, TileStatus tileStatus);
|
||||
void OnRemoveTile(TileKey const & tileKey, TileStatus tileStatus);
|
||||
|
||||
private:
|
||||
dp::RefPointer<dp::TextureManager> m_textureManager;
|
||||
dp::MasterPointer<dp::GpuProgramManager> m_gpuProgramManager;
|
||||
|
||||
private:
|
||||
vector<RenderGroup *> m_renderGroups;
|
||||
vector<UserMarkRenderGroup *> m_userMarkRenderGroups;
|
||||
vector<unique_ptr<RenderGroup>> m_renderGroups;
|
||||
vector<unique_ptr<RenderGroup>> m_deferredRenderGroups;
|
||||
vector<unique_ptr<UserMarkRenderGroup>> m_userMarkRenderGroups;
|
||||
dp::MasterPointer<gui::LayerRenderer> m_guiRenderer;
|
||||
dp::MasterPointer<MyPosition> m_myPositionMark;
|
||||
|
||||
|
@ -116,12 +122,16 @@ private:
|
|||
|
||||
Viewport m_viewport;
|
||||
ScreenBase m_view;
|
||||
TTilesCollection m_tiles;
|
||||
|
||||
TileTree m_tileTree;
|
||||
|
||||
ScreenBase m_newView;
|
||||
mutex m_modelViewMutex;
|
||||
|
||||
dp::OverlayTree m_overlayTree;
|
||||
|
||||
private:
|
||||
friend string DebugPrint(vector<unique_ptr<RenderGroup>> const & groups);
|
||||
};
|
||||
|
||||
} // namespace df
|
||||
|
|
23
drape_frontend/read_manager.cpp
Normal file → Executable file
23
drape_frontend/read_manager.cpp
Normal file → Executable file
|
@ -17,14 +17,14 @@ namespace
|
|||
|
||||
struct LessCoverageCell
|
||||
{
|
||||
bool operator()(shared_ptr<TileInfo> const & l, TTilePair const & r) const
|
||||
bool operator()(shared_ptr<TileInfo> const & l, TileKey const & r) const
|
||||
{
|
||||
return l->GetTileKey() < r.first;
|
||||
return l->GetTileKey() < r;
|
||||
}
|
||||
|
||||
bool operator()(TTilePair const & l, shared_ptr<TileInfo> const & r) const
|
||||
bool operator()(TileKey const & l, shared_ptr<TileInfo> const & r) const
|
||||
{
|
||||
return l.first < r->GetTileKey();
|
||||
return l < r->GetTileKey();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -51,18 +51,11 @@ void ReadManager::UpdateCoverage(ScreenBase const & screen, TTilesCollection con
|
|||
if (screen == m_currentViewport)
|
||||
return;
|
||||
|
||||
auto newTilesTask = [this, &screen](TTilePair const & tileKey)
|
||||
{
|
||||
int const newScale = df::GetTileScaleBase(screen);
|
||||
if (newScale == tileKey.first.m_zoomLevel)
|
||||
PushTaskBackForTileKey(tileKey);
|
||||
};
|
||||
|
||||
if (MustDropAllTiles(screen))
|
||||
{
|
||||
for_each(m_tileInfos.begin(), m_tileInfos.end(), bind(&ReadManager::CancelTileInfo, this, _1));
|
||||
m_tileInfos.clear();
|
||||
for_each(tiles.begin(), tiles.end(), newTilesTask);
|
||||
for_each(tiles.begin(), tiles.end(), bind(&ReadManager::PushTaskBackForTileKey, this, _1));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -76,7 +69,7 @@ void ReadManager::UpdateCoverage(ScreenBase const & screen, TTilesCollection con
|
|||
back_inserter(outdatedTiles), LessCoverageCell());
|
||||
|
||||
// Find rects that go in into viewport
|
||||
buffer_vector<TTilePair, 8> inputRects;
|
||||
buffer_vector<TileKey, 8> inputRects;
|
||||
#ifdef _MSC_VER
|
||||
vs_bug::
|
||||
#endif
|
||||
|
@ -86,7 +79,7 @@ void ReadManager::UpdateCoverage(ScreenBase const & screen, TTilesCollection con
|
|||
|
||||
for_each(outdatedTiles.begin(), outdatedTiles.end(), bind(&ReadManager::ClearTileInfo, this, _1));
|
||||
for_each(m_tileInfos.begin(), m_tileInfos.end(), bind(&ReadManager::PushTaskFront, this, _1));
|
||||
for_each(inputRects.begin(), inputRects.end(), newTilesTask);
|
||||
for_each(inputRects.begin(), inputRects.end(), bind(&ReadManager::PushTaskBackForTileKey, this, _1));
|
||||
}
|
||||
m_currentViewport = screen;
|
||||
}
|
||||
|
@ -124,7 +117,7 @@ bool ReadManager::MustDropAllTiles(ScreenBase const & screen) const
|
|||
return (oldScale != newScale) || !m_currentViewport.GlobalRect().IsIntersect(screen.GlobalRect());
|
||||
}
|
||||
|
||||
void ReadManager::PushTaskBackForTileKey(TTilePair const & tileKey)
|
||||
void ReadManager::PushTaskBackForTileKey(TileKey const & tileKey)
|
||||
{
|
||||
shared_ptr<TileInfo> tileInfo(new TileInfo(EngineContext(tileKey, m_commutator)));
|
||||
m_tileInfos.insert(tileInfo);
|
||||
|
|
0
drape_frontend/read_manager.hpp
Normal file → Executable file
0
drape_frontend/read_manager.hpp
Normal file → Executable file
17
drape_frontend/render_group.cpp
Normal file → Executable file
17
drape_frontend/render_group.cpp
Normal file → Executable file
|
@ -55,9 +55,8 @@ bool RenderGroup::IsLess(RenderGroup const & other) const
|
|||
return m_state < other.m_state;
|
||||
}
|
||||
|
||||
RenderGroupComparator::RenderGroupComparator(TTilesCollection const & activeTiles)
|
||||
: m_activeTiles(activeTiles)
|
||||
, m_needGroupMergeOperation(false)
|
||||
RenderGroupComparator::RenderGroupComparator()
|
||||
: m_needGroupMergeOperation(false)
|
||||
, m_needBucketsMergeOperation(false)
|
||||
{
|
||||
}
|
||||
|
@ -68,13 +67,7 @@ void RenderGroupComparator::ResetInternalState()
|
|||
m_needGroupMergeOperation = false;
|
||||
}
|
||||
|
||||
bool RenderGroupComparator::NeedToDelete(TileKey const & key)
|
||||
{
|
||||
auto const & tileIt = m_activeTiles.find(key);
|
||||
return tileIt == m_activeTiles.end();
|
||||
}
|
||||
|
||||
bool RenderGroupComparator::operator()(RenderGroup const * l, RenderGroup const * r)
|
||||
bool RenderGroupComparator::operator()(unique_ptr<RenderGroup> const & l, unique_ptr<RenderGroup> const & r)
|
||||
{
|
||||
dp::GLState const & lState = l->GetState();
|
||||
dp::GLState const & rState = r->GetState();
|
||||
|
@ -82,10 +75,10 @@ bool RenderGroupComparator::operator()(RenderGroup const * l, RenderGroup const
|
|||
TileKey const & lKey = l->GetTileKey();
|
||||
TileKey const & rKey = r->GetTileKey();
|
||||
|
||||
if (!l->IsPendingOnDelete() && (l->IsEmpty() || NeedToDelete(lKey)))
|
||||
if (!l->IsPendingOnDelete() && l->IsEmpty())
|
||||
l->DeleteLater();
|
||||
|
||||
if (!r->IsPendingOnDelete() && (r->IsEmpty() || NeedToDelete(rKey)))
|
||||
if (!r->IsPendingOnDelete() && r->IsEmpty())
|
||||
r->DeleteLater();
|
||||
|
||||
bool lPendingOnDelete = l->IsPendingOnDelete();
|
||||
|
|
8
drape_frontend/render_group.hpp
Normal file → Executable file
8
drape_frontend/render_group.hpp
Normal file → Executable file
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "std/vector.hpp"
|
||||
#include "std/set.hpp"
|
||||
#include "std/unique_ptr.hpp"
|
||||
|
||||
class ScreenBase;
|
||||
namespace dp { class OverlayTree; }
|
||||
|
@ -61,18 +62,15 @@ private:
|
|||
class RenderGroupComparator
|
||||
{
|
||||
public:
|
||||
RenderGroupComparator(TTilesCollection const & activeTiles);
|
||||
RenderGroupComparator();
|
||||
|
||||
void ResetInternalState();
|
||||
|
||||
bool operator()(RenderGroup const * l, RenderGroup const * r);
|
||||
bool operator()(unique_ptr<RenderGroup> const & l, unique_ptr<RenderGroup> const & r);
|
||||
|
||||
private:
|
||||
TTilesCollection const & m_activeTiles;
|
||||
bool m_needGroupMergeOperation;
|
||||
bool m_needBucketsMergeOperation;
|
||||
|
||||
bool NeedToDelete(TileKey const & key);
|
||||
};
|
||||
|
||||
class UserMarkRenderGroup : public BaseRenderGroup
|
||||
|
|
18
drape_frontend/tile_key.cpp
Normal file → Executable file
18
drape_frontend/tile_key.cpp
Normal file → Executable file
|
@ -51,4 +51,22 @@ string DebugPrint(TileKey const & key)
|
|||
return out.str();
|
||||
}
|
||||
|
||||
string DebugPrint(TileStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case TileStatus::Unknown:
|
||||
return "Unknown";
|
||||
case TileStatus::Rendered:
|
||||
return "Rendered";
|
||||
case TileStatus::Requested:
|
||||
return "Requested";
|
||||
case TileStatus::Deferred:
|
||||
return "Deferred";
|
||||
default:
|
||||
ASSERT(false, ());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} //namespace df
|
||||
|
|
8
drape_frontend/tile_key.hpp
Normal file → Executable file
8
drape_frontend/tile_key.hpp
Normal file → Executable file
|
@ -5,12 +5,12 @@
|
|||
namespace df
|
||||
{
|
||||
|
||||
enum TileStatus
|
||||
enum class TileStatus
|
||||
{
|
||||
Unknown = 0,
|
||||
Rendered,
|
||||
Requested,
|
||||
Clipped
|
||||
Deferred
|
||||
};
|
||||
|
||||
struct TileKey
|
||||
|
@ -29,7 +29,9 @@ struct TileKey
|
|||
int m_zoomLevel;
|
||||
|
||||
private:
|
||||
friend string DebugPrint(TileKey const & );
|
||||
friend string DebugPrint(TileKey const & key);
|
||||
};
|
||||
|
||||
string DebugPrint(TileStatus status);
|
||||
|
||||
} // namespace df
|
||||
|
|
372
drape_frontend/tile_tree.cpp
Normal file
372
drape_frontend/tile_tree.cpp
Normal file
|
@ -0,0 +1,372 @@
|
|||
#include "tile_tree.hpp"
|
||||
|
||||
#include "../std/algorithm.hpp"
|
||||
#include "../std/utility.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
TileTree::TileTree()
|
||||
: m_root(new Node())
|
||||
{
|
||||
}
|
||||
|
||||
TileTree::~TileTree()
|
||||
{
|
||||
m_root.reset();
|
||||
}
|
||||
|
||||
void TileTree::Clear()
|
||||
{
|
||||
m_root.reset(new Node());
|
||||
}
|
||||
|
||||
void TileTree::BeginRequesting(int const zoomLevel)
|
||||
{
|
||||
AbortRequestedTiles(m_root, zoomLevel);
|
||||
}
|
||||
|
||||
void TileTree::RequestTile(TileKey const & tileKey)
|
||||
{
|
||||
InsertToNode(m_root, tileKey);
|
||||
}
|
||||
|
||||
void TileTree::EndRequesting()
|
||||
{
|
||||
SimplifyTree(nullptr);
|
||||
}
|
||||
|
||||
void TileTree::GetRequestedTiles(TTilesCollection & tiles)
|
||||
{
|
||||
FindRequestedTiles(m_root, tiles);
|
||||
}
|
||||
|
||||
bool TileTree::ContainsTileKey(TileKey const & tileKey)
|
||||
{
|
||||
return ContainsTileKey(m_root, tileKey);
|
||||
}
|
||||
|
||||
void TileTree::ClipByRect(m2::RectD const & rect, TTileHandler const & addTile,
|
||||
TTileHandler const & removeTile)
|
||||
{
|
||||
ClipNode(m_root, rect, removeTile);
|
||||
CheckDeferredTiles(m_root, addTile, removeTile);
|
||||
SimplifyTree(removeTile);
|
||||
}
|
||||
|
||||
bool TileTree::ProcessTile(TileKey const & tileKey, TTileHandler const & addTile,
|
||||
TTileHandler const & removeTile, TTileHandler const & deferTile)
|
||||
{
|
||||
bool const result = ProcessNode(m_root, tileKey, addTile, removeTile, deferTile);
|
||||
if (result)
|
||||
SimplifyTree(removeTile);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void TileTree::InsertToNode(TNodePtr const & node, TileKey const & tileKey)
|
||||
{
|
||||
// here we try to insert new tile to the node. The tree is built in such way that
|
||||
// child nodes always have got the same zoom level
|
||||
|
||||
// insert to empty node
|
||||
if (node->m_children.empty())
|
||||
{
|
||||
node->m_children.emplace_back(TNodePtr(new Node(tileKey, TileStatus::Requested)));
|
||||
return;
|
||||
}
|
||||
|
||||
int const childrenZoomLevel = node->m_children.front()->m_tileKey.m_zoomLevel;
|
||||
if (tileKey.m_zoomLevel > childrenZoomLevel)
|
||||
{
|
||||
// here zoom level of node's children less than new tile's zoom level
|
||||
// so we are looking for node to insert new tile recursively
|
||||
|
||||
// looking for parent node
|
||||
auto parentNodeIt = find_if(node->m_children.begin(), node->m_children.end(), [&tileKey](TNodePtr const & n)
|
||||
{
|
||||
return IsTileBelow(n->m_tileKey, tileKey);
|
||||
});
|
||||
|
||||
// insert to parent node
|
||||
if (parentNodeIt == node->m_children.end())
|
||||
{
|
||||
TileKey parentTileKey = GetParentTile(tileKey, childrenZoomLevel);
|
||||
node->m_children.emplace_back(TNodePtr(new Node(parentTileKey, TileStatus::Unknown)));
|
||||
InsertToNode(node->m_children.back(), tileKey);
|
||||
}
|
||||
else
|
||||
InsertToNode(*parentNodeIt, tileKey);
|
||||
}
|
||||
else if (tileKey.m_zoomLevel < childrenZoomLevel)
|
||||
{
|
||||
// here zoom level of node's children more than new tile's zoom level
|
||||
// so we paste new tile and redistribute children of current node
|
||||
// between new tile and his siblings
|
||||
|
||||
list<TNodePtr> newChildren;
|
||||
newChildren.emplace_back(new Node(tileKey, TileStatus::Requested));
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
// looking for parent node
|
||||
TileKey parentTileKey = GetParentTile((*it)->m_tileKey, tileKey.m_zoomLevel);
|
||||
auto parentNodeIt = find_if(newChildren.begin(), newChildren.end(), [&parentTileKey](TNodePtr const & n)
|
||||
{
|
||||
return n->m_tileKey == parentTileKey;
|
||||
});
|
||||
|
||||
// insert to parent node
|
||||
if (parentNodeIt == newChildren.end())
|
||||
{
|
||||
newChildren.emplace_back(TNodePtr(new Node(parentTileKey, TileStatus::Unknown)));
|
||||
newChildren.back()->m_children.emplace_back(move(*it));
|
||||
}
|
||||
else
|
||||
(*parentNodeIt)->m_children.emplace_back(move(*it));
|
||||
}
|
||||
node->m_children.swap(newChildren);
|
||||
}
|
||||
else
|
||||
{
|
||||
// here zoom level of node's children equals to new tile's zoom level
|
||||
// so we insert new tile if we haven't got one
|
||||
|
||||
auto it = find_if(node->m_children.begin(), node->m_children.end(), [&tileKey](TNodePtr const & n)
|
||||
{
|
||||
return n->m_tileKey == tileKey;
|
||||
});
|
||||
if (it != node->m_children.end())
|
||||
{
|
||||
if ((*it)->m_tileStatus == TileStatus::Unknown)
|
||||
{
|
||||
(*it)->m_tileStatus = TileStatus::Requested;
|
||||
(*it)->m_isRemoved = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
node->m_children.emplace_back(TNodePtr(new Node(tileKey, TileStatus::Requested)));
|
||||
}
|
||||
}
|
||||
|
||||
void TileTree::AbortRequestedTiles(TNodePtr const & node, int const zoomLevel)
|
||||
{
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
if ((*it)->m_tileStatus == TileStatus::Requested && (*it)->m_tileKey.m_zoomLevel != zoomLevel)
|
||||
(*it)->m_tileStatus = TileStatus::Unknown;
|
||||
|
||||
AbortRequestedTiles(*it, zoomLevel);
|
||||
}
|
||||
}
|
||||
|
||||
void TileTree::FindRequestedTiles(TNodePtr const & node, TTilesCollection & tiles)
|
||||
{
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
if ((*it)->m_tileStatus == TileStatus::Requested)
|
||||
tiles.insert((*it)->m_tileKey);
|
||||
|
||||
FindRequestedTiles(*it, tiles);
|
||||
}
|
||||
}
|
||||
|
||||
bool TileTree::ContainsTileKey(TNodePtr const & node, TileKey const & tileKey)
|
||||
{
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
if (tileKey == (*it)->m_tileKey)
|
||||
return (*it)->m_tileStatus != TileStatus::Unknown;
|
||||
else if (IsTileBelow((*it)->m_tileKey, tileKey))
|
||||
return ContainsTileKey(*it, tileKey);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TileTree::ClipNode(TNodePtr const & node, m2::RectD const & rect, TTileHandler const & removeTile)
|
||||
{
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end();)
|
||||
{
|
||||
m2::RectD const tileRect = (*it)->m_tileKey.GetGlobalRect();
|
||||
if(rect.IsIntersect(tileRect))
|
||||
{
|
||||
ClipNode(*it, rect, removeTile);
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveTile(*it, removeTile);
|
||||
ClipNode(*it, rect, removeTile);
|
||||
it = node->m_children.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileTree::RemoveTile(TNodePtr const & node, TTileHandler const & removeTile)
|
||||
{
|
||||
if (removeTile != nullptr && !node->m_isRemoved)
|
||||
removeTile(node->m_tileKey, node->m_tileStatus);
|
||||
|
||||
node->m_isRemoved = true;
|
||||
node->m_tileStatus = TileStatus::Unknown;
|
||||
}
|
||||
|
||||
bool TileTree::ProcessNode(TNodePtr const & node, TileKey const & tileKey,
|
||||
TTileHandler const & addTile, TTileHandler const & removeTile,
|
||||
TTileHandler const & deferTile)
|
||||
{
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
if (tileKey == (*it)->m_tileKey)
|
||||
{
|
||||
if ((*it)->m_tileStatus == TileStatus::Unknown)
|
||||
return false;
|
||||
|
||||
DeleteTilesBelow(*it, removeTile);
|
||||
|
||||
if (node->m_tileStatus == TileStatus::Rendered)
|
||||
{
|
||||
(*it)->m_tileStatus = TileStatus::Deferred;
|
||||
if (deferTile != nullptr)
|
||||
deferTile((*it)->m_tileKey, (*it)->m_tileStatus);
|
||||
(*it)->m_isRemoved = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*it)->m_tileStatus = TileStatus::Rendered;
|
||||
if (addTile != nullptr)
|
||||
addTile((*it)->m_tileKey, (*it)->m_tileStatus);
|
||||
(*it)->m_isRemoved = false;
|
||||
}
|
||||
|
||||
DeleteTilesAbove(node, addTile, removeTile);
|
||||
return true;
|
||||
}
|
||||
else if (IsTileBelow((*it)->m_tileKey, tileKey))
|
||||
return ProcessNode(*it, tileKey, addTile, removeTile, deferTile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TileTree::DeleteTilesBelow(TNodePtr const & node, TTileHandler const & removeTile)
|
||||
{
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
RemoveTile(*it, removeTile);
|
||||
DeleteTilesBelow(*it, removeTile);
|
||||
}
|
||||
node->m_children.clear();
|
||||
}
|
||||
|
||||
void TileTree::DeleteTilesAbove(TNodePtr const & node, TTileHandler const & addTile, TTileHandler const & removeTile)
|
||||
{
|
||||
if (node->m_tileStatus == TileStatus::Requested)
|
||||
return;
|
||||
|
||||
// check if all child tiles are ready
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
if ((*it)->m_tileStatus == TileStatus::Requested)
|
||||
return;
|
||||
|
||||
// add deferred tiles
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
if ((*it)->m_tileStatus == TileStatus::Deferred)
|
||||
{
|
||||
if (addTile != nullptr)
|
||||
addTile((*it)->m_tileKey, (*it)->m_tileStatus);
|
||||
|
||||
(*it)->m_tileStatus = TileStatus::Rendered;
|
||||
(*it)->m_isRemoved = false;
|
||||
}
|
||||
}
|
||||
|
||||
// remove current tile
|
||||
if (node != m_root)
|
||||
RemoveTile(node, removeTile);
|
||||
}
|
||||
|
||||
void TileTree::SimplifyTree(TTileHandler const & removeTile)
|
||||
{
|
||||
SimplifyTree(m_root, removeTile);
|
||||
ClearObsoleteTiles(m_root, removeTile);
|
||||
}
|
||||
|
||||
void TileTree::SimplifyTree(TNodePtr const & node, TTileHandler const & removeTile)
|
||||
{
|
||||
if (HaveChildrenSameStatus(node, TileStatus::Unknown))
|
||||
{
|
||||
// all children of children are rendered
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
if (!HaveChildrenSameStatus(*it, TileStatus::Rendered))
|
||||
return;
|
||||
|
||||
// move children to grandfather
|
||||
list<TNodePtr> newChildren;
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
RemoveTile(*it, removeTile);
|
||||
newChildren.splice(newChildren.begin(), (*it)->m_children);
|
||||
}
|
||||
|
||||
node->m_children.swap(newChildren);
|
||||
}
|
||||
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
SimplifyTree(*it, removeTile);
|
||||
}
|
||||
|
||||
bool TileTree::ClearObsoleteTiles(TNodePtr const & node, TTileHandler const & removeTile)
|
||||
{
|
||||
bool canClear = true;
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
canClear &= ClearObsoleteTiles(*it, removeTile);
|
||||
|
||||
if (canClear)
|
||||
{
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
RemoveTile(*it, removeTile);
|
||||
|
||||
node->m_children.clear();
|
||||
}
|
||||
|
||||
return canClear && node->m_tileStatus == TileStatus::Unknown;
|
||||
}
|
||||
|
||||
bool TileTree::HaveChildrenSameStatus(TNodePtr const & node, TileStatus tileStatus)
|
||||
{
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
if ((*it)->m_tileStatus != tileStatus)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TileTree::CheckDeferredTiles(TNodePtr const & node, TTileHandler const & addTile, TTileHandler const & removeTile)
|
||||
{
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
DeleteTilesAbove(node, addTile, removeTile);
|
||||
CheckDeferredTiles(*it, addTile, removeTile);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugPrintNode(TileTree::TNodePtr const & node, ostringstream & out, string const & offset)
|
||||
{
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
out << offset << "{ " << DebugPrint((*it)->m_tileKey) << ", "
|
||||
<< DebugPrint((*it)->m_tileStatus) << ((*it)->m_isRemoved ? ", removed" : "") << "}\n";
|
||||
DebugPrintNode(*it, out, offset + " ");
|
||||
}
|
||||
}
|
||||
|
||||
string DebugPrint(TileTree const & tileTree)
|
||||
{
|
||||
ostringstream out;
|
||||
out << "\n{\n";
|
||||
DebugPrintNode(tileTree.m_root, out, " ");
|
||||
out << "}\n";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
} // namespace df
|
88
drape_frontend/tile_tree.hpp
Normal file
88
drape_frontend/tile_tree.hpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
|
||||
#include "tile_utils.hpp"
|
||||
|
||||
#include "../geometry/rect2d.hpp"
|
||||
|
||||
#include "../std/function.hpp"
|
||||
#include "../std/list.hpp"
|
||||
#include "../std/sstream.hpp"
|
||||
#include "../std/unique_ptr.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
class TileTree
|
||||
{
|
||||
public:
|
||||
TileTree();
|
||||
~TileTree();
|
||||
|
||||
using TTileHandler = function<void(TileKey const &, TileStatus)>;
|
||||
|
||||
void BeginRequesting(int const zoomLevel);
|
||||
void RequestTile(TileKey const & tileKey);
|
||||
void EndRequesting();
|
||||
|
||||
bool ProcessTile(TileKey const & tileKey, TTileHandler const & addTile,
|
||||
TTileHandler const & removeTile, TTileHandler const & deferTile);
|
||||
void ClipByRect(m2::RectD const & rect, TTileHandler const & addTile,
|
||||
TTileHandler const & removeTile);
|
||||
void Clear();
|
||||
|
||||
bool ContainsTileKey(TileKey const & tileKey);
|
||||
void GetRequestedTiles(TTilesCollection & tiles);
|
||||
|
||||
private:
|
||||
struct Node;
|
||||
using TNodePtr = unique_ptr<Node>;
|
||||
|
||||
void InsertToNode(TNodePtr const & node, TileKey const & tileKey);
|
||||
void AbortRequestedTiles(TNodePtr const & node, int const zoomLevel);
|
||||
|
||||
void FindRequestedTiles(TNodePtr const & node, TTilesCollection & tiles);
|
||||
bool ContainsTileKey(TNodePtr const & node, TileKey const & tileKey);
|
||||
|
||||
void ClipNode(TNodePtr const & node, m2::RectD const & rect,
|
||||
TTileHandler const & removeTile);
|
||||
|
||||
void RemoveTile(TNodePtr const & node, TTileHandler const & removeTile);
|
||||
|
||||
bool ProcessNode(TNodePtr const & node, TileKey const & tileKey,
|
||||
TTileHandler const & addTile, TTileHandler const & removeTile,
|
||||
TTileHandler const & deferTile);
|
||||
|
||||
void DeleteTilesBelow(TNodePtr const & node, TTileHandler const & removeTile);
|
||||
void DeleteTilesAbove(TNodePtr const & node, TTileHandler const & addTile,
|
||||
TTileHandler const & removeTile);
|
||||
|
||||
void SimplifyTree(TTileHandler const & removeTile);
|
||||
void SimplifyTree(TNodePtr const & node, TTileHandler const & removeTile);
|
||||
bool ClearObsoleteTiles(TNodePtr const & node, TTileHandler const & removeTile);
|
||||
void CheckDeferredTiles(TNodePtr const & node, TTileHandler const & addTile,
|
||||
TTileHandler const & removeTile);
|
||||
|
||||
bool HaveChildrenSameStatus(TNodePtr const & node, TileStatus tileStatus);
|
||||
|
||||
private:
|
||||
struct Node
|
||||
{
|
||||
TileKey m_tileKey;
|
||||
list<TNodePtr> m_children;
|
||||
TileStatus m_tileStatus = TileStatus::Unknown;
|
||||
bool m_isRemoved = false;
|
||||
|
||||
Node() = default;
|
||||
Node(TileKey const & key, TileStatus status)
|
||||
: m_tileKey(key), m_tileStatus(status)
|
||||
{}
|
||||
};
|
||||
|
||||
TNodePtr m_root;
|
||||
|
||||
private:
|
||||
friend void DebugPrintNode(TileTree::TNodePtr const & node, ostringstream & out, string const & offset);
|
||||
friend string DebugPrint(TileTree const & tileTree);
|
||||
};
|
||||
|
||||
} // namespace df
|
17
drape_frontend/tile_utils.cpp
Normal file → Executable file
17
drape_frontend/tile_utils.cpp
Normal file → Executable file
|
@ -28,7 +28,7 @@ int Minificate(int coord, int zoom, int targetZoom)
|
|||
|
||||
} // namespace
|
||||
|
||||
void CalcTilesCoverage(TileKey const & tileKey, int targetZoom, set<TileKey> & tiles)
|
||||
void CalcTilesCoverage(TileKey const & tileKey, int targetZoom, TTilesCollection & tiles)
|
||||
{
|
||||
CalcTilesCoverage(tileKey, targetZoom, [&tiles](TileKey const & tileKey)
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ void CalcTilesCoverage(TileKey const & tileKey, int targetZoom, set<TileKey> & t
|
|||
});
|
||||
}
|
||||
|
||||
void CalcTilesCoverage(set<TileKey> const & tileKeys, int targetZoom, set<TileKey> & tiles)
|
||||
void CalcTilesCoverage(set<TileKey> const & tileKeys, int targetZoom, TTilesCollection & tiles)
|
||||
{
|
||||
for(TileKey const & tileKey : tileKeys)
|
||||
CalcTilesCoverage(tileKey, targetZoom, tiles);
|
||||
|
@ -51,9 +51,7 @@ void CalcTilesCoverage(TileKey const & tileKey, int targetZoom, function<void(Ti
|
|||
else if (tileKey.m_zoomLevel > targetZoom)
|
||||
{
|
||||
// minification
|
||||
processTile(TileKey(Minificate(tileKey.m_x, tileKey.m_zoomLevel, targetZoom),
|
||||
Minificate(tileKey.m_y, tileKey.m_zoomLevel, targetZoom),
|
||||
targetZoom));
|
||||
processTile(GetParentTile(tileKey, targetZoom));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -96,4 +94,13 @@ bool IsTileBelow(TileKey const & tileKey, TileKey const & targetTileKey)
|
|||
return targetTileKey.m_y >= startY && targetTileKey.m_y < startY + tilesInRow;
|
||||
}
|
||||
|
||||
TileKey GetParentTile(TileKey const & tileKey, int targetZoom)
|
||||
{
|
||||
ASSERT(tileKey.m_zoomLevel > targetZoom, ());
|
||||
|
||||
return TileKey(Minificate(tileKey.m_x, tileKey.m_zoomLevel, targetZoom),
|
||||
Minificate(tileKey.m_y, tileKey.m_zoomLevel, targetZoom),
|
||||
targetZoom);
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
|
|
10
drape_frontend/tile_utils.hpp
Normal file → Executable file
10
drape_frontend/tile_utils.hpp
Normal file → Executable file
|
@ -7,14 +7,13 @@
|
|||
namespace df
|
||||
{
|
||||
|
||||
using TTilesCollection = map<TileKey, TileStatus>;
|
||||
using TTilePair = pair<TileKey, TileStatus>;
|
||||
using TTilesCollection = set<TileKey>;
|
||||
|
||||
/// this function determines the coverage of a tile in specified zoom level
|
||||
void CalcTilesCoverage(TileKey const & tileKey, int targetZoom, set<TileKey> & tiles);
|
||||
void CalcTilesCoverage(TileKey const & tileKey, int targetZoom, TTilesCollection & tiles);
|
||||
|
||||
/// this function determines the coverage of tiles in specified zoom level
|
||||
void CalcTilesCoverage(set<TileKey> const & tileKeys, int targetZoom, set<TileKey> & tiles);
|
||||
void CalcTilesCoverage(set<TileKey> const & tileKeys, int targetZoom, TTilesCollection & tiles);
|
||||
|
||||
/// this function determines the coverage of a tile in specified zoom level. Each new tile can be processed
|
||||
/// in processTile callback
|
||||
|
@ -26,6 +25,9 @@ bool IsTileAbove(TileKey const & tileKey, TileKey const & targetTileKey);
|
|||
/// this function checks if targetTileKey is below tileKey
|
||||
bool IsTileBelow(TileKey const & tileKey, TileKey const & targetTileKey);
|
||||
|
||||
/// this function returns parent tile on specified zoom level
|
||||
TileKey GetParentTile(TileKey const & tileKey, int targetZoom);
|
||||
|
||||
} // namespace df
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue