8 #include <QImageReader>
9 #include <QPixmapCache>
13 #include "coordinates.h"
15 #include "offlinemap.h"
18 int OfflineMap::parseMapFile(QIODevice
&device
, QList
<ReferencePoint
> &points
)
24 if (!device
.open(QIODevice::ReadOnly
))
27 while (!device
.atEnd()) {
28 QByteArray line
= device
.readLine();
31 if (line
.trimmed() != "OziExplorer Map Data File Version 2.2")
34 _imgPath
= line
.trimmed();
36 QList
<QByteArray
> list
= line
.split(',');
37 QString
key(list
.at(0).trimmed());
39 if (key
.startsWith("Point") && list
.count() == 17
40 && !list
.at(2).trimmed().isEmpty()) {
41 int x
= list
.at(2).trimmed().toInt(&res
);
44 int y
= list
.at(3).trimmed().toInt(&res
);
47 int latd
= list
.at(6).trimmed().toInt(&res
);
50 qreal latm
= list
.at(7).trimmed().toFloat(&res
);
53 int lond
= list
.at(9).trimmed().toInt(&res
);
56 qreal lonm
= list
.at(10).trimmed().toFloat(&res
);
60 if (list
.at(8).trimmed() == "S")
62 if (list
.at(11).trimmed() == "W")
64 points
.append(QPair
<QPoint
, Coordinates
>(QPoint(x
, y
),
65 Coordinates(lond
+ lonm
/60.0, latd
+ latm
/60.0)));
66 } else if (key
== "IWH") {
67 int w
= list
.at(2).trimmed().toInt(&res
);
70 int h
= list
.at(3).trimmed().toInt(&res
);
83 bool OfflineMap::computeTransformation(const QList
<ReferencePoint
> &points
)
85 if (points
.count() < 2)
90 for (size_t j
= 0; j
< c
.w(); j
++) {
91 for (size_t k
= 0; k
< c
.h(); k
++) {
92 for (int i
= 0; i
< points
.size(); i
++) {
94 QPointF p
= points
.at(i
).second
.toMercator();
99 t
[0] = points
.at(i
).first
.x();
100 t
[1] = points
.at(i
).first
.y();
101 c
.m(k
,j
) += f
[k
] * t
[j
];
108 for (int qi
= 0; qi
< points
.size(); qi
++) {
110 QPointF p
= points
.at(qi
).second
.toMercator();
115 for (size_t i
= 0; i
< Q
.h(); i
++)
116 for (size_t j
= 0; j
< Q
.w(); j
++)
117 Q
.m(i
,j
) += v
[i
] * v
[j
];
120 Matrix M
= Q
.augemented(c
);
124 _transform
= QTransform(M
.m(0,3), M
.m(1,3), M
.m(0,4), M
.m(1,4),
130 bool OfflineMap::computeResolution(QList
<ReferencePoint
> &points
)
132 if (points
.count() < 2)
135 int maxLon
= 0, minLon
= 0, maxLat
= 0, minLat
= 0;
136 qreal dLon
, pLon
, dLat
, pLat
;
138 for (int i
= 1; i
< points
.size(); i
++) {
139 if (points
.at(i
).second
.lon() < points
.at(minLon
).second
.lon())
141 if (points
.at(i
).second
.lon() > points
.at(maxLon
).second
.lon())
143 if (points
.at(i
).second
.lat() < points
.at(minLat
).second
.lon())
145 if (points
.at(i
).second
.lat() > points
.at(maxLat
).second
.lon())
149 dLon
= points
.at(minLon
).second
.distanceTo(points
.at(maxLon
).second
);
150 pLon
= QLineF(points
.at(minLon
).first
, points
.at(maxLon
).first
).length();
151 dLat
= points
.at(minLat
).second
.distanceTo(points
.at(maxLat
).second
);
152 pLat
= QLineF(points
.at(minLat
).first
, points
.at(maxLat
).first
).length();
154 _resolution
= (dLon
/pLon
+ dLat
/pLat
) / 2.0;
159 bool OfflineMap::getImageInfo(const QString
&path
)
161 QFileInfo
ii(_imgPath
);
163 _imgPath
= path
+ "/" + _imgPath
;
165 QImageReader
img(_imgPath
);
167 if (!_size
.isValid()) {
168 qWarning("%s: %s: error reading map image", qPrintable(_name
),
169 qPrintable(ii
.absoluteFilePath()));
176 bool OfflineMap::getTileInfo(const QStringList
&tiles
, const QString
&path
)
178 if (!_size
.isValid()) {
179 qWarning("%s: missing total image size (IWH)", qPrintable(_name
));
183 if (tiles
.isEmpty()) {
184 qWarning("%s: empty tile set", qPrintable(_name
));
188 QRegExp
rx("_[0-9]+_[0-9]+\\.");
189 for (int i
= 0; i
< tiles
.size(); i
++) {
190 if (tiles
.at(i
).contains(rx
)) {
191 _tileName
= QString(tiles
.at(i
)).replace(rx
, "_%1_%2.");
194 QByteArray ba
= _tar
.file(tiles
.at(i
));
196 _tileSize
= QImageReader(&buffer
).size();
198 _tileName
= path
+ "/" + _tileName
;
199 _tileSize
= QImageReader(path
+ "/" + tiles
.at(i
)).size();
201 if (!_tileSize
.isValid()) {
202 qWarning("%s: error retrieving tile size: %s: invalid image",
203 qPrintable(_name
), qPrintable(QFileInfo(tiles
.at(i
))
212 qWarning("%s: invalid tile names", qPrintable(_name
));
217 OfflineMap::OfflineMap(const QString
&path
, QObject
*parent
) : Map(parent
)
220 QList
<ReferencePoint
> points
;
226 _name
= fi
.fileName();
229 QFileInfoList mapFiles
= dir
.entryInfoList(QDir::Files
);
230 for (int i
= 0; i
< mapFiles
.count(); i
++) {
231 const QString
&fileName
= mapFiles
.at(i
).fileName();
232 if (fileName
.endsWith(".tar")) {
233 if (!_tar
.load(mapFiles
.at(i
).absoluteFilePath())) {
234 qWarning("%s: %s: error loading tar file", qPrintable(_name
),
235 qPrintable(fileName
));
238 QStringList tarFiles
= _tar
.files();
239 for (int j
= 0; j
< tarFiles
.size(); j
++) {
240 if (tarFiles
.at(j
).endsWith(".map")) {
241 QByteArray ba
= _tar
.file(tarFiles
.at(j
));
243 errorLine
= parseMapFile(buffer
, points
);
248 } else if (fileName
.endsWith(".map")) {
249 QFile
mapFile(mapFiles
.at(i
).absoluteFilePath());
250 errorLine
= parseMapFile(mapFile
, points
);
256 qWarning("%s: no map file found", qPrintable(_name
));
257 else if (errorLine
== -1)
258 qWarning("%s: error opening map file", qPrintable(_name
));
260 qWarning("%s: map file parse error on line: %d", qPrintable(_name
),
265 if (!computeTransformation(points
)) {
266 qWarning("%s: error computing map transformation", qPrintable(_name
));
269 computeResolution(points
);
272 if (!getTileInfo(_tar
.files()))
275 QDir
set(fi
.absoluteFilePath() + "/" + "set");
277 if (!getTileInfo(set
.entryList(), set
.absolutePath()))
280 if (!getImageInfo(fi
.absoluteFilePath()))
289 void OfflineMap::load()
291 if (_tileSize
.isValid())
294 _img
= new QImage(_imgPath
);
296 qWarning("%s: error loading map image", qPrintable(_imgPath
));
299 void OfflineMap::unload()
305 QRectF
OfflineMap::bounds() const
307 return QRectF(QPointF(0, 0), _size
);
310 qreal
OfflineMap::zoomFit(const QSize
&size
, const QRectF
&br
)
318 qreal
OfflineMap::resolution(const QPointF
&p
) const
325 qreal
OfflineMap::zoomIn()
330 qreal
OfflineMap::zoomOut()
335 void OfflineMap::draw(QPainter
*painter
, const QRectF
&rect
)
337 if (_tileSize
.isValid()) {
338 QPoint tl
= QPoint((int)floor(rect
.left() / (qreal
)_tileSize
.width())
339 * _tileSize
.width(), (int)floor(rect
.top() / _tileSize
.height())
340 * _tileSize
.height());
342 QSizeF
s(rect
.right() - tl
.x(), rect
.bottom() - tl
.y());
343 for (int i
= 0; i
< ceil(s
.width() / _tileSize
.width()); i
++) {
344 for (int j
= 0; j
< ceil(s
.height() / _tileSize
.height()); j
++) {
345 int x
= tl
.x() + i
* _tileSize
.width();
346 int y
= tl
.y() + j
* _tileSize
.height();
347 QString
tileName(_tileName
.arg(QString::number(x
),
348 QString::number(y
)));
352 QString key
= _tar
.fileName() + "/" + tileName
;
353 if (!QPixmapCache::find(key
, &pixmap
)) {
354 QByteArray ba
= _tar
.file(tileName
);
355 pixmap
= QPixmap::fromImage(QImage::fromData(ba
));
356 QPixmapCache::insert(key
, pixmap
);
359 pixmap
= QPixmap(tileName
);
361 if (pixmap
.isNull()) {
362 qWarning("%s: error loading tile image", qPrintable(
363 _tileName
.arg(QString::number(x
), QString::number(y
))));
364 painter
->fillRect(QRectF(QPoint(x
, y
), _tileSize
),
367 painter
->drawPixmap(QPoint(x
, y
), pixmap
);
372 painter
->fillRect(rect
, Qt::white
);
374 QPoint p
= rect
.topLeft().toPoint();
375 QImage crop
= _img
->copy(QRect(p
, rect
.size().toSize()));
376 painter
->drawImage(rect
.topLeft(), crop
);
381 QPointF
OfflineMap::ll2xy(const Coordinates
&c
) const
383 return _transform
.map(c
.toMercator());
386 Coordinates
OfflineMap::xy2ll(const QPointF
&p
) const
388 return Coordinates::fromMercator(_transform
.inverted().map(p
));