1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
#include "../base/SRC_FIRST.hpp"
#include "tiler.hpp"
#include "../indexer/mercator.hpp"
#include "../indexer/scales.hpp"
#include "../base/logging.hpp"
uint64_t Tiler::RectInfo::toUInt64Cell() const
{
/// pack y in 0-23 bits
/// pack x in 24-47 bits
/// pack tileScale in 48-55 bits
/// pack drawScale in 56-63 bits
ASSERT(m_y <= 0xFFFFFF, ());
ASSERT(m_x <= 0xFFFFFF, ());
ASSERT(m_tileScale <= 0xFF, ());
ASSERT(m_drawScale <= 0xFF, ());
return (m_y & 0xFFFFFF)
| ((m_x & 0xFFFFFF) << 24)
| (((uint64_t)m_tileScale & 0xFF) << 48)
| (((uint64_t)m_drawScale & 0xFF) << 56);
}
void Tiler::RectInfo::fromUInt64Cell(uint64_t v)
{
m_y = v & 0xFFFFFF;
m_x = (v >> 24) & 0xFFFFFF;
m_tileScale = (v >> 48) & 0xFF;
m_drawScale = (v >> 56) & 0xFF;
}
Tiler::RectInfo::RectInfo()
: m_drawScale(0), m_tileScale(0), m_x(0), m_y(0)
{}
Tiler::RectInfo::RectInfo(int drawScale, int tileScale, int x, int y)
: m_drawScale(drawScale), m_tileScale(tileScale), m_x(x), m_y(y)
{
int k = 1 << m_tileScale;
double rectSizeX = (MercatorBounds::maxX - MercatorBounds::minX) / k;
double rectSizeY = (MercatorBounds::maxY - MercatorBounds::minY) / k;
m_rect.setMinX(m_x * rectSizeX);
m_rect.setMaxX((m_x + 1) * rectSizeX);
m_rect.setMinY(m_y * rectSizeY);
m_rect.setMaxY((m_y + 1) * rectSizeY);
}
LessByDistance::LessByDistance(m2::PointD const & pt)
: m_pt(pt)
{
}
bool LessByDistance::operator()(Tiler::RectInfo const & l, Tiler::RectInfo const & r)
{
return l.m_rect.Center().Length(m_pt) < r.m_rect.Center().Length(m_pt);
}
bool operator<(Tiler::RectInfo const & l, Tiler::RectInfo const & r)
{
return l.toUInt64Cell() < r.toUInt64Cell();
}
int Tiler::drawScale(ScreenBase const & s) const
{
ScreenBase tmpS = s;
tmpS.Rotate(-tmpS.GetAngle());
m2::RectD glbRect;
m2::PointD pxCenter = tmpS.PixelRect().Center();
tmpS.PtoG(m2::RectD(pxCenter - m2::PointD(m_scaleEtalonSize / 2, m_scaleEtalonSize / 2),
pxCenter + m2::PointD(m_scaleEtalonSize / 2, m_scaleEtalonSize / 2)),
glbRect);
return scales::GetScaleLevel(glbRect);
}
int Tiler::tileScale(ScreenBase const & s) const
{
ScreenBase tmpS = s;
tmpS.Rotate(-tmpS.GetAngle());
/// slightly smaller than original to produce "antialiasing" effect using bilinear filtration.
size_t tileSize = static_cast<size_t>(m_tileSize / 1.05);
m2::RectD glbRect;
m2::PointD pxCenter = tmpS.PixelRect().Center();
tmpS.PtoG(m2::RectD(pxCenter - m2::PointD(tileSize / 2, tileSize / 2),
pxCenter + m2::PointD(tileSize / 2, tileSize / 2)),
glbRect);
double glbRectSize = min(glbRect.SizeX(), glbRect.SizeY());
int res = static_cast<int>(ceil(log((MercatorBounds::maxX - MercatorBounds::minX) / glbRectSize) / log(2.0)));
return res;
}
void Tiler::seed(ScreenBase const & screen, m2::PointD const & centerPt)
{
if (screen != m_screen)
++m_sequenceID;
m_screen = screen;
m_drawScale = drawScale(screen);
m_tileScale = tileScale(screen);
double rectSizeX = (MercatorBounds::maxX - MercatorBounds::minX) / (1 << m_tileScale);
double rectSizeY = (MercatorBounds::maxY - MercatorBounds::minY) / (1 << m_tileScale);
m2::AnyRectD const globalRect = m_screen.GlobalRect();
m2::RectD const clipRect = m_screen.ClipRect();
int minTileX = static_cast<int>(floor(clipRect.minX() / rectSizeX));
int maxTileX = static_cast<int>(ceil(clipRect.maxX() / rectSizeX));
int minTileY = static_cast<int>(floor(clipRect.minY() / rectSizeY));
int maxTileY = static_cast<int>(ceil(clipRect.maxY() / rectSizeY));
/// clearing previous coverage
m_coverage.clear();
/// generating new coverage
for (int tileY = minTileY; tileY < maxTileY; ++tileY)
for (int tileX = minTileX; tileX < maxTileX; ++tileX)
{
m2::RectD tileRect(tileX * rectSizeX,
tileY * rectSizeY,
(tileX + 1) * rectSizeX,
(tileY + 1) * rectSizeY);
if (globalRect.IsIntersect(m2::AnyRectD(tileRect)))
m_coverage.push_back(RectInfo(m_drawScale, m_tileScale, tileX, tileY));
}
/// sorting coverage elements
sort(m_coverage.begin(), m_coverage.end(), LessByDistance(centerPt));
}
Tiler::Tiler(size_t tileSize, size_t scaleEtalonSize)
: m_sequenceID(0), m_tileSize(tileSize), m_scaleEtalonSize(scaleEtalonSize)
{}
void Tiler::visibleTiles(vector<RectInfo> & tiles)
{
tiles = m_coverage;
}
size_t Tiler::sequenceID() const
{
return m_sequenceID;
}
|