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

Fixed broken handling of IMG "multi-maps" (maps with overviews)

This commit is contained in:
Martin Tůma 2023-02-27 22:06:31 +01:00
parent 108444d29b
commit f026387d76
11 changed files with 161 additions and 104 deletions

View File

@ -124,6 +124,7 @@ HEADERS += src/common/config.h \
src/map/ENC/rastertile.h \ src/map/ENC/rastertile.h \
src/map/ENC/style.h \ src/map/ENC/style.h \
src/map/IMG/section.h \ src/map/IMG/section.h \
src/map/IMG/zoom.h \
src/map/encmap.h \ src/map/encmap.h \
src/map/ENC/iso8211.h \ src/map/ENC/iso8211.h \
src/map/gemfmap.h \ src/map/gemfmap.h \

View File

@ -23,21 +23,18 @@ static SubFile::Type tileType(const QString &suffix)
return SubFile::Unknown; return SubFile::Unknown;
} }
void GMAPData::subProduct(QXmlStreamReader &reader, QString &dataDir, void GMAPData::subProduct(QXmlStreamReader &reader, QString &dataDir)
QString &baseMap)
{ {
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("Directory")) if (reader.name() == QLatin1String("Directory"))
dataDir = reader.readElementText(); dataDir = reader.readElementText();
else if (reader.name() == QLatin1String("BaseMap"))
baseMap = reader.readElementText();
else else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
} }
void GMAPData::mapProduct(QXmlStreamReader &reader, QString &dataDir, void GMAPData::mapProduct(QXmlStreamReader &reader, QString &dataDir,
QString &typFile, QString &baseMap) QString &typFile)
{ {
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("Name")) if (reader.name() == QLatin1String("Name"))
@ -45,14 +42,13 @@ void GMAPData::mapProduct(QXmlStreamReader &reader, QString &dataDir,
else if (reader.name() == QLatin1String("TYP")) else if (reader.name() == QLatin1String("TYP"))
typFile = reader.readElementText(); typFile = reader.readElementText();
else if (reader.name() == QLatin1String("SubProduct")) else if (reader.name() == QLatin1String("SubProduct"))
subProduct(reader, dataDir, baseMap); subProduct(reader, dataDir);
else else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
} }
bool GMAPData::readXML(const QString &path, QString &dataDir, QString &typFile, bool GMAPData::readXML(const QString &path, QString &dataDir, QString &typFile)
QString &baseMap)
{ {
QFile file(path); QFile file(path);
@ -62,7 +58,7 @@ bool GMAPData::readXML(const QString &path, QString &dataDir, QString &typFile,
QXmlStreamReader reader(&file); QXmlStreamReader reader(&file);
if (reader.readNextStartElement()) { if (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("MapProduct")) if (reader.name() == QLatin1String("MapProduct"))
mapProduct(reader, dataDir, typFile, baseMap); mapProduct(reader, dataDir, typFile);
else else
reader.raiseError("Not a GMAP XML file"); reader.raiseError("Not a GMAP XML file");
} }
@ -75,7 +71,7 @@ bool GMAPData::readXML(const QString &path, QString &dataDir, QString &typFile,
return true; return true;
} }
bool GMAPData::loadTile(const QDir &dir, bool baseMap) bool GMAPData::loadTile(const QDir &dir)
{ {
VectorTile *tile = new VectorTile(); VectorTile *tile = new VectorTile();
@ -103,19 +99,14 @@ bool GMAPData::loadTile(const QDir &dir, bool baseMap)
_tileTree.Insert(min, max, tile); _tileTree.Insert(min, max, tile);
_bounds |= tile->bounds(); _bounds |= tile->bounds();
if (tile->zooms().min() < _zooms.min())
_zooms.setMin(tile->zooms().min());
if (baseMap)
_baseMap = tile->zooms();
return true; return true;
} }
GMAPData::GMAPData(const QString &fileName) : MapData(fileName) GMAPData::GMAPData(const QString &fileName) : MapData(fileName)
{ {
QString dataDirPath, typFilePath, baseMapPath; QString dataDirPath, typFilePath;
if (!readXML(fileName, dataDirPath, typFilePath, baseMapPath)) if (!readXML(fileName, dataDirPath, typFilePath))
return; return;
QDir baseDir(QFileInfo(fileName).absoluteDir()); QDir baseDir(QFileInfo(fileName).absoluteDir());
@ -125,13 +116,11 @@ GMAPData::GMAPData(const QString &fileName) : MapData(fileName)
} }
QDir dataDir(baseDir.filePath(dataDirPath)); QDir dataDir(baseDir.filePath(dataDirPath));
QFileInfoList ml = dataDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); QFileInfoList ml = dataDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
QFileInfo baseMap(dataDir.filePath(baseMapPath));
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);
if (fi.isDir()) if (fi.isDir())
loadTile(QDir(fi.absoluteFilePath()), loadTile(QDir(fi.absoluteFilePath()));
fi.absoluteFilePath() == baseMap.absoluteFilePath());
} }
if (baseDir.exists(typFilePath)) { if (baseDir.exists(typFilePath)) {
@ -143,6 +132,8 @@ GMAPData::GMAPData(const QString &fileName) : MapData(fileName)
_errorString = "No usable map tile found"; _errorString = "No usable map tile found";
else else
_valid = true; _valid = true;
computeZooms();
} }
GMAPData::~GMAPData() GMAPData::~GMAPData()

View File

@ -15,13 +15,10 @@ public:
~GMAPData(); ~GMAPData();
private: private:
bool readXML(const QString &path, QString &dataDir, QString &typFile, bool readXML(const QString &path, QString &dataDir, QString &typFile);
QString &baseMap); void mapProduct(QXmlStreamReader &reader, QString &dataDir, QString &typFile);
void mapProduct(QXmlStreamReader &reader, QString &dataDir, void subProduct(QXmlStreamReader &reader, QString &dataDir);
QString &typFile, QString &baseMap); bool loadTile(const QDir &dir);
void subProduct(QXmlStreamReader &reader, QString &dataDir,
QString &baseMap);
bool loadTile(const QDir &dir, bool baseMap);
QList<const QString*> _files; QList<const QString*> _files;
}; };

View File

@ -156,32 +156,6 @@ bool IMGData::createTileTree(const TileMap &tileMap)
_tileTree.Insert(min, max, tile); _tileTree.Insert(min, max, tile);
_bounds |= tile->bounds(); _bounds |= tile->bounds();
if (tile->zooms().min() < _zooms.min())
_zooms.setMin(tile->zooms().min());
}
// Detect and mark basemap
TileTree::Iterator it;
bool baseMap = false;
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it)) {
VectorTile *tile = _tileTree.GetAt(it);
if (tile->zooms().min() > _zooms.min()) {
baseMap = true;
break;
}
}
if (baseMap) {
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it);
_tileTree.GetNext(it)) {
VectorTile *tile = _tileTree.GetAt(it);
if (tile->zooms().min() == _zooms.min())
_baseMap = tile->zooms();
}
} else {
/* Allow some extra zoom out on maps without basemaps, but not too much
as this would kill the rendering performance. */
_zooms.setMin(_zooms.min() - 2);
} }
return (_tileTree.Count() > 0); return (_tileTree.Count() > 0);
@ -209,6 +183,8 @@ IMGData::IMGData(const QString &fileName) : MapData(fileName)
return; return;
} }
computeZooms();
_valid = true; _valid = true;
} }

View File

@ -11,7 +11,7 @@ using namespace IMG;
bool MapData::polyCb(VectorTile *tile, void *context) bool MapData::polyCb(VectorTile *tile, void *context)
{ {
PolyCTX *ctx = (PolyCTX*)context; PolyCTX *ctx = (PolyCTX*)context;
tile->polys(ctx->rect, ctx->bits, ctx->baseMap, ctx->polygons, ctx->lines, tile->polys(ctx->rect, ctx->zoom, ctx->polygons, ctx->lines,
ctx->polyCache); ctx->polyCache);
return true; return true;
} }
@ -19,14 +19,13 @@ bool MapData::polyCb(VectorTile *tile, void *context)
bool MapData::pointCb(VectorTile *tile, void *context) bool MapData::pointCb(VectorTile *tile, void *context)
{ {
PointCTX *ctx = (PointCTX*)context; PointCTX *ctx = (PointCTX*)context;
tile->points(ctx->rect, ctx->bits, ctx->baseMap, ctx->points, tile->points(ctx->rect, ctx->zoom, ctx->points, ctx->pointCache);
ctx->pointCache);
return true; return true;
} }
MapData::MapData(const QString &fileName) MapData::MapData(const QString &fileName)
: _fileName(fileName), _typ(0), _style(0), _zooms(24, 28), _valid(false) : _fileName(fileName), _typ(0), _style(0), _valid(false)
{ {
_polyCache.setMaxCost(CACHED_SUBDIVS_COUNT); _polyCache.setMaxCost(CACHED_SUBDIVS_COUNT);
_pointCache.setMaxCost(CACHED_SUBDIVS_COUNT); _pointCache.setMaxCost(CACHED_SUBDIVS_COUNT);
@ -45,7 +44,7 @@ MapData::~MapData()
void MapData::polys(const RectC &rect, int bits, QList<Poly> *polygons, void MapData::polys(const RectC &rect, int bits, QList<Poly> *polygons,
QList<Poly> *lines) QList<Poly> *lines)
{ {
PolyCTX ctx(rect, bits, _baseMap, polygons, lines, &_polyCache); PolyCTX ctx(rect, zoom(bits), polygons, lines, &_polyCache);
double min[2], max[2]; double min[2], max[2];
min[0] = rect.left(); min[0] = rect.left();
@ -58,7 +57,7 @@ void MapData::polys(const RectC &rect, int bits, QList<Poly> *polygons,
void MapData::points(const RectC &rect, int bits, QList<Point> *points) void MapData::points(const RectC &rect, int bits, QList<Point> *points)
{ {
PointCTX ctx(rect, bits, _baseMap, points, &_pointCache); PointCTX ctx(rect, zoom(bits), points, &_pointCache);
double min[2], max[2]; double min[2], max[2];
min[0] = rect.left(); min[0] = rect.left();
@ -97,3 +96,41 @@ void MapData::clear()
_polyCache.clear(); _polyCache.clear();
_pointCache.clear(); _pointCache.clear();
} }
void MapData::computeZooms()
{
TileTree::Iterator it;
QSet<Zoom> zooms;
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it)) {
const QVector<Zoom> &z = _tileTree.GetAt(it)->zooms();
for (int i = 0; i < z.size(); i++)
zooms.insert(z.at(i));
}
_zooms = zooms.values();
std::sort(_zooms.begin(), _zooms.end());
bool baseMap = false;
for (int i = 1; i < _zooms.size(); i++) {
if (_zooms.at(i).level() > _zooms.at(i-1).level()) {
baseMap = true;
break;
}
}
_zoomLevels = Range(baseMap ? _zooms.first().bits()
: qMax(0, _zooms.first().bits() - 2), 28);
}
const Zoom &MapData::zoom(int bits) const
{
int id = 0;
for (int i = 1; i < _zooms.size(); i++) {
if (_zooms.at(i).bits() > bits)
break;
id++;
}
return _zooms.at(id);
}

View File

@ -8,9 +8,10 @@
#include "common/rectc.h" #include "common/rectc.h"
#include "common/rtree.h" #include "common/rtree.h"
#include "common/range.h" #include "common/range.h"
#include "common/hash.h"
#include "label.h" #include "label.h"
#include "raster.h" #include "raster.h"
#include "zoom.h"
namespace IMG { namespace IMG {
@ -55,7 +56,7 @@ public:
const QString &name() const {return _name;} const QString &name() const {return _name;}
const RectC &bounds() const {return _bounds;} const RectC &bounds() const {return _bounds;}
const Range &zooms() const {return _zooms;} const Range &zooms() const {return _zoomLevels;}
const Style *style() const {return _style;} const Style *style() const {return _style;}
void polys(const RectC &rect, int bits, QList<Poly> *polygons, void polys(const RectC &rect, int bits, QList<Poly> *polygons,
QList<Poly> *lines); QList<Poly> *lines);
@ -72,14 +73,16 @@ public:
protected: protected:
typedef RTree<VectorTile*, double, 2> TileTree; typedef RTree<VectorTile*, double, 2> TileTree;
void computeZooms();
QString _fileName; QString _fileName;
QString _name; QString _name;
RectC _bounds; RectC _bounds;
SubFile *_typ; SubFile *_typ;
Style *_style; Style *_style;
TileTree _tileTree; TileTree _tileTree;
Range _zooms; QList<Zoom> _zooms;
Range _baseMap; Range _zoomLevels;
bool _valid; bool _valid;
QString _errorString; QString _errorString;
@ -96,15 +99,14 @@ private:
struct PolyCTX struct PolyCTX
{ {
PolyCTX(const RectC &rect, int bits, const Range &baseMap, PolyCTX(const RectC &rect, const Zoom &zoom,
QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines, QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines,
QCache<const SubDiv*, MapData::Polys> *polyCache) QCache<const SubDiv*, MapData::Polys> *polyCache)
: rect(rect), bits(bits), baseMap(baseMap), polygons(polygons), : rect(rect), zoom(zoom), polygons(polygons), lines(lines),
lines(lines), polyCache(polyCache) {} polyCache(polyCache) {}
const RectC &rect; const RectC &rect;
int bits; const Zoom &zoom;
const Range &baseMap;
QList<MapData::Poly> *polygons; QList<MapData::Poly> *polygons;
QList<MapData::Poly> *lines; QList<MapData::Poly> *lines;
QCache<const SubDiv*, MapData::Polys> *polyCache; QCache<const SubDiv*, MapData::Polys> *polyCache;
@ -112,19 +114,19 @@ private:
struct PointCTX struct PointCTX
{ {
PointCTX(const RectC &rect, int bits, const Range &baseMap, PointCTX(const RectC &rect, const Zoom &zoom,
QList<MapData::Point> *points, QList<MapData::Point> *points,
QCache<const SubDiv*, QList<MapData::Point> > *pointCache) QCache<const SubDiv*, QList<MapData::Point> > *pointCache)
: rect(rect), bits(bits), baseMap(baseMap), points(points), : rect(rect), zoom(zoom), points(points), pointCache(pointCache) {}
pointCache(pointCache) {}
const RectC &rect; const RectC &rect;
int bits; const Zoom &zoom;
const Range &baseMap;
QList<MapData::Point> *points; QList<MapData::Point> *points;
QCache<const SubDiv*, QList<MapData::Point> > *pointCache; QCache<const SubDiv*, QList<MapData::Point> > *pointCache;
}; };
const Zoom &zoom(int bits) const;
static bool polyCb(VectorTile *tile, void *context); static bool polyCb(VectorTile *tile, void *context);
static bool pointCb(VectorTile *tile, void *context); static bool pointCb(VectorTile *tile, void *context);
@ -132,7 +134,6 @@ private:
QCache<const SubDiv*, QList<Point> > _pointCache; QCache<const SubDiv*, QList<Point> > _pointCache;
friend class VectorTile; friend class VectorTile;
friend struct PolyCTX;
}; };
} }

View File

@ -162,7 +162,7 @@ bool TREFile::load(int idx)
SubDivTree *tree = new SubDivTree(); SubDivTree *tree = new SubDivTree();
const MapLevel &level = _levels.at(idx); const MapLevel &level = _levels.at(idx);
_subdivs.insert(level.bits, tree); _subdivs.insert(level.level, tree);
quint32 skip = 0; quint32 skip = 0;
for (int i = 0; i < idx; i++) for (int i = 0; i < idx; i++)
@ -282,27 +282,24 @@ void TREFile::clear()
_subdivs.clear(); _subdivs.clear();
} }
int TREFile::level(int bits, const Range &baseMap) const TREFile::SubDivTree *TREFile::subdivs(const Zoom &zoom)
{ {
if (!baseMap.isNull()) { int idx = -1;
if (zooms() != baseMap && bits <= baseMap.max())
return -1;
if (zooms() == baseMap && bits > baseMap.max())
return -1;
}
int idx = _firstLevel; for (int i = _firstLevel; i < _levels.size(); i++) {
if (_levels.at(i).level == zoom.level()
for (int i = idx + 1; i < _levels.size(); i++) { && _levels.at(i).bits == zoom.bits()) {
if (_levels.at(i).bits > bits) idx = i;
break; break;
idx++; }
} }
if (idx < 0)
return 0;
if (!_subdivs.contains(_levels.at(idx).bits) && !load(idx)) if (!_subdivs.contains(_levels.at(idx).level) && !load(idx))
return -1; return 0;
return _levels.at(idx).bits; return _subdivs.value(_levels.at(idx).level);
} }
static bool cb(SubDiv *subdiv, void *context) static bool cb(SubDiv *subdiv, void *context)
@ -312,11 +309,10 @@ static bool cb(SubDiv *subdiv, void *context)
return true; return true;
} }
QList<SubDiv*> TREFile::subdivs(const RectC &rect, int bits, QList<SubDiv*> TREFile::subdivs(const RectC &rect, const Zoom &zoom)
const Range &baseMap)
{ {
QList<SubDiv*> list; QList<SubDiv*> list;
SubDivTree *tree = _subdivs.value(level(bits, baseMap)); const SubDivTree *tree = subdivs(zoom);
double min[2], max[2]; double min[2], max[2];
min[0] = rect.left(); min[0] = rect.left();
@ -329,3 +325,13 @@ QList<SubDiv*> TREFile::subdivs(const RectC &rect, int bits,
return list; return list;
} }
QVector<Zoom> TREFile::zooms() const
{
QVector<Zoom> ret;
for (int i = _firstLevel; i < _levels.size(); i++)
ret.append(Zoom(_levels.at(i).level, _levels.at(i).bits));
return ret;
}

View File

@ -28,11 +28,10 @@ public:
void clear(); void clear();
const RectC &bounds() const {return _bounds;} const RectC &bounds() const {return _bounds;}
QList<SubDiv*> subdivs(const RectC &rect, int bits, const Range &baseMap); QList<SubDiv*> subdivs(const RectC &rect, const Zoom &zoom);
quint32 shift(quint8 bits) const quint32 shift(quint8 bits) const
{return (bits == _levels.last().bits) ? (_flags >> 0xb) & 7 : 0;} {return (bits == _levels.last().bits) ? (_flags >> 0xb) & 7 : 0;}
Range zooms() const QVector<Zoom> zooms() const;
{return Range(_levels.at(_firstLevel).bits, _levels.last().bits);}
private: private:
struct MapLevel { struct MapLevel {
@ -43,7 +42,7 @@ private:
typedef RTree<SubDiv*, double, 2> SubDivTree; typedef RTree<SubDiv*, double, 2> SubDivTree;
bool load(int idx); bool load(int idx);
int level(int bits, const Range &baseMap); const SubDivTree *subdivs(const Zoom &zoom);
int readExtEntry(Handle &hdl, quint32 &polygons, quint32 &lines, int readExtEntry(Handle &hdl, quint32 &polygons, quint32 &lines,
quint32 &points); quint32 &points);

View File

@ -100,7 +100,7 @@ void VectorTile::clear()
_loaded = 0; _loaded = 0;
} }
void VectorTile::polys(const RectC &rect, int bits, const Range &baseMap, void VectorTile::polys(const RectC &rect, const Zoom &zoom,
QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines, QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines,
QCache<const SubDiv *, MapData::Polys> *polyCache) QCache<const SubDiv *, MapData::Polys> *polyCache)
{ {
@ -121,7 +121,7 @@ void VectorTile::polys(const RectC &rect, int bits, const Range &baseMap,
} }
} }
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits, baseMap); QList<SubDiv*> subdivs = _tre->subdivs(rect, zoom);
for (int i = 0; i < subdivs.size(); i++) { for (int i = 0; i < subdivs.size(); i++) {
SubDiv *subdiv = subdivs.at(i); SubDiv *subdiv = subdivs.at(i);
@ -169,7 +169,7 @@ void VectorTile::polys(const RectC &rect, int bits, const Range &baseMap,
delete rgnHdl; delete lblHdl; delete netHdl; delete nodHdl; delete nodHdl2; delete rgnHdl; delete lblHdl; delete netHdl; delete nodHdl; delete nodHdl2;
} }
void VectorTile::points(const RectC &rect, int bits, const Range &baseMap, void VectorTile::points(const RectC &rect, const Zoom &zoom,
QList<MapData::Point> *points, QCache<const SubDiv *, QList<MapData::Point> *points, QCache<const SubDiv *,
QList<MapData::Point> > *pointCache) QList<MapData::Point> > *pointCache)
{ {
@ -189,7 +189,7 @@ void VectorTile::points(const RectC &rect, int bits, const Range &baseMap,
} }
} }
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits, baseMap); QList<SubDiv*> subdivs = _tre->subdivs(rect, zoom);
for (int i = 0; i < subdivs.size(); i++) { for (int i = 0; i < subdivs.size(); i++) {
SubDiv *subdiv = subdivs.at(i); SubDiv *subdiv = subdivs.at(i);

View File

@ -23,14 +23,14 @@ public:
void clear(); void clear();
const RectC &bounds() const {return _tre->bounds();} const RectC &bounds() const {return _tre->bounds();}
Range zooms() const {return _tre->zooms();} QVector<Zoom> zooms() const {return _tre->zooms();}
SubFile *file(SubFile::Type type); SubFile *file(SubFile::Type type);
void polys(const RectC &rect, int bits, const Range &baseMap, void polys(const RectC &rect, const Zoom &zoom,
QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines, QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines,
QCache<const SubDiv *, MapData::Polys> *polyCache); QCache<const SubDiv *, MapData::Polys> *polyCache);
void points(const RectC &rect, int bits, const Range &baseMap, void points(const RectC &rect, const Zoom &zoom,
QList<MapData::Point> *points, QCache<const SubDiv*, QList<MapData::Point> *points, QCache<const SubDiv*,
QList<MapData::Point> > *pointCache); QList<MapData::Point> > *pointCache);

49
src/map/IMG/zoom.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef IMG_ZOOM_H
#define IMG_ZOOM_H
#include <QDebug>
#include "common/hash.h"
namespace IMG {
class Zoom
{
public:
Zoom() : _level(0), _bits(0) {}
Zoom(quint8 level, quint8 bits) : _level(level), _bits(bits) {}
quint8 level() const {return _level;}
quint8 bits() const {return _bits;}
bool operator<(const Zoom &other) const
{
return (_bits == other.bits())
? _level < other._level
: _bits < other._bits;
}
bool operator==(const Zoom &other) const
{
return _level == other._level && _bits == other._bits;
}
private:
quint8 _level;
quint8 _bits;
};
inline HASH_T qHash(const Zoom &zoom)
{
return ::qHash(zoom.level()) ^ ::qHash(zoom.bits());
}
}
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const IMG::Zoom &zoom)
{
dbg.nospace() << "Zoom(" << zoom.bits() << ", " << zoom.level() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
#endif // IMG_ZOOM_H