1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-06 06:43:22 +02: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/style.h \
src/map/IMG/section.h \
src/map/IMG/zoom.h \
src/map/encmap.h \
src/map/ENC/iso8211.h \
src/map/gemfmap.h \

View File

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

View File

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

View File

@ -156,32 +156,6 @@ bool IMGData::createTileTree(const TileMap &tileMap)
_tileTree.Insert(min, max, tile);
_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);
@ -209,6 +183,8 @@ IMGData::IMGData(const QString &fileName) : MapData(fileName)
return;
}
computeZooms();
_valid = true;
}

View File

@ -11,7 +11,7 @@ using namespace IMG;
bool MapData::polyCb(VectorTile *tile, void *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);
return true;
}
@ -19,14 +19,13 @@ bool MapData::polyCb(VectorTile *tile, void *context)
bool MapData::pointCb(VectorTile *tile, void *context)
{
PointCTX *ctx = (PointCTX*)context;
tile->points(ctx->rect, ctx->bits, ctx->baseMap, ctx->points,
ctx->pointCache);
tile->points(ctx->rect, ctx->zoom, ctx->points, ctx->pointCache);
return true;
}
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);
_pointCache.setMaxCost(CACHED_SUBDIVS_COUNT);
@ -45,7 +44,7 @@ MapData::~MapData()
void MapData::polys(const RectC &rect, int bits, QList<Poly> *polygons,
QList<Poly> *lines)
{
PolyCTX ctx(rect, bits, _baseMap, polygons, lines, &_polyCache);
PolyCTX ctx(rect, zoom(bits), polygons, lines, &_polyCache);
double min[2], max[2];
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)
{
PointCTX ctx(rect, bits, _baseMap, points, &_pointCache);
PointCTX ctx(rect, zoom(bits), points, &_pointCache);
double min[2], max[2];
min[0] = rect.left();
@ -97,3 +96,41 @@ void MapData::clear()
_polyCache.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/rtree.h"
#include "common/range.h"
#include "common/hash.h"
#include "label.h"
#include "raster.h"
#include "zoom.h"
namespace IMG {
@ -55,7 +56,7 @@ public:
const QString &name() const {return _name;}
const RectC &bounds() const {return _bounds;}
const Range &zooms() const {return _zooms;}
const Range &zooms() const {return _zoomLevels;}
const Style *style() const {return _style;}
void polys(const RectC &rect, int bits, QList<Poly> *polygons,
QList<Poly> *lines);
@ -72,14 +73,16 @@ public:
protected:
typedef RTree<VectorTile*, double, 2> TileTree;
void computeZooms();
QString _fileName;
QString _name;
RectC _bounds;
SubFile *_typ;
Style *_style;
TileTree _tileTree;
Range _zooms;
Range _baseMap;
QList<Zoom> _zooms;
Range _zoomLevels;
bool _valid;
QString _errorString;
@ -96,15 +99,14 @@ private:
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,
QCache<const SubDiv*, MapData::Polys> *polyCache)
: rect(rect), bits(bits), baseMap(baseMap), polygons(polygons),
lines(lines), polyCache(polyCache) {}
: rect(rect), zoom(zoom), polygons(polygons), lines(lines),
polyCache(polyCache) {}
const RectC &rect;
int bits;
const Range &baseMap;
const Zoom &zoom;
QList<MapData::Poly> *polygons;
QList<MapData::Poly> *lines;
QCache<const SubDiv*, MapData::Polys> *polyCache;
@ -112,19 +114,19 @@ private:
struct PointCTX
{
PointCTX(const RectC &rect, int bits, const Range &baseMap,
PointCTX(const RectC &rect, const Zoom &zoom,
QList<MapData::Point> *points,
QCache<const SubDiv*, QList<MapData::Point> > *pointCache)
: rect(rect), bits(bits), baseMap(baseMap), points(points),
pointCache(pointCache) {}
: rect(rect), zoom(zoom), points(points), pointCache(pointCache) {}
const RectC &rect;
int bits;
const Range &baseMap;
const Zoom &zoom;
QList<MapData::Point> *points;
QCache<const SubDiv*, QList<MapData::Point> > *pointCache;
};
const Zoom &zoom(int bits) const;
static bool polyCb(VectorTile *tile, void *context);
static bool pointCb(VectorTile *tile, void *context);
@ -132,7 +134,6 @@ private:
QCache<const SubDiv*, QList<Point> > _pointCache;
friend class VectorTile;
friend struct PolyCTX;
};
}

View File

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

View File

@ -100,7 +100,7 @@ void VectorTile::clear()
_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,
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++) {
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;
}
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> > *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++) {
SubDiv *subdiv = subdivs.at(i);

View File

@ -23,14 +23,14 @@ public:
void clear();
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);
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,
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> > *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