2 #include <QtAlgorithms>
4 #include "common/rectc.h"
5 #include "offlinemap.h"
10 #define ZOOM_THRESHOLD 0.9
12 #define TL(m) ((m)->xy2pp((m)->bounds().topLeft()))
13 #define BR(m) ((m)->xy2pp((m)->bounds().bottomRight()))
15 static bool resCmp(OfflineMap
*m1
, OfflineMap
*m2
)
19 r1
= m1
->resolution(m1
->bounds());
20 r2
= m2
->resolution(m2
->bounds());
25 static bool xCmp(const OfflineMap
*m1
, const OfflineMap
*m2
)
27 return TL(m1
).x() < TL(m2
).x();
30 static bool yCmp(const OfflineMap
*m1
, const OfflineMap
*m2
)
32 return TL(m1
).y() > TL(m2
).y();
35 void Atlas::computeZooms()
37 qSort(_maps
.begin(), _maps
.end(), resCmp
);
39 _zooms
.append(Zoom(0, _maps
.count() - 1));
40 for (int i
= 1; i
< _maps
.count(); i
++) {
41 qreal last
= _maps
.at(i
-1)->resolution(_maps
.at(i
)->bounds());
42 qreal cur
= _maps
.at(i
)->resolution(_maps
.at(i
)->bounds());
43 if (cur
< last
* ZOOM_THRESHOLD
) {
44 _zooms
.last().last
= i
-1;
45 _zooms
.append(Zoom(i
, _maps
.count() - 1));
50 void Atlas::computeBounds()
52 QList
<QPointF
> offsets
;
54 for (int i
= 0; i
< _maps
.count(); i
++)
55 offsets
.append(QPointF());
57 for (int z
= 0; z
< _zooms
.count(); z
++) {
59 for (int i
= _zooms
.at(z
).first
; i
<= _zooms
.at(z
).last
; i
++)
60 m
.append(_maps
.at(i
));
62 qSort(m
.begin(), m
.end(), xCmp
);
63 offsets
[_maps
.indexOf(m
.first())].setX(0);
64 for (int i
= 1; i
< m
.size(); i
++) {
65 qreal w
= round(m
.first()->pp2xy(TL(m
.at(i
))).x());
66 offsets
[_maps
.indexOf(m
.at(i
))].setX(w
);
69 qSort(m
.begin(), m
.end(), yCmp
);
70 offsets
[_maps
.indexOf(m
.first())].setY(0);
71 for (int i
= 1; i
< m
.size(); i
++) {
72 qreal h
= round(m
.first()->pp2xy(TL(m
.at(i
))).y());
73 offsets
[_maps
.indexOf(m
.at(i
))].setY(h
);
77 for (int i
= 0; i
< _maps
.count(); i
++)
78 _bounds
.append(Bounds(RectD(TL(_maps
.at(i
)), BR(_maps
.at(i
))),
79 QRectF(offsets
.at(i
), _maps
.at(i
)->bounds().size())));
82 Atlas::Atlas(const QString
&fileName
, QObject
*parent
)
83 : Map(parent
), _zoom(0), _mapIndex(-1), _valid(false)
85 QFileInfo
fi(fileName
);
87 QString suffix
= fi
.suffix().toLower();
91 _name
= fi
.dir().dirName();
93 if (suffix
== "tar") {
95 _errorString
= "Error reading tar file";
98 QString tbaFileName
= fi
.completeBaseName() + ".tba";
99 ba
= tar
.file(tbaFileName
);
100 } else if (suffix
== "tba") {
101 QFile
tbaFile(fileName
);
102 if (!tbaFile
.open(QIODevice::ReadOnly
)) {
103 _errorString
= QString("Error opening tba file: %1")
104 .arg(tbaFile
.errorString());
107 ba
= tbaFile
.readAll();
109 if (!ba
.startsWith("Atlas 1.0")) {
110 _errorString
= "Missing or invalid tba file";
114 QDir
dir(fi
.absolutePath());
115 QFileInfoList layers
= dir
.entryInfoList(QDir::Dirs
| QDir::NoDotAndDotDot
);
116 for (int n
= 0; n
< layers
.count(); n
++) {
117 QDir
zdir(layers
.at(n
).absoluteFilePath());
118 QFileInfoList maps
= zdir
.entryInfoList(QDir::Dirs
119 | QDir::NoDotAndDotDot
);
120 for (int i
= 0; i
< maps
.count(); i
++) {
121 QString mapFile
= maps
.at(i
).absoluteFilePath() + "/"
122 + maps
.at(i
).fileName() + ".map";
126 map
= new OfflineMap(mapFile
, tar
, this);
128 map
= new OfflineMap(mapFile
, this);
133 _errorString
= QString("Error loading map: %1: %2")
134 .arg(mapFile
, map
->errorString());
139 if (_maps
.isEmpty()) {
140 _errorString
= "No maps found in atlas";
150 QRectF
Atlas::bounds() const
154 for (int i
= _zooms
.at(_zoom
).first
; i
<= _zooms
.at(_zoom
).last
; i
++) {
155 if (_bounds
.at(i
).xy
.right() > s
.width())
156 s
.setWidth(_bounds
.at(i
).xy
.right());
157 if (_bounds
.at(i
).xy
.bottom() > s
.height())
158 s
.setHeight(_bounds
.at(i
).xy
.bottom());
161 return QRectF(QPointF(0, 0), s
);
164 int Atlas::zoomFit(const QSize
&size
, const RectC
&br
)
170 _zoom
= _zooms
.size() - 1;
174 for (int z
= 0; z
< _zooms
.count(); z
++) {
175 for (int i
= _zooms
.at(z
).first
; i
<= _zooms
.at(z
).last
; i
++) {
176 if (!_bounds
.at(i
).pp
.contains(_maps
.at(i
)->ll2pp(br
.center())))
179 QRect sbr
= QRectF(_maps
.at(i
)->ll2xy(br
.topLeft()),
180 _maps
.at(i
)->ll2xy(br
.bottomRight())).toRect().normalized();
182 if (sbr
.size().width() > size
.width()
183 || sbr
.size().height() > size
.height())
194 void Atlas::setZoom(int zoom
)
202 _zoom
= qMin(_zoom
+ 1, _zooms
.size() - 1);
210 _zoom
= qMax(_zoom
- 1, 0);
216 QPointF
Atlas::ll2xy(const Coordinates
&c
)
221 pp
= _maps
.at(_mapIndex
)->ll2pp(c
);
222 if (_mapIndex
< 0 || !_bounds
.at(_mapIndex
).pp
.contains(pp
)) {
223 _mapIndex
= _zooms
.at(_zoom
).first
;
224 for (int i
= _zooms
.at(_zoom
).first
; i
<= _zooms
.at(_zoom
).last
; i
++) {
225 pp
= _maps
.at(i
)->ll2pp(c
);
226 if (_bounds
.at(i
).pp
.contains(pp
)) {
233 QPointF p
= _maps
.at(_mapIndex
)->pp2xy(pp
);
234 return p
+ _bounds
.at(_mapIndex
).xy
.topLeft();
237 Coordinates
Atlas::xy2ll(const QPointF
&p
)
239 int idx
= _zooms
.at(_zoom
).first
;
241 for (int i
= _zooms
.at(_zoom
).first
; i
<= _zooms
.at(_zoom
).last
; i
++) {
242 if (_bounds
.at(i
).xy
.contains(p
)) {
248 QPointF p2
= p
- _bounds
.at(idx
).xy
.topLeft();
249 return _maps
.at(idx
)->xy2ll(p2
);
252 void Atlas::draw(QPainter
*painter
, const QRectF
&rect
, bool block
)
257 for (int i
= _zooms
.at(_zoom
).first
; i
<= _zooms
.at(_zoom
).last
; i
++) {
258 if (_bounds
.at(i
).xy
.contains(rect
)) {
259 draw(painter
, rect
, i
);
265 for (int i
= _zooms
.at(_zoom
).first
; i
<= _zooms
.at(_zoom
).last
; i
++) {
266 QRectF ir
= rect
.intersected(_bounds
.at(i
).xy
);
268 draw(painter
, ir
, i
);
272 void Atlas::draw(QPainter
*painter
, const QRectF
&rect
, int mapIndex
)
274 OfflineMap
*map
= _maps
.at(mapIndex
);
275 const QPointF offset
= _bounds
.at(mapIndex
).xy
.topLeft();
276 QRectF pr
= QRectF(rect
.topLeft() - offset
, rect
.size());
280 painter
->translate(offset
);
281 map
->draw(painter
, pr
, true);
282 painter
->translate(-offset
);
287 for (int i
= 0; i
< _maps
.count(); i
++)
288 _maps
.at(i
)->unload();
291 bool Atlas::isAtlas(const QString
&path
)
294 QString suffix
= fi
.suffix().toLower();
297 if (suffix
== "tar") {
300 QString tbaFileName
= fi
.completeBaseName() + ".tba";
301 return tar
.contains(tbaFileName
);
302 } else if (suffix
== "tba")