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/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 \

View File

@ -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
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;
if (!file.readVUInt32(hdl, recordSize))
return false;
recordOffset = hdl.pos + recordSize;
recordOffset = hdl.pos() + recordSize;
if (recordOffset > offset + size)
return false;
};

View File

@ -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 &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])
{
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

View File

@ -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

View File

@ -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
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
{
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);

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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();
}

View File

@ -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

View File

@ -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;
}

View File

@ -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();

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()
{
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;

View File

@ -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();

View File

@ -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()));
}
}

View File

@ -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;

View File

@ -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);;"

View File

@ -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);

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)
{
Config config;

View File

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