mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-28 05:34:47 +01:00
Load TRE subdivs on demand, not all on tile load
This commit is contained in:
parent
c9a62e8b61
commit
d07b6c6a9d
@ -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<MapLevel> ml(levelsCount);
|
||||
_levels = QVector<MapLevel>(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<SubDiv*> 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<SubDiv*> 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<SubDiv*> 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
|
||||
|
@ -23,17 +23,39 @@ public:
|
||||
QList<SubDiv*> 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<SubDiv*, double, 2> SubDivTree;
|
||||
|
||||
bool load();
|
||||
bool load(int idx);
|
||||
int level(int bits);
|
||||
bool parsePoly(Handle hdl, quint32 pos, const QMap<int, int> &level2bits,
|
||||
QMap<quint32, int> &map);
|
||||
bool parsePoints(Handle hdl, quint32 pos, const QMap<int, int> &level2bits);
|
||||
|
||||
friend QDebug operator<<(QDebug dbg, const MapLevel &level);
|
||||
|
||||
RectC _bounds;
|
||||
QList<int> _levels;
|
||||
QVector<MapLevel> _levels;
|
||||
quint32 _subdivOffset;
|
||||
Extended _extended;
|
||||
int _firstLevel;
|
||||
|
||||
QMap<int, SubDivTree*> _subdivs;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const TREFile::MapLevel &level);
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
#endif // TREFILE_H
|
||||
|
Loading…
Reference in New Issue
Block a user