mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-06-28 12:09:15 +02:00
Added support for GMAP maps
This commit is contained in:
@ -32,7 +32,7 @@ bool BitStream1::read(int bits, quint32 &val)
|
||||
|
||||
bool BitStream1::flush()
|
||||
{
|
||||
if (_length && !_file.seek(_hdl, _hdl.pos + _length))
|
||||
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
|
||||
return false;
|
||||
|
||||
_length = 0;
|
||||
@ -68,7 +68,7 @@ bool BitStream4::read(int bits, quint32 &val)
|
||||
|
||||
bool BitStream4::flush()
|
||||
{
|
||||
if (_length && !_file.seek(_hdl, _hdl.pos + _length))
|
||||
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
|
||||
return false;
|
||||
|
||||
_length = 0;
|
||||
|
151
src/map/IMG/gmap.cpp
Normal file
151
src/map/IMG/gmap.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
#include <QXmlStreamReader>
|
||||
#include <QDir>
|
||||
#include "vectortile.h"
|
||||
#include "gmap.h"
|
||||
|
||||
|
||||
static SubFile::Type tileType(const QString &suffix)
|
||||
{
|
||||
if (!suffix.compare("TRE"))
|
||||
return SubFile::TRE;
|
||||
else if (!suffix.compare("RGN"))
|
||||
return SubFile::RGN;
|
||||
else if (!suffix.compare("LBL"))
|
||||
return SubFile::LBL;
|
||||
else if (!suffix.compare("TYP"))
|
||||
return SubFile::TYP;
|
||||
else if (!suffix.compare("GMP"))
|
||||
return SubFile::GMP;
|
||||
else if (!suffix.compare("NET"))
|
||||
return SubFile::NET;
|
||||
else
|
||||
return SubFile::Unknown;
|
||||
}
|
||||
|
||||
void GMAP::subProduct(QXmlStreamReader &reader, QString &dataDir,
|
||||
QString &baseMap)
|
||||
{
|
||||
while (reader.readNextStartElement()) {
|
||||
if (reader.name() == "Directory")
|
||||
dataDir = reader.readElementText();
|
||||
else if (reader.name() == "BaseMap")
|
||||
baseMap = reader.readElementText();
|
||||
else
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
void GMAP::mapProduct(QXmlStreamReader &reader, QString &dataDir,
|
||||
QString &typFile, QString &baseMap)
|
||||
{
|
||||
while (reader.readNextStartElement()) {
|
||||
if (reader.name() == "Name")
|
||||
_name = reader.readElementText();
|
||||
else if (reader.name() == "TYP")
|
||||
typFile = reader.readElementText();
|
||||
else if (reader.name() == "SubProduct")
|
||||
subProduct(reader, dataDir, baseMap);
|
||||
else
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
bool GMAP::readXML(const QString &path, QString &dataDir, QString &typFile,
|
||||
QString &baseMap)
|
||||
{
|
||||
QFile file(path);
|
||||
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||
return false;
|
||||
|
||||
QXmlStreamReader reader(&file);
|
||||
if (reader.readNextStartElement()) {
|
||||
if (reader.name() == "MapProduct")
|
||||
mapProduct(reader, dataDir, typFile, baseMap);
|
||||
else
|
||||
reader.raiseError("Not a GMAP XML file");
|
||||
}
|
||||
if (reader.error()) {
|
||||
_errorString = QString("%1: %2").arg(reader.lineNumber())
|
||||
.arg(reader.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GMAP::loadTile(const QDir &dir, quint16 &id)
|
||||
{
|
||||
VectorTile *tile = new VectorTile();
|
||||
|
||||
QFileInfoList ml = dir.entryInfoList(QDir::Files);
|
||||
for (int i = 0; i < ml.size(); i++) {
|
||||
const QFileInfo &fi = ml.at(i);
|
||||
SubFile::Type type = tileType(fi.suffix());
|
||||
if (VectorTile::isTileFile(type)) {
|
||||
SubFile *file = tile->addFile(fi.absoluteFilePath(), type);
|
||||
file->setId(id++);
|
||||
}
|
||||
}
|
||||
|
||||
if (!tile->init()) {
|
||||
qWarning("%s: Invalid map tile", qPrintable(dir.path()));
|
||||
delete tile;
|
||||
return false;
|
||||
}
|
||||
|
||||
double min[2], max[2];
|
||||
min[0] = tile->bounds().left();
|
||||
min[1] = tile->bounds().bottom();
|
||||
max[0] = tile->bounds().right();
|
||||
max[1] = tile->bounds().top();
|
||||
_tileTree.Insert(min, max, tile);
|
||||
|
||||
_bounds |= tile->bounds();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GMAP::GMAP(const QString &fileName) : _fileName(fileName)
|
||||
{
|
||||
QString dataDirPath, typFile, baseMap;
|
||||
if (!readXML(fileName, dataDirPath, typFile, baseMap))
|
||||
return;
|
||||
|
||||
QDir baseDir(QFileInfo(fileName).absoluteDir());
|
||||
if (!baseDir.exists(dataDirPath)) {
|
||||
_errorString = "Missing/invalid map data directory";
|
||||
return;
|
||||
}
|
||||
QDir dataDir(baseDir.filePath(dataDirPath));
|
||||
QFileInfoList ml = dataDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
|
||||
quint16 id = 0;
|
||||
for (int i = 0; i < ml.size(); i++) {
|
||||
const QFileInfo &fi = ml.at(i);
|
||||
if (fi.isDir() && fi.baseName() != baseMap)
|
||||
loadTile(QDir(fi.absoluteFilePath()), id);
|
||||
}
|
||||
|
||||
if (baseDir.exists(typFile))
|
||||
_typ = new SubFile(baseDir.filePath(typFile));
|
||||
|
||||
if (!_tileTree.Count())
|
||||
_errorString = "No usable map tile found";
|
||||
else
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
bool GMAP::isGMAP(const QString &path)
|
||||
{
|
||||
QFile file(path);
|
||||
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||
return false;
|
||||
|
||||
QXmlStreamReader reader(&file);
|
||||
if (reader.readNextStartElement() && reader.name() == "MapProduct")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
30
src/map/IMG/gmap.h
Normal file
30
src/map/IMG/gmap.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef GMAP_H
|
||||
#define GMAP_H
|
||||
|
||||
#include "mapdata.h"
|
||||
|
||||
class QXmlStreamReader;
|
||||
class QDir;
|
||||
|
||||
class GMAP : public MapData
|
||||
{
|
||||
public:
|
||||
GMAP(const QString &fileName);
|
||||
|
||||
QString fileName() const {return _fileName;}
|
||||
|
||||
static bool isGMAP(const QString &path);
|
||||
|
||||
private:
|
||||
QString _fileName;
|
||||
|
||||
bool readXML(const QString &path, QString &dataDir, QString &typFile,
|
||||
QString &baseMap);
|
||||
void mapProduct(QXmlStreamReader &reader, QString &dataDir,
|
||||
QString &typFile, QString &baseMap);
|
||||
void subProduct(QXmlStreamReader &reader, QString &dataDir,
|
||||
QString &baseMap);
|
||||
bool loadTile(const QDir &dir, quint16 &id);
|
||||
};
|
||||
|
||||
#endif // GMAP_H
|
@ -55,7 +55,7 @@ bool HuffmanTable::getBuffer(const SubFile &file, SubFile::Handle &hdl,
|
||||
return false;
|
||||
if (!file.readVUInt32(hdl, recordSize))
|
||||
return false;
|
||||
recordOffset = hdl.pos + recordSize;
|
||||
recordOffset = hdl.pos() + recordSize;
|
||||
if (recordOffset > offset + size)
|
||||
return false;
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <QMap>
|
||||
#include <QtEndian>
|
||||
#include "common/programpaths.h"
|
||||
|
||||
#include "vectortile.h"
|
||||
#include "img.h"
|
||||
|
||||
@ -8,32 +8,6 @@
|
||||
|
||||
typedef QMap<QString, VectorTile*> TileMap;
|
||||
|
||||
struct PolyCTX
|
||||
{
|
||||
PolyCTX(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
|
||||
QList<IMG::Poly> *lines, QCache<const SubDiv*, IMG::Polys> *polyCache)
|
||||
: rect(rect), bits(bits), polygons(polygons), lines(lines),
|
||||
polyCache(polyCache) {}
|
||||
|
||||
const RectC ▭
|
||||
int bits;
|
||||
QList<IMG::Poly> *polygons;
|
||||
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 ▭
|
||||
int bits;
|
||||
QList<IMG::Point> *points;
|
||||
QCache<const SubDiv*, QList<IMG::Point> > *pointCache;
|
||||
};
|
||||
|
||||
static SubFile::Type tileType(const char str[3])
|
||||
{
|
||||
if (!memcmp(str, "TRE", 3))
|
||||
@ -52,8 +26,7 @@ static SubFile::Type tileType(const char str[3])
|
||||
return SubFile::Unknown;
|
||||
}
|
||||
|
||||
IMG::IMG(const QString &fileName)
|
||||
: _file(fileName), _typ(0), _style(0), _valid(false)
|
||||
IMG::IMG(const QString &fileName) : _file(fileName)
|
||||
{
|
||||
#define CHECK(condition) \
|
||||
if (!(condition)) { \
|
||||
@ -191,86 +164,6 @@ IMG::IMG(const QString &fileName)
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
IMG::~IMG()
|
||||
{
|
||||
TileTree::Iterator it;
|
||||
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it))
|
||||
delete _tileTree.GetAt(it);
|
||||
|
||||
delete _typ;
|
||||
delete _style;
|
||||
}
|
||||
|
||||
void IMG::load()
|
||||
{
|
||||
Q_ASSERT(!_style);
|
||||
|
||||
if (_typ)
|
||||
_style = new Style(_typ);
|
||||
else {
|
||||
QFile typFile(ProgramPaths::typFile());
|
||||
if (typFile.open(QIODevice::ReadOnly)) {
|
||||
SubFile typ(&typFile);
|
||||
_style = new Style(&typ);
|
||||
} else
|
||||
_style = new Style();
|
||||
}
|
||||
}
|
||||
|
||||
void IMG::clear()
|
||||
{
|
||||
TileTree::Iterator it;
|
||||
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it))
|
||||
_tileTree.GetAt(it)->clear();
|
||||
|
||||
delete _style;
|
||||
_style = 0;
|
||||
|
||||
_polyCache.clear();
|
||||
_pointCache.clear();
|
||||
}
|
||||
|
||||
static bool polyCb(VectorTile *tile, void *context)
|
||||
{
|
||||
PolyCTX *ctx = (PolyCTX*)context;
|
||||
tile->polys(ctx->rect, ctx->bits, ctx->polygons, ctx->lines, ctx->polyCache);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool pointCb(VectorTile *tile, void *context)
|
||||
{
|
||||
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];
|
||||
|
||||
min[0] = rect.left();
|
||||
min[1] = rect.bottom();
|
||||
max[0] = rect.right();
|
||||
max[1] = rect.top();
|
||||
|
||||
_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 ret = _file.read(data, maxSize);
|
||||
@ -292,28 +185,12 @@ template<class T> bool IMG::readValue(T &val)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IMG::readBlock(int blockNum, QByteArray &data)
|
||||
bool IMG::readBlock(int blockNum, char *data)
|
||||
{
|
||||
if (!_file.seek((qint64)blockNum * (qint64)_blockSize))
|
||||
return false;
|
||||
data.resize(_blockSize);
|
||||
if (read(data.data(), _blockSize) < _blockSize)
|
||||
if (read(data, _blockSize) < _blockSize)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const IMG::Point &point)
|
||||
{
|
||||
dbg.nospace() << "Point(" << hex << point.type << ", " << point.label
|
||||
<< ", " << point.poi << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug dbg, const IMG::Poly &poly)
|
||||
{
|
||||
dbg.nospace() << "Poly(" << hex << poly.type << ", " << poly.label << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
|
@ -2,105 +2,26 @@
|
||||
#define IMG_H
|
||||
|
||||
#include <QFile>
|
||||
#include <QByteArray>
|
||||
#include <QCache>
|
||||
#include <QDebug>
|
||||
#include "common/rtree.h"
|
||||
#include "common/rectc.h"
|
||||
#include "style.h"
|
||||
#include "label.h"
|
||||
#include "mapdata.h"
|
||||
|
||||
class VectorTile;
|
||||
class SubFile;
|
||||
class SubDiv;
|
||||
|
||||
class IMG
|
||||
class IMG : public MapData
|
||||
{
|
||||
public:
|
||||
struct Poly {
|
||||
/* QPointF insted of Coordinates for performance reasons (no need to
|
||||
duplicate all the vectors for drawing). Note, that we do not want to
|
||||
ll2xy() the points in the IMG class as this can not be done in
|
||||
parallel. */
|
||||
QVector<QPointF> points;
|
||||
Label label;
|
||||
quint32 type;
|
||||
RectC boundingRect;
|
||||
|
||||
bool operator<(const Poly &other) const
|
||||
{return type > other.type;}
|
||||
};
|
||||
|
||||
struct Point {
|
||||
Point() : id(0) {}
|
||||
|
||||
Coordinates coordinates;
|
||||
Label label;
|
||||
quint32 type;
|
||||
bool poi;
|
||||
quint64 id;
|
||||
|
||||
bool operator<(const Point &other) const
|
||||
{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();
|
||||
|
||||
void load();
|
||||
void clear();
|
||||
|
||||
QString fileName() const {return _file.fileName();}
|
||||
const QString &name() const {return _name;}
|
||||
const RectC &bounds() const {return _bounds;}
|
||||
|
||||
void polys(const RectC &rect, int bits, QList<Poly> *polygons,
|
||||
QList<Poly> *lines);
|
||||
void points(const RectC &rect, int bits, QList<Point> *points);
|
||||
const Style *style() const {return _style;}
|
||||
|
||||
bool isValid() const {return _valid;}
|
||||
const QString &errorString() const {return _errorString;}
|
||||
|
||||
private:
|
||||
friend class SubFile;
|
||||
|
||||
typedef RTree<VectorTile*, double, 2> TileTree;
|
||||
|
||||
int blockSize() const {return _blockSize;}
|
||||
bool readBlock(int blockNum, QByteArray &data);
|
||||
bool readBlock(int blockNum, char *data);
|
||||
qint64 read(char *data, qint64 maxSize);
|
||||
template<class T> bool readValue(T &val);
|
||||
|
||||
QFile _file;
|
||||
quint8 _key;
|
||||
int _blockSize;
|
||||
|
||||
QString _name;
|
||||
RectC _bounds;
|
||||
TileTree _tileTree;
|
||||
SubFile *_typ;
|
||||
Style *_style;
|
||||
|
||||
QCache<const SubDiv*, Polys> _polyCache;
|
||||
QCache<const SubDiv*, QList<Point> > _pointCache;
|
||||
|
||||
bool _valid;
|
||||
QString _errorString;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const IMG::Point &point);
|
||||
QDebug operator<<(QDebug dbg, const IMG::Poly &poly);
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
#endif // IMG_H
|
||||
|
@ -12,6 +12,9 @@ public:
|
||||
LBLFile(IMG *img)
|
||||
: SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0),
|
||||
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||
LBLFile(const QString &path)
|
||||
: SubFile(path), _codec(0), _offset(0), _size(0), _poiOffset(0),
|
||||
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||
LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0),
|
||||
_poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||
|
108
src/map/IMG/mapdata.cpp
Normal file
108
src/map/IMG/mapdata.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
#include "common/programpaths.h"
|
||||
#include "vectortile.h"
|
||||
#include "style.h"
|
||||
#include "mapdata.h"
|
||||
|
||||
|
||||
struct PolyCTX
|
||||
{
|
||||
PolyCTX(const RectC &rect, int bits, QList<MapData::Poly> *polygons,
|
||||
QList<MapData::Poly> *lines, QCache<const SubDiv*,
|
||||
MapData::Polys> *polyCache) : rect(rect), bits(bits), polygons(polygons),
|
||||
lines(lines), polyCache(polyCache) {}
|
||||
|
||||
const RectC ▭
|
||||
int bits;
|
||||
QList<MapData::Poly> *polygons;
|
||||
QList<MapData::Poly> *lines;
|
||||
QCache<const SubDiv*, MapData::Polys> *polyCache;
|
||||
};
|
||||
|
||||
struct PointCTX
|
||||
{
|
||||
PointCTX(const RectC &rect, int bits, QList<MapData::Point> *points,
|
||||
QCache<const SubDiv*, QList<MapData::Point> > *pointCache)
|
||||
: rect(rect), bits(bits), points(points), pointCache(pointCache) {}
|
||||
|
||||
const RectC ▭
|
||||
int bits;
|
||||
QList<MapData::Point> *points;
|
||||
QCache<const SubDiv*, QList<MapData::Point> > *pointCache;
|
||||
};
|
||||
|
||||
inline bool polyCb(VectorTile *tile, void *context)
|
||||
{
|
||||
PolyCTX *ctx = (PolyCTX*)context;
|
||||
tile->polys(ctx->rect, ctx->bits, ctx->polygons, ctx->lines, ctx->polyCache);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool pointCb(VectorTile *tile, void *context)
|
||||
{
|
||||
PointCTX *ctx = (PointCTX*)context;
|
||||
tile->points(ctx->rect, ctx->bits, ctx->points, ctx->pointCache);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
MapData::~MapData()
|
||||
{
|
||||
TileTree::Iterator it;
|
||||
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it))
|
||||
delete _tileTree.GetAt(it);
|
||||
|
||||
delete _typ;
|
||||
delete _style;
|
||||
}
|
||||
|
||||
void MapData::polys(const RectC &rect, int bits, QList<Poly> *polygons,
|
||||
QList<Poly> *lines)
|
||||
{
|
||||
PolyCTX ctx(rect, bits, polygons, lines, &_polyCache);
|
||||
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, polyCb, &ctx);
|
||||
}
|
||||
|
||||
void MapData::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);
|
||||
}
|
||||
|
||||
void MapData::load()
|
||||
{
|
||||
Q_ASSERT(!_style);
|
||||
|
||||
if (_typ)
|
||||
_style = new Style(_typ);
|
||||
else {
|
||||
SubFile typ(ProgramPaths::typFile());
|
||||
_style = new Style(&typ);
|
||||
}
|
||||
}
|
||||
|
||||
void MapData::clear()
|
||||
{
|
||||
TileTree::Iterator it;
|
||||
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it))
|
||||
_tileTree.GetAt(it)->clear();
|
||||
|
||||
delete _style;
|
||||
_style = 0;
|
||||
|
||||
_polyCache.clear();
|
||||
_pointCache.clear();
|
||||
}
|
105
src/map/IMG/mapdata.h
Normal file
105
src/map/IMG/mapdata.h
Normal file
@ -0,0 +1,105 @@
|
||||
#ifndef MAPDATA_H
|
||||
#define MAPDATA_H
|
||||
|
||||
#include <QList>
|
||||
#include <QPointF>
|
||||
#include <QCache>
|
||||
#include <QDebug>
|
||||
#include "common/rectc.h"
|
||||
#include "common/rtree.h"
|
||||
#include "label.h"
|
||||
|
||||
class Style;
|
||||
class SubDiv;
|
||||
class SubFile;
|
||||
class VectorTile;
|
||||
|
||||
class MapData
|
||||
{
|
||||
public:
|
||||
struct Poly {
|
||||
/* QPointF insted of Coordinates for performance reasons (no need to
|
||||
duplicate all the vectors for drawing). Note, that we do not want to
|
||||
ll2xy() the points in the IMG class as this can not be done in
|
||||
parallel. */
|
||||
QVector<QPointF> points;
|
||||
Label label;
|
||||
quint32 type;
|
||||
RectC boundingRect;
|
||||
|
||||
bool operator<(const Poly &other) const
|
||||
{return type > other.type;}
|
||||
};
|
||||
|
||||
struct Point {
|
||||
Point() : id(0) {}
|
||||
|
||||
Coordinates coordinates;
|
||||
Label label;
|
||||
quint32 type;
|
||||
bool poi;
|
||||
quint64 id;
|
||||
|
||||
bool operator<(const Point &other) const
|
||||
{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;
|
||||
};
|
||||
|
||||
MapData() : _typ(0), _style(0), _valid(false) {}
|
||||
virtual ~MapData();
|
||||
|
||||
const QString &name() const {return _name;}
|
||||
const RectC &bounds() const {return _bounds;}
|
||||
const Style *style() const {return _style;}
|
||||
void polys(const RectC &rect, int bits, QList<Poly> *polygons,
|
||||
QList<Poly> *lines);
|
||||
void points(const RectC &rect, int bits, QList<Point> *points);
|
||||
|
||||
void load();
|
||||
void clear();
|
||||
|
||||
virtual QString fileName() const = 0;
|
||||
|
||||
bool isValid() const {return _valid;}
|
||||
QString errorString() const {return _errorString;}
|
||||
|
||||
protected:
|
||||
typedef RTree<VectorTile*, double, 2> TileTree;
|
||||
|
||||
QString _name;
|
||||
RectC _bounds;
|
||||
SubFile *_typ;
|
||||
Style *_style;
|
||||
|
||||
TileTree _tileTree;
|
||||
QCache<const SubDiv*, Polys> _polyCache;
|
||||
QCache<const SubDiv*, QList<Point> > _pointCache;
|
||||
|
||||
bool _valid;
|
||||
QString _errorString;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
inline QDebug operator<<(QDebug dbg, const MapData::Point &point)
|
||||
{
|
||||
dbg.nospace() << "Point(" << hex << point.type << ", " << point.label
|
||||
<< ", " << point.poi << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug dbg, const MapData::Poly &poly)
|
||||
{
|
||||
dbg.nospace() << "Poly(" << hex << poly.type << ", " << poly.label << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
#endif // MAPDATA_H
|
@ -6,9 +6,12 @@
|
||||
class NETFile : public SubFile
|
||||
{
|
||||
public:
|
||||
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _multiplier(0) {}
|
||||
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_offset(0), _size(0), _multiplier(0) {}
|
||||
NETFile(IMG *img)
|
||||
: SubFile(img), _offset(0), _size(0), _multiplier(0) {}
|
||||
NETFile(const QString &path)
|
||||
: SubFile(path), _offset(0), _size(0), _multiplier(0) {}
|
||||
NETFile(SubFile *gmp, quint32 offset)
|
||||
: SubFile(gmp, offset), _offset(0), _size(0), _multiplier(0) {}
|
||||
|
||||
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
|
||||
|
||||
|
@ -35,7 +35,7 @@ bool RGNFile::skipClassFields(Handle &hdl) const
|
||||
break;
|
||||
}
|
||||
|
||||
return seek(hdl, hdl.pos + rs);
|
||||
return seek(hdl, hdl.pos() + rs);
|
||||
}
|
||||
|
||||
bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
|
||||
@ -133,7 +133,7 @@ bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv,
|
||||
qint16 lon, lat;
|
||||
quint16 len;
|
||||
|
||||
while (hdl.pos < (int)segment.end()) {
|
||||
while (hdl.pos() < (int)segment.end()) {
|
||||
IMG::Poly poly;
|
||||
|
||||
if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr)
|
||||
@ -206,7 +206,7 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
|
||||
if (!seek(hdl, segment.offset()))
|
||||
return false;
|
||||
|
||||
while (hdl.pos < (int)segment.end()) {
|
||||
while (hdl.pos() < (int)segment.end()) {
|
||||
IMG::Poly poly;
|
||||
QPoint pos;
|
||||
|
||||
@ -305,7 +305,7 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
|
||||
if (!seek(hdl, segment.offset()))
|
||||
return false;
|
||||
|
||||
while (hdl.pos < (int)segment.end()) {
|
||||
while (hdl.pos() < (int)segment.end()) {
|
||||
IMG::Point point;
|
||||
|
||||
if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr)
|
||||
@ -327,7 +327,7 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
|
||||
point.poi = labelPtr & 0x400000;
|
||||
if (lbl && (labelPtr & 0x3FFFFF)) {
|
||||
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi);
|
||||
point.id = ((quint64)point.type)<<40 | ((quint64)lbl->offset())<<24
|
||||
point.id = ((quint64)point.type)<<40 | ((quint64)lbl->id())<<24
|
||||
| (labelPtr & 0x3FFFFF);
|
||||
}
|
||||
|
||||
@ -351,7 +351,7 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
|
||||
if (!seek(hdl, segment.offset()))
|
||||
return false;
|
||||
|
||||
while (hdl.pos < (int)segment.end()) {
|
||||
while (hdl.pos() < (int)segment.end()) {
|
||||
IMG::Point point;
|
||||
|
||||
if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype)
|
||||
@ -382,7 +382,7 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
|
||||
if (lbl && (labelPtr & 0x3FFFFF)) {
|
||||
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi);
|
||||
point.id = ((quint64)point.type)<<40
|
||||
| ((quint64)lbl->offset())<<24 | (labelPtr & 0x3FFFFF);
|
||||
| ((quint64)lbl->id())<<24 | (labelPtr & 0x3FFFFF);
|
||||
}
|
||||
|
||||
points->append(point);
|
||||
|
@ -24,6 +24,10 @@ public:
|
||||
: SubFile(img), _offset(0), _size(0), _polygonsOffset(0),
|
||||
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
|
||||
_pointsSize(0), _init(false) {clearFlags();}
|
||||
RGNFile(const QString &path)
|
||||
: SubFile(path), _offset(0), _size(0), _polygonsOffset(0),
|
||||
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
|
||||
_pointsSize(0), _init(false) {clearFlags();}
|
||||
RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _offset(0),
|
||||
_size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0),
|
||||
_linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false)
|
||||
|
@ -341,7 +341,7 @@ static bool skipLocalization(SubFile *file, SubFile::Handle &hdl)
|
||||
len = len >> 2;
|
||||
}
|
||||
|
||||
if (!file->seek(hdl, hdl.pos + len))
|
||||
if (!file->seek(hdl, hdl.pos() + len))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -890,7 +890,7 @@ bool Style::parseDrawOrder(SubFile *file, SubFile::Handle &hdl,
|
||||
|
||||
bool Style::parseTYPFile(SubFile *file)
|
||||
{
|
||||
SubFile::Handle hdl;
|
||||
SubFile::Handle hdl(file);
|
||||
Section points, lines, polygons, order;
|
||||
quint16 tmp16, codepage;
|
||||
|
||||
|
@ -5,22 +5,35 @@
|
||||
|
||||
bool SubFile::seek(Handle &handle, quint32 pos) const
|
||||
{
|
||||
if (_file)
|
||||
return _file->seek(pos);
|
||||
else {
|
||||
if (handle._file) {
|
||||
int blockNum = pos / BLOCK_SIZE;
|
||||
|
||||
if (handle._blockNum != blockNum) {
|
||||
if (!handle._file->seek((qint64)blockNum * BLOCK_SIZE))
|
||||
return false;
|
||||
if (handle._file->read(handle._data.data(), BLOCK_SIZE) < 0)
|
||||
return false;
|
||||
handle._blockNum = blockNum;
|
||||
}
|
||||
|
||||
handle._blockPos = pos % BLOCK_SIZE;
|
||||
handle._pos = pos;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
quint32 blockSize = _img->blockSize();
|
||||
int blockNum = pos / blockSize;
|
||||
|
||||
if (handle.blockNum != blockNum) {
|
||||
if (handle._blockNum != blockNum) {
|
||||
if (blockNum >= _blocks->size())
|
||||
return false;
|
||||
if (!_img->readBlock(_blocks->at(blockNum), handle.data))
|
||||
if (!_img->readBlock(_blocks->at(blockNum), handle._data.data()))
|
||||
return false;
|
||||
handle.blockNum = blockNum;
|
||||
handle._blockNum = blockNum;
|
||||
}
|
||||
|
||||
handle.blockPos = pos % blockSize;
|
||||
handle.pos = pos;
|
||||
handle._blockPos = pos % blockSize;
|
||||
handle._pos = pos;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -28,14 +41,10 @@ bool SubFile::seek(Handle &handle, quint32 pos) const
|
||||
|
||||
bool SubFile::readByte(Handle &handle, quint8 &val) const
|
||||
{
|
||||
if (_file)
|
||||
return _file->getChar((char*)&val);
|
||||
else {
|
||||
val = handle.data.at(handle.blockPos++);
|
||||
handle.pos++;
|
||||
return (handle.blockPos >= _img->blockSize())
|
||||
? seek(handle, handle.pos) : true;
|
||||
}
|
||||
int blockSize = handle._file ? BLOCK_SIZE : _img->blockSize();
|
||||
val = handle._data.at(handle._blockPos++);
|
||||
handle._pos++;
|
||||
return (handle._blockPos >= blockSize) ? seek(handle, handle._pos) : true;
|
||||
}
|
||||
|
||||
bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
|
||||
@ -77,7 +86,7 @@ bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
|
||||
return false;
|
||||
|
||||
if (!(bits & 1)) {
|
||||
seek(hdl, hdl.pos - 1);
|
||||
seek(hdl, hdl._pos - 1);
|
||||
if (!((bits>>1) & 1)) {
|
||||
if (!((bits>>2) & 1)) {
|
||||
if (!readUInt32(hdl, bitfield))
|
||||
@ -97,8 +106,3 @@ bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString SubFile::fileName() const
|
||||
{
|
||||
return _file ? _file->fileName() : _img->fileName();
|
||||
}
|
||||
|
@ -3,38 +3,64 @@
|
||||
|
||||
#include <QVector>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include "img.h"
|
||||
|
||||
class QFile;
|
||||
class IMG;
|
||||
|
||||
#define BLOCK_SIZE 8192
|
||||
|
||||
class SubFile
|
||||
{
|
||||
public:
|
||||
enum Type {Unknown, TRE, RGN, LBL, NET, TYP, GMP};
|
||||
|
||||
struct Handle
|
||||
class Handle
|
||||
{
|
||||
Handle() : blockNum(-1), blockPos(-1), pos(-1) {}
|
||||
public:
|
||||
Handle(const SubFile *subFile)
|
||||
: _file(0), _blockNum(-1), _blockPos(-1), _pos(-1)
|
||||
{
|
||||
if (subFile && subFile->_path) {
|
||||
_file = new QFile(*(subFile->_path));
|
||||
_file->open(QIODevice::ReadOnly);
|
||||
_data.resize(BLOCK_SIZE);
|
||||
} else if (subFile)
|
||||
_data.resize(subFile->_img->blockSize());
|
||||
_blockNum = -1;
|
||||
_blockPos = -1;
|
||||
_pos = -1;
|
||||
}
|
||||
~Handle() {delete _file;}
|
||||
|
||||
QByteArray data;
|
||||
int blockNum;
|
||||
int blockPos;
|
||||
int pos;
|
||||
int pos() const {return _pos;}
|
||||
|
||||
private:
|
||||
friend class SubFile;
|
||||
|
||||
QFile *_file;
|
||||
QByteArray _data;
|
||||
int _blockNum;
|
||||
int _blockPos;
|
||||
int _pos;
|
||||
};
|
||||
|
||||
SubFile(IMG *img)
|
||||
: _gmpOffset(0), _img(img), _blocks(new QVector<quint16>()), _file(0) {}
|
||||
: _gmpOffset(0), _img(img), _blocks(new QVector<quint16>()), _path(0),
|
||||
_id(0) {}
|
||||
SubFile(SubFile *gmp, quint32 offset) : _gmpOffset(offset), _img(gmp->_img),
|
||||
_blocks(gmp->_blocks), _file(gmp->_file) {}
|
||||
SubFile(QFile *file)
|
||||
: _gmpOffset(0), _img(0), _blocks(0), _file(file) {}
|
||||
_blocks(gmp->_blocks), _path(gmp->_path), _id(gmp->id()) {}
|
||||
SubFile(const QString &path)
|
||||
: _gmpOffset(0), _img(0), _blocks(0), _path(new QString(path)), _id(0) {}
|
||||
~SubFile()
|
||||
{
|
||||
if (!_gmpOffset)
|
||||
if (!_gmpOffset) {
|
||||
delete _blocks;
|
||||
delete _path;
|
||||
}
|
||||
}
|
||||
|
||||
void addBlock(quint16 block) {_blocks->append(block);}
|
||||
void setId(quint16 id) {_id = id;}
|
||||
|
||||
bool seek(Handle &handle, quint32 pos) const;
|
||||
|
||||
@ -114,8 +140,8 @@ public:
|
||||
bool readVUInt32(Handle &hdl, quint32 &val) const;
|
||||
bool readVBitfield32(Handle &hdl, quint32 &bitfield) const;
|
||||
|
||||
quint16 offset() const {return _blocks->first();}
|
||||
QString fileName() const;
|
||||
quint16 id() const {return _blocks ? _blocks->first() : _id;}
|
||||
QString fileName() const {return _path ? *_path : _img->fileName();}
|
||||
|
||||
protected:
|
||||
quint32 _gmpOffset;
|
||||
@ -125,7 +151,8 @@ private:
|
||||
|
||||
IMG *_img;
|
||||
QVector<quint16> *_blocks;
|
||||
QFile *_file;
|
||||
QString *_path;
|
||||
quint16 _id;
|
||||
};
|
||||
|
||||
#endif // SUBFILE_H
|
||||
|
@ -39,7 +39,7 @@ TREFile::~TREFile()
|
||||
|
||||
bool TREFile::init()
|
||||
{
|
||||
Handle hdl;
|
||||
Handle hdl(this);
|
||||
quint8 locked;
|
||||
quint16 hdrLen;
|
||||
|
||||
@ -113,7 +113,7 @@ bool TREFile::init()
|
||||
|
||||
bool TREFile::load(int idx)
|
||||
{
|
||||
Handle hdl;
|
||||
Handle hdl(this);
|
||||
QList<SubDiv*> sl;
|
||||
SubDiv *s = 0;
|
||||
SubDivTree *tree = new SubDivTree();
|
||||
@ -199,7 +199,7 @@ bool TREFile::load(int idx)
|
||||
if (i)
|
||||
sl.at(i-1)->setExtEnds(polygons, lines, points);
|
||||
|
||||
if (!seek(hdl, hdl.pos + _extended.itemSize - 12))
|
||||
if (!seek(hdl, hdl.pos() + _extended.itemSize - 12))
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ class TREFile : public SubFile
|
||||
{
|
||||
public:
|
||||
TREFile(IMG *img) : SubFile(img) {}
|
||||
TREFile(const QString &path) : SubFile(path) {}
|
||||
TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {}
|
||||
~TREFile();
|
||||
|
||||
|
@ -59,6 +59,29 @@ SubFile *VectorTile::addFile(IMG *img, SubFile::Type type)
|
||||
}
|
||||
}
|
||||
|
||||
SubFile *VectorTile::addFile(const QString &path, SubFile::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case SubFile::TRE:
|
||||
_tre = new TREFile(path);
|
||||
return _tre;
|
||||
case SubFile::RGN:
|
||||
_rgn = new RGNFile(path);
|
||||
return _rgn;
|
||||
case SubFile::LBL:
|
||||
_lbl = new LBLFile(path);
|
||||
return _lbl;
|
||||
case SubFile::NET:
|
||||
_net = new NETFile(path);
|
||||
return _net;
|
||||
case SubFile::GMP:
|
||||
_gmp = new SubFile(path);
|
||||
return _gmp;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool VectorTile::init()
|
||||
{
|
||||
if (_gmp && !initGMP())
|
||||
@ -72,7 +95,7 @@ bool VectorTile::init()
|
||||
|
||||
bool VectorTile::initGMP()
|
||||
{
|
||||
SubFile::Handle hdl;
|
||||
SubFile::Handle hdl(_gmp);
|
||||
quint32 tre, rgn, lbl, net;
|
||||
|
||||
if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre)
|
||||
@ -92,7 +115,7 @@ void VectorTile::polys(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
|
||||
QList<IMG::Poly> *lines, QCache<const SubDiv *, IMG::Polys> *polyCache)
|
||||
const
|
||||
{
|
||||
SubFile::Handle rgnHdl, lblHdl, netHdl;
|
||||
SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net);
|
||||
|
||||
if (!_rgn->initialized() && !_rgn->init(rgnHdl))
|
||||
return;
|
||||
@ -131,7 +154,7 @@ void VectorTile::polys(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
|
||||
void VectorTile::points(const RectC &rect, int bits, QList<IMG::Point> *points,
|
||||
QCache<const SubDiv *, QList<IMG::Point> > *pointCache) const
|
||||
{
|
||||
SubFile::Handle rgnHdl, lblHdl;
|
||||
SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl);
|
||||
|
||||
if (!_rgn->initialized() && !_rgn->init(rgnHdl))
|
||||
return;
|
||||
|
@ -23,6 +23,7 @@ public:
|
||||
|
||||
SubFile *file(SubFile::Type type);
|
||||
SubFile *addFile(IMG *img, SubFile::Type type);
|
||||
SubFile *addFile(const QString &path, SubFile::Type type);
|
||||
|
||||
void polys(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
|
||||
QList<IMG::Poly> *lines, QCache<const SubDiv *, IMG::Polys> *polyCache)
|
||||
@ -37,8 +38,6 @@ public:
|
||||
|| type == SubFile::GMP);
|
||||
}
|
||||
|
||||
friend QDebug operator<<(QDebug dbg, const VectorTile &tile);
|
||||
|
||||
private:
|
||||
bool initGMP();
|
||||
|
||||
|
Reference in New Issue
Block a user