3 #include <QPixmapCache>
4 #include <QtConcurrent>
9 static bool readSources(QDataStream
&stream
)
16 for (int i
= 0; i
< num
; i
++) {
19 stream
.readRawData(name
.data(), name
.size());
22 return (stream
.status() == QDataStream::Ok
);
25 QRect
GEMFMap::rect(const Zoom
&zoom
) const
28 const QList
<Region
> &list
= zoom
.ranges
;
30 for (int i
= 0; i
< list
.size(); i
++) {
31 const Region
&rg
= list
.at(i
);
32 r
|= QRect(QPoint(rg
.minX
, rg
.minY
), QPoint(rg
.maxX
, rg
.maxY
));
38 bool GEMFMap::readHeader(QDataStream
&stream
)
42 stream
>> version
>> _tileSize
;
43 return (stream
.status() == QDataStream::Ok
44 && (version
>= 3 && version
<= 4));
47 bool GEMFMap::readRegions(QDataStream
&stream
)
49 qint32 num
, idx
, level
;
55 for (int i
= 0; i
< num
; i
++) {
56 stream
>> level
>> r
.minX
>> r
.maxX
>> r
.minY
>> r
.maxY
>> idx
59 if ((zi
= _zooms
.indexOf(level
)) < 0) {
61 _zooms
.append(Zoom(level
));
64 _zooms
[zi
].ranges
.append(r
);
67 return (stream
.status() == QDataStream::Ok
);
70 bool GEMFMap::computeBounds()
75 std::sort(_zooms
.begin(), _zooms
.end());
77 const Zoom
&z
= _zooms
.first();
82 Coordinates
tl(OSM::tile2ll(r
.topLeft(), z
.level
));
83 tl
.rlat() = -tl
.lat();
84 Coordinates
br(OSM::tile2ll(QPoint(r
.right() + 1, r
.bottom() + 1), z
.level
));
85 br
.rlat() = -br
.lat();
86 // Workaround of broken zoom levels 0 and 1 due to numerical
88 tl
.rlat() = qMin(tl
.lat(), OSM::BOUNDS
.top());
89 br
.rlat() = qMax(br
.lat(), OSM::BOUNDS
.bottom());
91 _bounds
= RectC(tl
, br
);
96 GEMFMap::GEMFMap(const QString
&fileName
, QObject
*parent
)
97 : Map(fileName
, parent
), _file(fileName
), _zi(0), _mapRatio(1.0),
100 if (!_file
.open(QIODevice::ReadOnly
)) {
101 _errorString
= _file
.errorString();
105 QDataStream
stream(&_file
);
107 if (!readHeader(stream
)) {
108 _errorString
= "Invalid/unsupported GEMF file";
111 if (!readSources(stream
)) {
112 _errorString
= "Error reading tile sources";
115 if (!readRegions(stream
)) {
116 _errorString
= "Error reading tile ranges";
119 if (!computeBounds()) {
120 _errorString
= "Invalid map area";
129 qreal
GEMFMap::resolution(const QRectF
&rect
)
131 return OSM::resolution(rect
.center(), _zooms
.at(_zi
).level
, _tileSize
);
134 int GEMFMap::zoomFit(const QSize
&size
, const RectC
&rect
)
137 _zi
= _zooms
.size() - 1;
139 QRectF
tbr(OSM::ll2m(rect
.topLeft()), OSM::ll2m(rect
.bottomRight()));
140 QPointF
sc(tbr
.width() / size
.width(), tbr
.height() / size
.height());
141 int zoom
= OSM::scale2zoom(qMax(sc
.x(), -sc
.y()) / _mapRatio
,
145 for (int i
= 1; i
< _zooms
.size(); i
++) {
146 if (_zooms
.at(i
).level
> zoom
)
155 int GEMFMap::zoomIn()
157 _zi
= qMin(_zi
+ 1, _zooms
.size() - 1);
161 int GEMFMap::zoomOut()
163 _zi
= qMax(_zi
- 1, 0);
167 QRectF
GEMFMap::bounds()
169 return QRectF(ll2xy(_bounds
.topLeft()), ll2xy(_bounds
.bottomRight()));
172 QPointF
GEMFMap::ll2xy(const Coordinates
&c
)
174 qreal scale
= OSM::zoom2scale(_zooms
.at(_zi
).level
, _tileSize
);
175 QPointF m
= OSM::ll2m(c
);
176 return QPointF(m
.x() / scale
, m
.y() / -scale
) / _mapRatio
;
179 Coordinates
GEMFMap::xy2ll(const QPointF
&p
)
181 qreal scale
= OSM::zoom2scale(_zooms
.at(_zi
).level
, _tileSize
);
182 return OSM::m2ll(QPointF(p
.x() * scale
, -p
.y() * scale
) * _mapRatio
);
185 void GEMFMap::load(const Projection
&in
, const Projection
&out
,
186 qreal deviceRatio
, bool hidpi
)
191 _mapRatio
= hidpi
? deviceRatio
: 1.0;
192 _file
.open(QIODevice::ReadOnly
);
195 void GEMFMap::unload()
200 qreal
GEMFMap::tileSize() const
202 return (_tileSize
/ _mapRatio
);
205 QByteArray
GEMFMap::tileData(const QPoint
&tile
)
207 const Zoom
&z
= _zooms
.at(_zi
);
209 for(int i
= 0; i
< z
.ranges
.size(); i
++) {
210 const Region
&r
= z
.ranges
.at(i
);
211 QRect
rect(QPoint(r
.minX
, r
.minY
), QPoint(r
.maxX
, r
.maxY
));
213 if (rect
.contains(tile
)) {
214 quint32 x
= tile
.x() - r
.minX
;
215 quint32 y
= tile
.y() - r
.minY
;
216 quint32 idx
= x
* (r
.maxY
+ 1 - r
.minY
) + y
;
217 quint64 offset
= idx
* 12;
221 if (!_file
.seek(offset
+ r
.offset
))
223 QDataStream
stream(&_file
);
224 stream
>> address
>> size
;
225 if (stream
.status() != QDataStream::Ok
)
228 if (!_file
.seek(address
))
233 return (_file
.read(data
.data(), data
.size()) == size
)
234 ? data
: QByteArray();
241 void GEMFMap::draw(QPainter
*painter
, const QRectF
&rect
, Flags flags
)
244 const Zoom
&z
= _zooms
.at(_zi
);
245 qreal scale
= OSM::zoom2scale(z
.level
, _tileSize
);
249 QPoint tile
= OSM::mercator2tile(QPointF(rect
.topLeft().x() * scale
,
250 -rect
.topLeft().y() * scale
) * _mapRatio
, z
.level
);
251 QPointF
tl(floor(rect
.left() / tileSize())
252 * tileSize(), floor(rect
.top() / tileSize()) * tileSize());
254 QSizeF
s(qMin(rect
.right() - tl
.x(), b
.width()),
255 qMin(rect
.bottom() - tl
.y(), b
.height()));
256 int width
= ceil(s
.width() / tileSize());
257 int height
= ceil(s
.height() / tileSize());
260 QList
<RenderTile
> tiles
;
262 for (int i
= 0; i
< width
; i
++) {
263 for (int j
= 0; j
< height
; j
++) {
265 QPoint
t(tile
.x() + i
, tile
.y() + j
);
266 QString key
= path() + "-" + QString::number(z
.level
) + "_"
267 + QString::number(t
.x()) + "_" + QString::number(t
.y());
269 if (QPixmapCache::find(key
, &pm
)) {
270 QPointF
tp(qMax(tl
.x(), b
.left()) + (t
.x() - tile
.x())
271 * tileSize(), qMax(tl
.y(), b
.top()) + (t
.y() - tile
.y())
273 drawTile(painter
, pm
, tp
);
275 tiles
.append(RenderTile(t
, tileData(t
), key
));
280 QFuture
<void> future
= QtConcurrent::map(tiles
, &RenderTile::load
);
281 future
.waitForFinished();
283 for (int i
= 0; i
< tiles
.size(); i
++) {
284 const RenderTile
&mt
= tiles
.at(i
);
285 QPixmap
pm(mt
.pixmap());
289 QPixmapCache::insert(mt
.key(), pm
);
291 QPointF
tp(qMax(tl
.x(), b
.left()) + (mt
.xy().x() - tile
.x())
292 * tileSize(), qMax(tl
.y(), b
.top()) + (mt
.xy().y() - tile
.y())
294 drawTile(painter
, pm
, tp
);
298 void GEMFMap::drawTile(QPainter
*painter
, QPixmap
&pixmap
, QPointF
&tp
)
300 pixmap
.setDevicePixelRatio(_mapRatio
);
301 painter
->drawPixmap(tp
, pixmap
);
304 Map
*GEMFMap::create(const QString
&path
, bool *isDir
)
309 return new GEMFMap(path
);
313 QDebug
operator<<(QDebug dbg
, const GEMFMap::Region
®ion
)
315 dbg
.nospace() << "Region(" << QRect(QPoint(region
.minX
, region
.minY
),
316 QPoint(region
.maxX
, region
.maxY
)) << ", " << region
.offset
<< ")";
321 QDebug
operator<<(QDebug dbg
, const GEMFMap::Zoom
&zoom
)
323 dbg
.nospace() << "Zoom(" << zoom
.level
<< ", " << zoom
.ranges
<< ")";
327 #endif // QT_NO_DEBUG