Silenced some more clazy warnings
[GPXSee.git] / src / map / ozimap.cpp
blob68852f1a0cba874cee8ca0311fca52dc39655ec3
1 #include <QPainter>
2 #include <QFileInfo>
3 #include <QMap>
4 #include <QDir>
5 #include <QBuffer>
6 #include <QImageReader>
7 #include <QPixmapCache>
8 #include <QRegularExpression>
9 #include "common/coordinates.h"
10 #include "common/rectc.h"
11 #include "tar.h"
12 #include "ozf.h"
13 #include "image.h"
14 #include "mapfile.h"
15 #include "gmifile.h"
16 #include "rectd.h"
17 #include "ozimap.h"
20 static QString tarFile(const QString &path)
22 QDir dir(path);
23 QFileInfoList files = dir.entryInfoList(QDir::Files);
25 for (int i = 0; i < files.size(); i++) {
26 const QFileInfo &fi = files.at(i);
28 if (fi.suffix().toLower() == "tar")
29 return fi.absoluteFilePath();
32 return QString();
35 QString OziMap::calibrationFile(const QStringList &files, const QString path,
36 CalibrationType &type)
38 for (int i = 0; i < files.size(); i++) {
39 QFileInfo fi(files.at(i));
40 QString suffix(fi.suffix().toLower());
42 if (path.endsWith(fi.path())) {
43 if (suffix == "map") {
44 type = MAP;
45 return files.at(i);
46 } else if (suffix == "gmi") {
47 type = GMI;
48 return files.at(i);
53 type = Unknown;
54 return QString();
57 OziMap::OziMap(const QString &fileName, CalibrationType type,
58 const Projection &proj, QObject *parent) : Map(fileName, parent), _img(0),
59 _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0), _valid(false)
61 // TAR maps
62 if (type == Unknown) {
63 _tar = new Tar(fileName);
64 if (!_tar->open()) {
65 _errorString = _tar->errorString();
66 return;
68 QStringList files(_tar->files());
69 QString cf(calibrationFile(files, ".", type));
71 if (type == GMI) {
72 QByteArray ba(_tar->file(cf));
73 QBuffer buffer(&ba);
74 GmiFile gmi(buffer);
75 if (!gmi.isValid()) {
76 _errorString = gmi.errorString();
77 return;
78 } else {
79 _name = Util::file2name(fileName);
80 _map.size = gmi.size();
81 _map.path = gmi.image();
82 _calibrationPoints = gmi.calibrationPoints();
83 _projection = proj;
84 computeTransform();
86 } else if (type == MAP) {
87 QByteArray ba(_tar->file(cf));
88 QBuffer buffer(&ba);
89 MapFile mf(buffer);
90 if (!mf.isValid()) {
91 _errorString = mf.errorString();
92 return;
93 } else {
94 _name = mf.name();
95 _map.size = mf.size();
96 _map.path = mf.image();
97 _projection = mf.projection();
98 _transform = mf.transform();
100 } else {
101 _errorString = "No calibration file found";
102 return;
105 if (!setTileInfo(files))
106 return;
108 _tar->close();
110 // regular MAP or GMI maps
111 } else {
112 QFile file(fileName);
114 if (type == MAP) {
115 MapFile mf(file);
116 if (!mf.isValid()) {
117 _errorString = mf.errorString();
118 return;
119 } else {
120 _name = mf.name();
121 _map.size = mf.size();
122 _map.path = mf.image();
123 _projection = mf.projection();
124 _transform = mf.transform();
126 } else if (type == GMI) {
127 GmiFile gmi(file);
128 if (!gmi.isValid()) {
129 _errorString = gmi.errorString();
130 return;
131 } else {
132 _name = Util::file2name(fileName);
133 _map.size = gmi.size();
134 _map.path = gmi.image();
135 _calibrationPoints = gmi.calibrationPoints();
136 _projection = proj;
137 computeTransform();
141 QFileInfo fi(fileName);
142 QDir set(fi.absolutePath() + "/" + "set");
143 if (set.exists()) {
144 if (!setTileInfo(set.entryList(), set.absolutePath()))
145 return;
146 } else {
147 if (!setImageInfo(fi.absolutePath()))
148 return;
152 _valid = true;
155 OziMap::OziMap(const QString &dirName, Tar &tar, const Projection &proj,
156 QObject *parent) : Map(dirName, parent), _img(0), _tar(0), _ozf(0), _zoom(0),
157 _mapRatio(1.0), _valid(false)
159 CalibrationType type;
160 QString cf(calibrationFile(tar.files(), dirName, type));
162 if (type == MAP) {
163 QByteArray ba = tar.file(cf);
164 QBuffer buffer(&ba);
165 MapFile mf(buffer);
166 if (!mf.isValid()) {
167 _errorString = mf.errorString();
168 return;
171 _name = mf.name();
172 _map.size = mf.size();
173 _projection = mf.projection();
174 _transform = mf.transform();
175 } else if (type == GMI) {
176 QByteArray ba = tar.file(cf);
177 QBuffer buffer(&ba);
178 GmiFile gmi(buffer);
179 if (!gmi.isValid()) {
180 _errorString = gmi.errorString();
181 return;
184 _name = Util::file2name(cf);
185 _map.size = gmi.size();
186 _calibrationPoints = gmi.calibrationPoints();
187 _projection = proj;
188 computeTransform();
189 } else {
190 _errorString = "No calibration file found";
191 return;
194 QString tf(tarFile(dirName));
195 if (tf.isNull()) {
196 _errorString = "No map tar file found";
197 return;
199 _tar = new Tar(tf);
200 if (!_tar->open()) {
201 _errorString = _tar->fileName() + ": " + _tar->errorString();
202 return;
204 if (!setTileInfo(_tar->files())) {
205 _errorString = _tar->fileName() + ": " + _errorString;
206 return;
208 _tar->close();
210 _valid = true;
213 OziMap::~OziMap()
215 delete _img;
216 delete _tar;
217 delete _ozf;
220 bool OziMap::setImageInfo(const QString &path)
222 QFileInfo ii(_map.path);
224 if (ii.isRelative())
225 ii.setFile(path + "/" + _map.path);
227 if (!ii.exists()) {
228 int last = _map.path.lastIndexOf('\\');
229 if (last >= 0 && last < _map.path.length() - 1) {
230 QString fn(_map.path.mid(last + 1, _map.path.length() - last - 1));
231 ii.setFile(path + "/" + fn);
235 if (ii.exists())
236 _map.path = ii.absoluteFilePath();
237 else {
238 _errorString = QString("%1: No such image file").arg(_map.path);
239 return false;
242 if (OZF::isOZF(_map.path)) {
243 _ozf = new OZF(_map.path);
244 if (!_ozf->open()) {
245 _errorString = QString("%1: %2").arg(_map.path, _ozf->errorString());
246 return false;
248 _scale = _ozf->scale(_zoom);
249 _ozf->close();
250 } else {
251 QImageReader ir(_map.path);
252 if (!ir.canRead()) {
253 _errorString = QString("%1: Unsupported/invalid image file")
254 .arg(_map.path);
255 return false;
257 _map.size = ir.size();
260 return true;
263 bool OziMap::setTileInfo(const QStringList &tiles, const QString &path)
265 static const QRegularExpression rx("_[0-9]+_[0-9]+\\.");
267 if (!_map.size.isValid()) {
268 _errorString = "Missing total image size (IWH)";
269 return false;
272 for (int i = 0; i < tiles.size(); i++) {
273 const QString &tile = tiles.at(i);
275 if (tile.startsWith("set/") && tile.contains(rx)) {
276 _tile.path = QString(tile).replace(rx, "_%1_%2.");
278 if (_tar) {
279 QByteArray ba(_tar->file(tile));
280 QBuffer buffer(&ba);
281 _tile.size = QImageReader(&buffer).size();
282 } else {
283 _tile.path = path + "/" + _tile.path;
284 _tile.size = QImageReader(path + "/" + tile).size();
286 if (!_tile.size.isValid()) {
287 _errorString = QString("Error retrieving tile size: "
288 "%1: Invalid image").arg(QFileInfo(tile).fileName());
289 return false;
292 _map.path = QString();
293 return true;
297 _errorString = "Invalid/missing tile set";
298 return false;
301 void OziMap::load(const Projection &in, const Projection &out,
302 qreal deviceRatio, bool hidpi)
304 Q_UNUSED(out);
306 _mapRatio = hidpi ? deviceRatio : 1.0;
307 if (!_calibrationPoints.isEmpty()) {
308 _projection = in;
309 computeTransform();
312 if (_tar) {
313 Q_ASSERT(!_tar->isOpen());
314 if (!_tar->open()) {
315 qWarning("%s: %s", qPrintable(_tar->fileName()),
316 qPrintable(_tar->errorString()));
317 return;
320 if (_ozf) {
321 Q_ASSERT(!_ozf->isOpen());
322 if (!_ozf->open()) {
323 qWarning("%s: %s", qPrintable(_ozf->fileName()),
324 qPrintable(_ozf->errorString()));
325 return;
328 if (!_tile.isValid() && !_ozf) {
329 Q_ASSERT(!_img);
330 _img = new Image(_map.path);
331 _img->setDevicePixelRatio(_mapRatio);
335 void OziMap::unload()
337 delete _img;
338 _img = 0;
340 if (_tar && _tar->isOpen())
341 _tar->close();
343 if (_ozf && _ozf->isOpen())
344 _ozf->close();
347 void OziMap::drawTiled(QPainter *painter, const QRectF &rect) const
349 QSizeF ts(_tile.size.width() / _mapRatio, _tile.size.height() / _mapRatio);
350 QPointF tl(floor(rect.left() / ts.width()) * ts.width(),
351 floor(rect.top() / ts.height()) * ts.height());
353 QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
354 for (int i = 0; i < ceil(s.width() / ts.width()); i++) {
355 for (int j = 0; j < ceil(s.height() / ts.height()); j++) {
356 int x = round(tl.x() * _mapRatio + i * _tile.size.width());
357 int y = round(tl.y() * _mapRatio + j * _tile.size.height());
359 QString tileName(_tile.path.arg(QString::number(x),
360 QString::number(y)));
361 QPixmap pixmap;
363 if (_tar) {
364 QString key = _tar->fileName() + "/" + tileName;
365 if (!QPixmapCache::find(key, &pixmap)) {
366 QByteArray ba = _tar->file(tileName);
367 pixmap = QPixmap::fromImage(QImage::fromData(ba));
368 if (!pixmap.isNull())
369 QPixmapCache::insert(key, pixmap);
371 } else
372 pixmap = QPixmap(tileName);
374 if (pixmap.isNull())
375 qWarning("%s: error loading tile image", qPrintable(tileName));
376 else {
377 pixmap.setDevicePixelRatio(_mapRatio);
378 QPointF tp(tl.x() + i * ts.width(), tl.y() + j * ts.height());
379 painter->drawPixmap(tp, pixmap);
385 void OziMap::drawOZF(QPainter *painter, const QRectF &rect) const
387 QSizeF ts(_ozf->tileSize().width() / _mapRatio, _ozf->tileSize().height()
388 / _mapRatio);
389 QPointF tl(floor(rect.left() / ts.width()) * ts.width(),
390 floor(rect.top() / ts.height()) * ts.height());
392 QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
393 for (int i = 0; i < ceil(s.width() / ts.width()); i++) {
394 for (int j = 0; j < ceil(s.height() / ts.height()); j++) {
395 int x = round(tl.x() * _mapRatio + i * _ozf->tileSize().width());
396 int y = round(tl.y() * _mapRatio + j * _ozf->tileSize().height());
398 QPixmap pixmap;
399 QString key(_ozf->fileName() + "/" + QString::number(_zoom) + "_"
400 + QString::number(x) + "_" + QString::number(y));
402 if (!QPixmapCache::find(key, &pixmap)) {
403 pixmap = _ozf->tile(_zoom, x, y);
404 if (!pixmap.isNull())
405 QPixmapCache::insert(key, pixmap);
408 if (pixmap.isNull())
409 qWarning("%s: error loading tile image", qPrintable(key));
410 else {
411 pixmap.setDevicePixelRatio(_mapRatio);
412 QPointF tp(tl.x() + i * ts.width(), tl.y() + j * ts.height());
413 painter->drawPixmap(tp, pixmap);
419 void OziMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
421 Q_UNUSED(flags);
423 if (_ozf)
424 drawOZF(painter, rect);
425 else if (_img)
426 _img->draw(painter, rect, flags);
427 else if (_tile.isValid())
428 drawTiled(painter, rect);
431 QPointF OziMap::ll2xy(const Coordinates &c)
433 QPointF p(_transform.proj2img(_projection.ll2xy(c)));
434 return _ozf
435 ? QPointF(p.x() * _scale.x(), p.y() * _scale.y()) / _mapRatio
436 : p / _mapRatio;
439 Coordinates OziMap::xy2ll(const QPointF &p)
441 return _ozf
442 ? _projection.xy2ll(_transform.img2proj(QPointF(p.x() / _scale.x(),
443 p.y() / _scale.y()) * _mapRatio))
444 : _projection.xy2ll(_transform.img2proj(p * _mapRatio));
447 QRectF OziMap::bounds()
449 return _ozf
450 ? QRectF(QPointF(0, 0), _ozf->size(_zoom) / _mapRatio)
451 : QRectF(QPointF(0, 0), _map.size / _mapRatio);
454 int OziMap::zoomFit(const QSize &size, const RectC &rect)
456 if (!_ozf)
457 return _zoom;
459 if (!rect.isValid())
460 rescale(0);
461 else {
462 RectD prect(rect, _projection);
463 QRectF sbr(_transform.proj2img(prect.topLeft()),
464 _transform.proj2img(prect.bottomRight()));
466 for (int i = 0; i < _ozf->zooms(); i++) {
467 rescale(i);
468 if (sbr.size().width() * _scale.x() <= size.width()
469 && sbr.size().height() * _scale.y() <= size.height())
470 break;
474 return _zoom;
477 int OziMap::zoomIn()
479 if (_ozf)
480 rescale(qMax(_zoom - 1, 0));
482 return _zoom;
485 int OziMap::zoomOut()
487 if (_ozf)
488 rescale(qMin(_zoom + 1, _ozf->zooms() - 1));
490 return _zoom;
493 void OziMap::rescale(int zoom)
495 _zoom = zoom;
496 _scale = _ozf->scale(zoom);
499 void OziMap::computeTransform()
501 QList<ReferencePoint> rp;
503 for (int i = 0; i < _calibrationPoints.size(); i++)
504 rp.append(_calibrationPoints.at(i).rp(_projection));
506 _transform = Transform(rp);
509 Map *OziMap::createTAR(const QString &path, const Projection &proj, bool *isDir)
511 if (isDir)
512 *isDir = false;
514 return new OziMap(path, Unknown, proj);
517 Map *OziMap::createMAP(const QString &path, const Projection &proj, bool *isDir)
519 if (isDir)
520 *isDir = false;
522 return new OziMap(path, MAP, proj);
525 Map *OziMap::createGMI(const QString &path, const Projection &proj, bool *isDir)
527 if (isDir)
528 *isDir = false;
530 return new OziMap(path, GMI, proj);