forked from organicmaps/organicmaps-tmp
Removed tile tree and style zoom level
This commit is contained in:
parent
498a9f03e1
commit
f910ac00e7
16 changed files with 100 additions and 1602 deletions
|
@ -75,8 +75,6 @@ SOURCES += \
|
|||
threads_commutator.cpp \
|
||||
tile_info.cpp \
|
||||
tile_key.cpp \
|
||||
tile_tree.cpp \
|
||||
tile_tree_builder.cpp \
|
||||
tile_utils.cpp \
|
||||
transparent_layer.cpp \
|
||||
user_event_stream.cpp \
|
||||
|
@ -169,8 +167,6 @@ HEADERS += \
|
|||
threads_commutator.hpp \
|
||||
tile_info.hpp \
|
||||
tile_key.hpp \
|
||||
tile_tree.hpp \
|
||||
tile_tree_builder.hpp \
|
||||
tile_utils.hpp \
|
||||
transparent_layer.hpp \
|
||||
user_event_stream.hpp \
|
||||
|
|
|
@ -22,7 +22,5 @@ SOURCES += \
|
|||
memory_feature_index_tests.cpp \
|
||||
navigator_test.cpp \
|
||||
object_pool_tests.cpp \
|
||||
tile_tree_tests.cpp \
|
||||
tile_utils_tests.cpp \
|
||||
user_event_stream_tests.cpp \
|
||||
|
||||
|
|
|
@ -1,493 +0,0 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "drape_frontend/tile_tree_builder.hpp"
|
||||
|
||||
#include "drape/glstate.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class TileTreeTester
|
||||
{
|
||||
public:
|
||||
TileTreeTester()
|
||||
{
|
||||
m_tree = make_unique<df::TileTree>();
|
||||
}
|
||||
|
||||
void RequestTiles(int const tileScale, m2::RectD const & clipRect)
|
||||
{
|
||||
double const range = MercatorBounds::maxX - MercatorBounds::minX;
|
||||
double const rectSize = range / (1 << tileScale);
|
||||
int const minTileX = static_cast<int>(floor(clipRect.minX() / rectSize));
|
||||
int const maxTileX = static_cast<int>(ceil(clipRect.maxX() / rectSize));
|
||||
int const minTileY = static_cast<int>(floor(clipRect.minY() / rectSize));
|
||||
int const maxTileY = static_cast<int>(ceil(clipRect.maxY() / rectSize));
|
||||
|
||||
m_tree->BeginRequesting(tileScale, clipRect);
|
||||
for (int tileY = minTileY; tileY < maxTileY; ++tileY)
|
||||
{
|
||||
for (int tileX = minTileX; tileX < maxTileX; ++tileX)
|
||||
{
|
||||
df::TileKey key(tileX, tileY, tileScale);
|
||||
if (clipRect.IsIntersect(key.GetGlobalRect()))
|
||||
m_tree->RequestTile(key);
|
||||
}
|
||||
}
|
||||
m_tree->EndRequesting();
|
||||
}
|
||||
|
||||
void FlushTile(int const currentZoomLevel, df::TileKey const & tileKey)
|
||||
{
|
||||
m_tree->ProcessTile(tileKey, currentZoomLevel, dp::GLState(0, dp::GLState::DepthLayer::GeometryLayer), nullptr);
|
||||
}
|
||||
|
||||
void FinishTiles(int const currentZoomLevel, df::TTilesCollection const & tiles)
|
||||
{
|
||||
m_tree->FinishTiles(tiles, currentZoomLevel);
|
||||
}
|
||||
|
||||
unique_ptr<df::TileTree> const & GetTree()
|
||||
{
|
||||
return m_tree;
|
||||
}
|
||||
|
||||
private:
|
||||
unique_ptr<df::TileTree> m_tree;
|
||||
};
|
||||
|
||||
UNIT_TEST(TileTree_TilesRequesting)
|
||||
{
|
||||
using namespace df;
|
||||
|
||||
TileTreeBuilder builder;
|
||||
TileTreeComparer comparer;
|
||||
TileTreeTester treeTester;
|
||||
|
||||
treeTester.RequestTiles(4, m2::RectD(-20, -20, 20, 20));
|
||||
|
||||
unique_ptr<TileTree> result = builder.Build(Node(TileKey(-1, -1, 4), TileStatus::Requested)
|
||||
.Node(TileKey(0, -1, 4), TileStatus::Requested)
|
||||
.Node(TileKey(-1, 0, 4), TileStatus::Requested)
|
||||
.Node(TileKey(0, 0, 4), TileStatus::Requested));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
}
|
||||
|
||||
UNIT_TEST(TileTree_TilesFlushing)
|
||||
{
|
||||
using namespace df;
|
||||
|
||||
TileTreeBuilder builder;
|
||||
TileTreeComparer comparer;
|
||||
TileTreeTester treeTester;
|
||||
|
||||
treeTester.RequestTiles(4, m2::RectD(-20, -20, 20, 20));
|
||||
treeTester.FlushTile(4, TileKey(0, -1, 4));
|
||||
treeTester.FlushTile(4, TileKey(0, 0, 4));
|
||||
|
||||
unique_ptr<TileTree> result = builder.Build(Node(TileKey(-1, -1, 4), TileStatus::Requested)
|
||||
.Node(TileKey(0, -1, 4), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 0, 4), TileStatus::Requested)
|
||||
.Node(TileKey(0, 0, 4), TileStatus::Rendered));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
}
|
||||
|
||||
UNIT_TEST(TileTree_TilesFinishing)
|
||||
{
|
||||
using namespace df;
|
||||
|
||||
TileTreeBuilder builder;
|
||||
TileTreeComparer comparer;
|
||||
TileTreeTester treeTester;
|
||||
|
||||
treeTester.RequestTiles(4, m2::RectD(-20, -20, 20, 20));
|
||||
treeTester.FlushTile(4, TileKey(0, -1, 4));
|
||||
treeTester.FlushTile(4, TileKey(0, 0, 4));
|
||||
TTilesCollection tiles = { TileKey(-1, -1, 4), TileKey(-1, 0, 4) };
|
||||
treeTester.FinishTiles(4, tiles);
|
||||
|
||||
unique_ptr<TileTree> result = builder.Build(Node(TileKey(-1, -1, 4), TileStatus::Rendered)
|
||||
.Node(TileKey(0, -1, 4), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 0, 4), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 0, 4), TileStatus::Rendered));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
}
|
||||
|
||||
UNIT_TEST(TileTree_MapShifting)
|
||||
{
|
||||
using namespace df;
|
||||
|
||||
TileTreeBuilder builder;
|
||||
TileTreeComparer comparer;
|
||||
TileTreeTester treeTester;
|
||||
|
||||
treeTester.RequestTiles(4, m2::RectD(-20, -20, 20, 20));
|
||||
treeTester.FlushTile(4, TileKey(0, -1, 4));
|
||||
treeTester.FlushTile(4, TileKey(0, 0, 4));
|
||||
treeTester.RequestTiles(4, m2::RectD(-10, -20, 30, 20));
|
||||
|
||||
unique_ptr<TileTree> result = builder.Build(Node(TileKey(-1, -1, 4), TileStatus::Requested)
|
||||
.Node(TileKey(0, -1, 4), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 0, 4), TileStatus::Requested)
|
||||
.Node(TileKey(0, 0, 4), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -1, 4), TileStatus::Requested)
|
||||
.Node(TileKey(1, 0, 4), TileStatus::Requested));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
}
|
||||
|
||||
UNIT_TEST(TileTree_MapMagnification)
|
||||
{
|
||||
using namespace df;
|
||||
|
||||
TileTreeBuilder builder;
|
||||
TileTreeComparer comparer;
|
||||
TileTreeTester treeTester;
|
||||
|
||||
treeTester.RequestTiles(4, m2::RectD(-20, -20, 20, 20));
|
||||
treeTester.FlushTile(4, TileKey(0, -1, 4));
|
||||
treeTester.FlushTile(4, TileKey(0, 0, 4));
|
||||
treeTester.FlushTile(4, TileKey(-1, -1, 4));
|
||||
treeTester.FlushTile(4, TileKey(-1, 0, 4));
|
||||
treeTester.RequestTiles(5, m2::RectD(-20, -20, 20, 20));
|
||||
|
||||
unique_ptr<TileTree> result = builder.Build(Node(TileKey(-1, -1, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(-2, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(0, -1, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(0, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(0, -1, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, -1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(-1, 0, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(-2, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-2, 1, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, 1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(0, 0, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(0, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Requested)));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
|
||||
treeTester.FlushTile(5, TileKey(-1, -2, 5));
|
||||
treeTester.FlushTile(5, TileKey(-2, -1, 5));
|
||||
treeTester.FlushTile(5, TileKey(0, -1, 5));
|
||||
treeTester.FlushTile(5, TileKey(-2, 1, 5));
|
||||
treeTester.FlushTile(5, TileKey(1, 0, 5));
|
||||
treeTester.FlushTile(5, TileKey(0, 1, 5));
|
||||
|
||||
result = builder.Build(Node(TileKey(-1, -1, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(-2, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(0, -1, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(0, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(0, -1, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(1, -1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(-1, 0, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(-2, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-2, 1, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(-1, 1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(0, 0, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(0, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Requested)));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
|
||||
treeTester.FlushTile(5, TileKey(-2, -2, 5));
|
||||
treeTester.FlushTile(5, TileKey(-1, -1, 5));
|
||||
|
||||
result = builder.Build(Node(TileKey(-1, -1, 4),
|
||||
TileStatus::Unknown,
|
||||
true /* isRemoved */).Children(Node(TileKey(-2, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Rendered))
|
||||
.Node(TileKey(0, -1, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(0, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(0, -1, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(1, -1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(-1, 0, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(-2, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-2, 1, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(-1, 1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(0, 0, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(0, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Requested)));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
|
||||
treeTester.FlushTile(5, TileKey(0, -2, 5));
|
||||
|
||||
// a tile comes several times
|
||||
treeTester.FlushTile(5, TileKey(1, -2, 5));
|
||||
treeTester.FlushTile(5, TileKey(1, -2, 5));
|
||||
treeTester.FlushTile(5, TileKey(1, -2, 5));
|
||||
treeTester.FlushTile(5, TileKey(1, -2, 5));
|
||||
|
||||
result = builder.Build(Node(TileKey(-1, -1, 4),
|
||||
TileStatus::Unknown,
|
||||
true /* isRemoved */).Children(Node(TileKey(-2, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Rendered))
|
||||
.Node(TileKey(0, -1, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(0, -2, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(1, -2, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(0, -1, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(1, -1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(-1, 0, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(-2, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-2, 1, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(-1, 1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(0, 0, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(0, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Requested)));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
|
||||
treeTester.FlushTile(5, TileKey(1, -1, 5));
|
||||
treeTester.FlushTile(5, TileKey(-2, 0, 5));
|
||||
treeTester.FlushTile(5, TileKey(-1, 0, 5));
|
||||
treeTester.FlushTile(5, TileKey(-1, 1, 5));
|
||||
treeTester.FlushTile(5, TileKey(0, 0, 5));
|
||||
treeTester.FlushTile(5, TileKey(1, 1, 5));
|
||||
|
||||
result = builder.Build(Node(TileKey(-2, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Rendered));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
}
|
||||
|
||||
UNIT_TEST(TileTree_MapMinification)
|
||||
{
|
||||
using namespace df;
|
||||
|
||||
TileTreeBuilder builder;
|
||||
TileTreeComparer comparer;
|
||||
TileTreeTester treeTester;
|
||||
|
||||
treeTester.RequestTiles(5, m2::RectD(-20, -20, 20, 20));
|
||||
TTilesCollection tiles = { TileKey(-2, -2, 5), TileKey(-1, -2, 5), TileKey(-2, -1, 5), TileKey(-1, -1, 5),
|
||||
TileKey(0, -2, 5), TileKey(1, -2, 5), TileKey(0, -1, 5), TileKey(1, -1, 5),
|
||||
TileKey(-2, 0, 5), TileKey(-1, 0, 5), TileKey(-2, 1, 5), TileKey(-1, 1, 5),
|
||||
TileKey(0, 0, 5), TileKey(1, 0, 5), TileKey(0, 1, 5), TileKey(1, 1, 5) };
|
||||
treeTester.FinishTiles(5, tiles);
|
||||
|
||||
unique_ptr<TileTree> result = builder.Build(Node(TileKey(-2, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Rendered));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
|
||||
treeTester.RequestTiles(4, m2::RectD(-20, -20, 20, 20));
|
||||
|
||||
result = builder.Build(Node(TileKey(-1, -1, 4),
|
||||
TileStatus::Requested).Children(Node(TileKey(-2, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Rendered))
|
||||
.Node(TileKey(0, -1, 4),
|
||||
TileStatus::Requested).Children(Node(TileKey(0, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -1, 5), TileStatus::Rendered))
|
||||
.Node(TileKey(-1, 0, 4),
|
||||
TileStatus::Requested).Children(Node(TileKey(-2, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 1, 5), TileStatus::Rendered))
|
||||
.Node(TileKey(0, 0, 4),
|
||||
TileStatus::Requested).Children(Node(TileKey(0, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Rendered)));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
|
||||
treeTester.FlushTile(4, TileKey(0, -1, 4));
|
||||
treeTester.FlushTile(4, TileKey(-1, 0, 4));
|
||||
|
||||
result = builder.Build(Node(TileKey(-1, -1, 4),
|
||||
TileStatus::Requested).Children(Node(TileKey(-2, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Rendered))
|
||||
.Node(TileKey(0, -1, 4),
|
||||
TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 0, 4),
|
||||
TileStatus::Rendered)
|
||||
.Node(TileKey(0, 0, 4),
|
||||
TileStatus::Requested).Children(Node(TileKey(0, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Rendered)));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
|
||||
treeTester.FlushTile(4, TileKey(-1, -1, 4));
|
||||
treeTester.FlushTile(4, TileKey(0, 0, 4));
|
||||
|
||||
result = builder.Build(Node(TileKey(-1, -1, 4), TileStatus::Rendered)
|
||||
.Node(TileKey(0, -1, 4), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 0, 4), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 0, 4), TileStatus::Rendered));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
}
|
||||
|
||||
UNIT_TEST(TileTree_MapMagMin)
|
||||
{
|
||||
using namespace df;
|
||||
|
||||
TileTreeBuilder builder;
|
||||
TileTreeComparer comparer;
|
||||
TileTreeTester treeTester;
|
||||
|
||||
treeTester.RequestTiles(5, m2::RectD(-20, -20, 20, 20));
|
||||
TTilesCollection tiles = { TileKey(-2, -2, 5), TileKey(-1, -2, 5), TileKey(-2, -1, 5), TileKey(-1, -1, 5),
|
||||
TileKey(0, -2, 5), TileKey(1, -2, 5), TileKey(0, -1, 5), TileKey(1, -1, 5),
|
||||
TileKey(-2, -0, 5), TileKey(-1, 0, 5), TileKey(-2, 1, 5), TileKey(-1, 1, 5),
|
||||
TileKey(0, 0, 5), TileKey(1, 0, 5), TileKey(0, 1, 5), TileKey(1, 1, 5) };
|
||||
treeTester.FinishTiles(5, tiles);
|
||||
treeTester.RequestTiles(4, m2::RectD(-20, -20, 20, 20));
|
||||
treeTester.FlushTile(4, TileKey(0, -1, 4));
|
||||
treeTester.FlushTile(4, TileKey(-1, 0, 4));
|
||||
// Zoom in 5th level again
|
||||
treeTester.RequestTiles(5, m2::RectD(-20, -20, 20, 20));
|
||||
|
||||
unique_ptr<TileTree> result = builder.Build(Node(TileKey(-1, -1, 4),
|
||||
TileStatus::Unknown).Children(Node(TileKey(-2, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Rendered))
|
||||
.Node(TileKey(0, -1, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(0, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, -2, 5), TileStatus::Requested)
|
||||
.Node(TileKey(0, -1, 5), TileStatus::Requested)
|
||||
.Node(TileKey(1, -1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(-1, 0, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(-2, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-2, 1, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, 1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(0, 0, 4),
|
||||
TileStatus::Unknown).Children(Node(TileKey(0, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Rendered)));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
|
||||
// current zoom level = 5, but tile (-1, -1, 4) is requested to flush
|
||||
treeTester.FlushTile(5, TileKey(-1, -1, 4));
|
||||
// the tree must be the same
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
|
||||
treeTester.FlushTile(5, TileKey(0, -2, 5));
|
||||
treeTester.FlushTile(5, TileKey(1, -2, 5));
|
||||
treeTester.FlushTile(5, TileKey(0, -1, 5));
|
||||
treeTester.FlushTile(5, TileKey(1, -1, 5));
|
||||
treeTester.FlushTile(5, TileKey(-1, 0, 5));
|
||||
|
||||
result = builder.Build(Node(TileKey(-1, -1, 4),
|
||||
TileStatus::Unknown).Children(Node(TileKey(-2, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Rendered))
|
||||
.Node(TileKey(0, -1, 4),
|
||||
TileStatus::Unknown,
|
||||
true /* isRemoved */).Children(Node(TileKey(0, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -1, 5), TileStatus::Rendered))
|
||||
.Node(TileKey(-1, 0, 4),
|
||||
TileStatus::Rendered).Children(Node(TileKey(-2, 0, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, 0, 5), TileStatus::Deferred)
|
||||
.Node(TileKey(-2, 1, 5), TileStatus::Requested)
|
||||
.Node(TileKey(-1, 1, 5), TileStatus::Requested))
|
||||
.Node(TileKey(0, 0, 4),
|
||||
TileStatus::Unknown).Children(Node(TileKey(0, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Rendered)));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
|
||||
treeTester.FlushTile(5, TileKey(-2, 0, 5));
|
||||
treeTester.FlushTile(5, TileKey(-2, 1, 5));
|
||||
treeTester.FlushTile(5, TileKey(-1, 1, 5));
|
||||
|
||||
result = builder.Build(Node(TileKey(-2, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -2, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, -1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-2, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(-1, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 0, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(0, 1, 5), TileStatus::Rendered)
|
||||
.Node(TileKey(1, 1, 5), TileStatus::Rendered));
|
||||
|
||||
TEST(comparer.IsEqual(treeTester.GetTree(), result), ("Tree = ", treeTester.GetTree(), "Result = ", result));
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
#include "testing/testing.hpp"
|
||||
|
||||
#include "drape_frontend/tile_utils.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
UNIT_TEST(TileUtils_EqualityTest)
|
||||
{
|
||||
df::TileKey key(1 /* x */, 2 /* y */, 2 /* zoom level */);
|
||||
set<df::TileKey> output;
|
||||
df::CalcTilesCoverage(key, 2 /* targetZoom */, output);
|
||||
|
||||
TEST_EQUAL(output.size(), 1, ());
|
||||
TEST_EQUAL(*output.begin(), key, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(TileUtils_MinificationTest)
|
||||
{
|
||||
df::TileKey key(500 /* x */, 300 /* y */, 12 /* zoom level */);
|
||||
set<df::TileKey> output;
|
||||
df::CalcTilesCoverage(key, 11 /* targetZoom */, output);
|
||||
TEST_EQUAL(output.size(), 1, ());
|
||||
TEST_EQUAL(*output.begin(), df::TileKey(250, 150, 11), ());
|
||||
|
||||
df::TileKey key2(-351 /* x */, 300 /* y */, 12 /* zoom level */);
|
||||
set<df::TileKey> output2;
|
||||
df::CalcTilesCoverage(key2, 10 /* targetZoom */, output2);
|
||||
TEST_EQUAL(output2.size(), 1, ());
|
||||
TEST_EQUAL(*output2.begin(), df::TileKey(-88, 75, 10), ());
|
||||
|
||||
set<df::TileKey> tileKeys =
|
||||
{
|
||||
df::TileKey(-351 /* x */, 300 /* y */, 12 /* zoom level */),
|
||||
df::TileKey(-350 /* x */, 300 /* y */, 12 /* zoom level */)
|
||||
};
|
||||
set<df::TileKey> output3;
|
||||
df::CalcTilesCoverage(tileKeys, 10 /* targetZoom */, output3);
|
||||
TEST_EQUAL(output3.size(), 1, ());
|
||||
TEST_EQUAL(*output3.begin(), df::TileKey(-88, 75, 10), ());
|
||||
|
||||
TEST_EQUAL(df::IsTileAbove(key, df::TileKey(250, 150, 11)), true, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(TileUtils_MagnificationTest)
|
||||
{
|
||||
df::TileKey key(1 /* x */, 2 /* y */, 2 /* zoom level */);
|
||||
set<df::TileKey> output;
|
||||
df::CalcTilesCoverage(key, 4 /* targetZoom */, output);
|
||||
|
||||
set<df::TileKey> expectedResult =
|
||||
{
|
||||
df::TileKey(4, 8, 4), df::TileKey(5, 8, 4), df::TileKey(6, 8, 4), df::TileKey(7, 8, 4),
|
||||
df::TileKey(4, 9, 4), df::TileKey(5, 9, 4), df::TileKey(6, 9, 4), df::TileKey(7, 9, 4),
|
||||
df::TileKey(4, 10, 4), df::TileKey(5, 10, 4), df::TileKey(6, 10, 4), df::TileKey(7, 10, 4),
|
||||
df::TileKey(4, 11, 4), df::TileKey(5, 11, 4), df::TileKey(6, 11, 4), df::TileKey(7, 11, 4)
|
||||
};
|
||||
|
||||
TEST_EQUAL(output, expectedResult, ());
|
||||
|
||||
df::TileKey key2(-1 /* x */, -2 /* y */, 2 /* zoom level */);
|
||||
set<df::TileKey> output2;
|
||||
df::CalcTilesCoverage(key2, 4 /* targetZoom */, output2);
|
||||
|
||||
set<df::TileKey> expectedResult2 =
|
||||
{
|
||||
df::TileKey(-4, -8, 4), df::TileKey(-3, -8, 4), df::TileKey(-2, -8, 4), df::TileKey(-1, -8, 4),
|
||||
df::TileKey(-4, -7, 4), df::TileKey(-3, -7, 4), df::TileKey(-2, -7, 4), df::TileKey(-1, -7, 4),
|
||||
df::TileKey(-4, -6, 4), df::TileKey(-3, -6, 4), df::TileKey(-2, -6, 4), df::TileKey(-1, -6, 4),
|
||||
df::TileKey(-4, -5, 4), df::TileKey(-3, -5, 4), df::TileKey(-2, -5, 4), df::TileKey(-1, -5, 4)
|
||||
};
|
||||
|
||||
TEST_EQUAL(output2, expectedResult2, ());
|
||||
|
||||
for (df::TileKey const & k : expectedResult)
|
||||
TEST_EQUAL(df::IsTileBelow(key, k), true, ());
|
||||
}
|
||||
|
||||
}
|
|
@ -74,7 +74,9 @@ bool RemoveGroups(ToDo & filter, vector<drape_ptr<RenderGroup>> & groups)
|
|||
--count;
|
||||
}
|
||||
else
|
||||
{
|
||||
++current;
|
||||
}
|
||||
}
|
||||
|
||||
return startCount != count;
|
||||
|
@ -167,7 +169,6 @@ FrontendRenderer::FrontendRenderer(Params const & params)
|
|||
, m_modelViewChangedFn(params.m_modelViewChangedFn)
|
||||
, m_tapEventInfoFn(params.m_tapEventFn)
|
||||
, m_userPositionChangedFn(params.m_positionChangedFn)
|
||||
, m_tileTree(new TileTree())
|
||||
, m_requestedTiles(params.m_requestedTiles)
|
||||
, m_maxGeneration(0)
|
||||
{
|
||||
|
@ -253,7 +254,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
|
|||
if (!IsUserMarkLayer(key))
|
||||
{
|
||||
if (CheckTileGenerations(key))
|
||||
m_tileTree->ProcessTile(key, GetCurrentZoomLevelForData(), state, move(bucket));
|
||||
AddToRenderGroup(state, move(bucket), key);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -269,7 +270,6 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
|
|||
case Message::FlushOverlays:
|
||||
{
|
||||
ref_ptr<FlushOverlaysMessage> msg = message;
|
||||
int const zoom = GetCurrentZoomLevelForData();
|
||||
TOverlaysRenderData renderData = msg->AcceptRenderData();
|
||||
for (auto & overlayRenderData : renderData)
|
||||
{
|
||||
|
@ -277,8 +277,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
|
|||
if (CheckTileGenerations(overlayRenderData.m_tileKey))
|
||||
{
|
||||
PrepareBucket(overlayRenderData.m_state, overlayRenderData.m_bucket);
|
||||
m_tileTree->ProcessTile(overlayRenderData.m_tileKey, zoom,
|
||||
overlayRenderData.m_state, move(overlayRenderData.m_bucket));
|
||||
AddToRenderGroup(overlayRenderData.m_state, move(overlayRenderData.m_bucket), overlayRenderData.m_tileKey);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -297,7 +296,6 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
|
|||
m_notFinishedTiles.erase(it);
|
||||
}
|
||||
}
|
||||
m_tileTree->FinishTiles(msg->GetTiles(), GetCurrentZoomLevelForData());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -544,14 +542,10 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
|
|||
|
||||
case Message::UpdateMapStyle:
|
||||
{
|
||||
// Clear tile tree.
|
||||
m_tileTree->Invalidate();
|
||||
|
||||
// Clear all graphics.
|
||||
for (RenderLayer & layer : m_layers)
|
||||
{
|
||||
layer.m_renderGroups.clear();
|
||||
layer.m_deferredRenderGroups.clear();
|
||||
layer.m_isDirty = false;
|
||||
}
|
||||
|
||||
|
@ -727,18 +721,16 @@ void FrontendRenderer::InvalidateRect(m2::RectD const & gRect)
|
|||
m2::RectD rect = gRect;
|
||||
if (rect.Intersect(screen.ClipRect()))
|
||||
{
|
||||
m_tileTree->Invalidate();
|
||||
ResolveTileKeys(rect, tiles);
|
||||
|
||||
auto eraseFunction = [&tiles](drape_ptr<RenderGroup> && group)
|
||||
{
|
||||
return tiles.count(group->GetTileKey()) == 0;
|
||||
return tiles.count(group->GetTileKey()) == 0;
|
||||
};
|
||||
|
||||
for (RenderLayer & layer : m_layers)
|
||||
{
|
||||
RemoveGroups(eraseFunction, layer.m_renderGroups);
|
||||
RemoveGroups(eraseFunction, layer.m_deferredRenderGroups);
|
||||
layer.m_isDirty = true;
|
||||
}
|
||||
|
||||
|
@ -770,55 +762,24 @@ void FrontendRenderer::OnResize(ScreenBase const & screen)
|
|||
m_framebuffer->SetSize(viewportRect.SizeX(), viewportRect.SizeY());
|
||||
}
|
||||
|
||||
void FrontendRenderer::AddToRenderGroup(vector<drape_ptr<RenderGroup>> & groups,
|
||||
dp::GLState const & state,
|
||||
void FrontendRenderer::AddToRenderGroup(dp::GLState const & state,
|
||||
drape_ptr<dp::RenderBucket> && renderBucket,
|
||||
TileKey const & newTile)
|
||||
{
|
||||
RenderLayer::RenderLayerID id = RenderLayer::GetLayerID(state);
|
||||
RenderLayer & layer = m_layers[id];
|
||||
|
||||
drape_ptr<RenderGroup> group = make_unique_dp<RenderGroup>(state, newTile);
|
||||
ref_ptr<dp::GpuProgram> program = m_gpuProgramManager->GetProgram(state.GetProgramIndex());
|
||||
ref_ptr<dp::GpuProgram> program3d = m_gpuProgramManager->GetProgram(state.GetProgram3dIndex());
|
||||
|
||||
group->SetRenderParams(program, program3d, make_ref(&m_generalUniforms));
|
||||
group->AddBucket(move(renderBucket));
|
||||
groups.push_back(move(group));
|
||||
}
|
||||
|
||||
void FrontendRenderer::OnAddRenderGroup(TileKey const & tileKey, dp::GLState const & state,
|
||||
drape_ptr<dp::RenderBucket> && renderBucket)
|
||||
{
|
||||
RenderLayer::RenderLayerID id = RenderLayer::GetLayerID(state);
|
||||
RenderLayer & layer = m_layers[id];
|
||||
AddToRenderGroup(layer.m_renderGroups, state, move(renderBucket), tileKey);
|
||||
layer.m_renderGroups.push_back(move(group));
|
||||
layer.m_renderGroups.back()->Appear();
|
||||
layer.m_isDirty = true;
|
||||
}
|
||||
|
||||
void FrontendRenderer::OnDeferRenderGroup(TileKey const & tileKey, dp::GLState const & state,
|
||||
drape_ptr<dp::RenderBucket> && renderBucket)
|
||||
{
|
||||
RenderLayer::RenderLayerID id = RenderLayer::GetLayerID(state);
|
||||
AddToRenderGroup(m_layers[id].m_deferredRenderGroups, state, move(renderBucket), tileKey);
|
||||
}
|
||||
|
||||
void FrontendRenderer::OnActivateTile(TileKey const & tileKey)
|
||||
{
|
||||
for (RenderLayer & layer : m_layers)
|
||||
{
|
||||
MoveTileFunctor<ActivateTilePredicate> f(ActivateTilePredicate(tileKey), layer.m_renderGroups);
|
||||
layer.m_isDirty |= RemoveGroups(f, layer.m_deferredRenderGroups);
|
||||
}
|
||||
}
|
||||
|
||||
void FrontendRenderer::OnRemoveTile(TileKey const & tileKey)
|
||||
{
|
||||
auto removePredicate = [&tileKey](drape_ptr<RenderGroup> const & group)
|
||||
{
|
||||
return group->GetTileKey() == tileKey;
|
||||
};
|
||||
RemoveRenderGroups(removePredicate);
|
||||
}
|
||||
|
||||
void FrontendRenderer::RemoveRenderGroups(TRenderGroupRemovePredicate const & predicate)
|
||||
{
|
||||
ASSERT(predicate != nullptr, ());
|
||||
|
@ -828,7 +789,6 @@ void FrontendRenderer::RemoveRenderGroups(TRenderGroupRemovePredicate const & pr
|
|||
{
|
||||
RemoveTilePredicate f(predicate);
|
||||
RemoveGroups(f, layer.m_renderGroups);
|
||||
RemoveGroups(predicate, layer.m_deferredRenderGroups);
|
||||
layer.m_isDirty |= f.m_deletionMark;
|
||||
}
|
||||
}
|
||||
|
@ -993,7 +953,7 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView)
|
|||
GLFunctions::glClearDepth();
|
||||
RenderOverlayLayer(modelView);
|
||||
|
||||
m_gpsTrackRenderer->RenderTrack(modelView, GetCurrentZoomLevel(),
|
||||
m_gpsTrackRenderer->RenderTrack(modelView, m_currentZoomLevel,
|
||||
make_ref(m_gpuProgramManager), m_generalUniforms);
|
||||
|
||||
GLFunctions::glDisable(gl_const::GLDepthTest);
|
||||
|
@ -1197,17 +1157,6 @@ void FrontendRenderer::RefreshBgColor()
|
|||
GLFunctions::glClearColor(c.GetRedF(), c.GetGreenF(), c.GetBlueF(), 1.0f);
|
||||
}
|
||||
|
||||
int FrontendRenderer::GetCurrentZoomLevel() const
|
||||
{
|
||||
return m_currentZoomLevel;
|
||||
}
|
||||
|
||||
int FrontendRenderer::GetCurrentZoomLevelForData() const
|
||||
{
|
||||
int const upperScale = scales::GetUpperScale();
|
||||
return (m_currentZoomLevel <= upperScale ? m_currentZoomLevel : upperScale);
|
||||
}
|
||||
|
||||
void FrontendRenderer::DisablePerspective()
|
||||
{
|
||||
m_perspectiveDiscarded = false;
|
||||
|
@ -1361,36 +1310,37 @@ void FrontendRenderer::ResolveTileKeys(ScreenBase const & screen, TTilesCollecti
|
|||
|
||||
void FrontendRenderer::ResolveTileKeys(m2::RectD const & rect, TTilesCollection & tiles)
|
||||
{
|
||||
// equal for x and y
|
||||
int const zoomLevel = GetCurrentZoomLevelForData();
|
||||
|
||||
double const range = MercatorBounds::maxX - MercatorBounds::minX;
|
||||
double const rectSize = range / (1 << zoomLevel);
|
||||
|
||||
int const minTileX = static_cast<int>(floor(rect.minX() / rectSize));
|
||||
int const maxTileX = static_cast<int>(ceil(rect.maxX() / rectSize));
|
||||
int const minTileY = static_cast<int>(floor(rect.minY() / rectSize));
|
||||
int const maxTileY = static_cast<int>(ceil(rect.maxY() / rectSize));
|
||||
int const dataZoomLevel = ClipTileZoomByMaxDataZoom(m_currentZoomLevel);
|
||||
|
||||
m_notFinishedTiles.clear();
|
||||
|
||||
// request new tiles
|
||||
m_tileTree->BeginRequesting(zoomLevel, rect);
|
||||
for (int tileY = minTileY; tileY < maxTileY; ++tileY)
|
||||
// Request new tiles.
|
||||
buffer_vector<TileKey, 8> tilesToDelete;
|
||||
CoverageResult result = CalcTilesCoverage(rect, dataZoomLevel,
|
||||
[this, &rect, &tiles, &tilesToDelete](int tileX, int tileY)
|
||||
{
|
||||
for (int tileX = minTileX; tileX < maxTileX; ++tileX)
|
||||
TileKey key(tileX, tileY, m_currentZoomLevel);
|
||||
if (rect.IsIntersect(key.GetGlobalRect()))
|
||||
{
|
||||
TileKey key(tileX, tileY, zoomLevel);
|
||||
if (rect.IsIntersect(key.GetGlobalRect()))
|
||||
{
|
||||
key.m_styleZoomLevel = GetCurrentZoomLevel();
|
||||
tiles.insert(key);
|
||||
m_notFinishedTiles.insert(key);
|
||||
m_tileTree->RequestTile(key);
|
||||
}
|
||||
tiles.insert(key);
|
||||
m_notFinishedTiles.insert(key);
|
||||
}
|
||||
}
|
||||
m_tileTree->EndRequesting();
|
||||
else
|
||||
{
|
||||
tilesToDelete.push_back(key);
|
||||
}
|
||||
});
|
||||
|
||||
// Remove old tiles.
|
||||
auto removePredicate = [this, &result, &tilesToDelete](drape_ptr<RenderGroup> const & group)
|
||||
{
|
||||
TileKey const & key = group->GetTileKey();
|
||||
return key.m_zoomLevel != m_currentZoomLevel ||
|
||||
key.m_x < result.m_minTileX || key.m_x > result.m_maxTileX ||
|
||||
key.m_y < result.m_minTileY || key.m_y > result.m_maxTileY ||
|
||||
find(tilesToDelete.begin(), tilesToDelete.end(), key) != tilesToDelete.end();
|
||||
};
|
||||
RemoveRenderGroups(removePredicate);
|
||||
}
|
||||
|
||||
FrontendRenderer::Routine::Routine(FrontendRenderer & renderer) : m_renderer(renderer) {}
|
||||
|
@ -1401,11 +1351,6 @@ void FrontendRenderer::Routine::Do()
|
|||
m_renderer.m_myPositionController->SetListener(ref_ptr<MyPositionController::Listener>(&m_renderer));
|
||||
m_renderer.m_userEventStream.SetListener(ref_ptr<UserEventStream::Listener>(&m_renderer));
|
||||
|
||||
m_renderer.m_tileTree->SetHandlers(bind(&FrontendRenderer::OnAddRenderGroup, &m_renderer, _1, _2, _3),
|
||||
bind(&FrontendRenderer::OnDeferRenderGroup, &m_renderer, _1, _2, _3),
|
||||
bind(&FrontendRenderer::OnActivateTile, &m_renderer, _1),
|
||||
bind(&FrontendRenderer::OnRemoveTile, &m_renderer, _1));
|
||||
|
||||
dp::OGLContext * context = m_renderer.m_contextFactory->getDrawContext();
|
||||
context->makeCurrent();
|
||||
m_renderer.m_framebuffer->SetDefaultContext(context);
|
||||
|
@ -1517,12 +1462,9 @@ void FrontendRenderer::Routine::Do()
|
|||
|
||||
void FrontendRenderer::ReleaseResources()
|
||||
{
|
||||
m_tileTree.reset();
|
||||
for (RenderLayer & layer : m_layers)
|
||||
{
|
||||
layer.m_renderGroups.clear();
|
||||
layer.m_deferredRenderGroups.clear();
|
||||
}
|
||||
|
||||
m_userMarkRenderGroups.clear();
|
||||
m_guiRenderer.reset();
|
||||
m_myPositionController.reset();
|
||||
|
@ -1594,13 +1536,11 @@ void FrontendRenderer::UpdateScene(ScreenBase const & modelView)
|
|||
|
||||
auto removePredicate = [this](drape_ptr<RenderGroup> const & group)
|
||||
{
|
||||
return group->IsOverlay() && group->GetTileKey().m_styleZoomLevel > GetCurrentZoomLevel();
|
||||
return group->IsOverlay() && group->GetTileKey().m_zoomLevel > m_currentZoomLevel;
|
||||
};
|
||||
for (RenderLayer & layer : m_layers)
|
||||
{
|
||||
layer.m_isDirty |= RemoveGroups(removePredicate, layer.m_deferredRenderGroups);
|
||||
layer.m_isDirty |= RemoveGroups(removePredicate, layer.m_renderGroups);
|
||||
}
|
||||
|
||||
m_overlayTree->ForceUpdate();
|
||||
|
||||
if (m_lastReadModelView != modelView)
|
||||
|
@ -1640,7 +1580,9 @@ void FrontendRenderer::RenderLayer::Sort()
|
|||
m_isDirty = comparator.m_pendingOnDeleteFound;
|
||||
|
||||
while (!m_renderGroups.empty() && m_renderGroups.back()->CanBeDeleted())
|
||||
{
|
||||
m_renderGroups.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "drape_frontend/route_renderer.hpp"
|
||||
#include "drape_frontend/threads_commutator.hpp"
|
||||
#include "drape_frontend/tile_info.hpp"
|
||||
#include "drape_frontend/tile_tree.hpp"
|
||||
#include "drape_frontend/user_event_stream.hpp"
|
||||
|
||||
#include "drape/pointers.hpp"
|
||||
|
@ -163,8 +162,6 @@ private:
|
|||
|
||||
void ResolveTileKeys(ScreenBase const & screen, TTilesCollection & tiles);
|
||||
void ResolveTileKeys(m2::RectD const & rect, TTilesCollection & tiles);
|
||||
int GetCurrentZoomLevel() const;
|
||||
int GetCurrentZoomLevelForData() const;
|
||||
void ResolveZoomLevel(ScreenBase const & screen);
|
||||
void CheckPerspectiveMinScale();
|
||||
void CheckIsometryMinScale(ScreenBase const & screen);
|
||||
|
@ -205,17 +202,9 @@ private:
|
|||
void UpdateOverlayTree(ScreenBase const & modelView, drape_ptr<RenderGroup> & renderGroup);
|
||||
void EndUpdateOverlayTree();
|
||||
|
||||
void AddToRenderGroup(vector<drape_ptr<RenderGroup>> & groups,
|
||||
dp::GLState const & state,
|
||||
void AddToRenderGroup(dp::GLState const & state,
|
||||
drape_ptr<dp::RenderBucket> && renderBucket,
|
||||
TileKey const & newTile);
|
||||
void OnAddRenderGroup(TileKey const & tileKey, dp::GLState const & state,
|
||||
drape_ptr<dp::RenderBucket> && renderBucket);
|
||||
void OnDeferRenderGroup(TileKey const & tileKey, dp::GLState const & state,
|
||||
drape_ptr<dp::RenderBucket> && renderBucket);
|
||||
|
||||
void OnActivateTile(TileKey const & tileKey);
|
||||
void OnRemoveTile(TileKey const & tileKey);
|
||||
|
||||
using TRenderGroupRemovePredicate = function<bool(drape_ptr<RenderGroup> const &)>;
|
||||
void RemoveRenderGroups(TRenderGroupRemovePredicate const & predicate);
|
||||
|
@ -250,7 +239,6 @@ private:
|
|||
static RenderLayerID GetLayerID(dp::GLState const & renderGroup);
|
||||
|
||||
vector<drape_ptr<RenderGroup>> m_renderGroups;
|
||||
vector<drape_ptr<RenderGroup>> m_deferredRenderGroups;
|
||||
bool m_isDirty = false;
|
||||
|
||||
inline void Sort();
|
||||
|
@ -286,7 +274,6 @@ private:
|
|||
ScreenBase m_lastReadModelView;
|
||||
TTilesCollection m_notFinishedTiles;
|
||||
|
||||
unique_ptr<TileTree> m_tileTree;
|
||||
int m_currentZoomLevel = -1;
|
||||
|
||||
bool m_perspectiveDiscarded = false;
|
||||
|
|
|
@ -47,7 +47,7 @@ RuleDrawer::RuleDrawer(TDrawerCallback const & fn,
|
|||
m_globalRect = m_context->GetTileKey().GetGlobalRect();
|
||||
|
||||
int32_t tileSize = df::VisualParams::Instance().GetTileSize();
|
||||
m2::RectD const r = m_context->GetTileKey().GetGlobalRect(true /* considerStyleZoom */);
|
||||
m2::RectD const r = m_context->GetTileKey().GetGlobalRect(false /* clipByDataMaxZoom */);
|
||||
ScreenBase geometryConvertor;
|
||||
geometryConvertor.OnSize(0, 0, tileSize, tileSize);
|
||||
geometryConvertor.SetFromRect(m2::AnyRectD(r));
|
||||
|
|
|
@ -100,7 +100,7 @@ void TileInfo::ProcessID(FeatureID const & id)
|
|||
void TileInfo::InitStylist(FeatureType const & f, Stylist & s)
|
||||
{
|
||||
CheckCanceled();
|
||||
df::InitStylist(f, m_context->GetTileKey().m_styleZoomLevel, m_is3dBuildings, s);
|
||||
df::InitStylist(f, m_context->GetTileKey().m_zoomLevel, m_is3dBuildings, s);
|
||||
}
|
||||
|
||||
bool TileInfo::DoNeedReadIndex() const
|
||||
|
@ -116,8 +116,7 @@ void TileInfo::CheckCanceled() const
|
|||
|
||||
int TileInfo::GetZoomLevel() const
|
||||
{
|
||||
ASSERT_LESS_OR_EQUAL(m_context->GetTileKey().m_zoomLevel, scales::GetUpperScale(), ());
|
||||
return m_context->GetTileKey().m_zoomLevel;
|
||||
return ClipTileZoomByMaxDataZoom(m_context->GetTileKey().m_zoomLevel);
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include "drape_frontend/tile_key.hpp"
|
||||
#include "drape_frontend/tile_utils.hpp"
|
||||
|
||||
#include "indexer/scales.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
|
@ -8,21 +11,18 @@ namespace df
|
|||
TileKey::TileKey()
|
||||
: m_x(-1), m_y(-1),
|
||||
m_zoomLevel(-1),
|
||||
m_styleZoomLevel(-1),
|
||||
m_generation(0)
|
||||
{}
|
||||
|
||||
TileKey::TileKey(int x, int y, int zoomLevel)
|
||||
: m_x(x), m_y(y),
|
||||
m_zoomLevel(zoomLevel),
|
||||
m_styleZoomLevel(zoomLevel),
|
||||
m_generation(0)
|
||||
{}
|
||||
|
||||
TileKey::TileKey(TileKey const & key, uint64_t generation)
|
||||
: m_x(key.m_x), m_y(key.m_y),
|
||||
m_zoomLevel(key.m_zoomLevel),
|
||||
m_styleZoomLevel(key.m_styleZoomLevel),
|
||||
m_generation(generation)
|
||||
{}
|
||||
|
||||
|
@ -52,19 +52,17 @@ bool TileKey::LessStrict(TileKey const & other) const
|
|||
if (m_zoomLevel != other.m_zoomLevel)
|
||||
return m_zoomLevel < other.m_zoomLevel;
|
||||
|
||||
if (m_styleZoomLevel != other.m_styleZoomLevel)
|
||||
return m_styleZoomLevel < other.m_styleZoomLevel;
|
||||
|
||||
if (m_y != other.m_y)
|
||||
return m_y < other.m_y;
|
||||
|
||||
return m_x < other.m_x;
|
||||
}
|
||||
|
||||
m2::RectD TileKey::GetGlobalRect(bool considerStyleZoom) const
|
||||
m2::RectD TileKey::GetGlobalRect(bool clipByDataMaxZoom) const
|
||||
{
|
||||
double const worldSizeDevisor = 1 << (considerStyleZoom ? m_styleZoomLevel : m_zoomLevel);
|
||||
// Mercator SizeX and SizeY is equal
|
||||
int const zoomLevel = clipByDataMaxZoom ? ClipTileZoomByMaxDataZoom(m_zoomLevel) : m_zoomLevel;
|
||||
double const worldSizeDevisor = 1 << zoomLevel;
|
||||
// Mercator SizeX and SizeY are equal.
|
||||
double const rectSize = (MercatorBounds::maxX - MercatorBounds::minX) / worldSizeDevisor;
|
||||
|
||||
double const startX = m_x * rectSize;
|
||||
|
@ -77,27 +75,8 @@ string DebugPrint(TileKey const & key)
|
|||
{
|
||||
ostringstream out;
|
||||
out << "[x = " << key.m_x << ", y = " << key.m_y << ", zoomLevel = "
|
||||
<< key.m_zoomLevel << ", styleZoomLevel = " << key.m_styleZoomLevel
|
||||
<< ", gen = " << key.m_generation << "]";
|
||||
<< key.m_zoomLevel << ", gen = " << key.m_generation << "]";
|
||||
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
|
||||
|
|
|
@ -5,48 +5,31 @@
|
|||
namespace df
|
||||
{
|
||||
|
||||
enum class TileStatus
|
||||
{
|
||||
// tile does not participate in rendering or fake
|
||||
Unknown = 0,
|
||||
// tile is rendered
|
||||
Rendered,
|
||||
// tile has been requested to be rendered
|
||||
Requested,
|
||||
// tile is ready but it was deferred for rendering
|
||||
Deferred
|
||||
};
|
||||
|
||||
struct TileKey
|
||||
{
|
||||
TileKey();
|
||||
TileKey(int x, int y, int zoomLevel);
|
||||
TileKey(TileKey const & key, uint64_t generation);
|
||||
|
||||
// Operators < and == do not consider parameters m_styleZoomLevel and m_generation.
|
||||
// m_styleZoomLevel is used to work around FeaturesFetcher::ForEachFeatureID which is
|
||||
// not able to return correct rects on 18,19 zoom levels. So m_zoomLevel can not be
|
||||
// more than 17 for all subsystems except of styling.
|
||||
// Operators < and == do not consider parameter m_generation.
|
||||
// m_generation is used to determine a generation of geometry for this tile key.
|
||||
// Geometry with different generations must be able to group by (x, y, zoomlevel).
|
||||
bool operator < (TileKey const & other) const;
|
||||
bool operator == (TileKey const & other) const;
|
||||
|
||||
// This method implements strict comparison of tile keys. It's necessary to merger of
|
||||
// batches which must not merge batches with different m_styleZoomLevel and m_generation.
|
||||
// batches which must not merge batches with different m_generation.
|
||||
bool LessStrict(TileKey const & other) const;
|
||||
|
||||
m2::RectD GetGlobalRect(bool considerStyleZoom = false) const;
|
||||
m2::RectD GetGlobalRect(bool clipByDataMaxZoom = true) const;
|
||||
|
||||
int m_x;
|
||||
int m_y;
|
||||
int m_zoomLevel;
|
||||
|
||||
int m_styleZoomLevel;
|
||||
uint64_t m_generation;
|
||||
};
|
||||
|
||||
string DebugPrint(TileKey const & key);
|
||||
string DebugPrint(TileStatus status);
|
||||
|
||||
} // namespace df
|
||||
|
|
|
@ -1,451 +0,0 @@
|
|||
#include "tile_tree.hpp"
|
||||
|
||||
#include "std/algorithm.hpp"
|
||||
#include "std/utility.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
TileTree::TileTree()
|
||||
: m_root(new Node())
|
||||
{
|
||||
}
|
||||
|
||||
TileTree::~TileTree()
|
||||
{
|
||||
ResetHandlers();
|
||||
}
|
||||
|
||||
void TileTree::SetHandlers(TRenderGroupHandler const & addRenderGroup,
|
||||
TRenderGroupHandler const & deferRenderGroup,
|
||||
TTileHandler const & activateTile,
|
||||
TTileHandler const & removeTile)
|
||||
{
|
||||
m_addRenderGroupHandler = addRenderGroup;
|
||||
m_deferRenderGroupHandler = deferRenderGroup;
|
||||
m_activateTileHandler = activateTile;
|
||||
m_removeTileHandler = removeTile;
|
||||
}
|
||||
|
||||
void TileTree::Invalidate()
|
||||
{
|
||||
m_root.reset(new Node());
|
||||
}
|
||||
|
||||
void TileTree::ResetHandlers()
|
||||
{
|
||||
m_addRenderGroupHandler = nullptr;
|
||||
m_deferRenderGroupHandler = nullptr;
|
||||
m_activateTileHandler = nullptr;
|
||||
m_removeTileHandler = nullptr;
|
||||
}
|
||||
|
||||
void TileTree::BeginRequesting(int const zoomLevel, m2::RectD const & clipRect)
|
||||
{
|
||||
ClipByRect(clipRect);
|
||||
AbortTiles(m_root, zoomLevel);
|
||||
}
|
||||
|
||||
void TileTree::RequestTile(TileKey const & tileKey)
|
||||
{
|
||||
InsertToNode(m_root, tileKey);
|
||||
}
|
||||
|
||||
void TileTree::EndRequesting()
|
||||
{
|
||||
SimplifyTree();
|
||||
}
|
||||
|
||||
void TileTree::ClipByRect(m2::RectD const & rect)
|
||||
{
|
||||
ClipNode(m_root, rect);
|
||||
CheckDeferredTiles(m_root);
|
||||
SimplifyTree();
|
||||
}
|
||||
|
||||
void TileTree::ProcessTile(TileKey const & tileKey, int const zoomLevel,
|
||||
dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket)
|
||||
{
|
||||
bool const result = ProcessNode(m_root, tileKey, zoomLevel, state, move(bucket));
|
||||
if (result)
|
||||
SimplifyTree();
|
||||
}
|
||||
|
||||
void TileTree::FinishTiles(TTilesCollection const & tiles, int const zoomLevel)
|
||||
{
|
||||
bool changed = false;
|
||||
for (TileKey const & tileKey : tiles)
|
||||
changed |= FinishNode(m_root, tileKey, zoomLevel);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
CheckDeferredTiles(m_root);
|
||||
SimplifyTree();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
InsertToNodeBelow(node, tileKey, childrenZoomLevel);
|
||||
}
|
||||
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
|
||||
InsertToNodeAbove(node, tileKey);
|
||||
}
|
||||
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
|
||||
InsertToCurrentNode(node, tileKey);
|
||||
}
|
||||
}
|
||||
|
||||
void TileTree::InsertToCurrentNode(TNodePtr const & node, TileKey const & tileKey)
|
||||
{
|
||||
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::InsertToNodeAbove(TNodePtr const & node, TileKey const & tileKey)
|
||||
{
|
||||
list<TNodePtr> newChildren;
|
||||
newChildren.emplace_back(TNodePtr(new Node(tileKey, TileStatus::Requested)));
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end(); ++it)
|
||||
{
|
||||
// looking for parent node
|
||||
TileKey const 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);
|
||||
}
|
||||
|
||||
void TileTree::InsertToNodeBelow(TNodePtr const & node, TileKey const & tileKey, int const childrenZoomLevel)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
void TileTree::AbortTiles(TNodePtr const & node, int const zoomLevel)
|
||||
{
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
{
|
||||
if (childNode->m_tileKey.m_zoomLevel != zoomLevel)
|
||||
{
|
||||
if (childNode->m_tileStatus == TileStatus::Requested)
|
||||
childNode->m_tileStatus = TileStatus::Unknown;
|
||||
else if (childNode->m_tileStatus == TileStatus::Deferred)
|
||||
RemoveTile(childNode);
|
||||
}
|
||||
|
||||
AbortTiles(childNode, zoomLevel);
|
||||
}
|
||||
}
|
||||
|
||||
void TileTree::ClipNode(TNodePtr const & node, m2::RectD const & rect)
|
||||
{
|
||||
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);
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveTile(*it);
|
||||
ClipNode(*it, rect);
|
||||
it = node->m_children.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileTree::RemoveTile(TNodePtr const & node)
|
||||
{
|
||||
if (m_removeTileHandler != nullptr && !node->m_isRemoved)
|
||||
m_removeTileHandler(node->m_tileKey);
|
||||
|
||||
node->m_isRemoved = true;
|
||||
node->m_tileStatus = TileStatus::Unknown;
|
||||
}
|
||||
|
||||
bool TileTree::ProcessNode(TNodePtr const & node, TileKey const & tileKey, int const zoomLevel,
|
||||
dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket)
|
||||
{
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
{
|
||||
if (tileKey == childNode->m_tileKey)
|
||||
{
|
||||
// skip unknown tiles and tiles from different zoom level
|
||||
// A tile can get Unknown status if it becomes invalid before BR finished its processing
|
||||
if (childNode->m_tileStatus == TileStatus::Unknown || tileKey.m_zoomLevel != zoomLevel)
|
||||
return false;
|
||||
|
||||
// remove all tiles below current
|
||||
DeleteTilesBelow(childNode);
|
||||
|
||||
// add or defer render group
|
||||
if (node->m_tileStatus == TileStatus::Rendered)
|
||||
{
|
||||
childNode->m_tileStatus = TileStatus::Deferred;
|
||||
if (m_deferRenderGroupHandler != nullptr)
|
||||
m_deferRenderGroupHandler(tileKey, state, move(bucket));
|
||||
childNode->m_isRemoved = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
childNode->m_tileStatus = TileStatus::Rendered;
|
||||
if (m_addRenderGroupHandler != nullptr)
|
||||
m_addRenderGroupHandler(tileKey, state, move(bucket));
|
||||
childNode->m_isRemoved = false;
|
||||
}
|
||||
|
||||
// try to remove tile above
|
||||
TryDeleteTileAbove(node);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (IsTileBelow(childNode->m_tileKey, tileKey))
|
||||
return ProcessNode(childNode, tileKey, zoomLevel, state, move(bucket));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TileTree::FinishNode(TNodePtr const & node, TileKey const & tileKey, int const zoomLevel)
|
||||
{
|
||||
bool changed = false;
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
{
|
||||
if (childNode->m_tileKey == tileKey && childNode->m_tileStatus == TileStatus::Requested)
|
||||
{
|
||||
// here a tile has finished, but we hadn't got any data from BR. It means that
|
||||
// this tile is empty, so we mark this tile as rendered
|
||||
childNode->m_tileStatus = TileStatus::Rendered;
|
||||
childNode->m_isRemoved = false;
|
||||
|
||||
if (childNode->m_tileKey.m_zoomLevel >= zoomLevel)
|
||||
DeleteTilesBelow(childNode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
changed |= FinishNode(childNode, tileKey, zoomLevel);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void TileTree::DeleteTilesBelow(TNodePtr const & node)
|
||||
{
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
{
|
||||
RemoveTile(childNode);
|
||||
DeleteTilesBelow(childNode);
|
||||
}
|
||||
node->m_children.clear();
|
||||
}
|
||||
|
||||
void TileTree::TryDeleteTileAbove(TNodePtr const & node)
|
||||
{
|
||||
if (node->m_tileStatus == TileStatus::Requested || node->m_children.empty())
|
||||
return;
|
||||
|
||||
// check if all child tiles are ready
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
if (childNode->m_tileStatus == TileStatus::Requested)
|
||||
return;
|
||||
|
||||
// add deferred tiles
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
{
|
||||
if (childNode->m_tileStatus == TileStatus::Deferred)
|
||||
{
|
||||
if (m_activateTileHandler != nullptr)
|
||||
m_activateTileHandler(childNode->m_tileKey);
|
||||
|
||||
childNode->m_tileStatus = TileStatus::Rendered;
|
||||
childNode->m_isRemoved = false;
|
||||
}
|
||||
}
|
||||
|
||||
// remove current tile
|
||||
if (node != m_root)
|
||||
RemoveTile(node);
|
||||
}
|
||||
|
||||
void TileTree::SimplifyTree()
|
||||
{
|
||||
ClearEmptyLevels(m_root);
|
||||
ClearObsoleteTiles(m_root);
|
||||
}
|
||||
|
||||
void TileTree::ClearEmptyLevels(TNodePtr const & node)
|
||||
{
|
||||
if (HaveChildrenSameStatus(node, TileStatus::Unknown))
|
||||
{
|
||||
// all grandchildren have the same zoom level?
|
||||
if (!HaveGrandchildrenSameZoomLevel(node))
|
||||
return;
|
||||
|
||||
// move grandchildren to grandfather
|
||||
list<TNodePtr> newChildren;
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
{
|
||||
RemoveTile(childNode);
|
||||
newChildren.splice(newChildren.begin(), childNode->m_children);
|
||||
}
|
||||
node->m_children.swap(newChildren);
|
||||
}
|
||||
|
||||
// remove unknown nodes without children
|
||||
for (auto it = node->m_children.begin(); it != node->m_children.end();)
|
||||
{
|
||||
if((*it)->m_tileStatus == TileStatus::Unknown && (*it)->m_children.empty())
|
||||
{
|
||||
RemoveTile(*it);
|
||||
it = node->m_children.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
ClearEmptyLevels(childNode);
|
||||
}
|
||||
|
||||
bool TileTree::ClearObsoleteTiles(TNodePtr const & node)
|
||||
{
|
||||
bool canClear = true;
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
canClear &= ClearObsoleteTiles(childNode);
|
||||
|
||||
if (canClear)
|
||||
{
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
RemoveTile(childNode);
|
||||
|
||||
node->m_children.clear();
|
||||
}
|
||||
|
||||
return canClear && node->m_tileStatus == TileStatus::Unknown;
|
||||
}
|
||||
|
||||
bool TileTree::HaveChildrenSameStatus(TNodePtr const & node, TileStatus tileStatus) const
|
||||
{
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
if (childNode->m_tileStatus != tileStatus)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TileTree::HaveGrandchildrenSameZoomLevel(TNodePtr const & node) const
|
||||
{
|
||||
if (node->m_children.empty())
|
||||
return true;
|
||||
|
||||
int zoomLevel = -1;
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
{
|
||||
if (childNode->m_children.empty())
|
||||
continue;
|
||||
|
||||
int z = childNode->m_children.front()->m_tileKey.m_zoomLevel;
|
||||
|
||||
if (zoomLevel != -1 && zoomLevel != z)
|
||||
return false;
|
||||
|
||||
zoomLevel = z;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TileTree::CheckDeferredTiles(TNodePtr const & node)
|
||||
{
|
||||
for (TNodePtr const & childNode : node->m_children)
|
||||
{
|
||||
TryDeleteTileAbove(childNode);
|
||||
CheckDeferredTiles(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugPrintNode(TileTree::TNodePtr const & node, ostringstream & out, string const & offset)
|
||||
{
|
||||
for (TileTree::TNodePtr const & childNode : node->m_children)
|
||||
{
|
||||
out << offset << "{ " << DebugPrint(childNode->m_tileKey) << ", "
|
||||
<< DebugPrint(childNode->m_tileStatus) << (childNode->m_isRemoved ? ", removed" : "") << "}\n";
|
||||
DebugPrintNode(childNode, out, offset + " ");
|
||||
}
|
||||
}
|
||||
|
||||
string DebugPrint(TileTree const & tileTree)
|
||||
{
|
||||
ostringstream out;
|
||||
out << "\n{\n";
|
||||
DebugPrintNode(tileTree.m_root, out, " ");
|
||||
out << "}\n";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
} // namespace df
|
|
@ -1,117 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "tile_utils.hpp"
|
||||
#include "render_group.hpp"
|
||||
|
||||
#include "drape/glstate.hpp"
|
||||
#include "drape/pointers.hpp"
|
||||
#include "geometry/rect2d.hpp"
|
||||
|
||||
#include "std/function.hpp"
|
||||
#include "std/list.hpp"
|
||||
#include "std/sstream.hpp"
|
||||
#include "std/unique_ptr.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
/// This class implements K-d tree of visible tiles.
|
||||
class TileTree
|
||||
{
|
||||
public:
|
||||
TileTree();
|
||||
~TileTree();
|
||||
|
||||
using TTileHandler = function<void(TileKey const &)>;
|
||||
using TRenderGroupHandler = function<void(TileKey const &, dp::GLState const &,
|
||||
drape_ptr<dp::RenderBucket> &&)>;
|
||||
|
||||
/// This method sets following handlers:
|
||||
/// addRenderGroup is called when render group can be created by a tile and rendered at once,
|
||||
/// deferRenderGroup is called when render group can be created by a tile but has to be deferred,
|
||||
/// activateTile is called when previously deferred tile can be rendered,
|
||||
/// removeTile is called when a tile must be removed from rendering.
|
||||
void SetHandlers(TRenderGroupHandler const & addRenderGroup,
|
||||
TRenderGroupHandler const & deferRenderGroup,
|
||||
TTileHandler const & activateTile,
|
||||
TTileHandler const & removeTile);
|
||||
|
||||
void Invalidate();
|
||||
|
||||
/// This method must be called before requesting bunch of tiles.
|
||||
void BeginRequesting(int const zoomLevel, m2::RectD const & clipRect);
|
||||
/// This method requests a new tile.
|
||||
void RequestTile(TileKey const & tileKey);
|
||||
/// This method must be called after requesting bunch of tiles.
|
||||
void EndRequesting();
|
||||
|
||||
/// This method processes received from BR (backend renderer) tile.
|
||||
void ProcessTile(TileKey const & tileKey, int const zoomLevel,
|
||||
dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket);
|
||||
/// This method processes a message about finishing reading tiles on BR.
|
||||
void FinishTiles(TTilesCollection const & tiles, int const zoomLevel);
|
||||
|
||||
private:
|
||||
struct Node;
|
||||
using TNodePtr = unique_ptr<Node>;
|
||||
|
||||
void ResetHandlers();
|
||||
|
||||
void InsertToNode(TNodePtr const & node, TileKey const & tileKey);
|
||||
void InsertToCurrentNode(TNodePtr const & node, TileKey const & tileKey);
|
||||
void InsertToNodeAbove(TNodePtr const & node, TileKey const & tileKey);
|
||||
void InsertToNodeBelow(TNodePtr const & node, TileKey const & tileKey, int const childrenZoomLevel);
|
||||
void AbortTiles(TNodePtr const & node, int const zoomLevel);
|
||||
|
||||
void ClipByRect(m2::RectD const & rect);
|
||||
|
||||
void ClipNode(TNodePtr const & node, m2::RectD const & rect);
|
||||
void CheckDeferredTiles(TNodePtr const & node);
|
||||
|
||||
void RemoveTile(TNodePtr const & node);
|
||||
|
||||
bool ProcessNode(TNodePtr const & node, TileKey const & tileKey, int const zoomLevel,
|
||||
dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket);
|
||||
bool FinishNode(TNodePtr const & node, TileKey const & tileKey, int const zoomLevel);
|
||||
|
||||
void DeleteTilesBelow(TNodePtr const & node);
|
||||
void TryDeleteTileAbove(TNodePtr const & node);
|
||||
|
||||
void SimplifyTree();
|
||||
void ClearEmptyLevels(TNodePtr const & node);
|
||||
bool ClearObsoleteTiles(TNodePtr const & node);
|
||||
|
||||
bool HaveChildrenSameStatus(TNodePtr const & node, TileStatus tileStatus) const;
|
||||
bool HaveGrandchildrenSameZoomLevel(TNodePtr const & node) const;
|
||||
|
||||
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)
|
||||
{}
|
||||
|
||||
Node(TileKey const & key, TileStatus status, bool isRemoved)
|
||||
: m_tileKey(key), m_tileStatus(status), m_isRemoved(isRemoved)
|
||||
{}
|
||||
};
|
||||
|
||||
TNodePtr m_root;
|
||||
TRenderGroupHandler m_addRenderGroupHandler;
|
||||
TRenderGroupHandler m_deferRenderGroupHandler;
|
||||
TTileHandler m_activateTileHandler;
|
||||
TTileHandler m_removeTileHandler;
|
||||
|
||||
friend void DebugPrintNode(TileTree::TNodePtr const & node, ostringstream & out, string const & offset);
|
||||
friend string DebugPrint(TileTree const & tileTree);
|
||||
|
||||
friend class TileTreeBuilder;
|
||||
friend class TileTreeComparer;
|
||||
};
|
||||
|
||||
} // namespace df
|
|
@ -1,120 +0,0 @@
|
|||
#include "drape_frontend/tile_tree_builder.hpp"
|
||||
|
||||
#include "std/algorithm.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
TileTreeBuilderNode::TileTreeBuilderNode()
|
||||
: m_prevBrother(nullptr)
|
||||
, m_tileStatus(TileStatus::Unknown)
|
||||
, m_isRemoved(false)
|
||||
{
|
||||
}
|
||||
|
||||
TileTreeBuilderNode::TileTreeBuilderNode(TileKey const & tileKey, TileStatus tileStatus, bool isRemoved)
|
||||
: m_prevBrother(nullptr)
|
||||
, m_tileKey(tileKey)
|
||||
, m_tileStatus(tileStatus)
|
||||
, m_isRemoved(isRemoved)
|
||||
{
|
||||
}
|
||||
|
||||
TileTreeBuilderNode::TileTreeBuilderNode(TileTreeBuilderNode & node)
|
||||
: m_prevBrother(node.m_prevBrother)
|
||||
, m_nextBrother(move(node.m_nextBrother))
|
||||
, m_child(move(node.m_child))
|
||||
, m_tileKey(node.m_tileKey)
|
||||
, m_tileStatus(node.m_tileStatus)
|
||||
, m_isRemoved(node.m_isRemoved)
|
||||
{
|
||||
}
|
||||
|
||||
TileTreeBuilderNode & TileTreeBuilderNode::Node(TileKey const & tileKey, TileStatus tileStatus, bool isRemoved)
|
||||
{
|
||||
m_nextBrother.reset(new TileTreeBuilderNode(tileKey, tileStatus, isRemoved));
|
||||
m_nextBrother->m_prevBrother = this;
|
||||
return *m_nextBrother.get();
|
||||
}
|
||||
|
||||
TileTreeBuilderNode & TileTreeBuilderNode::Children(TileTreeBuilderNode & node)
|
||||
{
|
||||
m_child.reset(new TileTreeBuilderNode(node));
|
||||
return *this;
|
||||
}
|
||||
|
||||
TileTreeBuilderNode Node(TileKey const & tileKey, TileStatus tileStatus, bool isRemoved)
|
||||
{
|
||||
TileTreeBuilderNode node(tileKey, tileStatus, isRemoved);
|
||||
return node;
|
||||
}
|
||||
|
||||
unique_ptr<TileTree> TileTreeBuilder::Build(TileTreeBuilderNode const & root)
|
||||
{
|
||||
unique_ptr<TileTree> tree = make_unique<TileTree>();
|
||||
InsertIntoNode(tree->m_root, root);
|
||||
return tree;
|
||||
}
|
||||
|
||||
void TileTreeBuilder::InsertIntoNode(TileTree::TNodePtr & node, TileTreeBuilderNode const & builderNode)
|
||||
{
|
||||
node->m_children.push_back(CreateNode(& builderNode));
|
||||
if (builderNode.m_child != nullptr)
|
||||
InsertIntoNode(node->m_children.back(), *builderNode.m_child.get());
|
||||
|
||||
TileTreeBuilderNode * n = builderNode.m_prevBrother;
|
||||
while (n != nullptr)
|
||||
{
|
||||
node->m_children.push_back(CreateNode(n));
|
||||
if (n->m_child != nullptr)
|
||||
InsertIntoNode(node->m_children.back(), *n->m_child.get());
|
||||
n = n->m_prevBrother;
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<TileTree::Node> TileTreeBuilder::CreateNode(TileTreeBuilderNode const * node)
|
||||
{
|
||||
return make_unique<TileTree::Node>(node->m_tileKey, node->m_tileStatus, node->m_isRemoved);
|
||||
}
|
||||
|
||||
bool TileTreeComparer::IsEqual(unique_ptr<TileTree> const & tree1, unique_ptr<TileTree> const & tree2) const
|
||||
{
|
||||
return CompareSubtree(tree1->m_root, tree2->m_root);
|
||||
}
|
||||
|
||||
bool TileTreeComparer::CompareSubtree(TileTree::TNodePtr const & node1, TileTree::TNodePtr const & node2) const
|
||||
{
|
||||
if (!CompareNodes(node1, node2))
|
||||
return false;
|
||||
|
||||
for (TileTree::TNodePtr const & n1 : node1->m_children)
|
||||
{
|
||||
auto found = find_if(node2->m_children.begin(), node2->m_children.end(), [this, &n1](TileTree::TNodePtr const & n2)
|
||||
{
|
||||
return CompareNodes(n1, n2);
|
||||
});
|
||||
|
||||
if (found != node2->m_children.end())
|
||||
{
|
||||
if (!CompareSubtree(n1, *found))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TileTreeComparer::CompareNodes(TileTree::TNodePtr const & node1, TileTree::TNodePtr const & node2) const
|
||||
{
|
||||
if (!(node1->m_tileKey == node2->m_tileKey) || node1->m_tileStatus != node2->m_tileStatus ||
|
||||
node1->m_isRemoved != node2->m_isRemoved || node1->m_children.size() != node2->m_children.size())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} //namespace df
|
|
@ -1,58 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "drape_frontend/tile_tree.hpp"
|
||||
|
||||
#include "std/list.hpp"
|
||||
#include "std/unique_ptr.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
// These classes can be used only for tests!
|
||||
|
||||
class TileTreeBuilderNode
|
||||
{
|
||||
friend class TileTreeBuilder;
|
||||
public:
|
||||
TileTreeBuilderNode & Node(TileKey const & tileKey, TileStatus tileStatus, bool isRemoved = false);
|
||||
TileTreeBuilderNode & Children(TileTreeBuilderNode & node);
|
||||
|
||||
private:
|
||||
TileTreeBuilderNode();
|
||||
TileTreeBuilderNode(TileKey const & tileKey, TileStatus tileStatus, bool isRemoved);
|
||||
TileTreeBuilderNode(TileTreeBuilderNode & node);
|
||||
|
||||
TileTreeBuilderNode * m_prevBrother;
|
||||
unique_ptr<TileTreeBuilderNode> m_nextBrother;
|
||||
unique_ptr<TileTreeBuilderNode> m_child;
|
||||
|
||||
TileKey m_tileKey;
|
||||
TileStatus m_tileStatus;
|
||||
bool m_isRemoved;
|
||||
|
||||
friend TileTreeBuilderNode Node(TileKey const &, TileStatus, bool);
|
||||
};
|
||||
|
||||
TileTreeBuilderNode Node(TileKey const & tileKey, TileStatus tileStatus, bool isRemoved = false);
|
||||
|
||||
class TileTreeBuilder
|
||||
{
|
||||
public:
|
||||
unique_ptr<TileTree> Build(TileTreeBuilderNode const & root);
|
||||
|
||||
private:
|
||||
void InsertIntoNode(TileTree::TNodePtr & node, TileTreeBuilderNode const & builderNode);
|
||||
unique_ptr<TileTree::Node> CreateNode(TileTreeBuilderNode const * node);
|
||||
};
|
||||
|
||||
class TileTreeComparer
|
||||
{
|
||||
public:
|
||||
bool IsEqual(unique_ptr<TileTree> const & tree1, unique_ptr<TileTree> const & tree2) const;
|
||||
|
||||
private:
|
||||
bool CompareSubtree(TileTree::TNodePtr const & node1, TileTree::TNodePtr const & node2) const;
|
||||
bool CompareNodes(TileTree::TNodePtr const & node1, TileTree::TNodePtr const & node2) const;
|
||||
};
|
||||
|
||||
} // namespace df
|
|
@ -1,4 +1,8 @@
|
|||
#include "tile_utils.hpp"
|
||||
#include "drape_frontend/tile_utils.hpp"
|
||||
|
||||
#include "indexer/scales.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/stl_add.hpp"
|
||||
|
@ -6,109 +10,39 @@
|
|||
namespace df
|
||||
{
|
||||
|
||||
namespace
|
||||
CoverageResult CalcTilesCoverage(m2::RectD const & rect, int targetZoom,
|
||||
function<void(int, int)> const & processTile)
|
||||
{
|
||||
double const range = MercatorBounds::maxX - MercatorBounds::minX;
|
||||
double const rectSize = range / (1 << targetZoom);
|
||||
|
||||
int Minificate(int coord, int zoom, int targetZoom)
|
||||
{
|
||||
ASSERT(targetZoom < zoom, ());
|
||||
CoverageResult result;
|
||||
result.m_minTileX = static_cast<int>(floor(rect.minX() / rectSize));
|
||||
result.m_maxTileX = static_cast<int>(ceil(rect.maxX() / rectSize));
|
||||
result.m_minTileY = static_cast<int>(floor(rect.minY() / rectSize));
|
||||
result.m_maxTileY = static_cast<int>(ceil(rect.maxY() / rectSize));
|
||||
|
||||
int z = zoom - targetZoom;
|
||||
if (coord >= 0)
|
||||
return coord >> z;
|
||||
|
||||
// here we iteratively minificate zoom
|
||||
int c = -coord;
|
||||
ASSERT(c > 0, ());
|
||||
while (z > 0)
|
||||
if (processTile != nullptr)
|
||||
{
|
||||
// c = c / 2 + 1, if c is odd
|
||||
// c = c / 2, if c is even
|
||||
c = (c + 1) >> 1;
|
||||
z--;
|
||||
for (int tileY = result.m_minTileY; tileY < result.m_maxTileY; ++tileY)
|
||||
for (int tileX = result.m_minTileX; tileX < result.m_maxTileX; ++tileX)
|
||||
processTile(tileX, tileY);
|
||||
}
|
||||
return -c;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void CalcTilesCoverage(TileKey const & tileKey, int targetZoom, TTilesCollection & tiles)
|
||||
{
|
||||
CalcTilesCoverage(tileKey, targetZoom, MakeInsertFunctor(tiles));
|
||||
}
|
||||
|
||||
void CalcTilesCoverage(set<TileKey> const & tileKeys, int targetZoom, TTilesCollection & tiles)
|
||||
{
|
||||
for(TileKey const & tileKey : tileKeys)
|
||||
CalcTilesCoverage(tileKey, targetZoom, tiles);
|
||||
}
|
||||
|
||||
void CalcTilesCoverage(TileKey const & tileKey, int targetZoom, function<void(TileKey const &)> const & processTile)
|
||||
{
|
||||
ASSERT(processTile != nullptr, ());
|
||||
|
||||
if (tileKey.m_zoomLevel == targetZoom)
|
||||
processTile(tileKey);
|
||||
else if (tileKey.m_zoomLevel > targetZoom)
|
||||
{
|
||||
// minification
|
||||
processTile(GetParentTile(tileKey, targetZoom));
|
||||
}
|
||||
else
|
||||
{
|
||||
// magnification
|
||||
int const z = targetZoom - tileKey.m_zoomLevel;
|
||||
int const tilesInRow = 1 << z;
|
||||
int const startX = tileKey.m_x << z;
|
||||
int const startY = tileKey.m_y << z;
|
||||
for (int x = 0; x < tilesInRow; x++)
|
||||
for (int y = 0; y < tilesInRow; y++)
|
||||
processTile(TileKey(startX + x, startY + y, targetZoom));
|
||||
}
|
||||
}
|
||||
|
||||
bool IsTileAbove(TileKey const & tileKey, TileKey const & targetTileKey)
|
||||
{
|
||||
if (tileKey.m_zoomLevel <= targetTileKey.m_zoomLevel)
|
||||
return false;
|
||||
|
||||
int const x = Minificate(tileKey.m_x, tileKey.m_zoomLevel, targetTileKey.m_zoomLevel);
|
||||
if (x != targetTileKey.m_x)
|
||||
return false;
|
||||
|
||||
int const y = Minificate(tileKey.m_y, tileKey.m_zoomLevel, targetTileKey.m_zoomLevel);
|
||||
return y == targetTileKey.m_y;
|
||||
}
|
||||
|
||||
bool IsTileBelow(TileKey const & tileKey, TileKey const & targetTileKey)
|
||||
{
|
||||
if (tileKey.m_zoomLevel >= targetTileKey.m_zoomLevel)
|
||||
return false;
|
||||
|
||||
int const z = targetTileKey.m_zoomLevel - tileKey.m_zoomLevel;
|
||||
int const tilesInRow = 1 << z;
|
||||
int const startX = tileKey.m_x << z;
|
||||
if (targetTileKey.m_x < startX || targetTileKey.m_x >= startX + tilesInRow)
|
||||
return false;
|
||||
|
||||
int const startY = tileKey.m_y << z;
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsNeighbours(TileKey const & tileKey1, TileKey const & tileKey2)
|
||||
{
|
||||
return !((tileKey1.m_x == tileKey2.m_x) && (tileKey1.m_y == tileKey2.m_y)) &&
|
||||
(abs(tileKey1.m_x - tileKey2.m_x) < 2) &&
|
||||
(abs(tileKey1.m_y - tileKey2.m_y) < 2);
|
||||
(abs(tileKey1.m_x - tileKey2.m_x) < 2) &&
|
||||
(abs(tileKey1.m_y - tileKey2.m_y) < 2);
|
||||
}
|
||||
|
||||
int ClipTileZoomByMaxDataZoom(int zoom)
|
||||
{
|
||||
int const upperScale = scales::GetUpperScale();
|
||||
return zoom <= upperScale ? zoom : upperScale;
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
|
|
|
@ -1,33 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "tile_key.hpp"
|
||||
#include "drape_frontend/tile_key.hpp"
|
||||
|
||||
#include "std/function.hpp"
|
||||
#include "std/set.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
using TTilesCollection = set<TileKey>;
|
||||
|
||||
/// This function determines the coverage of a tile in specified zoom level.
|
||||
void CalcTilesCoverage(TileKey const & tileKey, int targetZoom, TTilesCollection & tiles);
|
||||
struct CoverageResult
|
||||
{
|
||||
int m_minTileX = 0;
|
||||
int m_maxTileX = 0;
|
||||
int m_minTileY = 0;
|
||||
int m_maxTileY = 0;
|
||||
};
|
||||
|
||||
/// This function determines the coverage of tiles in specified zoom level.
|
||||
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.
|
||||
void CalcTilesCoverage(TileKey const & tileKey, int targetZoom, function<void(TileKey const &)> const & processTile);
|
||||
|
||||
/// This function checks if targetTileKey is above tileKey.
|
||||
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);
|
||||
/// This function determines the tiles coverage in specified zoom level.
|
||||
/// Each tile can be processed in processTile callback.
|
||||
CoverageResult CalcTilesCoverage(m2::RectD const & rect, int targetZoom,
|
||||
function<void(int, int)> const & processTile);
|
||||
|
||||
/// This function checks if tileKey1 and tileKey2 are neighbours
|
||||
bool IsNeighbours(TileKey const & tileKey1, TileKey const & tileKey2);
|
||||
|
||||
/// This function performs clipping by maximum zoom label available for map data.
|
||||
int ClipTileZoomByMaxDataZoom(int zoom);
|
||||
|
||||
} // namespace df
|
||||
|
|
Loading…
Add table
Reference in a new issue