1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-24 11:45:53 +01:00

Redesigned IMG caching

(Cache encoded data rather than raw data)
This commit is contained in:
Martin Tůma 2020-02-07 22:10:06 +01:00
parent df1be4aeb9
commit 325e83569c
9 changed files with 381 additions and 282 deletions

View File

@ -4,23 +4,34 @@
#include "vectortile.h" #include "vectortile.h"
#include "img.h" #include "img.h"
#define CACHED_SUBDIVS_COUNT 2048 // ~32MB
#define CACHE_SIZE 8388608 /* 8MB */
typedef QMap<QString, VectorTile*> TileMap; typedef QMap<QString, VectorTile*> TileMap;
struct CTX struct PolyCTX
{ {
CTX(const RectC &rect, int bits, QList<IMG::Poly> *polygons, PolyCTX(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
QList<IMG::Poly> *lines, QList<IMG::Point> *points) QList<IMG::Poly> *lines, QCache<const SubDiv*, IMG::Polys> *polyCache)
: rect(rect), bits(bits), polygons(polygons), lines(lines), : rect(rect), bits(bits), polygons(polygons), lines(lines),
points(points) {} polyCache(polyCache) {}
const RectC &rect; const RectC &rect;
int bits; int bits;
QList<IMG::Poly> *polygons; QList<IMG::Poly> *polygons;
QList<IMG::Poly> *lines; QList<IMG::Poly> *lines;
QCache<const SubDiv*, IMG::Polys> *polyCache;
};
struct PointCTX
{
PointCTX(const RectC &rect, int bits, QList<IMG::Point> *points,
QCache<const SubDiv*, QList<IMG::Point> > *pointCache)
: rect(rect), bits(bits), points(points), pointCache(pointCache) {}
const RectC &rect;
int bits;
QList<IMG::Point> *points; QList<IMG::Point> *points;
QCache<const SubDiv*, QList<IMG::Point> > *pointCache;
}; };
static SubFile::Type tileType(const char str[3]) static SubFile::Type tileType(const char str[3])
@ -78,8 +89,9 @@ IMG::IMG(const QString &fileName)
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2))); QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed(); _name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
_blockSize = 1 << (e1 + e2); _blockSize = 1 << (e1 + e2);
_blockCache.setMaxCost(CACHE_SIZE / _blockSize);
_polyCache.setMaxCost(CACHED_SUBDIVS_COUNT);
_pointCache.setMaxCost(CACHED_SUBDIVS_COUNT);
// Read the FAT table // Read the FAT table
quint8 flag; quint8 flag;
@ -214,20 +226,28 @@ void IMG::clear()
delete _style; delete _style;
_style = 0; _style = 0;
_blockCache.clear(); _polyCache.clear();
_pointCache.clear();
} }
static bool cb(VectorTile *tile, void *context) static bool polyCb(VectorTile *tile, void *context)
{ {
CTX *ctx = (CTX*)context; PolyCTX *ctx = (PolyCTX*)context;
tile->objects(ctx->rect, ctx->bits, ctx->polygons, ctx->lines, ctx->points); tile->polys(ctx->rect, ctx->bits, ctx->polygons, ctx->lines, ctx->polyCache);
return true; return true;
} }
void IMG::objects(const RectC &rect, int bits, QList<Poly> *polygons, static bool pointCb(VectorTile *tile, void *context)
QList<Poly> *lines, QList<Point> *points)
{ {
CTX ctx(rect, bits, polygons, lines, points); PointCTX *ctx = (PointCTX*)context;
tile->points(ctx->rect, ctx->bits, ctx->points, ctx->pointCache);
return true;
}
void IMG::polys(const RectC &rect, int bits, QList<Poly> *polygons,
QList<Poly> *lines)
{
PolyCTX ctx(rect, bits, polygons, lines, &_polyCache);
double min[2], max[2]; double min[2], max[2];
min[0] = rect.left(); min[0] = rect.left();
@ -235,7 +255,20 @@ void IMG::objects(const RectC &rect, int bits, QList<Poly> *polygons,
max[0] = rect.right(); max[0] = rect.right();
max[1] = rect.top(); max[1] = rect.top();
_tileTree.Search(min, max, cb, &ctx); _tileTree.Search(min, max, polyCb, &ctx);
}
void IMG::points(const RectC &rect, int bits, QList<Point> *points)
{
PointCTX ctx(rect, bits, points, &_pointCache);
double min[2], max[2];
min[0] = rect.left();
min[1] = rect.bottom();
max[0] = rect.right();
max[1] = rect.top();
_tileTree.Search(min, max, pointCb, &ctx);
} }
qint64 IMG::read(char *data, qint64 maxSize) qint64 IMG::read(char *data, qint64 maxSize)
@ -261,16 +294,11 @@ template<class T> bool IMG::readValue(T &val)
bool IMG::readBlock(int blockNum, QByteArray &data) bool IMG::readBlock(int blockNum, QByteArray &data)
{ {
QByteArray *block = _blockCache[blockNum]; if (!_file.seek((qint64)blockNum * (qint64)_blockSize))
if (!block) { return false;
if (!_file.seek((qint64)blockNum * (qint64)_blockSize)) data.resize(_blockSize);
return false; if (read(data.data(), _blockSize) < _blockSize)
data.resize(_blockSize); return false;
if (read(data.data(), _blockSize) < _blockSize)
return false;
_blockCache.insert(blockNum, new QByteArray(data));
} else
data = *block;
return true; return true;
} }

View File

@ -12,6 +12,7 @@
class VectorTile; class VectorTile;
class SubFile; class SubFile;
class SubDiv;
class IMG class IMG
{ {
@ -24,6 +25,7 @@ public:
QVector<QPointF> points; QVector<QPointF> points;
Label label; Label label;
quint32 type; quint32 type;
RectC boundingRect;
bool operator<(const Poly &other) const bool operator<(const Poly &other) const
{return type > other.type;} {return type > other.type;}
@ -42,6 +44,14 @@ public:
{return id < other.id;} {return id < other.id;}
}; };
struct Polys {
Polys() {}
Polys(const QList<Poly> &polygons, const QList<Poly> &lines)
: polygons(polygons), lines(lines) {}
QList<Poly> polygons;
QList<Poly> lines;
};
IMG(const QString &fileName); IMG(const QString &fileName);
~IMG(); ~IMG();
@ -53,8 +63,9 @@ public:
const QString &name() const {return _name;} const QString &name() const {return _name;}
const RectC &bounds() const {return _bounds;} const RectC &bounds() const {return _bounds;}
void objects(const RectC &rect, int bits, QList<Poly> *polygons, void polys(const RectC &rect, int bits, QList<Poly> *polygons,
QList<Poly> *lines, QList<Point> *points); QList<Poly> *lines);
void points(const RectC &rect, int bits, QList<Point> *points);
const Style *style() const {return _style;} const Style *style() const {return _style;}
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
@ -73,7 +84,6 @@ private:
QFile _file; QFile _file;
quint8 _key; quint8 _key;
int _blockSize; int _blockSize;
QCache<int, QByteArray> _blockCache;
QString _name; QString _name;
RectC _bounds; RectC _bounds;
@ -81,6 +91,9 @@ private:
SubFile *_typ; SubFile *_typ;
Style *_style; Style *_style;
QCache<const SubDiv*, Polys> _polyCache;
QCache<const SubDiv*, QList<Point> > _pointCache;
bool _valid; bool _valid;
QString _errorString; QString _errorString;
}; };

View File

@ -39,7 +39,7 @@ bool RGNFile::skipClassFields(Handle &hdl) const
} }
bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3], bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
Segment::Type type) const SegmentType type) const
{ {
quint32 bitfield = 0xFFFFFFFF; quint32 bitfield = 0xFFFFFFFF;
@ -53,7 +53,7 @@ bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
quint32 m = flags[(i >> 4) + 1] >> ((i * 2) & 0x1e) & 3; quint32 m = flags[(i >> 4) + 1] >> ((i * 2) & 0x1e) & 3;
switch (i) { switch (i) {
case 5: case 5:
if (m == 1 && type == Segment::Point) { if (m == 1 && type == Point) {
quint16 u16; quint16 u16;
if (!readUInt16(hdl, u16)) if (!readUInt16(hdl, u16))
return false; return false;
@ -116,10 +116,15 @@ bool RGNFile::init(Handle &hdl)
return true; return true;
} }
bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv, bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net, SegmentType segmentType, LBLFile *lbl, Handle &lblHdl, NETFile *net,
Handle &netHdl, QList<IMG::Poly> *polys) const Handle &netHdl, QList<IMG::Poly> *polys) const
{ {
const SubDiv::Segment &segment = (segmentType == Line)
? subdiv->lines() : subdiv->polygons();
if (!segment.isValid())
return true;
if (!seek(hdl, segment.start())) if (!seek(hdl, segment.start()))
return false; return false;
@ -145,14 +150,14 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
if (!readUInt8(hdl, bitstreamInfo)) if (!readUInt8(hdl, bitstreamInfo))
return false; return false;
poly.type = (segment.type() == Segment::Polygon) poly.type = (segmentType == Polygon)
? ((quint32)(type & 0x7F)) << 8 : ((quint32)(type & 0x3F)) << 8; ? ((quint32)(type & 0x7F)) << 8 : ((quint32)(type & 0x3F)) << 8;
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())), QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits()))); subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y())); Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
RectC br(c, c); poly.boundingRect = RectC(c, c);
poly.points.append(QPointF(c.lon(), c.lat())); poly.points.append(QPointF(c.lon(), c.lat()));
qint32 lonDelta, latDelta; qint32 lonDelta, latDelta;
@ -164,14 +169,11 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y())); Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat())); poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c); poly.boundingRect = poly.boundingRect.united(c);
} }
if (!(stream.atEnd() && stream.flush())) if (!(stream.atEnd() && stream.flush()))
return false; return false;
if (!rect.intersects(br))
continue;
if (lbl && (labelPtr & 0x3FFFFF)) { if (lbl && (labelPtr & 0x3FFFFF)) {
if (labelPtr & 0x800000) { if (labelPtr & 0x800000) {
quint32 lblOff; quint32 lblOff;
@ -188,22 +190,25 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
return true; return true;
} }
bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl, bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
const SubDiv *subdiv, quint32 shift, const Segment &segment, LBLFile *lbl, SegmentType segmentType, LBLFile *lbl, Handle &lblHdl,
Handle &lblHdl, QList<IMG::Poly> *polys, bool line) const QList<IMG::Poly> *polys) const
{ {
quint32 labelPtr, len; quint32 labelPtr, len;
quint8 type, subtype; quint8 type, subtype;
qint16 lon, lat; qint16 lon, lat;
const SubDiv::Segment &segment = (segmentType == Line)
? subdiv->extLines() : subdiv->extPolygons();
if (!segment.isValid())
return true;
if (!seek(hdl, segment.start())) if (!seek(hdl, segment.start()))
return false; return false;
while (hdl.pos < (int)segment.end()) { while (hdl.pos < (int)segment.end()) {
IMG::Poly poly; IMG::Poly poly;
QPoint pos; QPoint pos;
RectC br;
if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype) if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype)
&& readInt16(hdl, lon) && readInt16(hdl, lat) && readInt16(hdl, lon) && readInt16(hdl, lat)
@ -218,7 +223,8 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
(subdiv->lat()<<8) + ((qint32)lat<<(32-subdiv->bits()))); (subdiv->lat()<<8) + ((qint32)lat<<(32-subdiv->bits())));
qint32 lonDelta, latDelta; qint32 lonDelta, latDelta;
HuffmanStream stream(*this, hdl, len, _huffmanTable, line); HuffmanStream stream(*this, hdl, len, _huffmanTable,
segmentType == Line);
if (shift) { if (shift) {
if (!stream.readOffset(lonDelta, latDelta)) if (!stream.readOffset(lonDelta, latDelta))
@ -227,7 +233,7 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
pos.y() | latDelta<<(32-subdiv->bits()-shift)); pos.y() | latDelta<<(32-subdiv->bits()-shift));
} }
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y())); Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
br = RectC(c, c); poly.boundingRect = RectC(c, c);
poly.points.append(QPointF(c.lon(), c.lat())); poly.points.append(QPointF(c.lon(), c.lat()));
while (stream.readNext(lonDelta, latDelta)) { while (stream.readNext(lonDelta, latDelta)) {
@ -236,7 +242,7 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y())); Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat())); poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c); poly.boundingRect = poly.boundingRect.united(c);
} }
if (!(stream.atEnd() && stream.flush())) if (!(stream.atEnd() && stream.flush()))
@ -245,7 +251,7 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
pos = QPoint(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())), pos = QPoint(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits()))); subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y())); Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
br = RectC(c, c); poly.boundingRect = RectC(c, c);
poly.points.append(QPointF(c.lon(), c.lat())); poly.points.append(QPointF(c.lon(), c.lat()));
quint8 bitstreamInfo; quint8 bitstreamInfo;
@ -261,7 +267,7 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y())); Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat())); poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c); poly.boundingRect = poly.boundingRect.united(c);
} }
if (!(stream.atEnd() && stream.flush())) if (!(stream.atEnd() && stream.flush()))
return false; return false;
@ -271,13 +277,10 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
return false; return false;
if (subtype & 0x80 && !skipClassFields(hdl)) if (subtype & 0x80 && !skipClassFields(hdl))
return false; return false;
if (subtype & 0x40 && !skipLclFields(hdl, line ? _linesFlags if (subtype & 0x40 && !skipLclFields(hdl, segmentType == Line
: _polygonsFlags, segment.type())) ? _linesFlags : _polygonsFlags, segmentType))
return false; return false;
if (!rect.intersects(br))
continue;
if (lbl && (labelPtr & 0x3FFFFF)) if (lbl && (labelPtr & 0x3FFFFF))
poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF); poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
@ -287,14 +290,18 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
return true; return true;
} }
bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv, bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, SegmentType segmentType, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Point> *points) const QList<IMG::Point> *points) const
{ {
quint8 type, subtype; quint8 type, subtype;
qint16 lon, lat; qint16 lon, lat;
quint32 labelPtr; quint32 labelPtr;
const SubDiv::Segment &segment = (segmentType == IndexedPoint)
? subdiv->idxPoints() : subdiv->points();
if (!segment.isValid())
return true;
if (!seek(hdl, segment.start())) if (!seek(hdl, segment.start()))
return false; return false;
@ -317,9 +324,6 @@ bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
point.coordinates = Coordinates(toWGS24(subdiv->lon() + lonOffset), point.coordinates = Coordinates(toWGS24(subdiv->lon() + lonOffset),
toWGS24(subdiv->lat() + latOffset)); toWGS24(subdiv->lat() + latOffset));
if (!rect.contains(point.coordinates))
continue;
point.poi = labelPtr & 0x400000; point.poi = labelPtr & 0x400000;
if (lbl && (labelPtr & 0x3FFFFF)) { if (lbl && (labelPtr & 0x3FFFFF)) {
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi); point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi);
@ -333,14 +337,17 @@ bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
return true; return true;
} }
bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl, bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
const SubDiv *subdiv, const Segment &segment, LBLFile *lbl,
Handle &lblHdl, QList<IMG::Point> *points) const Handle &lblHdl, QList<IMG::Point> *points) const
{ {
quint8 type, subtype; quint8 type, subtype;
qint16 lon, lat; qint16 lon, lat;
quint32 labelPtr; quint32 labelPtr;
const SubDiv::Segment &segment = subdiv->extPoints();
if (!segment.isValid())
return true;
if (!seek(hdl, segment.start())) if (!seek(hdl, segment.start()))
return false; return false;
@ -363,10 +370,12 @@ bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl,
return false; return false;
if (subtype & 0x80 && !skipClassFields(hdl)) if (subtype & 0x80 && !skipClassFields(hdl))
return false; return false;
if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags, segment.type())) if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags, Point))
return false; return false;
if (!rect.contains(point.coordinates)) // Discard NT points breaking style draw order logic (and causing huge
// performance drawback)
if (point.type == 0x11400)
continue; continue;
point.poi = labelPtr & 0x400000; point.poi = labelPtr & 0x400000;
@ -382,85 +391,13 @@ bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl,
return true; return true;
} }
void RGNFile::objects(const RectC &rect, const SubDiv *subdiv, QMap<RGNFile::SegmentType, SubDiv::Segment> RGNFile::segments(Handle &hdl,
LBLFile *lbl, NETFile *net, QList<IMG::Poly> *polygons, SubDiv *subdiv) const
QList<IMG::Poly> *lines, QList<IMG::Point> *points)
{ {
Handle rgnHdl, lblHdl, netHdl; QMap<SegmentType, SubDiv::Segment> ret;
if (!_init && !init(rgnHdl))
return;
QVector<Segment> seg(segments(rgnHdl, subdiv));
for (int i = 0; i < seg.size(); i++) {
const Segment &segment = seg.at(i);
if (segment.start() == segment.end())
continue;
switch (segment.type()) {
case Segment::Point:
case Segment::IndexedPoint:
if (points)
pointObjects(rect, rgnHdl, subdiv, segment, lbl, lblHdl,
points);
break;
case Segment::Line:
if (lines)
polyObjects(rect, rgnHdl, subdiv, segment, lbl, lblHdl, net,
netHdl, lines);
break;
case Segment::Polygon:
if (polygons)
polyObjects(rect, rgnHdl, subdiv, segment, lbl, lblHdl, net,
netHdl, polygons);
break;
case Segment::RoadReference:
break;
}
}
}
void RGNFile::extObjects(const RectC &rect, const SubDiv *subdiv, quint32 shift,
LBLFile *lbl, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
QList<IMG::Point> *points)
{
Handle rgnHdl, lblHdl;
if (!_init && !init(rgnHdl))
return;
if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) {
quint32 start = _polygonsOffset + subdiv->polygonsOffset();
quint32 end = subdiv->polygonsEnd()
? _polygonsOffset + subdiv->polygonsEnd()
: _polygonsOffset + _polygonsSize;
extPolyObjects(rect, rgnHdl, subdiv, shift, Segment(start, end,
Segment::Polygon), lbl, lblHdl, polygons, false);
}
if (lines && subdiv->linesOffset() != subdiv->linesEnd()) {
quint32 start = _linesOffset + subdiv->linesOffset();
quint32 end = subdiv->linesEnd()
? _linesOffset + subdiv->linesEnd()
: _linesOffset + _linesSize;
extPolyObjects(rect, rgnHdl, subdiv, shift, Segment(start, end,
Segment::Line), lbl, lblHdl, lines, true);
}
if (points && subdiv->pointsOffset() != subdiv->pointsEnd()) {
quint32 start = _pointsOffset + subdiv->pointsOffset();
quint32 end = subdiv->pointsEnd()
? _pointsOffset + subdiv->pointsEnd()
: _pointsOffset + _pointsSize;
extPointObjects(rect, rgnHdl, subdiv, Segment(start, end,
Segment::Point), lbl, lblHdl, points);
}
}
QVector<RGNFile::Segment> RGNFile::segments(Handle &hdl, const SubDiv *subdiv)
const
{
if (subdiv->offset() == subdiv->end() || !(subdiv->objects() & 0x1F)) if (subdiv->offset() == subdiv->end() || !(subdiv->objects() & 0x1F))
return QVector<Segment>(); return ret;
quint32 offset = _offset + subdiv->offset(); quint32 offset = _offset + subdiv->offset();
@ -470,57 +407,66 @@ QVector<RGNFile::Segment> RGNFile::segments(Handle &hdl, const SubDiv *subdiv)
no++; no++;
if (!seek(hdl, offset)) if (!seek(hdl, offset))
return QVector<Segment>(); return ret;
QVector<Segment> ret;
quint32 start = offset + 2 * (no - 1); quint32 start = offset + 2 * (no - 1);
quint32 ls = 0;
SegmentType lt = (SegmentType)0;
quint16 po; quint16 po;
int cnt = 0; int cnt = 0;
for (quint16 mask = 0x1; mask <= 0x10; mask <<= 1) { for (quint16 mask = 0x1; mask <= 0x10; mask <<= 1) {
if (subdiv->objects() & mask) { if (subdiv->objects() & mask) {
if (cnt) { if (cnt) {
if (!readUInt16(hdl, po)) if (!readUInt16(hdl, po) || !po)
return QVector<Segment>(); return QMap<RGNFile::SegmentType, SubDiv::Segment>();
start = offset + po; start = offset + po;
} }
if (!ret.isEmpty()) if (ls)
ret.last().setEnd(start); ret.insert(lt, SubDiv::Segment(ls, start));
ret.append(Segment(start, (Segment::Type)mask));
lt = (SegmentType)mask;
ls = start;
cnt++; cnt++;
} }
} }
ret.last().setEnd(subdiv->end() ? _offset + subdiv->end() : _offset + _size); ret.insert(lt, SubDiv::Segment(ls, subdiv->end()
? _offset + subdiv->end() : _offset + _size));
return ret; return ret;
} }
#ifndef QT_NO_DEBUG bool RGNFile::subdivInit(Handle &hdl, SubDiv *subdiv) const
QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment)
{ {
QString type; QMap<RGNFile::SegmentType, SubDiv::Segment> seg(segments(hdl, subdiv));
switch (segment.type()) { SubDiv::Segment extPoints, extLines, extPolygons;
case RGNFile::Segment::Point:
type = "Point"; if (subdiv->extPointsOffset() != subdiv->extPointsEnd()) {
break; quint32 start = _pointsOffset + subdiv->extPointsOffset();
case RGNFile::Segment::IndexedPoint: quint32 end = subdiv->extPointsEnd()
type = "IndexedPoint"; ? _pointsOffset + subdiv->extPointsEnd()
break; : _pointsOffset + _pointsSize;
case RGNFile::Segment::Line: extPoints = SubDiv::Segment(start, end);
type = "Line"; }
break; if (subdiv->extPolygonsOffset() != subdiv->extPolygonsEnd()) {
case RGNFile::Segment::Polygon: quint32 start = _polygonsOffset + subdiv->extPolygonsOffset();
type = "Polygon"; quint32 end = subdiv->extPolygonsEnd()
break; ? _polygonsOffset + subdiv->extPolygonsEnd()
case RGNFile::Segment::RoadReference: : _polygonsOffset + _polygonsSize;
type = "RoadReference"; extPolygons = SubDiv::Segment(start, end);
break; }
if (subdiv->extLinesOffset() != subdiv->extLinesEnd()) {
quint32 start = _linesOffset + subdiv->extLinesOffset();
quint32 end = subdiv->extLinesEnd()
? _linesOffset + subdiv->extLinesEnd()
: _linesOffset + _linesSize;
extLines = SubDiv::Segment(start, end);
} }
dbg.nospace() << "Segment(" << segment.start() << ", " << segment.end() subdiv->init(seg.value(Point), seg.value(IndexedPoint), seg.value(Line),
- segment.start() << ", " << type << ")"; seg.value(Polygon), seg.value(RoadReference), extPoints, extLines,
extPolygons);
return dbg.space(); return true;
} }
#endif // QT_NO_DEBUG

View File

@ -12,6 +12,14 @@ class NETFile;
class RGNFile : public SubFile class RGNFile : public SubFile
{ {
public: public:
enum SegmentType {
Point = 0x1,
IndexedPoint = 0x2,
Line = 0x4,
Polygon = 0x8,
RoadReference = 0x10
};
RGNFile(IMG *img) RGNFile(IMG *img)
: SubFile(img), _offset(0), _size(0), _polygonsOffset(0), : SubFile(img), _offset(0), _size(0), _polygonsOffset(0),
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0), _polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
@ -21,65 +29,29 @@ public:
_linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false) _linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false)
{clearFlags();} {clearFlags();}
void objects(const RectC &rect, const SubDiv *subdiv, bool initialized() const {return _init;}
LBLFile *lbl, NETFile *net, QList<IMG::Poly> *polygons,
QList<IMG::Poly> *lines, QList<IMG::Point> *points);
void extObjects(const RectC &rect, const SubDiv *subdiv, quint32 shift,
LBLFile *lbl, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
QList<IMG::Point> *points);
private:
class Segment {
public:
enum Type {
Point = 0x1,
IndexedPoint = 0x2,
Line = 0x4,
Polygon = 0x8,
RoadReference = 0x10
};
Segment() : _start(0), _end(0), _type(Point) {}
Segment(quint32 start, Type type)
: _start(start), _end(0), _type(type) {}
Segment(quint32 start, quint32 end, Type type)
: _start(start), _end(end), _type(type) {}
void setEnd(quint32 end) {_end = end;}
quint32 start() const {return _start;}
quint32 end() const {return _end;}
Type type() const {return _type;}
private:
quint32 _start;
quint32 _end;
Type _type;
};
bool init(Handle &hdl); bool init(Handle &hdl);
QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const; bool polyObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType,
bool polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv, LBLFile *lbl, Handle &lblHdl, NETFile *net, Handle &netHdl,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net, QList<IMG::Poly> *polys) const;
Handle &netHdl, QList<IMG::Poly> *polys) const; bool pointObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType,
bool pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv, LBLFile *lbl, Handle &lblHdl, QList<IMG::Point> *points) const;
const Segment &segment, LBLFile *lbl, Handle &lblHdl, bool extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
QList<IMG::Point> *points) const; SegmentType segmentType, LBLFile *lbl, Handle &lblHdl,
bool extPolyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv, QList<IMG::Poly> *polys) const;
quint32 shift, const Segment &segment, LBLFile *lbl, Handle &lblHdl, bool extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
QList<IMG::Poly> *polys, bool line) const; Handle &lblHdl, QList<IMG::Point> *points) const;
bool extPointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Point> *points) const;
bool subdivInit(Handle &hdl, SubDiv *subdiv) const;
private:
QMap<SegmentType, SubDiv::Segment> segments(Handle &hdl, SubDiv *subdiv)
const;
void clearFlags(); void clearFlags();
bool skipClassFields(Handle &hdl) const; bool skipClassFields(Handle &hdl) const;
bool skipLclFields(Handle &hdl, const quint32 flags[3], bool skipLclFields(Handle &hdl, const quint32 flags[3], SegmentType type)
Segment::Type type) const; const;
friend QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment);
quint32 _offset; quint32 _offset;
quint32 _size; quint32 _size;
@ -99,8 +71,4 @@ private:
bool _init; bool _init;
}; };
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment);
#endif // QT_NO_DEBUG
#endif // RGNFILE_H #endif // RGNFILE_H

View File

@ -939,9 +939,6 @@ Style::Style(SubFile *typ)
if (typ) if (typ)
parseTYPFile(typ); parseTYPFile(typ);
// Override stuff breaking the style display logic
_points[0x11400] = Point(None);
} }
const Style::Line &Style::line(quint32 type) const const Style::Line &Style::line(quint32 type) const

View File

@ -7,55 +7,123 @@
class SubDiv { class SubDiv {
public: public:
SubDiv(quint32 offset, qint32 lon, qint32 lat, int bits, quint8 objects) class Segment {
: _offset(offset), _end(0), _lon(lon), _lat(lat), _bits(bits), public:
_objects(objects), _polygonsOffset(0), _polygonsEnd(0), _linesOffset(0), Segment() : _start(0), _end(0) {}
_linesEnd(0), _pointsOffset(0), _pointsEnd(0) {} Segment(quint32 start, quint32 end) : _start(start), _end(end) {}
void setEnd(quint32 end) {_end = end;}
bool isValid() const {return (_end > _start);}
quint32 start() const {return _start;}
quint32 end() const {return _end;}
private:
quint32 _start, _end;
};
SubDiv(quint32 offset, qint32 lon, qint32 lat, int bits, quint8 objects)
: _lon(lon), _lat(lat), _bits(bits), _init(false)
{
_tre.objects = objects;
_tre.offset = offset;
_tre.end = 0;
_tre.polygonsOffset = 0;
_tre.polygonsEnd = 0;
_tre.linesOffset = 0;
_tre.linesEnd = 0;
_tre.pointsOffset = 0;
_tre.pointsEnd = 0;
}
void setEnd(quint32 end) {_tre.end = end;}
void setExtOffsets(quint32 polygon, quint32 line, quint32 point)
{
_tre.polygonsOffset = polygon;
_tre.linesOffset = line;
_tre.pointsOffset = point;
}
void setExtEnds(quint32 polygon, quint32 line, quint32 point)
{
_tre.polygonsEnd = polygon;
_tre.linesEnd = line;
_tre.pointsEnd = point;
}
void init(const Segment &points, const Segment &idxPoints,
const Segment &lines, const Segment &polygons,
const Segment &roadReferences, const Segment &extPoints,
const Segment &extLines, const Segment &extPolygons)
{
_rgn.points = points;
_rgn.idxPoints = idxPoints;
_rgn.lines = lines;
_rgn.polygons = polygons;
_rgn.roadReferences = roadReferences;
_rgn.extPoints = extPoints;
_rgn.extLines = extLines;
_rgn.extPolygons = extPolygons;
_init = true;
}
bool initialized() const {return _init;}
quint32 offset() const {return _offset;}
quint32 end() const {return _end;}
qint32 lon() const {return _lon;} qint32 lon() const {return _lon;}
qint32 lat() const {return _lat;} qint32 lat() const {return _lat;}
quint8 bits() const {return _bits;} quint8 bits() const {return _bits;}
quint8 objects() const {return _objects;}
// Extended types objects (TRE7) // Valid only after initialization
void setExtOffsets(quint32 polygon, quint32 line, quint32 point) const Segment &points() const {return _rgn.points;}
{_polygonsOffset = polygon; _linesOffset = line; _pointsOffset = point;} const Segment &idxPoints() const {return _rgn.idxPoints;}
void setExtEnds(quint32 polygon, quint32 line, quint32 point) const Segment &lines() const {return _rgn.lines;}
{_polygonsEnd = polygon; _linesEnd = line; _pointsEnd = point;} const Segment &polygons() const {return _rgn.polygons;}
const Segment &extPoints() const {return _rgn.extPoints;}
const Segment &extLines() const {return _rgn.extLines;}
const Segment &extPolygons() const {return _rgn.extPolygons;}
quint32 polygonsOffset() const {return _polygonsOffset;} // Valid only until initialization
quint32 polygonsEnd() const {return _polygonsEnd;} quint8 objects() const {return _tre.objects;}
quint32 linesOffset() const {return _linesOffset;} quint32 offset() const {return _tre.offset;}
quint32 linesEnd() const {return _linesEnd;} quint32 end() const {return _tre.end;}
quint32 pointsOffset() const {return _pointsOffset;} quint32 extPolygonsOffset() const {return _tre.polygonsOffset;}
quint32 pointsEnd() const {return _pointsEnd;} quint32 extPolygonsEnd() const {return _tre.polygonsEnd;}
quint32 extLinesOffset() const {return _tre.linesOffset;}
quint32 extLinesEnd() const {return _tre.linesEnd;}
quint32 extPointsOffset() const {return _tre.pointsOffset;}
quint32 extPointsEnd() const {return _tre.pointsEnd;}
private: private:
quint32 _offset; struct TRE
quint32 _end; {
quint8 objects;
quint32 offset;
quint32 end;
quint32 polygonsOffset;
quint32 polygonsEnd;
quint32 linesOffset;
quint32 linesEnd;
quint32 pointsOffset;
quint32 pointsEnd;
};
struct RGN
{
Segment points;
Segment idxPoints;
Segment lines;
Segment polygons;
Segment roadReferences;
Segment extPoints;
Segment extLines;
Segment extPolygons;
};
qint32 _lon, _lat; qint32 _lon, _lat;
quint8 _bits; quint8 _bits;
quint8 _objects; bool _init;
union {
quint32 _polygonsOffset; TRE _tre;
quint32 _polygonsEnd; RGN _rgn;
quint32 _linesOffset; };
quint32 _linesEnd;
quint32 _pointsOffset;
quint32 _pointsEnd;
}; };
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const SubDiv &subdiv)
{
Coordinates c(toWGS24(subdiv.lon()), toWGS24(subdiv.lat()));
dbg.nospace() << "SubDiv(" << c << ", " << subdiv.offset()
<< ", " << subdiv.end() << ", " << subdiv.objects() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
#endif // SUBDIV_H #endif // SUBDIV_H

View File

@ -1,5 +1,23 @@
#include "vectortile.h" #include "vectortile.h"
static void copyPolys(const RectC &rect, QList<IMG::Poly> *src,
QList<IMG::Poly> *dst)
{
for (int i = 0; i < src->size(); i++)
if (rect.intersects(src->at(i).boundingRect))
dst->append(src->at(i));
}
static void copyPoints(const RectC &rect, QList<IMG::Point> *src,
QList<IMG::Point> *dst)
{
for (int j = 0; j < src->size(); j++)
if (rect.contains(src->at(j).coordinates))
dst->append(src->at(j));
}
SubFile *VectorTile::file(SubFile::Type type) SubFile *VectorTile::file(SubFile::Type type)
{ {
switch (type) { switch (type) {
@ -70,17 +88,75 @@ bool VectorTile::initGMP()
return true; return true;
} }
void VectorTile::objects(const RectC &rect, int bits, void VectorTile::polys(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines, QList<IMG::Poly> *lines, QCache<const SubDiv *, IMG::Polys> *polyCache)
QList<IMG::Point> *points) const const
{ {
SubFile::Handle rgnHdl, lblHdl, netHdl;
if (!_rgn->initialized() && !_rgn->init(rgnHdl))
return;
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits); QList<SubDiv*> subdivs = _tre->subdivs(rect, bits);
for (int i = 0; i < subdivs.size(); i++) { for (int i = 0; i < subdivs.size(); i++) {
const SubDiv *subdiv = subdivs.at(i); SubDiv *subdiv = subdivs.at(i);
quint32 shift = _tre->shift(subdiv->bits());
_rgn->objects(rect, subdiv, _lbl, _net, polygons, lines, points); IMG::Polys *polys = polyCache->object(subdiv);
_rgn->extObjects(rect, subdiv, shift, _lbl, polygons, lines, points); if (!polys) {
quint32 shift = _tre->shift(subdiv->bits());
QList<IMG::Poly> p, l;
if (!subdiv->initialized() && !_rgn->subdivInit(rgnHdl, subdiv))
continue;
_rgn->polyObjects(rgnHdl, subdiv, RGNFile::Polygon, _lbl, lblHdl,
_net, netHdl, &p);
_rgn->polyObjects(rgnHdl, subdiv, RGNFile::Line, _lbl, lblHdl,
_net, netHdl, &l);
_rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Polygon, _lbl,
lblHdl, &p);
_rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Line, _lbl,
lblHdl, &l);
copyPolys(rect, &p, polygons);
copyPolys(rect, &l, lines);
polyCache->insert(subdiv, new IMG::Polys(p, l));
} else {
copyPolys(rect, &(polys->polygons), polygons);
copyPolys(rect, &(polys->lines), lines);
}
}
}
void VectorTile::points(const RectC &rect, int bits, QList<IMG::Point> *points,
QCache<const SubDiv *, QList<IMG::Point> > *pointCache) const
{
SubFile::Handle rgnHdl, lblHdl;
if (!_rgn->initialized() && !_rgn->init(rgnHdl))
return;
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits);
for (int i = 0; i < subdivs.size(); i++) {
SubDiv *subdiv = subdivs.at(i);
QList<IMG::Point> *pl = pointCache->object(subdiv);
if (!pl) {
QList<IMG::Point> p;
if (!subdiv->initialized() && !_rgn->subdivInit(rgnHdl, subdiv))
continue;
_rgn->pointObjects(rgnHdl, subdiv, RGNFile::Point, _lbl, lblHdl,
&p);
_rgn->pointObjects(rgnHdl, subdiv, RGNFile::IndexedPoint, _lbl,
lblHdl, &p);
_rgn->extPointObjects(rgnHdl, subdiv, _lbl, lblHdl, &p);
copyPoints(rect, &p, points);
pointCache->insert(subdiv, new QList<IMG::Point>(p));
} else
copyPoints(rect, pl, points);
} }
} }

View File

@ -24,8 +24,11 @@ public:
SubFile *file(SubFile::Type type); SubFile *file(SubFile::Type type);
SubFile *addFile(IMG *img, SubFile::Type type); SubFile *addFile(IMG *img, SubFile::Type type);
void objects(const RectC &rect, int bits, QList<IMG::Poly> *polygons, void polys(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
QList<IMG::Poly> *lines, QList<IMG::Point> *points) const; QList<IMG::Poly> *lines, QCache<const SubDiv *, IMG::Polys> *polyCache)
const;
void points(const RectC &rect, int bits, QList<IMG::Point> *points,
QCache<const SubDiv*, QList<IMG::Point> > *pointCache) const;
static bool isTileFile(SubFile::Type type) static bool isTileFile(SubFile::Type type)
{ {

View File

@ -322,7 +322,6 @@ Coordinates IMGMap::xy2ll(const QPointF &p)
return _projection.xy2ll(_transform.img2proj(p)); return _projection.xy2ll(_transform.img2proj(p));
} }
void IMGMap::drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons) void IMGMap::drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons)
{ {
for (int n = 0; n < _img.style()->drawOrder().size(); n++) { for (int n = 0; n < _img.style()->drawOrder().size(); n++) {
@ -585,13 +584,14 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
RectD polyRect(_transform.img2proj(ttl), _transform.img2proj( RectD polyRect(_transform.img2proj(ttl), _transform.img2proj(
QPointF(ttl.x() + TILE_SIZE, ttl.y() + TILE_SIZE))); QPointF(ttl.x() + TILE_SIZE, ttl.y() + TILE_SIZE)));
_img.objects(polyRect.toRectC(_projection, 4), _zoom, _img.polys(polyRect.toRectC(_projection, 4), _zoom,
&(tile.polygons()), &(tile.lines()), 0); &(tile.polygons()), &(tile.lines()));
RectD pointRect(_transform.img2proj(QPointF(ttl.x() - TEXT_EXTENT, RectD pointRect(_transform.img2proj(QPointF(ttl.x() - TEXT_EXTENT,
ttl.y() - TEXT_EXTENT)), _transform.img2proj(QPointF(ttl.x() ttl.y() - TEXT_EXTENT)), _transform.img2proj(QPointF(ttl.x()
+ TILE_SIZE + TEXT_EXTENT, ttl.y() + TILE_SIZE + TEXT_EXTENT))); + TILE_SIZE + TEXT_EXTENT, ttl.y() + TILE_SIZE + TEXT_EXTENT)));
_img.objects(pointRect.toRectC(_projection, 4), _zoom, _img.points(pointRect.toRectC(_projection, 4), _zoom,
0, 0, &(tile.points())); &(tile.points()));
} }
} }
} }