From d07b6c6a9dd954eaccabec0fb62253cc845686ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Tue, 16 Jul 2019 22:08:23 +0200 Subject: [PATCH] Load TRE subdivs on demand, not all on tile load --- src/map/IMG/trefile.cpp | 230 ++++++++++++++++++++++------------------ src/map/IMG/trefile.h | 26 ++++- 2 files changed, 153 insertions(+), 103 deletions(-) diff --git a/src/map/IMG/trefile.cpp b/src/map/IMG/trefile.cpp index 9b852c0d..3838760e 100644 --- a/src/map/IMG/trefile.cpp +++ b/src/map/IMG/trefile.cpp @@ -3,12 +3,6 @@ #include "trefile.h" -struct MapLevel { - quint8 level; - quint8 bits; - quint16 subdivs; -}; - static void unlock(quint8 *dst, const quint8 *src, quint32 size, quint32 key) { static const unsigned char shuf[] = { @@ -46,6 +40,12 @@ TREFile::~TREFile() bool TREFile::init() { Handle hdl; + quint8 locked; + quint16 hdrLen; + + if (!(seek(hdl, 0) && readUInt16(hdl, hdrLen) + && seek(hdl, 0x0D) && readByte(hdl, locked))) + return false; // Tile bounds qint32 north, east, south, west; @@ -55,30 +55,18 @@ bool TREFile::init() _bounds = RectC(Coordinates(toWGS84(west), toWGS84(north)), Coordinates(toWGS84(east), toWGS84(south))); - return true; -} - -bool TREFile::load() -{ - Handle hdl; - quint8 locked; - quint16 hdrLen; - - if (!(seek(hdl, 0) && readUInt16(hdl, hdrLen) - && seek(hdl, 0x0D) && readByte(hdl, locked))) - return false; - - quint32 levelsOffset, levelsSize, subdivOffset, subdivSize; + // Levels & subdivs info + quint32 levelsOffset, levelsSize, subdivSize; if (!(seek(hdl, 0x21) && readUInt32(hdl, levelsOffset) - && readUInt32(hdl, levelsSize) && readUInt32(hdl, subdivOffset) + && readUInt32(hdl, levelsSize) && readUInt32(hdl, _subdivOffset) && readUInt32(hdl, subdivSize))) return false; - quint32 extOffset, extSize = 0; - quint16 extItemSize = 0; + // TRE7 info if (hdrLen > 0x9A) { - if (!(seek(hdl, 0x7C) && readUInt32(hdl, extOffset) - && readUInt32(hdl, extSize) && readUInt16(hdl, extItemSize))) + if (!(seek(hdl, 0x7C) && readUInt32(hdl, _extended.offset) + && readUInt32(hdl, _extended.size) + && readUInt16(hdl, _extended.itemSize))) return false; } @@ -99,92 +87,124 @@ bool TREFile::load() } quint32 levelsCount = levelsSize / 4; - QVector ml(levelsCount); + _levels = QVector(levelsCount); for (quint32 i = 0; i < levelsCount; i++) { quint8 *zoom = levels + (i * 4); - ml[i].level = *zoom; - ml[i].bits = *(zoom + 1); - ml[i].subdivs = *(zoom + 2) | (quint16)(*(zoom + 3)) << 8; - if ((ml[i].level & 0xF) > 15 || ml[i].bits > 24) + _levels[i].level = *zoom; + _levels[i].bits = *(zoom + 1); + _levels[i].subdivs = *(zoom + 2) | (quint16)(*(zoom + 3)) << 8; + if (_levels[i].bits > 24 || !_levels[i].subdivs) return false; } - // Subdivisions - if (!seek(hdl, subdivOffset)) - return false; - SubDiv *s = 0; - QList sl; - - for (int i = 0; i < ml.size(); i++) { - if (!(ml.at(i).level & 0x80)) - _subdivs.insert(ml.at(i).bits, new SubDivTree()); - - for (int j = 0; j < ml.at(i).subdivs; j++) { - quint32 offset; - qint32 lon, lat; - quint8 objects; - quint16 width, height, nextLevel; - - if (!(readUInt24(hdl, offset) && readByte(hdl, objects) - && readInt24(hdl, lon) && readInt24(hdl, lat) - && readUInt16(hdl, width) && readUInt16(hdl, height))) - return false; - if (i != (int)levelsCount - 1) - if (!readUInt16(hdl, nextLevel)) - return false; - - if (s) - s->setEnd(offset); - - if (ml.at(i).level & 0x80) { - sl.append(0); - s = 0; - continue; - } - - width &= 0x7FFF; - width <<= (24 - ml.at(i).bits); - height <<= (24 - ml.at(i).bits); - - s = new SubDiv(offset, lon, lat, ml.at(i).bits, objects); - sl.append(s); - - double min[2], max[2]; - RectC bounds(Coordinates(toWGS84(lon - width), - toWGS84(lat + height + 1)), Coordinates(toWGS84(lon + width + 1), - toWGS84(lat - height))); - - min[0] = bounds.left(); - min[1] = bounds.bottom(); - max[0] = bounds.right(); - max[1] = bounds.top(); - _subdivs[ml.at(i).bits]->Insert(min, max, s); + // Get first non-inherited level + _firstLevel = -1; + for (int i = 0; i < _levels.size(); i++) { + if (!(_levels.at(i).level & 0x80)) { + _firstLevel = i; + break; } } - // objects with extended types (TRE7) - if (extSize && extItemSize >= 12 - && (sl.size() - (int)(extSize/extItemSize) + 1 >= 0)) { + return (_firstLevel >= 0); +} + +bool TREFile::load(int idx) +{ + Handle hdl; + + quint32 skip = 0; + for (int i = 0; i < idx; i++) + skip += _levels.at(i).subdivs; + + if (!seek(hdl, _subdivOffset + skip * 16)) + return false; + + _subdivs.insert(_levels.at(idx).bits, new SubDivTree()); + QList sl; + SubDiv *s = 0; + + for (int j = 0; j < _levels.at(idx).subdivs; j++) { + quint32 offset; + qint32 lon, lat; + quint8 objects; + quint16 width, height, nextLevel; + + if (!(readUInt24(hdl, offset) && readByte(hdl, objects) + && readInt24(hdl, lon) && readInt24(hdl, lat) + && readUInt16(hdl, width) && readUInt16(hdl, height))) + return false; + if (idx != _levels.size() - 1) + if (!readUInt16(hdl, nextLevel)) + return false; + + if (s) + s->setEnd(offset); + + width &= 0x7FFF; + width <<= (24 - _levels.at(idx).bits); + height <<= (24 - _levels.at(idx).bits); + + s = new SubDiv(offset, lon, lat, _levels.at(idx).bits, objects); + sl.append(s); + + double min[2], max[2]; + RectC bounds(Coordinates(toWGS84(lon - width), + toWGS84(lat + height + 1)), Coordinates(toWGS84(lon + width + 1), + toWGS84(lat - height))); + + min[0] = bounds.left(); + min[1] = bounds.bottom(); + max[0] = bounds.right(); + max[1] = bounds.top(); + _subdivs[_levels.at(idx).bits]->Insert(min, max, s); + } + + if (idx != _levels.size() - 1) { + quint32 offset; + if (!readUInt24(hdl, offset)) + return false; + s->setEnd(offset); + } + + + // Objects with extended types (TRE7) + if (_extended.size && _extended.itemSize >= 12) { + /* Some maps skip entries for the inherited levels, some don't. Our + decision is based on the difference between the extended subdivs + count and the total subdivs count. */ + quint32 totalSubdivs = 0; + for (int i = 0; i < _levels.size(); i++) + totalSubdivs += _levels.at(i).subdivs; + quint32 extendedSubdivs = _extended.size / _extended.itemSize; + quint32 diff = totalSubdivs - extendedSubdivs + 1; + quint32 polygons, lines, points; - if (!seek(hdl, extOffset)) + if (!seek(hdl, _extended.offset + (skip - diff) * _extended.itemSize)) return false; - for (int i = sl.size() - (extSize/extItemSize) + 1; i < sl.size(); i++) { + for (int i = 0; i < sl.size(); i++) { if (!(readUInt32(hdl, polygons) && readUInt32(hdl, lines) && readUInt32(hdl, points))) return false; - if (!seek(hdl, hdl.pos + extItemSize - 12)) - return false; - if (i && sl.at(i-1)) + + sl.at(i)->setExtOffsets(polygons, lines, points); + if (i) sl.at(i-1)->setExtEnds(polygons, lines, points); - if (sl.at(i)) - sl.at(i)->setExtOffsets(polygons, lines, points); + + if (!seek(hdl, hdl.pos + _extended.itemSize - 12)) + return false; + } + + if (idx != _levels.size() - 1) { + if (!(readUInt32(hdl, polygons) && readUInt32(hdl, lines) + && readUInt32(hdl, points))) + return false; + sl.last()->setExtEnds(polygons, lines, points); } } - _levels = _subdivs.keys(); - return true; } @@ -202,23 +222,22 @@ void TREFile::clear() qDeleteAll(_subdivs); _subdivs.clear(); - _levels.clear(); } int TREFile::level(int bits) { - if (_levels.isEmpty() && !load()) - return -1; + int idx = _firstLevel; - int l = _levels.first(); - for (int i = 0; i < _levels.size(); i++) { - if (_levels.at(i) > bits) + for (int i = idx + 1; i < _levels.size(); i++) { + if (_levels.at(i).bits > bits) break; - else - l = _levels.at(i); + idx++; } - return l; + if (!_subdivs.contains(_levels.at(idx).bits) && !load(idx)) + return -1; + + return _levels.at(idx).bits; } static bool cb(SubDiv *subdiv, void *context) @@ -244,3 +263,12 @@ QList TREFile::subdivs(const RectC &rect, int bits) return list; } + +#ifndef QT_NO_DEBUG +QDebug operator<<(QDebug dbg, const TREFile::MapLevel &level) +{ + dbg.nospace() << "MapLevel(" << level.level << ", " << level.bits << ", " + << level.subdivs << ")"; + return dbg.space(); +} +#endif // QT_NO_DEBUG diff --git a/src/map/IMG/trefile.h b/src/map/IMG/trefile.h index 2f92a86a..1cec1161 100644 --- a/src/map/IMG/trefile.h +++ b/src/map/IMG/trefile.h @@ -23,17 +23,39 @@ public: QList subdivs(const RectC &rect, int bits); private: + struct MapLevel { + quint8 level; + quint8 bits; + quint16 subdivs; + }; + struct Extended { + quint32 offset; + quint32 size; + quint16 itemSize; + + Extended() : offset(0), size(0), itemSize(0) {} + }; typedef RTree SubDivTree; - bool load(); + bool load(int idx); int level(int bits); bool parsePoly(Handle hdl, quint32 pos, const QMap &level2bits, QMap &map); bool parsePoints(Handle hdl, quint32 pos, const QMap &level2bits); + friend QDebug operator<<(QDebug dbg, const MapLevel &level); + RectC _bounds; - QList _levels; + QVector _levels; + quint32 _subdivOffset; + Extended _extended; + int _firstLevel; + QMap _subdivs; }; +#ifndef QT_NO_DEBUG +QDebug operator<<(QDebug dbg, const TREFile::MapLevel &level); +#endif // QT_NO_DEBUG + #endif // TREFILE_H