From 172b2b1b143397c966ee317e75117e7614fae216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Thu, 7 Mar 2019 22:58:43 +0100 Subject: [PATCH] Improved rmap support --- gpxsee.pro | 3 +- src/map/color.h | 18 ++++++ src/map/maplist.cpp | 6 +- src/map/ozf.cpp | 15 ++--- src/map/rmap.cpp | 132 ++++++++++++++++++++++++++++++++++++-------- src/map/rmap.h | 2 + 6 files changed, 140 insertions(+), 36 deletions(-) create mode 100644 src/map/color.h diff --git a/gpxsee.pro b/gpxsee.pro index edd37ef6..23de0dfc 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -160,7 +160,8 @@ HEADERS += src/common/config.h \ src/map/obliquestereographic.h \ src/GUI/coordinatesitem.h \ src/map/rmap.h \ - src/map/calibrationpoint.h + src/map/calibrationpoint.h \ + src/map/color.h SOURCES += src/main.cpp \ src/common/coordinates.cpp \ src/common/rectc.cpp \ diff --git a/src/map/color.h b/src/map/color.h new file mode 100644 index 00000000..4ff60057 --- /dev/null +++ b/src/map/color.h @@ -0,0 +1,18 @@ +#ifndef COLOR_H +#define COLOR_H + +#include + +namespace Color +{ + inline QRgb bgr2rgb(quint32 bgr) + { + quint32 b = (bgr & 0x000000FF); + quint32 g = (bgr & 0x0000FF00) >> 8; + quint32 r = (bgr & 0x00FF0000) >> 16; + + return (0xFF000000 | r << 16 | g << 8 | b); + } +} + +#endif // COLOR_H diff --git a/src/map/maplist.cpp b/src/map/maplist.cpp index 97b2a7a4..9b0f1154 100644 --- a/src/map/maplist.cpp +++ b/src/map/maplist.cpp @@ -59,7 +59,7 @@ bool MapList::loadFile(const QString &path, bool *atlas, bool dir) map = new GeoTIFFMap(path, this); else if (suffix == "mbtiles") map = new MBTilesMap(path, this); - else if (suffix == "rmap") + else if (suffix == "rmap" || suffix == "rtmap") map = new RMap(path, this); else map = new OziMap(path, this); @@ -117,13 +117,13 @@ QString MapList::formats() { return tr("Supported files") - + " (*.jnx *.map *.mbtiles *.rmap *.tar *.tba *.tif *.tiff *.xml);;" + + " (*.jnx *.map *.mbtiles *.rmap *.rtmap *.tar *.tba *.tif *.tiff *.xml);;" + tr("MBTiles maps") + " (*.mbtiles);;" + tr("Garmin JNX maps") + " (*.jnx);;" + tr("OziExplorer maps") + " (*.map);;" + tr("TrekBuddy maps/atlases") + " (*.tar *.tba);;" + tr("GeoTIFF images") + " (*.tif *.tiff);;" - + tr("TwoNav maps") + " (*.rmap);;" + + tr("TwoNav maps") + " (*.rmap *.rtmap);;" + tr("Online map sources") + " (*.xml)"; } diff --git a/src/map/ozf.cpp b/src/map/ozf.cpp index e583a84e..47dfa635 100644 --- a/src/map/ozf.cpp +++ b/src/map/ozf.cpp @@ -1,6 +1,7 @@ #include #include #include +#include "color.h" #include "ozf.h" @@ -128,7 +129,7 @@ bool OZF::readHeaders() bool OZF::readTileTable() { - quint32 tableOffset, headerOffset, bgr0, w, h; + quint32 tableOffset, headerOffset, w, h; quint16 x, y; int zooms; @@ -164,15 +165,9 @@ bool OZF::readTileTable() zoom.palette = QVector(256); if (!read(&(zoom.palette[0]), sizeof(quint32) * 256)) return false; - for (int i = 0; i < zoom.palette.size(); i++) { - bgr0 = qFromLittleEndian(zoom.palette.at(i)); - - quint32 b = (bgr0 & 0x000000FF); - quint32 g = (bgr0 & 0x0000FF00) >> 8; - quint32 r = (bgr0 & 0x00FF0000) >> 16; - - zoom.palette[i] = 0xFF000000 | r << 16 | g << 8 | b; - } + for (int i = 0; i < zoom.palette.size(); i++) + zoom.palette[i] = Color::bgr2rgb(qFromLittleEndian( + zoom.palette.at(i))); zoom.tiles = QVector(zoom.dim.width() * zoom.dim.height() + 1); for (int i = 0; i < zoom.tiles.size(); i++) diff --git a/src/map/rmap.cpp b/src/map/rmap.cpp index ee427fe8..f307b6aa 100644 --- a/src/map/rmap.cpp +++ b/src/map/rmap.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "common/rectc.h" #include "common/wgs84.h" #include "common/config.h" @@ -10,6 +11,7 @@ #include "utm.h" #include "pcs.h" #include "rectd.h" +#include "color.h" #include "rmap.h" @@ -52,7 +54,7 @@ static Projection parseProjection(const QString &str, const GCS *gcs) int zone; switch (id) { - case 0: + case 0: // UTM if (fields.size() < 4) return Projection(); zone = fields.at(2).toInt(&ret); @@ -62,11 +64,43 @@ static Projection parseProjection(const QString &str, const GCS *gcs) zone = -zone; pcs = PCS(gcs, 9807, UTM::setup(zone), 9001); return Projection(&pcs); - case 1: + case 1: // LatLon return Projection(gcs); - case 2: + case 2: // Mercator pcs = PCS(gcs, 1024, Projection::Setup(), 9001); return Projection(&pcs); + case 3: // Transversal Mercator + if (fields.size() < 7) + return Projection(); + pcs = PCS(gcs, 9807, Projection::Setup(fields.at(3).toDouble(), + fields.at(2).toDouble(), fields.at(6).toDouble(), + fields.at(5).toDouble(), fields.at(4).toDouble(), + NAN, NAN), 9001); + return Projection(&pcs); + case 4: // Lambert 2SP + if (fields.size() < 8) + return Projection(); + pcs = PCS(gcs, 9802, Projection::Setup(fields.at(4).toDouble(), + fields.at(5).toDouble(), NAN, + fields.at(6).toDouble(), fields.at(7).toDouble(), + fields.at(3).toDouble(), fields.at(2).toDouble()), 9001); + return Projection(&pcs); + case 6: // BGN (British National Grid) + pcs = PCS(gcs, 9807, Projection::Setup(49, -2, 0.999601, 400000, + -100000, NAN, NAN), 9001); + return Projection(&pcs); + case 12: // France Lambert II etendu + pcs = PCS(gcs, 9801, Projection::Setup(52, 0, 0.99987742, 600000, + 2200000, NAN, NAN), 9001); + return Projection(&pcs); + case 14: // Swiss Grid + pcs = PCS(gcs, 9815, Projection::Setup(46.570866, 7.26225, 1.0, + 600000, 200000, 90.0, 90.0), 9001); + return Projection(&pcs); + case 184: // Swedish Grid + pcs = PCS(gcs, 9807, Projection::Setup(0, 15.808278, 1, 1500000, 0, + NAN, NAN), 9001); + return Projection(&pcs); default: return Projection(); } @@ -141,19 +175,45 @@ RMap::RMap(const QString &fileName, QObject *parent) return; } - quint32 tmp, width, height; - stream >> tmp >> tmp >> tmp; - stream >> width >> height; - QSize imageSize(width, -height); - stream >> tmp >> tmp; - stream >> width >> height; - _tileSize = QSize(width, height); + quint32 unknown, type, subtype, obfuscated, width, height, bpp, tileWidth, + tileHeight, paletteSize; quint64 IMPOffset; - stream >> IMPOffset; - stream >> tmp; + + stream >> type; + if (type > 5) + stream >> subtype >> obfuscated; + else + obfuscated = 0; + stream >> width >> height >> bpp >> unknown >> tileWidth >> tileHeight + >> IMPOffset >> paletteSize; + CHECK(stream.status() == QDataStream::Ok); + + if (!(type == 5 || (type >= 8 && type <= 10))) { + _errorString = QString::number(type) + ": unsupported map type"; + return; + } + if (obfuscated) { + _errorString = "Obfuscated maps not supported"; + return; + } + + QSize imageSize(width, -height); + _tileSize = QSize(tileWidth, tileHeight); + + if (paletteSize) { + quint32 bgr; + CHECK(paletteSize <= 256); + + _palette.resize(256); + for (int i = 0; i < (int)paletteSize; i++) { + stream >> bgr; + _palette[i] = Color::bgr2rgb(bgr); + } + } + qint32 zoomCount; stream >> zoomCount; - CHECK(stream.status() == QDataStream::Ok); + CHECK(stream.status() == QDataStream::Ok && zoomCount); QVector zoomOffsets(zoomCount); for (int i = 0; i < zoomCount; i++) @@ -183,7 +243,7 @@ RMap::RMap(const QString &fileName, QObject *parent) CHECK(file.seek(IMPOffset)); quint32 IMPSize; - stream >> tmp >> IMPSize; + stream >> unknown >> IMPSize; CHECK(stream.status() == QDataStream::Ok); QByteArray IMP(IMPSize + 1, 0); @@ -274,18 +334,46 @@ QPixmap RMap::tile(int x, int y) return QPixmap(); QDataStream stream(&_file); stream.setByteOrder(QDataStream::LittleEndian); - quint32 tag, len; - stream >> tag >> len; + quint32 tag; + stream >> tag; if (stream.status() != QDataStream::Ok) return QPixmap(); - QByteArray ba; - ba.resize(len); - if (stream.readRawData(ba.data(), ba.size()) != ba.size()) - return QPixmap(); + if (tag == 2) { + if (_palette.isEmpty()) + return QPixmap(); + quint32 width, height, size; + stream >> width >> height >> size; + QSize tileSize(width, -height); - QImage img(QImage::fromData(ba)); - return QPixmap::fromImage(img); + quint32 bes = qToBigEndian(tileSize.width() * tileSize.height()); + QByteArray ba; + ba.resize(sizeof(bes) + size); + memcpy(ba.data(), &bes, sizeof(bes)); + + if (stream.readRawData(ba.data() + sizeof(bes), size) != (int)size) + return QPixmap(); + QByteArray uba = qUncompress(ba); + if (uba.size() != tileSize.width() * tileSize.height()) + return QPixmap(); + QImage img((const uchar*)uba.constData(), tileSize.width(), + tileSize.height(), QImage::Format_Indexed8); + img.setColorTable(_palette); + + return QPixmap::fromImage(img); + } else if (tag == 7) { + quint32 len; + stream >> len; + + QByteArray ba; + ba.resize(len); + if (stream.readRawData(ba.data(), ba.size()) != ba.size()) + return QPixmap(); + + QImage img(QImage::fromData(ba)); + return QPixmap::fromImage(img); + } else + return QPixmap(); } void RMap::draw(QPainter *painter, const QRectF &rect, Flags flags) diff --git a/src/map/rmap.h b/src/map/rmap.h index 3cbf77de..3aa3ab79 100644 --- a/src/map/rmap.h +++ b/src/map/rmap.h @@ -2,6 +2,7 @@ #define RMAP_H #include +#include #include "map.h" #include "transform.h" #include "projection.h" @@ -54,6 +55,7 @@ private: qreal _mapRatio; QString _fileName; int _zoom; + QVector _palette; bool _valid; QString _errorString;