1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 05:34:47 +01:00

Yet another TrekBuddy compatability enhancement & fixes

+ related map API refactoring
This commit is contained in:
Martin Tůma 2023-09-14 18:36:03 +02:00
parent 00fff55cd3
commit 845a4b2921
51 changed files with 245 additions and 175 deletions

View File

@ -1750,7 +1750,7 @@ bool GUI::loadMapNode(const TreeNode<Map*> &node, MapAction *&action,
bool GUI::loadMap(const QString &fileName, MapAction *&action, int &showError) bool GUI::loadMap(const QString &fileName, MapAction *&action, int &showError)
{ {
TreeNode<Map*> maps(MapList::loadMaps(fileName)); TreeNode<Map*> maps(MapList::loadMaps(fileName, _mapView->inputProjection()));
QList<QAction*> existingActions(_mapsActionGroup->actions()); QList<QAction*> existingActions(_mapsActionGroup->actions());
return loadMapNode(maps, action, existingActions, showError); return loadMapNode(maps, action, existingActions, showError);
@ -1854,7 +1854,7 @@ void GUI::loadMapDir()
return; return;
QFileInfo fi(dir); QFileInfo fi(dir);
TreeNode<Map*> maps(MapList::loadMaps(dir)); TreeNode<Map*> maps(MapList::loadMaps(dir, _mapView->inputProjection()));
QList<QAction*> existingActions(_mapsActionGroup->actions()); QList<QAction*> existingActions(_mapsActionGroup->actions());
QList<MapAction*> actions; QList<MapAction*> actions;
QMenu *menu = new QMenu(maps.name()); QMenu *menu = new QMenu(maps.name());
@ -2985,7 +2985,7 @@ void GUI::loadInitialMaps(const QString &selected)
if (mapDir.isNull()) if (mapDir.isNull())
return; return;
TreeNode<Map*> maps(MapList::loadMaps(mapDir)); TreeNode<Map*> maps(MapList::loadMaps(mapDir, _mapView->inputProjection()));
createMapNodeMenu(createMapActionsNode(maps), _mapMenu, _mapsEnd); createMapNodeMenu(createMapActionsNode(maps), _mapMenu, _mapsEnd);
// Select the active map according to the user settings // Select the active map according to the user settings

View File

@ -81,15 +81,15 @@ ToolTip MapItem::info() const
return tt; return tt;
} }
MapItem::MapItem(MapAction *action, Map *map, const Projection &proj, MapItem::MapItem(MapAction *action, Map *map, GraphicsItem *parent)
GraphicsItem *parent) : PlaneItem(parent) : PlaneItem(parent)
{ {
Map *src = action->data().value<Map*>(); Map *src = action->data().value<Map*>();
Q_ASSERT(map->isReady()); Q_ASSERT(map->isReady());
_name = src->name(); _name = src->name();
_fileName = src->path(); _fileName = src->path();
_bounds = src->llBounds(proj); _bounds = src->llBounds();
connect(this, &MapItem::triggered, action, &MapAction::trigger); connect(this, &MapItem::triggered, action, &MapAction::trigger);

View File

@ -11,8 +11,7 @@ class MapItem : public QObject, public PlaneItem
Q_OBJECT Q_OBJECT
public: public:
MapItem(MapAction *action, Map *map, const Projection &proj, MapItem(MapAction *action, Map *map, GraphicsItem *parent = 0);
GraphicsItem *parent = 0);
QPainterPath shape() const {return _painterPath;} QPainterPath shape() const {return _painterPath;}
QRectF boundingRect() const {return _painterPath.boundingRect();} QRectF boundingRect() const {return _painterPath.boundingRect();}

View File

@ -250,7 +250,7 @@ void MapView::addWaypoints(const QVector<Waypoint> &waypoints)
MapItem *MapView::addMap(MapAction *map) MapItem *MapView::addMap(MapAction *map)
{ {
MapItem *mi = new MapItem(map, _map, _inputProjection); MapItem *mi = new MapItem(map, _map);
mi->setColor(_palette.nextColor()); mi->setColor(_palette.nextColor());
mi->setWidth(_areaWidth); mi->setWidth(_areaWidth);
mi->setPenStyle(_areaStyle); mi->setPenStyle(_areaStyle);
@ -331,7 +331,7 @@ int MapView::fitMapZoom() const
RectC br = _tr | _rr | _wr | _ar; RectC br = _tr | _rr | _wr | _ar;
return _map->zoomFit(viewport()->size() - QSize(2*MARGIN, 2*MARGIN), return _map->zoomFit(viewport()->size() - QSize(2*MARGIN, 2*MARGIN),
br.isNull() ? _map->llBounds(_inputProjection) : br); br.isNull() ? _map->llBounds() : br);
} }
QPointF MapView::contentCenter() const QPointF MapView::contentCenter() const

View File

@ -98,6 +98,7 @@ public:
void fitContentToSize(); void fitContentToSize();
RectC boundingRect() const; RectC boundingRect() const;
const Projection &inputProjection() const {return _inputProjection;}
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
signals: signals:

View File

@ -405,8 +405,10 @@ void AQMMap::drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp)
painter->drawPixmap(tp, pixmap); painter->drawPixmap(tp, pixmap);
} }
Map *AQMMap::create(const QString &path, bool *isDir) Map *AQMMap::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;

View File

@ -17,7 +17,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
@ -38,7 +38,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
struct File { struct File {

View File

@ -100,8 +100,9 @@ void Atlas::computeBounds()
QRectF(offsets.at(i), _maps.at(i)->bounds().size())); QRectF(offsets.at(i), _maps.at(i)->bounds().size()));
} }
Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent) Atlas::Atlas(const QString &fileName, bool TAR, const Projection &proj,
: Map(fileName, parent), _zoom(0), _mapIndex(-1), _valid(false) QObject *parent) : Map(fileName, parent), _zoom(0), _mapIndex(-1),
_valid(false)
{ {
QFileInfo fi(fileName); QFileInfo fi(fileName);
QByteArray ba; QByteArray ba;
@ -142,39 +143,39 @@ Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
for (int i = 0; i < maps.count(); i++) { for (int i = 0; i < maps.count(); i++) {
OziMap *map; OziMap *map;
if (TAR) if (TAR)
map = new OziMap(maps.at(i).absoluteFilePath(), tar, this); map = new OziMap(maps.at(i).absoluteFilePath(), tar, proj, this);
else { else {
QString cf(calibrationFile(maps.at(i).absoluteFilePath())); QString cf(calibrationFile(maps.at(i).absoluteFilePath()));
if (cf.isNull()) { if (cf.isNull()) {
_errorString = "No calibration file found"; _errorString = "No calibration file found";
return; return;
} }
map = new OziMap(cf, this); map = new OziMap(cf, proj, this);
} }
if (map->isValid()) if (map->isValid())
_maps.append(map); _maps.append(map);
else { else {
_errorString = QString("%1: %2") qWarning("%s: %s", qPrintable(map->path()),
.arg(map->path(), map->errorString()); qPrintable(map->errorString()));
return; delete map;
} }
} }
} }
if (_maps.isEmpty()) { if (_maps.isEmpty()) {
_errorString = "No maps found in atlas"; _errorString = "No usable map found in atlas";
return; return;
} }
_valid = true; _valid = true;
} }
RectC Atlas::llBounds(const Projection &proj) RectC Atlas::llBounds()
{ {
RectC bounds; RectC bounds;
for (int i = 0; i < _maps.size(); i++) for (int i = 0; i < _maps.size(); i++)
bounds |= _maps.at(i)->llBounds(proj); bounds |= _maps.at(i)->llBounds();
return bounds; return bounds;
} }
@ -330,18 +331,34 @@ void Atlas::unload()
_bounds.clear(); _bounds.clear();
} }
Map *Atlas::createTAR(const QString &path, bool *isDir) Map *Atlas::createTAR(const QString &path, const Projection &proj, bool *isDir)
{ {
if (isDir) if (isDir)
*isDir = true; *isDir = true;
return new Atlas(path, true); return new Atlas(path, true, proj);
} }
Map *Atlas::createTBA(const QString &path, bool *isDir) Map *Atlas::createTBA(const QString &path, const Projection &proj, bool *isDir)
{ {
if (isDir) if (isDir)
*isDir = true; *isDir = true;
return new Atlas(path, false); return new Atlas(path, false, proj);
} }
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Atlas::Bounds &bounds)
{
dbg.nospace() << "Bounds(" << bounds.xy << ", " << bounds.pp << ")";
return dbg.space();
}
QDebug operator<<(QDebug dbg, const Atlas::Zoom &zoom)
{
dbg.nospace() << "Zoom(" << zoom.first << ", " << zoom.last << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -12,12 +12,13 @@ class Atlas : public Map
Q_OBJECT Q_OBJECT
public: public:
Atlas(const QString &fileName, bool TAR, QObject *parent = 0); Atlas(const QString &fileName, bool TAR, const Projection &proj,
QObject *parent = 0);
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &proj); RectC llBounds();
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);
@ -37,8 +38,10 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *createTAR(const QString &path, bool *isDir); static Map *createTAR(const QString &path, const Projection &proj,
static Map *createTBA(const QString &path, bool *isDir); bool *isDir);
static Map *createTBA(const QString &path, const Projection &proj,
bool *isDir);
private: private:
struct Zoom { struct Zoom {
@ -61,6 +64,9 @@ private:
void computeZooms(); void computeZooms();
void computeBounds(); void computeBounds();
friend QDebug operator<<(QDebug dbg, const Bounds &bounds);
friend QDebug operator<<(QDebug dbg, const Zoom &zoom);
QString _name; QString _name;
QList<OziMap*> _maps; QList<OziMap*> _maps;
@ -73,4 +79,9 @@ private:
QString _errorString; QString _errorString;
}; };
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Atlas::Zoom &zoom);
QDebug operator<<(QDebug dbg, const Atlas::Bounds &bounds);
#endif // QT_NO_DEBUG
#endif // ATLAS_H #endif // ATLAS_H

View File

@ -462,8 +462,10 @@ void BSBMap::unload()
_img = 0; _img = 0;
} }
Map *BSBMap::create(const QString &path, bool *isMap) Map *BSBMap::create(const QString &path, const Projection &proj, bool *isMap)
{ {
Q_UNUSED(proj);
if (isMap) if (isMap)
*isMap = false; *isMap = false;

View File

@ -32,7 +32,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isMap); static Map *create(const QString &path, const Projection &proj, bool *isMap);
private: private:
bool parseBSB(const QByteArray &line); bool parseBSB(const QByteArray &line);

View File

@ -378,8 +378,10 @@ void ENCAtlas::draw(QPainter *painter, const QRectF &rect, Flags flags)
} }
} }
Map *ENCAtlas::create(const QString &path, bool *isDir) Map *ENCAtlas::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = true; *isDir = true;

View File

@ -22,7 +22,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds() {return _bounds;} QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _llBounds;} RectC llBounds() {return _llBounds;}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);
@ -44,7 +44,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private slots: private slots:
void jobFinished(ENCJob *job); void jobFinished(ENCJob *job);

View File

@ -345,8 +345,10 @@ void ENCMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
} }
} }
Map *ENCMap::create(const QString &path, bool *isMap) Map *ENCMap::create(const QString &path, const Projection &proj, bool *isMap)
{ {
Q_UNUSED(proj);
if (isMap) if (isMap)
*isMap = false; *isMap = false;

View File

@ -23,7 +23,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds() {return _bounds;} QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _llBounds;} RectC llBounds() {return _llBounds;}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);
@ -45,7 +45,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isMap); static Map *create(const QString &path, const Projection &proj, bool *isMap);
private slots: private slots:
void jobFinished(ENCJob *job); void jobFinished(ENCJob *job);

View File

@ -301,8 +301,10 @@ void GEMFMap::drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp)
painter->drawPixmap(tp, pixmap); painter->drawPixmap(tp, pixmap);
} }
Map *GEMFMap::create(const QString &path, bool *isDir) Map *GEMFMap::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;

View File

@ -14,7 +14,7 @@ public:
GEMFMap(const QString &fileName, QObject *parent = 0); GEMFMap(const QString &fileName, QObject *parent = 0);
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
int zoom() const {return _zi;} int zoom() const {return _zi;}
void setZoom(int zoom) {_zi = zoom;} void setZoom(int zoom) {_zi = zoom;}
@ -35,7 +35,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
struct Region { struct Region {

View File

@ -73,8 +73,10 @@ void GeoTIFFMap::unload()
_img = 0; _img = 0;
} }
Map *GeoTIFFMap::create(const QString &path, bool *isDir) Map *GeoTIFFMap::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;

View File

@ -29,7 +29,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
Projection _projection; Projection _projection;

View File

@ -1,5 +1,3 @@
#include "common/csv.h"
#include "pcs.h"
#include "gmifile.h" #include "gmifile.h"
static CalibrationPoint calibrationPoint(const QByteArray line) static CalibrationPoint calibrationPoint(const QByteArray line)
@ -19,7 +17,7 @@ static CalibrationPoint calibrationPoint(const QByteArray line)
: CalibrationPoint(); : CalibrationPoint();
} }
bool GmiFile::parse(QIODevice &device, QList<CalibrationPoint> &points) bool GmiFile::parse(QIODevice &device)
{ {
int ln = 1; int ln = 1;
int width, height; int width, height;
@ -56,7 +54,7 @@ bool GmiFile::parse(QIODevice &device, QList<CalibrationPoint> &points)
} else { } else {
CalibrationPoint cp(calibrationPoint(line)); CalibrationPoint cp(calibrationPoint(line));
if (cp.isValid()) if (cp.isValid())
points.append(cp); _points.append(cp);
else else
break; break;
} }
@ -66,32 +64,10 @@ bool GmiFile::parse(QIODevice &device, QList<CalibrationPoint> &points)
device.close(); device.close();
return (points.size() >= 2); return (_points.size() >= 2);
}
bool GmiFile::computeTransformation(const QList<CalibrationPoint> &points)
{
QList<ReferencePoint> rp;
Projection proj(GCS::WGS84());
for (int i = 0; i < points.size(); i++)
rp.append(points.at(i).rp(proj));
_transform = Transform(rp);
if (!_transform.isValid()) {
_errorString = _transform.errorString();
return false;
}
return true;
} }
GmiFile::GmiFile(QIODevice &file) GmiFile::GmiFile(QIODevice &file)
{ {
QList<CalibrationPoint> points; _valid = parse(file);
if (!parse(file, points))
return;
if (!computeTransformation(points))
return;
} }

View File

@ -1,32 +1,30 @@
#ifndef GMIFILE_H #ifndef GMIFILE_H
#define GMIFILE_H #define GMIFILE_H
#include "transform.h"
#include "calibrationpoint.h" #include "calibrationpoint.h"
class QIODevice; class QIODevice;
class GCS;
class GmiFile class GmiFile
{ {
public: public:
GmiFile(QIODevice &file); GmiFile(QIODevice &file);
bool isValid() const {return !_image.isNull() && _transform.isValid();} bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;} const QString &errorString() const {return _errorString;}
const Transform &transform() const {return _transform;}
const QString &image() const {return _image;} const QString &image() const {return _image;}
const QSize &size() const {return _size;} const QSize &size() const {return _size;}
const QList<CalibrationPoint> &calibrationPoints() const {return _points;}
private: private:
bool parse(QIODevice &device, QList<CalibrationPoint> &points); bool parse(QIODevice &device);
bool computeTransformation(const QList<CalibrationPoint> &points);
QString _image; QString _image;
QSize _size; QSize _size;
Transform _transform; QList<CalibrationPoint> _points;
bool _valid;
QString _errorString; QString _errorString;
}; };

View File

@ -264,16 +264,20 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
} }
} }
Map* IMGMap::createIMG(const QString &path, bool *isDir) Map* IMGMap::createIMG(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;
return new IMGMap(path, false); return new IMGMap(path, false);
} }
Map* IMGMap::createGMAP(const QString &path, bool *isDir) Map* IMGMap::createGMAP(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = true; *isDir = true;

View File

@ -55,7 +55,7 @@ public:
QString name() const {return _data.first()->name();} QString name() const {return _data.first()->name();}
QRectF bounds() {return _bounds;} QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _data.first()->bounds();} RectC llBounds() {return _data.first()->bounds();}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);
@ -77,8 +77,10 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map* createIMG(const QString &path, bool *isDir); static Map* createIMG(const QString &path, const Projection &proj,
static Map* createGMAP(const QString &path, bool *isDir); bool *isDir);
static Map* createGMAP(const QString &path, const Projection &proj,
bool *isDir);
private slots: private slots:
void jobFinished(IMGMapJob *job); void jobFinished(IMGMapJob *job);

View File

@ -274,8 +274,10 @@ void JNXMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
tree.Search(min, max, cb, &ctx); tree.Search(min, max, cb, &ctx);
} }
Map *JNXMap::create(const QString &path, bool *isDir) Map *JNXMap::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;

View File

@ -19,7 +19,7 @@ public:
~JNXMap(); ~JNXMap();
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom) {_zoom = zoom;} void setZoom(int zoom) {_zoom = zoom;}
@ -39,7 +39,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
struct Tile { struct Tile {

View File

@ -484,8 +484,10 @@ void KMZMap::draw(QPainter *painter, const QRectF &rect, int mapIndex)
painter->restore(); painter->restore();
} }
Map *KMZMap::create(const QString &path, bool *isDir) Map *KMZMap::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;

View File

@ -18,7 +18,7 @@ public:
KMZMap(const QString &fileName, QObject *parent = 0); KMZMap(const QString &fileName, QObject *parent = 0);
~KMZMap(); ~KMZMap();
RectC llBounds(const Projection &) {return _llbounds;} RectC llBounds() {return _llbounds;}
QRectF bounds(); QRectF bounds();
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
@ -39,7 +39,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
class Overlay { class Overlay {

View File

@ -30,12 +30,8 @@ static void growBottom(const Coordinates &c, RectC &rect)
rect.setBottom(c.lat()); rect.setBottom(c.lat());
} }
RectC Map::llBounds(const Projection &proj) RectC Map::llBounds()
{ {
Q_UNUSED(proj);
/* We use bounds() and xy2ll() here as this fallback implementation is
used ONLY for maps providing those functions since map creation. */
QRectF b(bounds()); QRectF b(bounds());
double dx = b.width() / SAMPLES; double dx = b.width() / SAMPLES;
double dy = b.height() / SAMPLES; double dy = b.height() / SAMPLES;

View File

@ -28,19 +28,19 @@ public:
: QObject(parent), _path(path) {} : QObject(parent), _path(path) {}
virtual ~Map() {} virtual ~Map() {}
/* Functions available since map creation */
const QString &path() const {return _path;} const QString &path() const {return _path;}
virtual QString name() const {return Util::file2name(path());} virtual QString name() const {return Util::file2name(path());}
virtual RectC llBounds(const Projection &proj);
virtual bool isValid() const {return true;} virtual bool isValid() const {return true;}
virtual bool isReady() const {return true;} virtual bool isReady() const {return true;}
virtual QString errorString() const {return QString();} virtual QString errorString() const {return QString();}
/* Functions that shall be called after load() */
virtual void load(const Projection &, const Projection &, qreal, bool) {} virtual void load(const Projection &, const Projection &, qreal, bool) {}
virtual void unload() {} virtual void unload() {}
/* llBounds() is mandatory for maps that do not provide bounds() until
load() is called! */
virtual RectC llBounds();
virtual QRectF bounds() = 0; virtual QRectF bounds() = 0;
virtual qreal resolution(const QRectF &rect); virtual qreal resolution(const QRectF &rect);

View File

@ -65,7 +65,7 @@ MapList::ParserMap MapList::parsers()
MapList::ParserMap MapList::_parsers = parsers(); MapList::ParserMap MapList::_parsers = parsers();
Map *MapList::loadFile(const QString &path, bool *isDir) Map *MapList::loadFile(const QString &path, const Projection &proj, bool *isDir)
{ {
ParserMap::iterator it; ParserMap::iterator it;
QFileInfo fi(Util::displayName(path)); QFileInfo fi(Util::displayName(path));
@ -76,7 +76,7 @@ Map *MapList::loadFile(const QString &path, bool *isDir)
if ((it = _parsers.find(suffix)) != _parsers.end()) { if ((it = _parsers.find(suffix)) != _parsers.end()) {
while (it != _parsers.end() && it.key() == suffix) { while (it != _parsers.end() && it.key() == suffix) {
delete map; delete map;
map = it.value()(path, isDir); map = it.value()(path, proj, isDir);
if (map->isValid()) if (map->isValid())
return map; return map;
else else
@ -85,7 +85,7 @@ Map *MapList::loadFile(const QString &path, bool *isDir)
} }
} else { } else {
for (it = _parsers.begin(); it != _parsers.end(); it++) { for (it = _parsers.begin(); it != _parsers.end(); it++) {
map = it.value()(path, isDir); map = it.value()(path, proj, isDir);
if (map->isValid()) if (map->isValid())
return map; return map;
else { else {
@ -103,7 +103,8 @@ Map *MapList::loadFile(const QString &path, bool *isDir)
return map ? map : new InvalidMap(path, "Unknown file format"); return map ? map : new InvalidMap(path, "Unknown file format");
} }
TreeNode<Map*> MapList::loadDir(const QString &path, TreeNode<Map*> *parent) TreeNode<Map*> MapList::loadDir(const QString &path, const Projection &proj,
TreeNode<Map*> *parent)
{ {
QDir md(path); QDir md(path);
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
@ -120,12 +121,12 @@ TreeNode<Map*> MapList::loadDir(const QString &path, TreeNode<Map*> *parent)
QString suffix = fi.suffix().toLower(); QString suffix = fi.suffix().toLower();
if (fi.isDir()) { if (fi.isDir()) {
TreeNode<Map*> child(loadDir(fi.absoluteFilePath(), &tree)); TreeNode<Map*> child(loadDir(fi.absoluteFilePath(), proj, &tree));
if (!child.isEmpty()) if (!child.isEmpty())
tree.addChild(child); tree.addChild(child);
} else if (filter().contains("*." + suffix)) { } else if (filter().contains("*." + suffix)) {
bool isDir = false; bool isDir = false;
Map *map = loadFile(fi.absoluteFilePath(), &isDir); Map *map = loadFile(fi.absoluteFilePath(), proj, &isDir);
if (isDir) { if (isDir) {
if (parent) if (parent)
parent->addItem(map); parent->addItem(map);
@ -140,13 +141,13 @@ TreeNode<Map*> MapList::loadDir(const QString &path, TreeNode<Map*> *parent)
return tree; return tree;
} }
TreeNode<Map *> MapList::loadMaps(const QString &path) TreeNode<Map *> MapList::loadMaps(const QString &path, const Projection &proj)
{ {
if (QFileInfo(path).isDir()) if (QFileInfo(path).isDir())
return loadDir(path); return loadDir(path, proj);
else { else {
TreeNode<Map*> tree; TreeNode<Map*> tree;
tree.addItem(loadFile(path)); tree.addItem(loadFile(path, proj));
return tree; return tree;
} }
} }

View File

@ -10,16 +10,18 @@ class Projection;
class MapList class MapList
{ {
public: public:
static TreeNode<Map*> loadMaps(const QString &path); static TreeNode<Map*> loadMaps(const QString &path, const Projection &proj);
static QString formats(); static QString formats();
static QStringList filter(); static QStringList filter();
private: private:
typedef Map*(*ParserCb)(const QString &, bool *isDir); typedef Map*(*ParserCb)(const QString &, const Projection &, bool *);
typedef QMultiMap<QString, ParserCb> ParserMap; typedef QMultiMap<QString, ParserCb> ParserMap;
static Map *loadFile(const QString &path, bool *isDir = 0); static Map *loadFile(const QString &path, const Projection &proj,
static TreeNode<Map*> loadDir(const QString &path, TreeNode<Map*> *parent = 0); bool *isDir = 0);
static TreeNode<Map*> loadDir(const QString &path, const Projection &proj,
TreeNode<Map*> *parent = 0);
static ParserMap parsers(); static ParserMap parsers();
static ParserMap _parsers; static ParserMap _parsers;

View File

@ -209,8 +209,11 @@ void MapsforgeMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
} }
} }
Map *MapsforgeMap::create(const QString &path, bool *isMap) Map *MapsforgeMap::create(const QString &path, const Projection &proj,
bool *isMap)
{ {
Q_UNUSED(proj);
if (isMap) if (isMap)
*isMap = false; *isMap = false;

View File

@ -52,7 +52,7 @@ public:
MapsforgeMap(const QString &fileName, QObject *parent = 0); MapsforgeMap(const QString &fileName, QObject *parent = 0);
QRectF bounds() {return _bounds;} QRectF bounds() {return _bounds;}
RectC llBounds(const Projection &) {return _data.bounds();} RectC llBounds() {return _data.bounds();}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);
@ -74,7 +74,7 @@ public:
bool isValid() const {return _data.isValid();} bool isValid() const {return _data.isValid();}
QString errorString() const {return _data.errorString();} QString errorString() const {return _data.errorString();}
static Map *create(const QString &path, bool *isMap); static Map *create(const QString &path, const Projection &proj, bool *isMap);
private slots: private slots:
void jobFinished(MapsforgeMapJob *job); void jobFinished(MapsforgeMapJob *job);

View File

@ -214,8 +214,9 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
} }
} }
Map *MapSource::create(const QString &path, bool *isDir) Map *MapSource::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
Config config; Config config;
QFile file(path); QFile file(path);

View File

@ -15,7 +15,7 @@ class Projection;
class MapSource class MapSource
{ {
public: public:
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
enum Type { enum Type {

View File

@ -338,8 +338,10 @@ Coordinates MBTilesMap::xy2ll(const QPointF &p)
* coordinatesRatio()); * coordinatesRatio());
} }
Map *MBTilesMap::create(const QString &path, bool *isDir) Map *MBTilesMap::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;

View File

@ -13,7 +13,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zi;} int zoom() const {return _zi;}
@ -34,7 +34,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
qreal tileSize() const; qreal tileSize() const;

View File

@ -590,8 +590,10 @@ Coordinates OruxMap::xy2ll(const QPointF &p)
return z.projection.xy2ll(z.transform.img2proj(p * _mapRatio)); return z.projection.xy2ll(z.transform.img2proj(p * _mapRatio));
} }
Map *OruxMap::create(const QString &path, bool *isDir) Map *OruxMap::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = true; *isDir = true;

View File

@ -40,7 +40,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
struct Zoom { struct Zoom {

View File

@ -309,8 +309,11 @@ Coordinates OsmdroidMap::xy2ll(const QPointF &p)
return OSM::m2ll(QPointF(p.x() * scale, -p.y() * scale) * _mapRatio); return OSM::m2ll(QPointF(p.x() * scale, -p.y() * scale) * _mapRatio);
} }
Map *OsmdroidMap::create(const QString &path, bool *isDir) Map *OsmdroidMap::create(const QString &path, const Projection &proj,
bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;

View File

@ -11,7 +11,7 @@ public:
OsmdroidMap(const QString &fileName, QObject *parent = 0); OsmdroidMap(const QString &fileName, QObject *parent = 0);
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
@ -32,7 +32,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
int limitZoom(int zoom) const; int limitZoom(int zoom) const;

View File

@ -17,6 +17,21 @@
#include "ozimap.h" #include "ozimap.h"
static QString tarFile(const QString &path)
{
QDir dir(path);
QFileInfoList files = dir.entryInfoList(QDir::Files);
for (int i = 0; i < files.size(); i++) {
const QFileInfo &fi = files.at(i);
if (fi.suffix().toLower() == "tar")
return fi.absoluteFilePath();
}
return QString();
}
QString OziMap::calibrationFile(const QStringList &files, const QString path, QString OziMap::calibrationFile(const QStringList &files, const QString path,
CalibrationType &type) CalibrationType &type)
{ {
@ -39,9 +54,9 @@ QString OziMap::calibrationFile(const QStringList &files, const QString path,
return QString(); return QString();
} }
OziMap::OziMap(const QString &fileName, QObject *parent) OziMap::OziMap(const QString &fileName, const Projection &proj, QObject *parent)
: Map(fileName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0), : Map(fileName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0),
_hasProj(true), _valid(false) _valid(false)
{ {
QFileInfo fi(fileName); QFileInfo fi(fileName);
QString suffix(fi.suffix().toLower()); QString suffix(fi.suffix().toLower());
@ -68,9 +83,9 @@ OziMap::OziMap(const QString &fileName, QObject *parent)
_name = Util::file2name(fileName); _name = Util::file2name(fileName);
_map.size = gmi.size(); _map.size = gmi.size();
_map.path = gmi.image(); _map.path = gmi.image();
_transform = gmi.transform(); _calibrationPoints = gmi.calibrationPoints();
_projection = Projection(GCS::WGS84()); _projection = proj;
_hasProj = false; computeTransform();
} }
} else if (type == MAP) { } else if (type == MAP) {
QByteArray ba(_tar->file(cf)); QByteArray ba(_tar->file(cf));
@ -119,9 +134,9 @@ OziMap::OziMap(const QString &fileName, QObject *parent)
_name = Util::file2name(fileName); _name = Util::file2name(fileName);
_map.size = gmi.size(); _map.size = gmi.size();
_map.path = gmi.image(); _map.path = gmi.image();
_transform = gmi.transform(); _calibrationPoints = gmi.calibrationPoints();
_projection = Projection(GCS::WGS84()); _projection = proj;
_hasProj = false; computeTransform();
} }
} else { } else {
_errorString = "Unknown file type"; _errorString = "Unknown file type";
@ -141,9 +156,9 @@ OziMap::OziMap(const QString &fileName, QObject *parent)
_valid = true; _valid = true;
} }
OziMap::OziMap(const QString &dirName, Tar &tar, QObject *parent) OziMap::OziMap(const QString &dirName, Tar &tar, const Projection &proj,
: Map(dirName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0), QObject *parent) : Map(dirName, parent), _img(0), _tar(0), _ozf(0), _zoom(0),
_hasProj(true), _valid(false) _mapRatio(1.0), _valid(false)
{ {
CalibrationType type; CalibrationType type;
QString cf(calibrationFile(tar.files(), dirName, type)); QString cf(calibrationFile(tar.files(), dirName, type));
@ -172,18 +187,20 @@ OziMap::OziMap(const QString &dirName, Tar &tar, QObject *parent)
_name = Util::file2name(cf); _name = Util::file2name(cf);
_map.size = gmi.size(); _map.size = gmi.size();
_transform = gmi.transform(); _calibrationPoints = gmi.calibrationPoints();
_projection = Projection(GCS::WGS84()); _projection = proj;
_hasProj = false; computeTransform();
} else { } else {
_errorString = "No calibration file found"; _errorString = "No calibration file found";
return; return;
} }
QFileInfo fi(cf); QString tf(tarFile(dirName));
QDir dir(dirName); if (tf.isNull()) {
_tar = new Tar(dir.absoluteFilePath(fi.completeBaseName() + ".tar")); _errorString = "No map tar file found";
return;
}
_tar = new Tar(tf);
if (!_tar->open()) { if (!_tar->open()) {
_errorString = _tar->fileName() + ": error reading tar file"; _errorString = _tar->fileName() + ": error reading tar file";
return; return;
@ -288,8 +305,10 @@ void OziMap::load(const Projection &in, const Projection &out,
Q_UNUSED(out); Q_UNUSED(out);
_mapRatio = hidpi ? deviceRatio : 1.0; _mapRatio = hidpi ? deviceRatio : 1.0;
if (!_hasProj) if (!_calibrationPoints.isEmpty()) {
_projection = in; _projection = in;
computeTransform();
}
if (_tar) { if (_tar) {
Q_ASSERT(!_tar->isOpen()); Q_ASSERT(!_tar->isOpen());
@ -473,18 +492,28 @@ void OziMap::rescale(int zoom)
_scale = _ozf->scale(zoom); _scale = _ozf->scale(zoom);
} }
Map *OziMap::createTAR(const QString &path, bool *isDir) void OziMap::computeTransform()
{
QList<ReferencePoint> rp;
for (int i = 0; i < _calibrationPoints.size(); i++)
rp.append(_calibrationPoints.at(i).rp(_projection));
_transform = Transform(rp);
}
Map *OziMap::createTAR(const QString &path, const Projection &proj, bool *isDir)
{ {
if (isDir) if (isDir)
*isDir = false; *isDir = false;
return new OziMap(path); return new OziMap(path, proj);
} }
Map *OziMap::createMAP(const QString &path, bool *isDir) Map *OziMap::createMAP(const QString &path, const Projection &proj, bool *isDir)
{ {
if (isDir) if (isDir)
*isDir = false; *isDir = false;
return new OziMap(path); return new OziMap(path, proj);
} }

View File

@ -3,6 +3,7 @@
#include "transform.h" #include "transform.h"
#include "projection.h" #include "projection.h"
#include "calibrationpoint.h"
#include "map.h" #include "map.h"
class Tar; class Tar;
@ -14,8 +15,10 @@ class OziMap : public Map
Q_OBJECT Q_OBJECT
public: public:
OziMap(const QString &fileName, QObject *parent = 0); OziMap(const QString &fileName, const Projection &proj,
OziMap(const QString &dirName, Tar &tar, QObject *parent = 0); QObject *parent = 0);
OziMap(const QString &dirName, Tar &tar, const Projection &proj,
QObject *parent = 0);
~OziMap(); ~OziMap();
QString name() const {return _name;} QString name() const {return _name;}
@ -47,8 +50,10 @@ public:
QPointF pp2xy(const PointD &p) const QPointF pp2xy(const PointD &p) const
{return _transform.proj2img(p) / _mapRatio;} {return _transform.proj2img(p) / _mapRatio;}
static Map *createTAR(const QString &path, bool *isDir); static Map *createTAR(const QString &path, const Projection &proj,
static Map *createMAP(const QString &path, bool *isDir); bool *isDir);
static Map *createMAP(const QString &path, const Projection &proj,
bool *isDir);
private: private:
enum CalibrationType { enum CalibrationType {
@ -70,6 +75,7 @@ private:
void drawImage(QPainter *painter, const QRectF &rect, Flags flags) const; void drawImage(QPainter *painter, const QRectF &rect, Flags flags) const;
void rescale(int zoom); void rescale(int zoom);
void computeTransform();
static QString calibrationFile(const QStringList &files, const QString path, static QString calibrationFile(const QStringList &files, const QString path,
CalibrationType &type); CalibrationType &type);
@ -84,7 +90,7 @@ private:
int _zoom; int _zoom;
QPointF _scale; QPointF _scale;
qreal _mapRatio; qreal _mapRatio;
bool _hasProj; QList<CalibrationPoint> _calibrationPoints;
bool _valid; bool _valid;
QString _errorString; QString _errorString;

View File

@ -491,8 +491,10 @@ void QCTMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
} }
} }
Map *QCTMap::create(const QString &path, bool *isDir) Map *QCTMap::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;

View File

@ -28,7 +28,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
bool readName(QDataStream &stream); bool readName(QDataStream &stream);

View File

@ -460,8 +460,10 @@ void RMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
} }
} }
Map *RMap::create(const QString &path, bool *isDir) Map *RMap::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;

View File

@ -34,7 +34,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
struct Header { struct Header {

View File

@ -256,8 +256,10 @@ Coordinates SqliteMap::xy2ll(const QPointF &p)
return OSM::m2ll(QPointF(p.x() * scale, -p.y() * scale) * _mapRatio); return OSM::m2ll(QPointF(p.x() * scale, -p.y() * scale) * _mapRatio);
} }
Map *SqliteMap::create(const QString &path, bool *isDir) Map *SqliteMap::create(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj);
if (isDir) if (isDir)
*isDir = false; *isDir = false;

View File

@ -11,7 +11,7 @@ public:
SqliteMap(const QString &fileName, QObject *parent = 0); SqliteMap(const QString &fileName, QObject *parent = 0);
QRectF bounds(); QRectF bounds();
RectC llBounds(const Projection &) {return _bounds;} RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
@ -32,7 +32,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
int limitZoom(int zoom) const; int limitZoom(int zoom) const;

View File

@ -9,8 +9,9 @@
#include "worldfilemap.h" #include "worldfilemap.h"
WorldFileMap::WorldFileMap(const QString &fileName, QObject *parent) WorldFileMap::WorldFileMap(const QString &fileName, const Projection &proj,
: Map(fileName, parent), _img(0), _mapRatio(1.0), _hasPRJ(false), _valid(false) QObject *parent) : Map(fileName, parent), _img(0), _mapRatio(1.0),
_hasPRJ(false), _valid(false)
{ {
QFileInfo fi(fileName); QFileInfo fi(fileName);
QDir dir(fi.absoluteDir()); QDir dir(fi.absoluteDir());
@ -37,7 +38,8 @@ WorldFileMap::WorldFileMap(const QString &fileName, QObject *parent)
_errorString = prjFile + ": " + prj.errorString(); _errorString = prjFile + ": " + prj.errorString();
return; return;
} }
} } else
_projection = proj;
// Find the corresponding image file // Find the corresponding image file
QList<QByteArray> formats(QImageReader::supportedImageFormats()); QList<QByteArray> formats(QImageReader::supportedImageFormats());
@ -81,14 +83,6 @@ Coordinates WorldFileMap::xy2ll(const QPointF &p)
return _projection.xy2ll(_transform.img2proj(p * _mapRatio)); return _projection.xy2ll(_transform.img2proj(p * _mapRatio));
} }
RectC WorldFileMap::llBounds(const Projection &proj)
{
if (_projection.isNull())
_projection = proj;
return Map::llBounds(proj);
}
QRectF WorldFileMap::bounds() QRectF WorldFileMap::bounds()
{ {
return QRectF(QPointF(0, 0), _size / _mapRatio); return QRectF(QPointF(0, 0), _size / _mapRatio);
@ -122,10 +116,11 @@ void WorldFileMap::unload()
_img = 0; _img = 0;
} }
Map *WorldFileMap::create(const QString &path, bool *isDir) Map *WorldFileMap::create(const QString &path, const Projection &proj,
bool *isDir)
{ {
if (isDir) if (isDir)
*isDir = false; *isDir = false;
return new WorldFileMap(path); return new WorldFileMap(path, proj);
} }

View File

@ -12,10 +12,10 @@ class WorldFileMap : public Map
Q_OBJECT Q_OBJECT
public: public:
WorldFileMap(const QString &fileName, QObject *parent = 0); WorldFileMap(const QString &fileName, const Projection &proj,
QObject *parent = 0);
~WorldFileMap(); ~WorldFileMap();
RectC llBounds(const Projection &proj);
QRectF bounds(); QRectF bounds();
QPointF ll2xy(const Coordinates &c); QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p); Coordinates xy2ll(const QPointF &p);
@ -29,7 +29,7 @@ public:
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
static Map *create(const QString &path, bool *isDir); static Map *create(const QString &path, const Projection &proj, bool *isDir);
private: private:
Projection _projection; Projection _projection;