From bf613f1b6d9b542ed4c33fa841f66f3cd13572e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Mon, 25 Jan 2021 21:37:07 +0100 Subject: [PATCH] Added support for raster polygon backgrounds --- gpxsee.pro | 1 + src/map/IMG/lblfile.cpp | 46 ++++++++++++++++++++++++++++++++++++++ src/map/IMG/lblfile.h | 10 +++++++++ src/map/IMG/mapdata.h | 2 ++ src/map/IMG/raster.h | 37 ++++++++++++++++++++++++++++++ src/map/IMG/rastertile.cpp | 23 +++++++++++++++---- src/map/IMG/rgnfile.cpp | 42 ++++++++++++++++++++++++---------- src/map/IMG/rgnfile.h | 6 ++--- src/map/IMG/style.cpp | 3 ++- 9 files changed, 150 insertions(+), 20 deletions(-) create mode 100644 src/map/IMG/raster.h diff --git a/gpxsee.pro b/gpxsee.pro index 4cad02cb..3f593094 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -97,6 +97,7 @@ HEADERS += src/common/config.h \ src/map/IMG/huffmantext.h \ src/map/IMG/nodfile.h \ src/map/IMG/mapdata.h \ + src/map/IMG/raster.h \ src/map/IMG/rastertile.h \ src/map/IMG/textpathitem.h \ src/map/IMG/textpointitem.h \ diff --git a/src/map/IMG/lblfile.cpp b/src/map/IMG/lblfile.cpp index 56f5443a..0b4b2653 100644 --- a/src/map/IMG/lblfile.cpp +++ b/src/map/IMG/lblfile.cpp @@ -93,6 +93,23 @@ bool LBLFile::load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl) } } + if (hdrLen >= 0x19A) { + quint32 size; + if (!(seek(hdl, _gmpOffset + 0x184) && readUInt32(hdl, _imgOffsetsOffset) + && readUInt32(hdl, size) && readUInt16(hdl, _imgOffsetsRecordSize) + && readUInt32(hdl, _imgOffsetsFlags) && readUInt32(hdl, _imgOffset) + && readUInt32(hdl, _imgSize))) + return false; + _imgOffsetsCount = size ? size / _imgOffsetsRecordSize : 0; + + quint32 maxId = _imgOffsetsCount - 1; + _imgOffsetIdSize = 0; + do { + _imgOffsetIdSize++; + maxId = maxId >> 8; + } while (maxId != 0); + } + if (_encoding == 11) { _huffmanText = new HuffmanText(); if (!_huffmanText->load(rgn, rgnHdl)) @@ -283,3 +300,32 @@ Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize) con return Label(); } } + +QByteArray LBLFile::readImage(Handle &hdl, quint32 id) const +{ + quint32 offset, nextOffset, size; + + if (!_imgOffsetsCount || id >= _imgOffsetsCount) + return QByteArray(); + + if (!(seek(hdl, _imgOffsetsOffset + id * _imgOffsetsRecordSize) + && readVUInt32(hdl, _imgOffsetsRecordSize, offset))) + return QByteArray(); + if (id == _imgOffsetsCount - 1) + nextOffset = _imgSize; + else { + if (!readVUInt32(hdl, _imgOffsetsRecordSize, nextOffset)) + return QByteArray(); + } + size = nextOffset - offset; + + if (!seek(hdl, _imgOffset + offset)) + return QByteArray(); + QByteArray ba; + ba.resize(size); + for (quint32 i = 0; i < size; i++) + if (!readUInt8(hdl, *(ba.data() + i))) + return QByteArray(); + + return ba; +} diff --git a/src/map/IMG/lblfile.h b/src/map/IMG/lblfile.h index fe41de1d..0831efae 100644 --- a/src/map/IMG/lblfile.h +++ b/src/map/IMG/lblfile.h @@ -30,6 +30,9 @@ public: Label label(Handle &hdl, quint32 offset, bool poi = false, bool capitalize = true) const; + quint8 imageIdSize() const {return _imgOffsetIdSize;} + QByteArray readImage(Handle &hdl, quint32 id) const; + private: Label str2label(const QVector &str, bool capitalize) const; Label label6b(Handle &hdl, quint32 offset, bool capitalize) const; @@ -43,6 +46,13 @@ private: quint32 _size; quint32 _poiOffset; quint32 _poiSize; + quint32 _imgOffsetsOffset; + quint32 _imgOffsetsCount; + quint32 _imgOffsetsRecordSize; + quint32 _imgOffsetsFlags; + quint32 _imgOffset; + quint32 _imgSize; + quint8 _imgOffsetIdSize; quint8 _poiMultiplier; quint8 _multiplier; quint8 _encoding; diff --git a/src/map/IMG/mapdata.h b/src/map/IMG/mapdata.h index bb0b46ca..49a615ce 100644 --- a/src/map/IMG/mapdata.h +++ b/src/map/IMG/mapdata.h @@ -9,6 +9,7 @@ #include "common/rtree.h" #include "common/range.h" #include "label.h" +#include "raster.h" class Style; class SubDiv; @@ -25,6 +26,7 @@ public: parallel. */ QVector points; Label label; + Raster raster; quint32 type; RectC boundingRect; diff --git a/src/map/IMG/raster.h b/src/map/IMG/raster.h new file mode 100644 index 00000000..b5b70991 --- /dev/null +++ b/src/map/IMG/raster.h @@ -0,0 +1,37 @@ +#ifndef RASTER_H +#define RASTER_H + +#include +#include +#include +#include "common/rectc.h" +#include "common/garmin.h" + +class Raster { +public: + Raster() {} + Raster(const QByteArray &img, const QRect &rect) : _img(img), _rect(rect) {} + + const QByteArray &img() const {return _img;} + const RectC rect() const + { + return RectC(Coordinates(toWGS32(_rect.left()), toWGS32(_rect.top())), + Coordinates(toWGS32(_rect.right()), toWGS32(_rect.bottom()))); + } + bool isValid() const {return !_img.isNull();} + +private: + QByteArray _img; + QRect _rect; +}; + +#ifndef QT_NO_DEBUG +inline QDebug operator<<(QDebug dbg, const Raster &raster) +{ + dbg.nospace() << "Raster(" << raster.img().size() << ", " << raster.rect() + << ")"; + return dbg.space(); +} +#endif // QT_NO_DEBUG + +#endif // RASTER_H diff --git a/src/map/IMG/rastertile.cpp b/src/map/IMG/rastertile.cpp index 82b105d5..b762958d 100644 --- a/src/map/IMG/rastertile.cpp +++ b/src/map/IMG/rastertile.cpp @@ -217,11 +217,26 @@ void RasterTile::drawPolygons(QPainter *painter) const MapData::Poly &poly = _polygons.at(i); if (poly.type != _style->drawOrder().at(n)) continue; - const Style::Polygon &style = _style->polygon(poly.type); - painter->setPen(style.pen()); - painter->setBrush(style.brush()); - painter->drawPolygon(poly.points); + if (poly.raster.isValid()) { + RectC r(poly.raster.rect()); + QPointF tl(_map->ll2xy(r.topLeft())); + QPointF br(_map->ll2xy(r.bottomRight())); + QSize size(QRectF(tl, br).toRect().size()); + + painter->drawImage(tl, QImage::fromData(poly.raster.img()). + scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + + //painter->setPen(Qt::blue); + //painter->setBrush(Qt::NoBrush); + //painter->drawRect(QRectF(tl, br)); + } else { + const Style::Polygon &style = _style->polygon(poly.type); + + painter->setPen(style.pen()); + painter->setBrush(style.brush()); + painter->drawPolygon(poly.points); + } } } } diff --git a/src/map/IMG/rgnfile.cpp b/src/map/IMG/rgnfile.cpp index 2a6f2276..37ad7053 100644 --- a/src/map/IMG/rgnfile.cpp +++ b/src/map/IMG/rgnfile.cpp @@ -29,7 +29,8 @@ RGNFile::~RGNFile() delete _huffmanTable; } -bool RGNFile::skipClassFields(Handle &hdl) const +bool RGNFile::readClassFields(Handle &hdl, SegmentType segmentType, + MapData::Poly *poly, const LBLFile *lbl, Handle *lblHdl) const { quint8 flags; quint32 rs; @@ -56,6 +57,22 @@ bool RGNFile::skipClassFields(Handle &hdl) const break; } + if (segmentType == Polygon && poly->type == 0x10613 + && lbl && rs >= lbl->imageIdSize() + 16U) { + quint32 id; + quint32 top, right, bottom, left; + + if (!(readVUInt32(hdl, lbl->imageIdSize(), id) + && readUInt32(hdl, top) && readUInt32(hdl, right) + && readUInt32(hdl, bottom) && readUInt32(hdl, left))) + return false; + + poly->raster = Raster(lbl->readImage(*lblHdl, id), + QRect(QPoint(left, top), QPoint(right, bottom))); + + rs -= lbl->imageIdSize() + 16; + } + return seek(hdl, pos(hdl) + rs); } @@ -153,7 +170,7 @@ void RGNFile::clear() bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType, const LBLFile *lbl, Handle &lblHdl, NETFile *net, - Handle &netHdl, QList *polys) const + Handle &netHdl, QList *polys) const { const SubDiv::Segment &segment = (segmentType == Line) ? subdiv->lines() : subdiv->polygons(); @@ -169,7 +186,7 @@ bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv, quint16 len; while (pos(hdl) < segment.end()) { - IMG::Poly poly; + MapData::Poly poly; if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr) && readInt16(hdl, lon) && readInt16(hdl, lat))) @@ -229,7 +246,7 @@ bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv, bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift, SegmentType segmentType, const LBLFile *lbl, Handle &lblHdl, - QList *polys) const + QList *polys) const { quint32 labelPtr, len; quint8 type, subtype; @@ -244,7 +261,7 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift, return false; while (pos(hdl) < segment.end()) { - IMG::Poly poly; + MapData::Poly poly; QPoint pos; if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype) @@ -319,7 +336,8 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift, if (subtype & 0x20 && !readUInt24(hdl, labelPtr)) return false; - if (subtype & 0x80 && !skipClassFields(hdl)) + if (subtype & 0x80 && !readClassFields(hdl, segmentType, &poly, lbl, + &lblHdl)) return false; if (subtype & 0x40 && !skipLclFields(hdl, segmentType == Line ? _linesLclFlags : _polygonsLclFlags)) @@ -340,7 +358,7 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift, bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType, const LBLFile *lbl, Handle &lblHdl, - QList *points) const + QList *points) const { const SubDiv::Segment &segment = (segmentType == IndexedPoint) ? subdiv->idxPoints() : subdiv->points(); @@ -352,7 +370,7 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv, return false; while (pos(hdl) < segment.end()) { - IMG::Point point; + MapData::Point point; quint8 type, subtype; qint16 lon, lat; quint32 labelPtr; @@ -383,7 +401,7 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv, } bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, - const LBLFile *lbl, Handle &lblHdl, QList *points) const + const LBLFile *lbl, Handle &lblHdl, QList *points) const { const SubDiv::Segment &segment = subdiv->extPoints(); @@ -394,7 +412,7 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, return false; while (pos(hdl) < segment.end()) { - IMG::Point point; + MapData::Point point; qint16 lon, lat; quint8 type, subtype; quint32 labelPtr = 0; @@ -405,7 +423,7 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, if (subtype & 0x20 && !readUInt24(hdl, labelPtr)) return false; - if (subtype & 0x80 && !skipClassFields(hdl)) + if (subtype & 0x80 && !readClassFields(hdl, Point)) return false; if (subtype & 0x40 && !skipLclFields(hdl, _pointsLclFlags)) return false; @@ -434,7 +452,7 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, quint32 shift, const NETFile *net, Handle &netHdl, const NODFile *nod, Handle &nodHdl, - const LBLFile *lbl, Handle &lblHdl, QList *lines) const + const LBLFile *lbl, Handle &lblHdl, QList *lines) const { quint32 size, blockIndexId; quint8 flags; diff --git a/src/map/IMG/rgnfile.h b/src/map/IMG/rgnfile.h index f872c3fa..e1a08db6 100644 --- a/src/map/IMG/rgnfile.h +++ b/src/map/IMG/rgnfile.h @@ -60,9 +60,9 @@ public: private: QMap segments(Handle &hdl, SubDiv *subdiv) const; - bool skipClassFields(Handle &hdl) const; - bool skipLclFields(Handle &hdl, const quint32 flags[3]) - const; + bool readClassFields(Handle &hdl, SegmentType segmentType, + MapData::Poly *poly = 0, const LBLFile *lbl = 0, Handle *lblHdl = 0) const; + bool skipLclFields(Handle &hdl, const quint32 flags[3]) const; bool skipGblFields(Handle &hdl, quint32 flags) const; HuffmanTable *_huffmanTable; diff --git a/src/map/IMG/style.cpp b/src/map/IMG/style.cpp index 0eb42e33..4fd449d4 100644 --- a/src/map/IMG/style.cpp +++ b/src/map/IMG/style.cpp @@ -113,7 +113,8 @@ void Style::defaultPolygonStyle() _polygons[0x10c05] = _polygons[TYPE(0x52)]; // Draw order - _drawOrder << TYPE(0x4b) << 0x10d01 << TYPE(0x4a) << TYPE(0x01) << 0x10800 + _drawOrder + << TYPE(0x4b) << 0x10d01 << 0x10613 << TYPE(0x4a) << TYPE(0x01) << 0x10800 << TYPE(0x02) << 0x10801 << TYPE(0x03) << 0x10802 << TYPE(0x17) << 0x10a04 << TYPE(0x18) << 0x1090c << TYPE(0x1a) << 0x1090e << TYPE(0x28) << 0x10b01 << TYPE(0x32) << 0x10b02 << TYPE(0x3c) << 0x10b03 << TYPE(0x3d) << 0x10b04