mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-27 21:24:47 +01:00
Added support for GMAP maps
This commit is contained in:
parent
e2339c67cd
commit
911c63df0c
@ -91,8 +91,10 @@ HEADERS += src/common/config.h \
|
||||
src/map/IMG/bitmapline.h \
|
||||
src/map/IMG/bitstream.h \
|
||||
src/map/IMG/deltastream.h \
|
||||
src/map/IMG/gmap.h \
|
||||
src/map/IMG/huffmanstream.h \
|
||||
src/map/IMG/huffmantable.h \
|
||||
src/map/IMG/mapdata.h \
|
||||
src/map/IMG/textpathitem.h \
|
||||
src/map/IMG/textpointitem.h \
|
||||
src/map/projection.h \
|
||||
@ -249,8 +251,10 @@ SOURCES += src/main.cpp \
|
||||
src/map/IMG/bitmapline.cpp \
|
||||
src/map/IMG/bitstream.cpp \
|
||||
src/map/IMG/deltastream.cpp \
|
||||
src/map/IMG/gmap.cpp \
|
||||
src/map/IMG/huffmanstream.cpp \
|
||||
src/map/IMG/huffmantable.cpp \
|
||||
src/map/IMG/mapdata.cpp \
|
||||
src/map/IMG/textpathitem.cpp \
|
||||
src/map/IMG/textpointitem.cpp \
|
||||
src/map/maplist.cpp \
|
||||
|
@ -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();
|
||||
|
||||
|
@ -13,6 +13,9 @@
|
||||
#include "IMG/textpathitem.h"
|
||||
#include "IMG/textpointitem.h"
|
||||
#include "IMG/bitmapline.h"
|
||||
#include "IMG/style.h"
|
||||
#include "IMG/img.h"
|
||||
#include "IMG/gmap.h"
|
||||
#include "pcs.h"
|
||||
#include "rectd.h"
|
||||
#include "imgmap.h"
|
||||
@ -35,9 +38,9 @@ public:
|
||||
const QString &key() const {return _key;}
|
||||
const QPoint &xy() const {return _xy;}
|
||||
QImage &img() {return _img;}
|
||||
QList<IMG::Poly> &polygons() {return _polygons;}
|
||||
QList<IMG::Poly> &lines() {return _lines;}
|
||||
QList<IMG::Point> &points() {return _points;}
|
||||
QList<MapData::Poly> &polygons() {return _polygons;}
|
||||
QList<MapData::Poly> &lines() {return _lines;}
|
||||
QList<MapData::Point> &points() {return _points;}
|
||||
|
||||
void render()
|
||||
{
|
||||
@ -70,9 +73,9 @@ private:
|
||||
QPoint _xy;
|
||||
QString _key;
|
||||
QImage _img;
|
||||
QList<IMG::Poly> _polygons;
|
||||
QList<IMG::Poly> _lines;
|
||||
QList<IMG::Point> _points;
|
||||
QList<MapData::Poly> _polygons;
|
||||
QList<MapData::Poly> _lines;
|
||||
QList<MapData::Point> _points;
|
||||
};
|
||||
|
||||
|
||||
@ -226,11 +229,17 @@ static bool rectNearPolygon(const QPolygonF &polygon, const QRectF &rect)
|
||||
|| polygon.containsPoint(rect.bottomRight(), Qt::OddEvenFill)));
|
||||
}
|
||||
|
||||
|
||||
IMGMap::IMGMap(const QString &fileName, QObject *parent)
|
||||
: Map(parent), _img(fileName), _projection(PCS::pcs(3857)), _valid(false)
|
||||
: Map(parent), _projection(PCS::pcs(3857)), _valid(false)
|
||||
{
|
||||
if (!_img.isValid()) {
|
||||
_errorString = _img.errorString();
|
||||
if (GMAP::isGMAP(fileName))
|
||||
_data = new GMAP(fileName);
|
||||
else
|
||||
_data = new IMG(fileName);
|
||||
|
||||
if (!_data->isValid()) {
|
||||
_errorString = _data->errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -242,17 +251,17 @@ IMGMap::IMGMap(const QString &fileName, QObject *parent)
|
||||
|
||||
void IMGMap::load()
|
||||
{
|
||||
_img.load();
|
||||
_data->load();
|
||||
}
|
||||
|
||||
void IMGMap::unload()
|
||||
{
|
||||
_img.clear();
|
||||
_data->clear();
|
||||
}
|
||||
|
||||
QRectF IMGMap::bounds()
|
||||
{
|
||||
RectD prect(_img.bounds(), _projection);
|
||||
RectD prect(_data->bounds(), _projection);
|
||||
return QRectF(_transform.proj2img(prect.topLeft()),
|
||||
_transform.proj2img(prect.bottomRight()));
|
||||
}
|
||||
@ -302,7 +311,7 @@ Transform IMGMap::transform(int zoom) const
|
||||
{
|
||||
double scale = _projection.isGeographic()
|
||||
? 360.0 / (1<<zoom) : (2.0 * M_PI * WGS84_RADIUS) / (1<<zoom);
|
||||
PointD topLeft(_projection.ll2xy(_img.bounds().topLeft()));
|
||||
PointD topLeft(_projection.ll2xy(_data->bounds().topLeft()));
|
||||
return Transform(ReferencePoint(PointD(0, 0), topLeft),
|
||||
PointD(scale, scale));
|
||||
}
|
||||
@ -322,14 +331,14 @@ Coordinates IMGMap::xy2ll(const QPointF &p)
|
||||
return _projection.xy2ll(_transform.img2proj(p));
|
||||
}
|
||||
|
||||
void IMGMap::drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons)
|
||||
void IMGMap::drawPolygons(QPainter *painter, const QList<MapData::Poly> &polygons)
|
||||
{
|
||||
for (int n = 0; n < _img.style()->drawOrder().size(); n++) {
|
||||
for (int n = 0; n < _data->style()->drawOrder().size(); n++) {
|
||||
for (int i = 0; i < polygons.size(); i++) {
|
||||
const IMG::Poly &poly = polygons.at(i);
|
||||
if (poly.type != _img.style()->drawOrder().at(n))
|
||||
const MapData::Poly &poly = polygons.at(i);
|
||||
if (poly.type != _data->style()->drawOrder().at(n))
|
||||
continue;
|
||||
const Style::Polygon &style = _img.style()->polygon(poly.type);
|
||||
const Style::Polygon &style = _data->style()->polygon(poly.type);
|
||||
|
||||
painter->setPen(style.pen());
|
||||
painter->setBrush(style.brush());
|
||||
@ -338,13 +347,13 @@ void IMGMap::drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons)
|
||||
}
|
||||
}
|
||||
|
||||
void IMGMap::drawLines(QPainter *painter, const QList<IMG::Poly> &lines)
|
||||
void IMGMap::drawLines(QPainter *painter, const QList<MapData::Poly> &lines)
|
||||
{
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
const IMG::Poly &poly = lines.at(i);
|
||||
const Style::Line &style = _img.style()->line(poly.type);
|
||||
const MapData::Poly &poly = lines.at(i);
|
||||
const Style::Line &style = _data->style()->line(poly.type);
|
||||
|
||||
if (style.background() == Qt::NoPen)
|
||||
continue;
|
||||
@ -354,8 +363,8 @@ void IMGMap::drawLines(QPainter *painter, const QList<IMG::Poly> &lines)
|
||||
}
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
const IMG::Poly &poly = lines.at(i);
|
||||
const Style::Line &style = _img.style()->line(poly.type);
|
||||
const MapData::Poly &poly = lines.at(i);
|
||||
const Style::Line &style = _data->style()->line(poly.type);
|
||||
|
||||
if (!style.img().isNull())
|
||||
BitmapLine::draw(painter, poly.points, style.img());
|
||||
@ -372,12 +381,11 @@ void IMGMap::drawTextItems(QPainter *painter, const QList<TextItem*> &textItems)
|
||||
textItems.at(i)->paint(painter);
|
||||
}
|
||||
|
||||
|
||||
void IMGMap::processPolygons(QList<IMG::Poly> &polygons,
|
||||
void IMGMap::processPolygons(QList<MapData::Poly> &polygons,
|
||||
QList<TextItem*> &textItems)
|
||||
{
|
||||
for (int i = 0; i < polygons.size(); i++) {
|
||||
IMG::Poly &poly = polygons[i];
|
||||
MapData::Poly &poly = polygons[i];
|
||||
for (int j = 0; j < poly.points.size(); j++) {
|
||||
QPointF &p = poly.points[j];
|
||||
p = ll2xy(Coordinates(p.x(), p.y()));
|
||||
@ -389,7 +397,7 @@ void IMGMap::processPolygons(QList<IMG::Poly> &polygons,
|
||||
if (_zoom <= 23 && (Style::isWaterArea(poly.type)
|
||||
|| Style::isMilitaryArea(poly.type)
|
||||
|| Style::isNatureReserve(poly.type))) {
|
||||
const Style::Polygon &style = _img.style()->polygon(poly.type);
|
||||
const Style::Polygon &style = _data->style()->polygon(poly.type);
|
||||
TextPointItem *item = new TextPointItem(
|
||||
centroid(poly.points).toPoint(), &poly.label.text(),
|
||||
poiFont(), 0, &style.brush().color());
|
||||
@ -402,13 +410,13 @@ void IMGMap::processPolygons(QList<IMG::Poly> &polygons,
|
||||
}
|
||||
}
|
||||
|
||||
void IMGMap::processLines(QList<IMG::Poly> &lines, const QRect &tileRect,
|
||||
void IMGMap::processLines(QList<MapData::Poly> &lines, const QRect &tileRect,
|
||||
QList<TextItem*> &textItems)
|
||||
{
|
||||
qStableSort(lines);
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
IMG::Poly &poly = lines[i];
|
||||
MapData::Poly &poly = lines[i];
|
||||
for (int j = 0; j < poly.points.size(); j++) {
|
||||
QPointF &p = poly.points[j];
|
||||
p = ll2xy(Coordinates(p.x(), p.y()));
|
||||
@ -420,12 +428,12 @@ void IMGMap::processLines(QList<IMG::Poly> &lines, const QRect &tileRect,
|
||||
processShields(lines, tileRect, textItems);
|
||||
}
|
||||
|
||||
void IMGMap::processStreetNames(QList<IMG::Poly> &lines, const QRect &tileRect,
|
||||
QList<TextItem*> &textItems)
|
||||
void IMGMap::processStreetNames(QList<MapData::Poly> &lines,
|
||||
const QRect &tileRect, QList<TextItem*> &textItems)
|
||||
{
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
IMG::Poly &poly = lines[i];
|
||||
const Style::Line &style = _img.style()->line(poly.type);
|
||||
MapData::Poly &poly = lines[i];
|
||||
const Style::Line &style = _data->style()->line(poly.type);
|
||||
|
||||
if (style.img().isNull() && style.foreground() == Qt::NoPen)
|
||||
continue;
|
||||
@ -449,7 +457,7 @@ void IMGMap::processStreetNames(QList<IMG::Poly> &lines, const QRect &tileRect,
|
||||
}
|
||||
}
|
||||
|
||||
void IMGMap::processShields(QList<IMG::Poly> &lines, const QRect &tileRect,
|
||||
void IMGMap::processShields(QList<MapData::Poly> &lines, const QRect &tileRect,
|
||||
QList<TextItem*> &textItems)
|
||||
{
|
||||
for (int type = FIRST_SHIELD; type <= LAST_SHIELD; type++) {
|
||||
@ -460,7 +468,7 @@ void IMGMap::processShields(QList<IMG::Poly> &lines, const QRect &tileRect,
|
||||
QHash<Label::Shield, const Label::Shield*> sp;
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
const IMG::Poly &poly = lines.at(i);
|
||||
const MapData::Poly &poly = lines.at(i);
|
||||
const Label::Shield &shield = poly.label.shield();
|
||||
if (!shield.isValid() || shield.type() != type
|
||||
|| !Style::isMajorRoad(poly.type))
|
||||
@ -513,14 +521,14 @@ void IMGMap::processShields(QList<IMG::Poly> &lines, const QRect &tileRect,
|
||||
}
|
||||
}
|
||||
|
||||
void IMGMap::processPoints(QList<IMG::Point> &points,
|
||||
void IMGMap::processPoints(QList<MapData::Point> &points,
|
||||
QList<TextItem*> &textItems)
|
||||
{
|
||||
qSort(points);
|
||||
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
IMG::Point &point = points[i];
|
||||
const Style::Point &style = _img.style()->point(point.type);
|
||||
MapData::Point &point = points[i];
|
||||
const Style::Point &style = _data->style()->point(point.type);
|
||||
|
||||
if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type)))
|
||||
continue;
|
||||
@ -574,7 +582,7 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
for (int j = 0; j < height; j++) {
|
||||
QPixmap pm;
|
||||
QPoint ttl(tl.x() + i * TILE_SIZE, tl.y() + j * TILE_SIZE);
|
||||
QString key = _img.fileName() + "-" + QString::number(_zoom) + "_"
|
||||
QString key = _data->fileName() + "-" + QString::number(_zoom) + "_"
|
||||
+ QString::number(ttl.x()) + "_" + QString::number(ttl.y());
|
||||
if (QPixmapCache::find(key, pm))
|
||||
painter->drawPixmap(ttl, pm);
|
||||
@ -584,13 +592,13 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||
|
||||
RectD polyRect(_transform.img2proj(ttl), _transform.img2proj(
|
||||
QPointF(ttl.x() + TILE_SIZE, ttl.y() + TILE_SIZE)));
|
||||
_img.polys(polyRect.toRectC(_projection, 4), _zoom,
|
||||
_data->polys(polyRect.toRectC(_projection, 4), _zoom,
|
||||
&(tile.polygons()), &(tile.lines()));
|
||||
|
||||
RectD pointRect(_transform.img2proj(QPointF(ttl.x() - TEXT_EXTENT,
|
||||
ttl.y() - TEXT_EXTENT)), _transform.img2proj(QPointF(ttl.x()
|
||||
+ TILE_SIZE + TEXT_EXTENT, ttl.y() + TILE_SIZE + TEXT_EXTENT)));
|
||||
_img.points(pointRect.toRectC(_projection, 4), _zoom,
|
||||
_data->points(pointRect.toRectC(_projection, 4), _zoom,
|
||||
&(tile.points()));
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "map.h"
|
||||
#include "projection.h"
|
||||
#include "transform.h"
|
||||
#include "IMG/img.h"
|
||||
#include "IMG/mapdata.h"
|
||||
|
||||
class TextItem;
|
||||
|
||||
@ -14,8 +14,9 @@ class IMGMap : public Map
|
||||
|
||||
public:
|
||||
IMGMap(const QString &fileName, QObject *parent = 0);
|
||||
~IMGMap() {delete _data;}
|
||||
|
||||
QString name() const {return _img.name();}
|
||||
QString name() const {return _data->name();}
|
||||
|
||||
QRectF bounds();
|
||||
|
||||
@ -43,21 +44,21 @@ private:
|
||||
|
||||
Transform transform(int zoom) const;
|
||||
void updateTransform();
|
||||
void drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons);
|
||||
void drawLines(QPainter *painter, const QList<IMG::Poly> &lines);
|
||||
void drawPolygons(QPainter *painter, const QList<MapData::Poly> &polygons);
|
||||
void drawLines(QPainter *painter, const QList<MapData::Poly> &lines);
|
||||
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
|
||||
|
||||
void processPolygons(QList<IMG::Poly> &polygons,
|
||||
void processPolygons(QList<MapData::Poly> &polygons,
|
||||
QList<TextItem *> &textItems);
|
||||
void processLines(QList<IMG::Poly> &lines, const QRect &tileRect,
|
||||
void processLines(QList<MapData::Poly> &lines, const QRect &tileRect,
|
||||
QList<TextItem*> &textItems);
|
||||
void processPoints(QList<IMG::Point> &points, QList<TextItem*> &textItems);
|
||||
void processShields(QList<IMG::Poly> &lines, const QRect &tileRect,
|
||||
void processPoints(QList<MapData::Point> &points, QList<TextItem*> &textItems);
|
||||
void processShields(QList<MapData::Poly> &lines, const QRect &tileRect,
|
||||
QList<TextItem*> &textItems);
|
||||
void processStreetNames(QList<IMG::Poly> &lines, const QRect &tileRect,
|
||||
void processStreetNames(QList<MapData::Poly> &lines, const QRect &tileRect,
|
||||
QList<TextItem*> &textItems);
|
||||
|
||||
IMG _img;
|
||||
MapData *_data;
|
||||
int _zoom;
|
||||
Projection _projection;
|
||||
Transform _transform;
|
||||
|
@ -8,20 +8,27 @@
|
||||
#include "mbtilesmap.h"
|
||||
#include "rmap.h"
|
||||
#include "imgmap.h"
|
||||
#include "IMG/gmap.h"
|
||||
#include "maplist.h"
|
||||
|
||||
|
||||
bool MapList::loadMap(Map* map, const QString &path, bool dir)
|
||||
bool MapList::loadMap(Map *map, const QString &path, bool dir)
|
||||
{
|
||||
if (map->isValid()) {
|
||||
if (map && map->isValid()) {
|
||||
_maps.append(map);
|
||||
return true;
|
||||
} else {
|
||||
} else if (map) {
|
||||
if (dir)
|
||||
_errorString += path + ": " + map->errorString() + "\n";
|
||||
else
|
||||
_errorString = map->errorString();
|
||||
return false;
|
||||
} else {
|
||||
if (dir)
|
||||
_errorString += path + ": " + "Unknown map format\n";
|
||||
else
|
||||
_errorString = "Unknown map format";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,18 +48,22 @@ Map *MapList::loadSource(const QString &path, bool dir)
|
||||
return map;
|
||||
}
|
||||
|
||||
bool MapList::loadFile(const QString &path, bool *atlas, bool dir)
|
||||
bool MapList::loadFile(const QString &path, bool *terminate, bool dir)
|
||||
{
|
||||
QFileInfo fi(path);
|
||||
QString suffix = fi.suffix().toLower();
|
||||
Map *map;
|
||||
Map *map = 0;
|
||||
|
||||
if (Atlas::isAtlas(path)) {
|
||||
*atlas = true;
|
||||
*terminate = true;
|
||||
map = new Atlas(path, this);
|
||||
} else if (suffix == "xml") {
|
||||
if (!(map = loadSource(path, dir)))
|
||||
if (MapSource::isMap(path) && !(map = loadSource(path, dir)))
|
||||
return false;
|
||||
else if (GMAP::isGMAP(path)) {
|
||||
*terminate = true;
|
||||
map = new IMGMap(path);
|
||||
}
|
||||
} else if (suffix == "jnx")
|
||||
map = new JNXMap(path, this);
|
||||
else if (suffix == "tif" || suffix == "tiff")
|
||||
@ -85,15 +96,15 @@ bool MapList::loadDirR(const QString &path)
|
||||
for (int i = 0; i < ml.size(); i++) {
|
||||
const QFileInfo &fi = ml.at(i);
|
||||
QString suffix = fi.suffix().toLower();
|
||||
bool atlas = false;
|
||||
bool terminate = false;
|
||||
|
||||
if (fi.isDir() && fi.fileName() != "set") {
|
||||
if (!loadDirR(fi.absoluteFilePath()))
|
||||
ret = false;
|
||||
} else if (filter().contains("*." + suffix)) {
|
||||
if (!loadFile(fi.absoluteFilePath(), &atlas, true))
|
||||
if (!loadFile(fi.absoluteFilePath(), &terminate, true))
|
||||
ret = false;
|
||||
if (atlas)
|
||||
if (terminate)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -120,7 +131,7 @@ QString MapList::formats()
|
||||
return
|
||||
tr("Supported files")
|
||||
+ " (*.img *.jnx *.map *.mbtiles *.rmap *.rtmap *.tar *.tba *.tif *.tiff *.xml);;"
|
||||
+ tr("Garmin IMG maps") + " (*.img);;"
|
||||
+ tr("Garmin IMG maps") + " (*.img *.xml);;"
|
||||
+ tr("Garmin JNX maps") + " (*.jnx);;"
|
||||
+ tr("OziExplorer maps") + " (*.map);;"
|
||||
+ tr("MBTiles maps") + " (*.mbtiles);;"
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
static QStringList filter();
|
||||
|
||||
private:
|
||||
bool loadFile(const QString &path, bool *atlas, bool dir);
|
||||
bool loadFile(const QString &path, bool *terminate, bool dir);
|
||||
bool loadDirR(const QString &path);
|
||||
Map *loadSource(const QString &path, bool dir);
|
||||
bool loadMap(Map *map, const QString &path, bool dir);
|
||||
|
@ -222,6 +222,20 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
|
||||
}
|
||||
}
|
||||
|
||||
bool MapSource::isMap(const QString &path)
|
||||
{
|
||||
QFile file(path);
|
||||
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||
return false;
|
||||
|
||||
QXmlStreamReader reader(&file);
|
||||
if (reader.readNextStartElement() && reader.name() == "map")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Map *MapSource::loadMap(const QString &path, QString &errorString)
|
||||
{
|
||||
Config config;
|
||||
|
@ -15,6 +15,7 @@ class MapSource
|
||||
{
|
||||
public:
|
||||
static Map *loadMap(const QString &path, QString &errorString);
|
||||
static bool isMap(const QString &path);
|
||||
|
||||
private:
|
||||
enum Type {
|
||||
|
Loading…
Reference in New Issue
Block a user