1
0
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:
Martin Tůma 2020-02-09 23:24:48 +01:00
parent e2339c67cd
commit 911c63df0c
26 changed files with 628 additions and 333 deletions

View File

@ -91,8 +91,10 @@ HEADERS += src/common/config.h \
src/map/IMG/bitmapline.h \ src/map/IMG/bitmapline.h \
src/map/IMG/bitstream.h \ src/map/IMG/bitstream.h \
src/map/IMG/deltastream.h \ src/map/IMG/deltastream.h \
src/map/IMG/gmap.h \
src/map/IMG/huffmanstream.h \ src/map/IMG/huffmanstream.h \
src/map/IMG/huffmantable.h \ src/map/IMG/huffmantable.h \
src/map/IMG/mapdata.h \
src/map/IMG/textpathitem.h \ src/map/IMG/textpathitem.h \
src/map/IMG/textpointitem.h \ src/map/IMG/textpointitem.h \
src/map/projection.h \ src/map/projection.h \
@ -249,8 +251,10 @@ SOURCES += src/main.cpp \
src/map/IMG/bitmapline.cpp \ src/map/IMG/bitmapline.cpp \
src/map/IMG/bitstream.cpp \ src/map/IMG/bitstream.cpp \
src/map/IMG/deltastream.cpp \ src/map/IMG/deltastream.cpp \
src/map/IMG/gmap.cpp \
src/map/IMG/huffmanstream.cpp \ src/map/IMG/huffmanstream.cpp \
src/map/IMG/huffmantable.cpp \ src/map/IMG/huffmantable.cpp \
src/map/IMG/mapdata.cpp \
src/map/IMG/textpathitem.cpp \ src/map/IMG/textpathitem.cpp \
src/map/IMG/textpointitem.cpp \ src/map/IMG/textpointitem.cpp \
src/map/maplist.cpp \ src/map/maplist.cpp \

View File

@ -32,7 +32,7 @@ bool BitStream1::read(int bits, quint32 &val)
bool BitStream1::flush() bool BitStream1::flush()
{ {
if (_length && !_file.seek(_hdl, _hdl.pos + _length)) if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
return false; return false;
_length = 0; _length = 0;
@ -68,7 +68,7 @@ bool BitStream4::read(int bits, quint32 &val)
bool BitStream4::flush() bool BitStream4::flush()
{ {
if (_length && !_file.seek(_hdl, _hdl.pos + _length)) if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
return false; return false;
_length = 0; _length = 0;

151
src/map/IMG/gmap.cpp Normal file
View 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
View 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

View File

@ -55,7 +55,7 @@ bool HuffmanTable::getBuffer(const SubFile &file, SubFile::Handle &hdl,
return false; return false;
if (!file.readVUInt32(hdl, recordSize)) if (!file.readVUInt32(hdl, recordSize))
return false; return false;
recordOffset = hdl.pos + recordSize; recordOffset = hdl.pos() + recordSize;
if (recordOffset > offset + size) if (recordOffset > offset + size)
return false; return false;
}; };

View File

@ -1,6 +1,6 @@
#include <QMap> #include <QMap>
#include <QtEndian> #include <QtEndian>
#include "common/programpaths.h"
#include "vectortile.h" #include "vectortile.h"
#include "img.h" #include "img.h"
@ -8,32 +8,6 @@
typedef QMap<QString, VectorTile*> TileMap; 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 &rect;
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 &rect;
int bits;
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])
{ {
if (!memcmp(str, "TRE", 3)) if (!memcmp(str, "TRE", 3))
@ -52,8 +26,7 @@ static SubFile::Type tileType(const char str[3])
return SubFile::Unknown; return SubFile::Unknown;
} }
IMG::IMG(const QString &fileName) IMG::IMG(const QString &fileName) : _file(fileName)
: _file(fileName), _typ(0), _style(0), _valid(false)
{ {
#define CHECK(condition) \ #define CHECK(condition) \
if (!(condition)) { \ if (!(condition)) { \
@ -191,86 +164,6 @@ IMG::IMG(const QString &fileName)
_valid = true; _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 IMG::read(char *data, qint64 maxSize)
{ {
qint64 ret = _file.read(data, maxSize); qint64 ret = _file.read(data, maxSize);
@ -292,28 +185,12 @@ template<class T> bool IMG::readValue(T &val)
return true; return true;
} }
bool IMG::readBlock(int blockNum, QByteArray &data) bool IMG::readBlock(int blockNum, char *data)
{ {
if (!_file.seek((qint64)blockNum * (qint64)_blockSize)) if (!_file.seek((qint64)blockNum * (qint64)_blockSize))
return false; return false;
data.resize(_blockSize); if (read(data, _blockSize) < _blockSize)
if (read(data.data(), _blockSize) < _blockSize)
return false; return false;
return true; 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

View File

@ -2,105 +2,26 @@
#define IMG_H #define IMG_H
#include <QFile> #include <QFile>
#include <QByteArray> #include "mapdata.h"
#include <QCache>
#include <QDebug>
#include "common/rtree.h"
#include "common/rectc.h"
#include "style.h"
#include "label.h"
class VectorTile; class IMG : public MapData
class SubFile;
class SubDiv;
class IMG
{ {
public: 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(const QString &fileName);
~IMG();
void load();
void clear();
QString fileName() const {return _file.fileName();} 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: private:
friend class SubFile; friend class SubFile;
typedef RTree<VectorTile*, double, 2> TileTree;
int blockSize() const {return _blockSize;} int blockSize() const {return _blockSize;}
bool readBlock(int blockNum, QByteArray &data); bool readBlock(int blockNum, char *data);
qint64 read(char *data, qint64 maxSize); qint64 read(char *data, qint64 maxSize);
template<class T> bool readValue(T &val); template<class T> bool readValue(T &val);
QFile _file; QFile _file;
quint8 _key; quint8 _key;
int _blockSize; 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 #endif // IMG_H

View File

@ -12,6 +12,9 @@ public:
LBLFile(IMG *img) LBLFile(IMG *img)
: SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0), : SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0),
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(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), LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0), _codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0),
_poiMultiplier(0), _multiplier(0), _encoding(0) {} _poiMultiplier(0), _multiplier(0), _encoding(0) {}

108
src/map/IMG/mapdata.cpp Normal file
View 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 &rect;
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 &rect;
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
View 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

View File

@ -6,9 +6,12 @@
class NETFile : public SubFile class NETFile : public SubFile
{ {
public: public:
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _multiplier(0) {} NETFile(IMG *img)
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), : SubFile(img), _offset(0), _size(0), _multiplier(0) {}
_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); bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);

View File

@ -35,7 +35,7 @@ bool RGNFile::skipClassFields(Handle &hdl) const
break; break;
} }
return seek(hdl, hdl.pos + rs); return seek(hdl, hdl.pos() + rs);
} }
bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3], bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
@ -133,7 +133,7 @@ bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv,
qint16 lon, lat; qint16 lon, lat;
quint16 len; quint16 len;
while (hdl.pos < (int)segment.end()) { while (hdl.pos() < (int)segment.end()) {
IMG::Poly poly; IMG::Poly poly;
if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr) 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())) if (!seek(hdl, segment.offset()))
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;
@ -305,7 +305,7 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
if (!seek(hdl, segment.offset())) if (!seek(hdl, segment.offset()))
return false; return false;
while (hdl.pos < (int)segment.end()) { while (hdl.pos() < (int)segment.end()) {
IMG::Point point; IMG::Point point;
if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr) if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr)
@ -327,7 +327,7 @@ bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
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);
point.id = ((quint64)point.type)<<40 | ((quint64)lbl->offset())<<24 point.id = ((quint64)point.type)<<40 | ((quint64)lbl->id())<<24
| (labelPtr & 0x3FFFFF); | (labelPtr & 0x3FFFFF);
} }
@ -351,7 +351,7 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
if (!seek(hdl, segment.offset())) if (!seek(hdl, segment.offset()))
return false; return false;
while (hdl.pos < (int)segment.end()) { while (hdl.pos() < (int)segment.end()) {
IMG::Point point; IMG::Point point;
if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype) 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)) { if (lbl && (labelPtr & 0x3FFFFF)) {
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi); point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi);
point.id = ((quint64)point.type)<<40 point.id = ((quint64)point.type)<<40
| ((quint64)lbl->offset())<<24 | (labelPtr & 0x3FFFFF); | ((quint64)lbl->id())<<24 | (labelPtr & 0x3FFFFF);
} }
points->append(point); points->append(point);

View File

@ -24,6 +24,10 @@ public:
: 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),
_pointsSize(0), _init(false) {clearFlags();} _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), RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _offset(0),
_size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0), _size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0),
_linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false) _linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false)

View File

@ -341,7 +341,7 @@ static bool skipLocalization(SubFile *file, SubFile::Handle &hdl)
len = len >> 2; len = len >> 2;
} }
if (!file->seek(hdl, hdl.pos + len)) if (!file->seek(hdl, hdl.pos() + len))
return false; return false;
return true; return true;
@ -890,7 +890,7 @@ bool Style::parseDrawOrder(SubFile *file, SubFile::Handle &hdl,
bool Style::parseTYPFile(SubFile *file) bool Style::parseTYPFile(SubFile *file)
{ {
SubFile::Handle hdl; SubFile::Handle hdl(file);
Section points, lines, polygons, order; Section points, lines, polygons, order;
quint16 tmp16, codepage; quint16 tmp16, codepage;

View File

@ -5,22 +5,35 @@
bool SubFile::seek(Handle &handle, quint32 pos) const bool SubFile::seek(Handle &handle, quint32 pos) const
{ {
if (_file) if (handle._file) {
return _file->seek(pos); int blockNum = pos / BLOCK_SIZE;
else {
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(); quint32 blockSize = _img->blockSize();
int blockNum = pos / blockSize; int blockNum = pos / blockSize;
if (handle.blockNum != blockNum) { if (handle._blockNum != blockNum) {
if (blockNum >= _blocks->size()) if (blockNum >= _blocks->size())
return false; return false;
if (!_img->readBlock(_blocks->at(blockNum), handle.data)) if (!_img->readBlock(_blocks->at(blockNum), handle._data.data()))
return false; return false;
handle.blockNum = blockNum; handle._blockNum = blockNum;
} }
handle.blockPos = pos % blockSize; handle._blockPos = pos % blockSize;
handle.pos = pos; handle._pos = pos;
return true; return true;
} }
@ -28,14 +41,10 @@ bool SubFile::seek(Handle &handle, quint32 pos) const
bool SubFile::readByte(Handle &handle, quint8 &val) const bool SubFile::readByte(Handle &handle, quint8 &val) const
{ {
if (_file) int blockSize = handle._file ? BLOCK_SIZE : _img->blockSize();
return _file->getChar((char*)&val); val = handle._data.at(handle._blockPos++);
else { handle._pos++;
val = handle.data.at(handle.blockPos++); return (handle._blockPos >= blockSize) ? seek(handle, handle._pos) : true;
handle.pos++;
return (handle.blockPos >= _img->blockSize())
? seek(handle, handle.pos) : true;
}
} }
bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
@ -77,7 +86,7 @@ bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
return false; return false;
if (!(bits & 1)) { if (!(bits & 1)) {
seek(hdl, hdl.pos - 1); seek(hdl, hdl._pos - 1);
if (!((bits>>1) & 1)) { if (!((bits>>1) & 1)) {
if (!((bits>>2) & 1)) { if (!((bits>>2) & 1)) {
if (!readUInt32(hdl, bitfield)) if (!readUInt32(hdl, bitfield))
@ -97,8 +106,3 @@ bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
return true; return true;
} }
QString SubFile::fileName() const
{
return _file ? _file->fileName() : _img->fileName();
}

View File

@ -3,38 +3,64 @@
#include <QVector> #include <QVector>
#include <QDebug> #include <QDebug>
#include <QFile>
#include "img.h"
class QFile;
class IMG; #define BLOCK_SIZE 8192
class SubFile class SubFile
{ {
public: public:
enum Type {Unknown, TRE, RGN, LBL, NET, TYP, GMP}; 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 pos() const {return _pos;}
int blockNum;
int blockPos; private:
int pos; friend class SubFile;
QFile *_file;
QByteArray _data;
int _blockNum;
int _blockPos;
int _pos;
}; };
SubFile(IMG *img) 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), SubFile(SubFile *gmp, quint32 offset) : _gmpOffset(offset), _img(gmp->_img),
_blocks(gmp->_blocks), _file(gmp->_file) {} _blocks(gmp->_blocks), _path(gmp->_path), _id(gmp->id()) {}
SubFile(QFile *file) SubFile(const QString &path)
: _gmpOffset(0), _img(0), _blocks(0), _file(file) {} : _gmpOffset(0), _img(0), _blocks(0), _path(new QString(path)), _id(0) {}
~SubFile() ~SubFile()
{ {
if (!_gmpOffset) if (!_gmpOffset) {
delete _blocks; delete _blocks;
delete _path;
}
} }
void addBlock(quint16 block) {_blocks->append(block);} void addBlock(quint16 block) {_blocks->append(block);}
void setId(quint16 id) {_id = id;}
bool seek(Handle &handle, quint32 pos) const; bool seek(Handle &handle, quint32 pos) const;
@ -114,8 +140,8 @@ public:
bool readVUInt32(Handle &hdl, quint32 &val) const; bool readVUInt32(Handle &hdl, quint32 &val) const;
bool readVBitfield32(Handle &hdl, quint32 &bitfield) const; bool readVBitfield32(Handle &hdl, quint32 &bitfield) const;
quint16 offset() const {return _blocks->first();} quint16 id() const {return _blocks ? _blocks->first() : _id;}
QString fileName() const; QString fileName() const {return _path ? *_path : _img->fileName();}
protected: protected:
quint32 _gmpOffset; quint32 _gmpOffset;
@ -125,7 +151,8 @@ private:
IMG *_img; IMG *_img;
QVector<quint16> *_blocks; QVector<quint16> *_blocks;
QFile *_file; QString *_path;
quint16 _id;
}; };
#endif // SUBFILE_H #endif // SUBFILE_H

View File

@ -39,7 +39,7 @@ TREFile::~TREFile()
bool TREFile::init() bool TREFile::init()
{ {
Handle hdl; Handle hdl(this);
quint8 locked; quint8 locked;
quint16 hdrLen; quint16 hdrLen;
@ -113,7 +113,7 @@ bool TREFile::init()
bool TREFile::load(int idx) bool TREFile::load(int idx)
{ {
Handle hdl; Handle hdl(this);
QList<SubDiv*> sl; QList<SubDiv*> sl;
SubDiv *s = 0; SubDiv *s = 0;
SubDivTree *tree = new SubDivTree(); SubDivTree *tree = new SubDivTree();
@ -199,7 +199,7 @@ bool TREFile::load(int idx)
if (i) if (i)
sl.at(i-1)->setExtEnds(polygons, lines, points); 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; goto error;
} }

View File

@ -14,6 +14,7 @@ class TREFile : public SubFile
{ {
public: public:
TREFile(IMG *img) : SubFile(img) {} TREFile(IMG *img) : SubFile(img) {}
TREFile(const QString &path) : SubFile(path) {}
TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {} TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {}
~TREFile(); ~TREFile();

View File

@ -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() bool VectorTile::init()
{ {
if (_gmp && !initGMP()) if (_gmp && !initGMP())
@ -72,7 +95,7 @@ bool VectorTile::init()
bool VectorTile::initGMP() bool VectorTile::initGMP()
{ {
SubFile::Handle hdl; SubFile::Handle hdl(_gmp);
quint32 tre, rgn, lbl, net; quint32 tre, rgn, lbl, net;
if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre) 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) QList<IMG::Poly> *lines, QCache<const SubDiv *, IMG::Polys> *polyCache)
const const
{ {
SubFile::Handle rgnHdl, lblHdl, netHdl; SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net);
if (!_rgn->initialized() && !_rgn->init(rgnHdl)) if (!_rgn->initialized() && !_rgn->init(rgnHdl))
return; 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, void VectorTile::points(const RectC &rect, int bits, QList<IMG::Point> *points,
QCache<const SubDiv *, QList<IMG::Point> > *pointCache) const QCache<const SubDiv *, QList<IMG::Point> > *pointCache) const
{ {
SubFile::Handle rgnHdl, lblHdl; SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl);
if (!_rgn->initialized() && !_rgn->init(rgnHdl)) if (!_rgn->initialized() && !_rgn->init(rgnHdl))
return; return;

View File

@ -23,6 +23,7 @@ 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);
SubFile *addFile(const QString &path, SubFile::Type type);
void polys(const RectC &rect, int bits, QList<IMG::Poly> *polygons, void polys(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
QList<IMG::Poly> *lines, QCache<const SubDiv *, IMG::Polys> *polyCache) QList<IMG::Poly> *lines, QCache<const SubDiv *, IMG::Polys> *polyCache)
@ -37,8 +38,6 @@ public:
|| type == SubFile::GMP); || type == SubFile::GMP);
} }
friend QDebug operator<<(QDebug dbg, const VectorTile &tile);
private: private:
bool initGMP(); bool initGMP();

View File

@ -13,6 +13,9 @@
#include "IMG/textpathitem.h" #include "IMG/textpathitem.h"
#include "IMG/textpointitem.h" #include "IMG/textpointitem.h"
#include "IMG/bitmapline.h" #include "IMG/bitmapline.h"
#include "IMG/style.h"
#include "IMG/img.h"
#include "IMG/gmap.h"
#include "pcs.h" #include "pcs.h"
#include "rectd.h" #include "rectd.h"
#include "imgmap.h" #include "imgmap.h"
@ -35,9 +38,9 @@ public:
const QString &key() const {return _key;} const QString &key() const {return _key;}
const QPoint &xy() const {return _xy;} const QPoint &xy() const {return _xy;}
QImage &img() {return _img;} QImage &img() {return _img;}
QList<IMG::Poly> &polygons() {return _polygons;} QList<MapData::Poly> &polygons() {return _polygons;}
QList<IMG::Poly> &lines() {return _lines;} QList<MapData::Poly> &lines() {return _lines;}
QList<IMG::Point> &points() {return _points;} QList<MapData::Point> &points() {return _points;}
void render() void render()
{ {
@ -70,9 +73,9 @@ private:
QPoint _xy; QPoint _xy;
QString _key; QString _key;
QImage _img; QImage _img;
QList<IMG::Poly> _polygons; QList<MapData::Poly> _polygons;
QList<IMG::Poly> _lines; QList<MapData::Poly> _lines;
QList<IMG::Point> _points; QList<MapData::Point> _points;
}; };
@ -226,11 +229,17 @@ static bool rectNearPolygon(const QPolygonF &polygon, const QRectF &rect)
|| polygon.containsPoint(rect.bottomRight(), Qt::OddEvenFill))); || polygon.containsPoint(rect.bottomRight(), Qt::OddEvenFill)));
} }
IMGMap::IMGMap(const QString &fileName, QObject *parent) 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()) { if (GMAP::isGMAP(fileName))
_errorString = _img.errorString(); _data = new GMAP(fileName);
else
_data = new IMG(fileName);
if (!_data->isValid()) {
_errorString = _data->errorString();
return; return;
} }
@ -242,17 +251,17 @@ IMGMap::IMGMap(const QString &fileName, QObject *parent)
void IMGMap::load() void IMGMap::load()
{ {
_img.load(); _data->load();
} }
void IMGMap::unload() void IMGMap::unload()
{ {
_img.clear(); _data->clear();
} }
QRectF IMGMap::bounds() QRectF IMGMap::bounds()
{ {
RectD prect(_img.bounds(), _projection); RectD prect(_data->bounds(), _projection);
return QRectF(_transform.proj2img(prect.topLeft()), return QRectF(_transform.proj2img(prect.topLeft()),
_transform.proj2img(prect.bottomRight())); _transform.proj2img(prect.bottomRight()));
} }
@ -302,7 +311,7 @@ Transform IMGMap::transform(int zoom) const
{ {
double scale = _projection.isGeographic() double scale = _projection.isGeographic()
? 360.0 / (1<<zoom) : (2.0 * M_PI * WGS84_RADIUS) / (1<<zoom); ? 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), return Transform(ReferencePoint(PointD(0, 0), topLeft),
PointD(scale, scale)); PointD(scale, scale));
} }
@ -322,14 +331,14 @@ 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<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++) { for (int i = 0; i < polygons.size(); i++) {
const IMG::Poly &poly = polygons.at(i); const MapData::Poly &poly = polygons.at(i);
if (poly.type != _img.style()->drawOrder().at(n)) if (poly.type != _data->style()->drawOrder().at(n))
continue; continue;
const Style::Polygon &style = _img.style()->polygon(poly.type); const Style::Polygon &style = _data->style()->polygon(poly.type);
painter->setPen(style.pen()); painter->setPen(style.pen());
painter->setBrush(style.brush()); 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); painter->setBrush(Qt::NoBrush);
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const IMG::Poly &poly = lines.at(i); const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _img.style()->line(poly.type); const Style::Line &style = _data->style()->line(poly.type);
if (style.background() == Qt::NoPen) if (style.background() == Qt::NoPen)
continue; continue;
@ -354,8 +363,8 @@ void IMGMap::drawLines(QPainter *painter, const QList<IMG::Poly> &lines)
} }
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const IMG::Poly &poly = lines.at(i); const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _img.style()->line(poly.type); const Style::Line &style = _data->style()->line(poly.type);
if (!style.img().isNull()) if (!style.img().isNull())
BitmapLine::draw(painter, poly.points, style.img()); 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); textItems.at(i)->paint(painter);
} }
void IMGMap::processPolygons(QList<MapData::Poly> &polygons,
void IMGMap::processPolygons(QList<IMG::Poly> &polygons,
QList<TextItem*> &textItems) QList<TextItem*> &textItems)
{ {
for (int i = 0; i < polygons.size(); i++) { 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++) { for (int j = 0; j < poly.points.size(); j++) {
QPointF &p = poly.points[j]; QPointF &p = poly.points[j];
p = ll2xy(Coordinates(p.x(), p.y())); 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) if (_zoom <= 23 && (Style::isWaterArea(poly.type)
|| Style::isMilitaryArea(poly.type) || Style::isMilitaryArea(poly.type)
|| Style::isNatureReserve(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( TextPointItem *item = new TextPointItem(
centroid(poly.points).toPoint(), &poly.label.text(), centroid(poly.points).toPoint(), &poly.label.text(),
poiFont(), 0, &style.brush().color()); 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) QList<TextItem*> &textItems)
{ {
qStableSort(lines); qStableSort(lines);
for (int i = 0; i < lines.size(); i++) { 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++) { for (int j = 0; j < poly.points.size(); j++) {
QPointF &p = poly.points[j]; QPointF &p = poly.points[j];
p = ll2xy(Coordinates(p.x(), p.y())); 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); processShields(lines, tileRect, textItems);
} }
void IMGMap::processStreetNames(QList<IMG::Poly> &lines, const QRect &tileRect, void IMGMap::processStreetNames(QList<MapData::Poly> &lines,
QList<TextItem*> &textItems) const QRect &tileRect, QList<TextItem*> &textItems)
{ {
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
IMG::Poly &poly = lines[i]; MapData::Poly &poly = lines[i];
const Style::Line &style = _img.style()->line(poly.type); const Style::Line &style = _data->style()->line(poly.type);
if (style.img().isNull() && style.foreground() == Qt::NoPen) if (style.img().isNull() && style.foreground() == Qt::NoPen)
continue; 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) QList<TextItem*> &textItems)
{ {
for (int type = FIRST_SHIELD; type <= LAST_SHIELD; type++) { 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; QHash<Label::Shield, const Label::Shield*> sp;
for (int i = 0; i < lines.size(); i++) { 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(); const Label::Shield &shield = poly.label.shield();
if (!shield.isValid() || shield.type() != type if (!shield.isValid() || shield.type() != type
|| !Style::isMajorRoad(poly.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) QList<TextItem*> &textItems)
{ {
qSort(points); qSort(points);
for (int i = 0; i < points.size(); i++) { for (int i = 0; i < points.size(); i++) {
IMG::Point &point = points[i]; MapData::Point &point = points[i];
const Style::Point &style = _img.style()->point(point.type); const Style::Point &style = _data->style()->point(point.type);
if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type))) if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type)))
continue; continue;
@ -574,7 +582,7 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
for (int j = 0; j < height; j++) { for (int j = 0; j < height; j++) {
QPixmap pm; QPixmap pm;
QPoint ttl(tl.x() + i * TILE_SIZE, tl.y() + j * TILE_SIZE); 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()); + QString::number(ttl.x()) + "_" + QString::number(ttl.y());
if (QPixmapCache::find(key, pm)) if (QPixmapCache::find(key, pm))
painter->drawPixmap(ttl, 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( 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.polys(polyRect.toRectC(_projection, 4), _zoom, _data->polys(polyRect.toRectC(_projection, 4), _zoom,
&(tile.polygons()), &(tile.lines())); &(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.points(pointRect.toRectC(_projection, 4), _zoom, _data->points(pointRect.toRectC(_projection, 4), _zoom,
&(tile.points())); &(tile.points()));
} }
} }

View File

@ -4,7 +4,7 @@
#include "map.h" #include "map.h"
#include "projection.h" #include "projection.h"
#include "transform.h" #include "transform.h"
#include "IMG/img.h" #include "IMG/mapdata.h"
class TextItem; class TextItem;
@ -14,8 +14,9 @@ class IMGMap : public Map
public: public:
IMGMap(const QString &fileName, QObject *parent = 0); IMGMap(const QString &fileName, QObject *parent = 0);
~IMGMap() {delete _data;}
QString name() const {return _img.name();} QString name() const {return _data->name();}
QRectF bounds(); QRectF bounds();
@ -43,21 +44,21 @@ private:
Transform transform(int zoom) const; Transform transform(int zoom) const;
void updateTransform(); void updateTransform();
void drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons); void drawPolygons(QPainter *painter, const QList<MapData::Poly> &polygons);
void drawLines(QPainter *painter, const QList<IMG::Poly> &lines); void drawLines(QPainter *painter, const QList<MapData::Poly> &lines);
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems); void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
void processPolygons(QList<IMG::Poly> &polygons, void processPolygons(QList<MapData::Poly> &polygons,
QList<TextItem *> &textItems); QList<TextItem *> &textItems);
void processLines(QList<IMG::Poly> &lines, const QRect &tileRect, void processLines(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems); QList<TextItem*> &textItems);
void processPoints(QList<IMG::Point> &points, QList<TextItem*> &textItems); void processPoints(QList<MapData::Point> &points, QList<TextItem*> &textItems);
void processShields(QList<IMG::Poly> &lines, const QRect &tileRect, void processShields(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems); QList<TextItem*> &textItems);
void processStreetNames(QList<IMG::Poly> &lines, const QRect &tileRect, void processStreetNames(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems); QList<TextItem*> &textItems);
IMG _img; MapData *_data;
int _zoom; int _zoom;
Projection _projection; Projection _projection;
Transform _transform; Transform _transform;

View File

@ -8,20 +8,27 @@
#include "mbtilesmap.h" #include "mbtilesmap.h"
#include "rmap.h" #include "rmap.h"
#include "imgmap.h" #include "imgmap.h"
#include "IMG/gmap.h"
#include "maplist.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); _maps.append(map);
return true; return true;
} else { } else if (map) {
if (dir) if (dir)
_errorString += path + ": " + map->errorString() + "\n"; _errorString += path + ": " + map->errorString() + "\n";
else else
_errorString = map->errorString(); _errorString = map->errorString();
return false; 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; 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); QFileInfo fi(path);
QString suffix = fi.suffix().toLower(); QString suffix = fi.suffix().toLower();
Map *map; Map *map = 0;
if (Atlas::isAtlas(path)) { if (Atlas::isAtlas(path)) {
*atlas = true; *terminate = true;
map = new Atlas(path, this); map = new Atlas(path, this);
} else if (suffix == "xml") { } else if (suffix == "xml") {
if (!(map = loadSource(path, dir))) if (MapSource::isMap(path) && !(map = loadSource(path, dir)))
return false; return false;
else if (GMAP::isGMAP(path)) {
*terminate = true;
map = new IMGMap(path);
}
} else if (suffix == "jnx") } else if (suffix == "jnx")
map = new JNXMap(path, this); map = new JNXMap(path, this);
else if (suffix == "tif" || suffix == "tiff") else if (suffix == "tif" || suffix == "tiff")
@ -85,15 +96,15 @@ bool MapList::loadDirR(const QString &path)
for (int i = 0; i < ml.size(); i++) { for (int i = 0; i < ml.size(); i++) {
const QFileInfo &fi = ml.at(i); const QFileInfo &fi = ml.at(i);
QString suffix = fi.suffix().toLower(); QString suffix = fi.suffix().toLower();
bool atlas = false; bool terminate = false;
if (fi.isDir() && fi.fileName() != "set") { if (fi.isDir() && fi.fileName() != "set") {
if (!loadDirR(fi.absoluteFilePath())) if (!loadDirR(fi.absoluteFilePath()))
ret = false; ret = false;
} else if (filter().contains("*." + suffix)) { } else if (filter().contains("*." + suffix)) {
if (!loadFile(fi.absoluteFilePath(), &atlas, true)) if (!loadFile(fi.absoluteFilePath(), &terminate, true))
ret = false; ret = false;
if (atlas) if (terminate)
break; break;
} }
} }
@ -120,7 +131,7 @@ QString MapList::formats()
return return
tr("Supported files") tr("Supported files")
+ " (*.img *.jnx *.map *.mbtiles *.rmap *.rtmap *.tar *.tba *.tif *.tiff *.xml);;" + " (*.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("Garmin JNX maps") + " (*.jnx);;"
+ tr("OziExplorer maps") + " (*.map);;" + tr("OziExplorer maps") + " (*.map);;"
+ tr("MBTiles maps") + " (*.mbtiles);;" + tr("MBTiles maps") + " (*.mbtiles);;"

View File

@ -23,7 +23,7 @@ public:
static QStringList filter(); static QStringList filter();
private: private:
bool loadFile(const QString &path, bool *atlas, bool dir); bool loadFile(const QString &path, bool *terminate, bool dir);
bool loadDirR(const QString &path); bool loadDirR(const QString &path);
Map *loadSource(const QString &path, bool dir); Map *loadSource(const QString &path, bool dir);
bool loadMap(Map *map, const QString &path, bool dir); bool loadMap(Map *map, const QString &path, bool dir);

View File

@ -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) Map *MapSource::loadMap(const QString &path, QString &errorString)
{ {
Config config; Config config;

View File

@ -15,6 +15,7 @@ class MapSource
{ {
public: public:
static Map *loadMap(const QString &path, QString &errorString); static Map *loadMap(const QString &path, QString &errorString);
static bool isMap(const QString &path);
private: private:
enum Type { enum Type {