diff --git a/gpxsee.pro b/gpxsee.pro index e4bab956..75117acb 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -20,6 +20,7 @@ equals(QT_MAJOR_VERSION, 5) : lessThan(QT_MINOR_VERSION, 4) {QT += opengl} INCLUDEPATH += ./src HEADERS += src/common/config.h \ src/GUI/graphicsscene.h \ + src/GUI/mapaction.h \ src/GUI/popup.h \ src/common/garmin.h \ src/common/staticassert.h \ diff --git a/src/GUI/gui.cpp b/src/GUI/gui.cpp index 0dc108ca..410fb726 100644 --- a/src/GUI/gui.cpp +++ b/src/GUI/gui.cpp @@ -51,6 +51,7 @@ #include "graphtab.h" #include "graphitem.h" #include "pathitem.h" +#include "mapaction.h" #include "gui.h" @@ -58,7 +59,6 @@ GUI::GUI() { - loadMaps(); loadPOIs(); createMapView(); @@ -106,24 +106,13 @@ GUI::GUI() updateStatusBarInfo(); } -void GUI::loadMaps() -{ - _ml = new MapList(this); - QString mapDir(ProgramPaths::mapDir()); - - if (!mapDir.isNull() && !_ml->loadDir(mapDir)) - qWarning("%s", qPrintable(_ml->errorPath() + ": " + _ml->errorString())); - - _map = new EmptyMap(this); -} - void GUI::loadPOIs() { _poi = new POI(this); - QString poiDir(ProgramPaths::poiDir()); - if (!poiDir.isNull() && !_poi->loadDir(poiDir)) - qWarning("%s", qPrintable(_poi->errorString())); + QString poiDir(ProgramPaths::poiDir()); + if (!poiDir.isNull()) + _poi->loadDir(poiDir); } void GUI::createBrowser() @@ -134,40 +123,56 @@ void GUI::createBrowser() void GUI::createMapActions() { - _mapsSignalMapper = new QSignalMapper(this); _mapsActionGroup = new QActionGroup(this); _mapsActionGroup->setExclusive(true); - for (int i = 0; i < _ml->maps().count(); i++) - createMapAction(_ml->maps().at(i)); + QString mapDir(ProgramPaths::mapDir()); + if (mapDir.isNull()) + return; - connect(_mapsSignalMapper, SIGNAL(mapped(int)), this, - SLOT(mapChanged(int))); + QString unused; + QList maps(MapList::loadMaps(mapDir, unused)); + for (int i = 0; i < maps.count(); i++) { + MapAction *a = createMapAction(maps.at(i)); + connect(a, SIGNAL(loaded()), this, SLOT(mapInitialized())); + } } -QAction *GUI::createMapAction(const Map *map) +MapAction *GUI::createMapAction(Map *map) { - QAction *a = new QAction(map->name(), this); + MapAction *a = new MapAction(map); a->setMenuRole(QAction::NoRole); a->setCheckable(true); a->setActionGroup(_mapsActionGroup); - - _mapActions.append(a); - _mapsSignalMapper->setMapping(a, _mapActions.size() - 1); - connect(a, SIGNAL(triggered()), _mapsSignalMapper, SLOT(map())); + connect(a, SIGNAL(triggered()), this, SLOT(mapChanged())); return a; } +void GUI::mapInitialized() +{ + MapAction *action = static_cast(QObject::sender()); + Map *map = action->data().value(); + + if (map->isValid()) { + if (!_mapsActionGroup->checkedAction()) + action->trigger(); + _showMapAction->setEnabled(true); + _clearMapCacheAction->setEnabled(true); + } else { + qWarning(qPrintable(map->name() + ": " + map->errorString())); + action->deleteLater(); + } +} + void GUI::createPOIFilesActions() { _poiFilesSignalMapper = new QSignalMapper(this); + connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this, + SLOT(poiFileChecked(int))); for (int i = 0; i < _poi->files().count(); i++) createPOIFileAction(_poi->files().at(i)); - - connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this, - SLOT(poiFileChecked(int))); } QAction *GUI::createPOIFileAction(const QString &fileName) @@ -281,8 +286,10 @@ void GUI::createActions() createPOIFilesActions(); // Map actions + createMapActions(); _showMapAction = new QAction(QIcon(SHOW_MAP_ICON), tr("Show map"), this); + _showMapAction->setEnabled(false); _showMapAction->setMenuRole(QAction::NoRole); _showMapAction->setCheckable(true); _showMapAction->setShortcut(SHOW_MAP_SHORTCUT); @@ -294,10 +301,10 @@ void GUI::createActions() _loadMapAction->setMenuRole(QAction::NoRole); connect(_loadMapAction, SIGNAL(triggered()), this, SLOT(loadMap())); _clearMapCacheAction = new QAction(tr("Clear tile cache"), this); + _clearMapCacheAction->setEnabled(false); _clearMapCacheAction->setMenuRole(QAction::NoRole); connect(_clearMapCacheAction, SIGNAL(triggered()), _mapView, SLOT(clearMapCache())); - createMapActions(); _nextMapAction = new QAction(tr("Next map"), this); _nextMapAction->setMenuRole(QAction::NoRole); _nextMapAction->setShortcut(NEXT_MAP_SHORTCUT); @@ -308,10 +315,6 @@ void GUI::createActions() _prevMapAction->setShortcut(PREV_MAP_SHORTCUT); connect(_prevMapAction, SIGNAL(triggered()), this, SLOT(prevMap())); addAction(_prevMapAction); - if (_ml->maps().isEmpty()) { - _showMapAction->setEnabled(false); - _clearMapCacheAction->setEnabled(false); - } _showCoordinatesAction = new QAction(tr("Show cursor coordinates"), this); _showCoordinatesAction->setMenuRole(QAction::NoRole); _showCoordinatesAction->setCheckable(true); @@ -506,7 +509,7 @@ void GUI::createMenus() #endif // Q_OS_MAC _mapMenu = menuBar()->addMenu(tr("&Map")); - _mapMenu->addActions(_mapActions); + _mapMenu->addActions(_mapsActionGroup->actions()); _mapsEnd = _mapMenu->addSeparator(); _mapMenu->addAction(_loadMapAction); _mapMenu->addAction(_clearMapCacheAction); @@ -608,6 +611,7 @@ void GUI::createToolBars() void GUI::createMapView() { + _map = new EmptyMap(this); _mapView = new MapView(_map, _poi, this); _mapView->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Expanding)); @@ -1322,25 +1326,49 @@ void GUI::loadMap() bool GUI::loadMap(const QString &fileName) { + // On OS X fileName may be a directory! + if (fileName.isEmpty()) return false; - QFileInfo fi(fileName); - bool res = fi.isDir() ? _ml->loadDir(fileName) : _ml->loadFile(fileName); + QString error; + QList maps = MapList::loadMaps(fileName, error); + if (maps.isEmpty()) { + error = tr("Error loading map:") + "\n\n" + + fileName + "\n\n" + error; + QMessageBox::critical(this, APP_NAME, error); + return false; + } - if (res) { - QAction *a = createMapAction(_ml->maps().last()); + for (int i = 0; i < maps.size(); i++) { + Map *map = maps.at(i); + MapAction *a = createMapAction(map); _mapMenu->insertAction(_mapsEnd, a); + if (map->isReady()) { + a->trigger(); + _showMapAction->setEnabled(true); + _clearMapCacheAction->setEnabled(true); + } else + connect(a, SIGNAL(loaded()), this, SLOT(mapLoaded())); + } + + return true; +} + +void GUI::mapLoaded() +{ + MapAction *action = static_cast(QObject::sender()); + Map *map = action->data().value(); + + if (map->isValid()) { + action->trigger(); _showMapAction->setEnabled(true); _clearMapCacheAction->setEnabled(true); - a->trigger(); - return true; } else { QString error = tr("Error loading map:") + "\n\n" - + fileName + "\n\n" + _ml->errorString(); + + map->name() + "\n\n" + map->errorString(); QMessageBox::critical(this, APP_NAME, error); - - return false; + action->deleteLater(); } } @@ -1382,31 +1410,42 @@ void GUI::updateWindowTitle() setWindowTitle(APP_NAME); } -void GUI::mapChanged(int index) +void GUI::mapChanged() { - _map = _ml->maps().at(index); + _map = _mapsActionGroup->checkedAction()->data().value(); _mapView->setMap(_map); } void GUI::nextMap() { - if (_ml->maps().count() < 2) + QAction *checked = _mapsActionGroup->checkedAction(); + if (!checked) return; - int next = (_ml->maps().indexOf(_map) + 1) % _ml->maps().count(); - _mapActions.at(next)->setChecked(true); - mapChanged(next); + QList maps = _mapsActionGroup->actions(); + for (int i = 1; i < maps.size(); i++) { + int next = (maps.indexOf(checked) + i) % maps.count(); + if (maps.at(next)->isEnabled()) { + maps.at(next)->trigger(); + break; + } + } } void GUI::prevMap() { - if (_ml->maps().count() < 2) + QAction *checked = _mapsActionGroup->checkedAction(); + if (!checked) return; - int prev = (_ml->maps().indexOf(_map) + _ml->maps().count() - 1) - % _ml->maps().count(); - _mapActions.at(prev)->setChecked(true); - mapChanged(prev); + QList maps = _mapsActionGroup->actions(); + for (int i = 1; i < maps.size(); i++) { + int prev = (maps.indexOf(checked) + maps.count() - i) % maps.count(); + if (maps.at(prev)->isEnabled()) { + maps.at(prev)->trigger(); + break; + } + } } void GUI::poiFileChecked(int index) @@ -1899,9 +1938,11 @@ void GUI::readSettings() _showMapAction->setChecked(true); else _mapView->showMap(false); - if (_ml->maps().count()) { - int index = mapIndex(settings.value(CURRENT_MAP_SETTING).toString()); - _mapActions.at(index)->trigger(); + QAction *ma = mapAction(settings.value(CURRENT_MAP_SETTING).toString()); + if (ma) { + ma->trigger(); + _showMapAction->setEnabled(true); + _clearMapCacheAction->setEnabled(true); } if (settings.value(SHOW_COORDINATES_SETTING, SHOW_COORDINATES_DEFAULT) .toBool()) { @@ -2175,11 +2216,23 @@ void GUI::readSettings() settings.endGroup(); } -int GUI::mapIndex(const QString &name) +QAction *GUI::mapAction(const QString &name) { - for (int i = 0; i < _ml->maps().count(); i++) - if (_ml->maps().at(i)->name() == name) - return i; + QList maps = _mapsActionGroup->actions(); + + // Last map + for (int i = 0; i < maps.count(); i++) { + Map *map = maps.at(i)->data().value(); + if (map->name() == name && map->isReady()) + return maps.at(i); + } + + // Any usable map + for (int i = 0; i < maps.count(); i++) { + Map *map = maps.at(i)->data().value(); + if (map->isReady()) + return maps.at(i); + } return 0; } diff --git a/src/GUI/gui.h b/src/GUI/gui.h index dd10b21f..8951bc6d 100644 --- a/src/GUI/gui.h +++ b/src/GUI/gui.h @@ -29,6 +29,7 @@ class Map; class MapList; class POI; class QScreen; +class MapAction; class GUI : public QMainWindow { @@ -64,7 +65,7 @@ private slots: void prevMap(); void openOptions(); - void mapChanged(int); + void mapChanged(); void graphChanged(int); void poiFileChecked(int); @@ -88,16 +89,18 @@ private slots: void screenChanged(QScreen *screen); void logicalDotsPerInchChanged(qreal dpi); + void mapLoaded(); + void mapInitialized(); + private: typedef QPair DateRange; - void loadMaps(); void loadPOIs(); void closeFiles(); void plot(QPrinter *printer); QAction *createPOIFileAction(const QString &fileName); - QAction *createMapAction(const Map *map); + MapAction *createMapAction(Map *map); void createPOIFilesActions(); void createMapActions(); void createActions(); @@ -127,7 +130,7 @@ private: qreal distance() const; qreal time() const; qreal movingTime() const; - int mapIndex(const QString &name); + QAction *mapAction(const QString &name); void readSettings(); void writeSettings(); @@ -196,11 +199,9 @@ private: QAction *_showCoordinatesAction; QAction *_openOptionsAction; QAction *_mapsEnd; - QList _mapActions; - QList _poiFilesActions; + QList _poiFilesActions; QSignalMapper *_poiFilesSignalMapper; - QSignalMapper *_mapsSignalMapper; QLabel *_fileNameLabel; QLabel *_distanceLabel; diff --git a/src/GUI/mapaction.h b/src/GUI/mapaction.h new file mode 100644 index 00000000..9282e999 --- /dev/null +++ b/src/GUI/mapaction.h @@ -0,0 +1,32 @@ +#ifndef MAPACTION_H +#define MAPACTION_H + +#include +#include "map/map.h" + +class MapAction : public QAction +{ + Q_OBJECT + +public: + MapAction(Map *map, QObject *parent = 0) : QAction(map->name(), parent) + { + map->setParent(this); + setData(QVariant::fromValue(map)); + setEnabled(map->isValid()); + connect(map, SIGNAL(mapLoaded()), this, SLOT(mapLoaded())); + } + +signals: + void loaded(); + +private slots: + void mapLoaded() + { + Map *map = data().value(); + setEnabled(map->isValid()); + emit loaded(); + } +}; + +#endif // MAPACTION_H diff --git a/src/GUI/mapview.cpp b/src/GUI/mapview.cpp index d086a9e2..5f592c4d 100644 --- a/src/GUI/mapview.cpp +++ b/src/GUI/mapview.cpp @@ -54,7 +54,7 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent) _map = map; _map->load(); _map->setProjection(_projection); - connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap())); + connect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap())); _poi = poi; connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI())); @@ -316,7 +316,7 @@ void MapView::setMap(Map *map) RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight())); _map->unload(); - disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap())); + disconnect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap())); _map = map; _map->load(); @@ -324,7 +324,7 @@ void MapView::setMap(Map *map) #ifdef ENABLE_HIDPI _map->setDevicePixelRatio(_deviceRatio, _mapRatio); #endif // ENABLE_HIDPI - connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap())); + connect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap())); digitalZoom(0); diff --git a/src/data/poi.cpp b/src/data/poi.cpp index 08635d5d..10a28a4a 100644 --- a/src/data/poi.cpp +++ b/src/data/poi.cpp @@ -17,7 +17,7 @@ POI::POI(QObject *parent) : QObject(parent) _useDEM = false; } -bool POI::loadFile(const QString &path, bool dir) +bool POI::loadFile(const QString &path) { Data data(path, true); FileIndex index; @@ -26,16 +26,8 @@ bool POI::loadFile(const QString &path, bool dir) index.start = _data.size(); if (!data.isValid()) { - if (dir) { - if (data.errorLine()) - _errorString += QString("%1:%2: %3\n").arg(path) - .arg(data.errorLine()).arg(data.errorString()); - else - _errorString += path + ": " + data.errorString() + "\n"; - } else { - _errorString = data.errorString(); - _errorLine = data.errorLine(); - } + _errorString = data.errorString(); + _errorLine = data.errorLine(); return false; } @@ -59,37 +51,22 @@ bool POI::loadFile(const QString &path, bool dir) return true; } -bool POI::loadFile(const QString &path) -{ - _errorString.clear(); - _errorLine = 0; - - return loadFile(path, false); -} - -bool POI::loadDir(const QString &path) +void POI::loadDir(const QString &path) { QDir md(path); md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); QFileInfoList fl = md.entryInfoList(); - bool ret = true; - - _errorString.clear(); - _errorLine = 0; for (int i = 0; i < fl.size(); i++) { const QFileInfo &fi = fl.at(i); - if (fi.isDir()) { - if (!loadDir(fi.absoluteFilePath())) - ret = false; - } else { - if (!loadFile(fi.absoluteFilePath(), true)) - ret = false; - } + if (fi.isDir()) + loadDir(fi.absoluteFilePath()); + else + if (!loadFile(fi.absoluteFilePath())) + qWarning(qPrintable(fi.absoluteFilePath() + ": " + + _errorString)); } - - return ret; } static bool cb(size_t data, void* context) diff --git a/src/data/poi.h b/src/data/poi.h index 7e281a8d..fffe0480 100644 --- a/src/data/poi.h +++ b/src/data/poi.h @@ -20,7 +20,7 @@ public: POI(QObject *parent = 0); bool loadFile(const QString &path); - bool loadDir(const QString &path); + void loadDir(const QString &path); const QString &errorString() const {return _errorString;} int errorLine() const {return _errorLine;} diff --git a/src/map/map.h b/src/map/map.h index 04adcd8c..180f0568 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -50,12 +50,15 @@ public: virtual void setProjection(const Projection &) {} virtual bool isValid() const {return true;} + virtual bool isReady() const {return true;} virtual QString errorString() const {return QString();} signals: - void loaded(); + void tilesLoaded(); + void mapLoaded(); }; +Q_DECLARE_METATYPE(Map*) Q_DECLARE_OPERATORS_FOR_FLAGS(Map::Flags) #endif // MAP_H diff --git a/src/map/maplist.cpp b/src/map/maplist.cpp index 6f0095a6..c4be21ec 100644 --- a/src/map/maplist.cpp +++ b/src/map/maplist.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "atlas.h" #include "ozimap.h" #include "jnxmap.h" @@ -12,31 +13,8 @@ #include "maplist.h" -bool MapList::loadMap(Map *map, const QString &path) -{ - if (map && map->isValid()) { - _maps.append(map); - return true; - } else { - _errorPath = path; - _errorString = (map) ? map->errorString() : "Unknown file format"; - return false; - } -} - -Map *MapList::loadSource(const QString &path) -{ - Map *map = MapSource::loadMap(path, _errorString); - - if (!map) - _errorPath = path; - else - map->setParent(this); - - return map; -} - -bool MapList::loadFile(const QString &path, bool *terminate) +Map *MapList::loadFile(const QString &path, QString &errorString, + bool *terminate) { QFileInfo fi(path); QString suffix = fi.suffix().toLower(); @@ -45,75 +23,94 @@ bool MapList::loadFile(const QString &path, bool *terminate) if (Atlas::isAtlas(path)) { if (terminate) *terminate = true; - map = new Atlas(path, this); + map = new Atlas(path); } else if (suffix == "xml") { - if (MapSource::isMap(path) && !(map = loadSource(path))) - return false; - else if (GMAP::isGMAP(path)) { + if (MapSource::isMap(path)) { + if (!(map = MapSource::loadMap(path, errorString))) + return 0; + } else if (GMAP::isGMAP(path)) { if (terminate) *terminate = true; - map = new IMGMap(path, this); + map = new IMGMap(path); } } else if (suffix == "jnx") - map = new JNXMap(path, this); + map = new JNXMap(path); else if (suffix == "tif" || suffix == "tiff") - map = new GeoTIFFMap(path, this); + map = new GeoTIFFMap(path); else if (suffix == "mbtiles") - map = new MBTilesMap(path, this); + map = new MBTilesMap(path); else if (suffix == "rmap" || suffix == "rtmap") - map = new RMap(path, this); + map = new RMap(path); else if (suffix == "img") - map = new IMGMap(path, this); + map = new IMGMap(path); else if (suffix == "map" || suffix == "tar") - map = new OziMap(path, this); + map = new OziMap(path); - if (!loadMap(map, path)) { + if (map && map->isValid()) + return map; + else { + errorString = (map) ? map->errorString() : "Unknown file format"; delete map; - return false; + return 0; } - - return true; } -bool MapList::loadDir(const QString &path) +QList MapList::loadDir(const QString &path, QString &errorString) { QDir md(path); md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); md.setSorting(QDir::DirsLast); QFileInfoList ml = md.entryInfoList(); - bool ret = true; + QList list; for (int i = 0; i < ml.size(); i++) { const QFileInfo &fi = ml.at(i); QString suffix = fi.suffix().toLower(); bool terminate = false; - if (fi.isDir() && fi.fileName() != "set") { - if (!loadDir(fi.absoluteFilePath())) - ret = false; - } else if (filter().contains("*." + suffix)) { - if (!loadFile(fi.absoluteFilePath(), &terminate)) - ret = false; + if (fi.isDir() && fi.fileName() != "set") + list.append(loadDir(fi.absoluteFilePath(), errorString)); + else if (filter().contains("*." + suffix)) { + Map *map = loadFile(fi.absoluteFilePath(), errorString, &terminate); + if (map) + list.append(map); + else + qWarning(qPrintable(path + ": " + errorString)); if (terminate) break; } } - return ret; + return list; +} + +QList MapList::loadMaps(const QString &path, QString &errorString) +{ + if (QFileInfo(path).isDir()) + return loadDir(path, errorString); + else { + QList list; + Map *map = loadFile(path, errorString, 0); + if (map) + list.append(map); + return list; + } } QString MapList::formats() { return - tr("Supported files") + " (" + filter().join(" ") + ");;" - + tr("Garmin IMG maps") + " (*.gmap *.gmapi *.img *.xml);;" - + tr("Garmin JNX maps") + " (*.jnx);;" - + tr("OziExplorer maps") + " (*.map);;" - + tr("MBTiles maps") + " (*.mbtiles);;" - + tr("TrekBuddy maps/atlases") + " (*.tar *.tba);;" - + tr("GeoTIFF images") + " (*.tif *.tiff);;" - + tr("TwoNav maps") + " (*.rmap *.rtmap);;" - + tr("Online map sources") + " (*.xml)"; + qApp->translate("MapList", "Supported files") + + " (" + filter().join(" ") + ");;" + + qApp->translate("MapList", "Garmin IMG maps") + + " (*.gmap *.gmapi *.img *.xml);;" + + qApp->translate("MapList", "Garmin JNX maps") + " (*.jnx);;" + + qApp->translate("MapList", "OziExplorer maps") + " (*.map);;" + + qApp->translate("MapList", "MBTiles maps") + " (*.mbtiles);;" + + qApp->translate("MapList", "TrekBuddy maps/atlases") + " (*.tar *.tba);;" + + qApp->translate("MapList", "GeoTIFF images") + " (*.tif *.tiff);;" + + qApp->translate("MapList", "TwoNav maps") + " (*.rmap *.rtmap);;" + + qApp->translate("MapList", "Online map sources") + " (*.xml)"; } QStringList MapList::filter() diff --git a/src/map/maplist.h b/src/map/maplist.h index b6976887..e558dcf1 100644 --- a/src/map/maplist.h +++ b/src/map/maplist.h @@ -1,36 +1,21 @@ #ifndef MAPLIST_H #define MAPLIST_H -#include #include class Map; -class MapList : public QObject +class MapList { - Q_OBJECT - public: - MapList(QObject *parent = 0) : QObject(parent) {} - - bool loadFile(const QString &path, bool *terminate = 0); - bool loadDir(const QString &path); - - const QList &maps() const {return _maps;} - - const QString &errorString() const {return _errorString;} - const QString &errorPath() const {return _errorPath;} - + static QList loadMaps(const QString &path, QString &errorString); static QString formats(); static QStringList filter(); private: - Map *loadSource(const QString &path); - bool loadMap(Map *map, const QString &path); - - QList _maps; - QString _errorString; - QString _errorPath; + static Map *loadFile(const QString &path, QString &errorString, + bool *terminate); + static QList loadDir(const QString &path, QString &errorString); }; #endif // MAPLIST_H diff --git a/src/map/onlinemap.cpp b/src/map/onlinemap.cpp index 92cf786f..4a3ec955 100644 --- a/src/map/onlinemap.cpp +++ b/src/map/onlinemap.cpp @@ -21,7 +21,7 @@ OnlineMap::OnlineMap(const QString &name, const QString &url, _tileLoader->setUrl(url); _tileLoader->setAuthorization(authorization); _tileLoader->setQuadTiles(quadTiles); - connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(loaded())); + connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(tilesLoaded())); } QRectF OnlineMap::bounds() diff --git a/src/map/wms.cpp b/src/map/wms.cpp index 7d5f0c76..bfd99877 100644 --- a/src/map/wms.cpp +++ b/src/map/wms.cpp @@ -218,10 +218,10 @@ void WMS::capabilities(QXmlStreamReader &reader, CTX &ctx) } } -bool WMS::parseCapabilities(const QString &path, const Setup &setup) +bool WMS::parseCapabilities() { - QFile file(path); - CTX ctx(setup); + QFile file(_path); + CTX ctx(_setup); QXmlStreamReader reader; @@ -244,7 +244,7 @@ bool WMS::parseCapabilities(const QString &path, const Setup &setup) reader.raiseError("Not a WMS Capabilities XML file"); } if (reader.error()) { - _errorString = QString("%1:%2: %3").arg(path).arg(reader.lineNumber()) + _errorString = QString("%1:%2: %3").arg(_path).arg(reader.lineNumber()) .arg(reader.errorString()); return false; } @@ -290,10 +290,10 @@ bool WMS::parseCapabilities(const QString &path, const Setup &setup) return false; } - _boundingBox = ctx.layers.first().boundingBox; + _bbox = ctx.layers.first().boundingBox; for (int i = 1; i < ctx.layers.size(); i++) - _boundingBox &= ctx.layers.at(i).boundingBox; - if (_boundingBox.isNull()) { + _bbox &= ctx.layers.at(i).boundingBox; + if (_bbox.isNull()) { _errorString = "Empty layers bounding box join"; return false; } @@ -306,42 +306,57 @@ bool WMS::parseCapabilities(const QString &path, const Setup &setup) return false; } - _tileUrl = ctx.url.isEmpty() ? setup.url() : ctx.url; + if (_version >= "1.3.0") { + if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown) + _cs = _projection.coordinateSystem(); + else + _cs = _setup.coordinateSystem(); + } else + _cs = CoordinateSystem::XY; + + _getMapUrl = ctx.url.isEmpty() ? _setup.url() : ctx.url; return true; } -bool WMS::getCapabilities(const QString &url, const QString &file, - const Authorization &authorization) +bool WMS::downloadCapabilities(const QString &url) { - Downloader d; - QList dl; - - dl.append(Download(url, file)); - - QEventLoop wait; - QObject::connect(&d, SIGNAL(finished()), &wait, SLOT(quit())); - if (d.get(dl, authorization)) - wait.exec(); - - if (!QFileInfo(file).exists()) { - _errorString = "Error downloading capabilities XML file"; - return false; + if (!_downloader) { + _downloader = new Downloader(this); + connect(_downloader, SIGNAL(finished()), this, + SLOT(capabilitiesReady())); } - return true; + QList dl; + dl.append(Download(url, _path)); + + return _downloader->get(dl, _setup.authorization()); } -WMS::WMS(const QString &file, const WMS::Setup &setup) : _valid(false) +void WMS::capabilitiesReady() { - QString capaUrl = QString("%1%2service=WMS&request=GetCapabilities") + if (!QFileInfo(_path).exists()) { + _errorString = "Error downloading capabilities XML file"; + _valid = false; + } else { + _ready = true; + _valid = parseCapabilities(); + } + + emit downloadFinished(); +} + +WMS::WMS(const QString &file, const WMS::Setup &setup, QObject *parent) + : QObject(parent), _setup(setup), _path(file), _downloader(0), _valid(false), + _ready(false) +{ + QString url = QString("%1%2service=WMS&request=GetCapabilities") .arg(setup.url(), setup.url().contains('?') ? "&" : "?"); if (!QFileInfo(file).exists()) - if (!getCapabilities(capaUrl, file, setup.authorization())) - return; - if (!parseCapabilities(file, setup)) - return; - - _valid = true; + _valid = downloadCapabilities(url); + else { + _ready = true; + _valid = parseCapabilities(); + } } diff --git a/src/map/wms.h b/src/map/wms.h index 63bea256..430c3d9e 100644 --- a/src/map/wms.h +++ b/src/map/wms.h @@ -12,8 +12,10 @@ class QXmlStreamReader; -class WMS +class WMS : public QObject { + Q_OBJECT + public: class Setup { @@ -48,17 +50,26 @@ public: }; - WMS(const QString &path, const Setup &setup); + WMS(const QString &path, const Setup &setup, QObject *parent = 0); + const RectC &bbox() const {return _bbox;} const Projection &projection() const {return _projection;} + CoordinateSystem cs() const {return _cs;} const RangeF &scaleDenominator() const {return _scaleDenominator;} - const RectC &boundingBox() const {return _boundingBox;} const QString &version() const {return _version;} - const QString &tileUrl() const {return _tileUrl;} + const QString &getMapUrl() const {return _getMapUrl;} + const WMS::Setup &setup() const {return _setup;} + bool isReady() const {return _valid && _ready;} bool isValid() const {return _valid;} const QString &errorString() const {return _errorString;} +signals: + void downloadFinished(); + +private slots: + void capabilitiesReady(); + private: struct Layer { QString name; @@ -97,20 +108,21 @@ private: RectC &pBoundingBox); void capability(QXmlStreamReader &reader, CTX &ctx); void capabilities(QXmlStreamReader &reader, CTX &ctx); - bool parseCapabilities(const QString &path, const Setup &setup); - bool getCapabilities(const QString &url, const QString &file, - const Authorization &authorization); + bool parseCapabilities(); + bool downloadCapabilities(const QString &url); + WMS::Setup _setup; + QString _path; + Downloader *_downloader; Projection _projection; RangeF _scaleDenominator; - RectC _boundingBox; + RectC _bbox; QString _version; - QString _tileUrl; + QString _getMapUrl; + CoordinateSystem _cs; - bool _valid; + bool _valid, _ready; QString _errorString; - - static Downloader *_downloader; }; #endif // WMS_H diff --git a/src/map/wmsmap.cpp b/src/map/wmsmap.cpp index dbb606c6..3f7476cb 100644 --- a/src/map/wmsmap.cpp +++ b/src/map/wmsmap.cpp @@ -14,109 +14,94 @@ double WMSMap::sd2res(double scaleDenominator) const { - return scaleDenominator * 0.28e-3 * _projection.units().fromMeters(1.0); + return scaleDenominator * _wms->projection().units().fromMeters(1.0) + * 0.28e-3; } -QString WMSMap::tileUrl(const QString &baseUrl, const QString &version) const +QString WMSMap::tileUrl() const { - QString url; + const WMS::Setup &setup = _wms->setup(); - url = QString("%1%2service=WMS&version=%3&request=GetMap&bbox=$bbox" + QString url = QString("%1%2service=WMS&version=%3&request=GetMap&bbox=$bbox" "&width=%4&height=%5&layers=%6&styles=%7&format=%8&transparent=true") - .arg(baseUrl, baseUrl.contains('?') ? "&" : "?", version, - QString::number(_tileSize), QString::number(_tileSize), _setup.layer(), - _setup.style(), _setup.format()); + .arg(_wms->getMapUrl(), _wms->getMapUrl().contains('?') ? "&" : "?", + _wms->version(), QString::number(_tileSize), QString::number(_tileSize), + setup.layer(), setup.style(), setup.format()); - if (version >= "1.3.0") - url.append(QString("&CRS=%1").arg(_setup.crs())); + if (_wms->version() >= "1.3.0") + url.append(QString("&CRS=%1").arg(setup.crs())); else - url.append(QString("&SRS=%1").arg(_setup.crs())); + url.append(QString("&SRS=%1").arg(setup.crs())); - for (int i = 0; i < _setup.dimensions().size(); i++) { - const KV &dim = _setup.dimensions().at(i); + for (int i = 0; i < setup.dimensions().size(); i++) { + const KV &dim = setup.dimensions().at(i); url.append(QString("&%1=%2").arg(dim.key(), dim.value())); } return url; } -QString WMSMap::tilesDir() const -{ - return QString(QDir(ProgramPaths::tilesDir()).filePath(_name)); -} - -void WMSMap::computeZooms(const RangeF &scaleDenominator) +void WMSMap::computeZooms() { _zooms.clear(); - if (scaleDenominator.size() > 0) { - double ld = log2(scaleDenominator.max() - EPSILON) - - log2(scaleDenominator.min() + EPSILON); + const RangeF &sd = _wms->scaleDenominator(); + if (sd.size() > 0) { + double ld = log2(sd.max() - EPSILON) - log2(sd.min() + EPSILON); int cld = (int)ceil(ld); double step = ld / (double)cld; - double lmax = log2(scaleDenominator.max() - EPSILON); + double lmax = log2(sd.max() - EPSILON); for (int i = 0; i <= cld; i++) _zooms.append(pow(2.0, lmax - i * step)); } else - _zooms.append(scaleDenominator.min() + EPSILON); + _zooms.append(sd.min() + EPSILON); } void WMSMap::updateTransform() { double pixelSpan = sd2res(_zooms.at(_zoom)); - if (_projection.isGeographic()) + if (_wms->projection().isGeographic()) pixelSpan /= deg2rad(WGS84_RADIUS); _transform = Transform(ReferencePoint(PointD(0, 0), - _projection.ll2xy(_bbox.topLeft())), PointD(pixelSpan, pixelSpan)); -} - -bool WMSMap::loadWMS() -{ - QString file = tilesDir() + "/" + CAPABILITIES_FILE; - - WMS wms(file, _setup); - if (!wms.isValid()) { - _errorString = wms.errorString(); - return false; - } - - _projection = wms.projection(); - _bbox = wms.boundingBox(); - _bounds = RectD(_bbox, _projection); - _tileLoader->setUrl(tileUrl(wms.tileUrl(), wms.version())); - - if (wms.version() >= "1.3.0") { - if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown) - _cs = _projection.coordinateSystem(); - else - _cs = _setup.coordinateSystem(); - } else - _cs = CoordinateSystem::XY; - - computeZooms(wms.scaleDenominator()); - updateTransform(); - - return true; + _wms->projection().ll2xy(_wms->bbox().topLeft())), + PointD(pixelSpan, pixelSpan)); } WMSMap::WMSMap(const QString &name, const WMS::Setup &setup, int tileSize, - QObject *parent) : Map(parent), _name(name), _setup(setup), _tileLoader(0), - _zoom(0), _tileSize(tileSize), _mapRatio(1.0), _valid(false) + QObject *parent) : Map(parent), _name(name), _tileLoader(0), _zoom(0), + _tileSize(tileSize), _mapRatio(1.0) { - _tileLoader = new TileLoader(tilesDir(), this); - _tileLoader->setAuthorization(_setup.authorization()); - connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(loaded())); + QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name)); - _valid = loadWMS(); + _tileLoader = new TileLoader(tilesDir, this); + _tileLoader->setAuthorization(setup.authorization()); + connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(tilesLoaded())); + + _wms = new WMS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this); + connect(_wms, SIGNAL(downloadFinished()), this, SLOT(wmsReady())); + if (_wms->isReady()) + init(); +} + +void WMSMap::init() +{ + _tileLoader->setUrl(tileUrl()); + _bounds = RectD(_wms->bbox(), _wms->projection()); + computeZooms(); + updateTransform(); +} + +void WMSMap::wmsReady() +{ + if (_wms->isValid()) + init(); + + emit mapLoaded(); } void WMSMap::clearCache() { _tileLoader->clearCache(); - _zoom = 0; - - if (!loadWMS()) - qWarning("%s: %s", qPrintable(_name), qPrintable(_errorString)); } QRectF WMSMap::bounds() @@ -128,10 +113,10 @@ QRectF WMSMap::bounds() int WMSMap::zoomFit(const QSize &size, const RectC &rect) { if (rect.isValid()) { - RectD prect(rect, _projection); + RectD prect(rect, _wms->projection()); PointD sc(prect.width() / size.width(), prect.height() / size.height()); double resolution = qMax(qAbs(sc.x()), qAbs(sc.y())); - if (_projection.isGeographic()) + if (_wms->projection().isGeographic()) resolution *= deg2rad(WGS84_RADIUS); _zoom = 0; @@ -169,12 +154,12 @@ int WMSMap::zoomOut() QPointF WMSMap::ll2xy(const Coordinates &c) { - return _transform.proj2img(_projection.ll2xy(c)) / _mapRatio; + return _transform.proj2img(_wms->projection().ll2xy(c)) / _mapRatio; } Coordinates WMSMap::xy2ll(const QPointF &p) { - return _projection.xy2ll(_transform.img2proj(p * _mapRatio)); + return _wms->projection().xy2ll(_transform.img2proj(p * _mapRatio)); } qreal WMSMap::tileSize() const @@ -197,7 +182,7 @@ void WMSMap::draw(QPainter *painter, const QRectF &rect, Flags flags) j * _tileSize))); PointD tbr(_transform.img2proj(QPointF(i * _tileSize + _tileSize, j * _tileSize + _tileSize))); - RectD bbox = (_cs.axisOrder() == CoordinateSystem::YX) + RectD bbox = (_wms->cs().axisOrder() == CoordinateSystem::YX) ? RectD(PointD(tbr.y(), tbr.x()), PointD(ttl.y(), ttl.x())) : RectD(ttl, tbr); diff --git a/src/map/wmsmap.h b/src/map/wmsmap.h index 367f219a..44f35983 100644 --- a/src/map/wmsmap.h +++ b/src/map/wmsmap.h @@ -36,34 +36,30 @@ public: {_mapRatio = mapRatio;} void clearCache(); - bool isValid() const {return _valid;} - QString errorString() const {return _errorString;} + bool isReady() const {return _wms->isReady();} + bool isValid() const {return _wms->isValid();} + QString errorString() const {return _wms->errorString();} + +private slots: + void wmsReady(); private: - QString tileUrl(const QString &baseUrl, const QString &version) const; + QString tileUrl() const; double sd2res(double scaleDenominator) const; - QString tilesDir() const; - void computeZooms(const RangeF &scaleDenominator); + void computeZooms(); void updateTransform(); - bool loadWMS(); qreal tileSize() const; + void init(); QString _name; - - WMS::Setup _setup; + WMS *_wms; TileLoader *_tileLoader; - Projection _projection; - Transform _transform; - CoordinateSystem _cs; - QVector _zooms; - RectC _bbox; RectD _bounds; + Transform _transform; + QVector _zooms; int _zoom; int _tileSize; qreal _mapRatio; - - bool _valid; - QString _errorString; }; #endif // WMSMAP_H diff --git a/src/map/wmts.cpp b/src/map/wmts.cpp index ebbca7d1..4319681c 100644 --- a/src/map/wmts.cpp +++ b/src/map/wmts.cpp @@ -58,7 +58,7 @@ void WMTS::tileMatrixSet(QXmlStreamReader &reader, CTX &ctx) { while (reader.readNextStartElement()) { if (reader.name() == "Identifier") { - if (reader.readElementText() != ctx.setup.set()) { + if (reader.readElementText() != _setup.set()) { skipParentElement(reader); return; } @@ -114,7 +114,7 @@ void WMTS::tileMatrixSetLink(QXmlStreamReader &reader, CTX &ctx) { while (reader.readNextStartElement()) { if (reader.name() == "TileMatrixSet") { - if (reader.readElementText() == ctx.setup.set()) + if (reader.readElementText() == _setup.set()) ctx.hasSet = true; else { skipParentElement(reader); @@ -163,7 +163,7 @@ void WMTS::layer(QXmlStreamReader &reader, CTX &ctx) { while (reader.readNextStartElement()) { if (reader.name() == "Identifier") { - if (reader.readElementText() == ctx.setup.layer()) + if (reader.readElementText() == _setup.layer()) ctx.hasLayer = true; else { skipParentElement(reader); @@ -172,10 +172,10 @@ void WMTS::layer(QXmlStreamReader &reader, CTX &ctx) } else if (reader.name() == "TileMatrixSetLink") tileMatrixSetLink(reader, ctx); else if (reader.name() == "WGS84BoundingBox") - _bounds = wgs84BoundingBox(reader); + ctx.bbox = wgs84BoundingBox(reader); else if (reader.name() == "ResourceURL") { const QXmlStreamAttributes &attr = reader.attributes(); - if (attr.value("resourceType") == "tile" && ctx.setup.rest()) + if (attr.value("resourceType") == "tile" && _setup.rest()) _tileUrl = attr.value("template").toString(); reader.skipCurrentElement(); } else if (reader.name() == "Style") { @@ -184,11 +184,11 @@ void WMTS::layer(QXmlStreamReader &reader, CTX &ctx) QString s = style(reader); if (isDefault) ctx.defaultStyle = s; - if (s == ctx.setup.style()) + if (s == _setup.style()) ctx.hasStyle = true; } else if (reader.name() == "Format") { QString format(reader.readElementText()); - if (bareFormat(format) == bareFormat(ctx.setup.format())) + if (bareFormat(format) == bareFormat(_setup.format())) ctx.hasFormat = true; } else reader.skipCurrentElement(); @@ -232,9 +232,9 @@ void WMTS::createZooms(const CTX &ctx) qSort(_zooms); } -bool WMTS::parseCapabilities(const QString &path, CTX &ctx) +bool WMTS::parseCapabilities(CTX &ctx) { - QFile file(path); + QFile file(_path); QXmlStreamReader reader; if (!file.open(QFile::ReadOnly | QFile::Text)) { @@ -250,30 +250,30 @@ bool WMTS::parseCapabilities(const QString &path, CTX &ctx) reader.raiseError("Not a Capabilities XML file"); } if (reader.error()) { - _errorString = QString("%1:%2: %3").arg(path).arg(reader.lineNumber()) + _errorString = QString("%1:%2: %3").arg(_path).arg(reader.lineNumber()) .arg(reader.errorString()); return false; } if (!ctx.hasLayer) { - _errorString = ctx.setup.layer() + ": layer not provided"; + _errorString = _setup.layer() + ": layer not provided"; return false; } - if (!ctx.hasStyle && !ctx.setup.style().isEmpty()) { - _errorString = ctx.setup.style() + ": style not provided"; + if (!ctx.hasStyle && !_setup.style().isEmpty()) { + _errorString = _setup.style() + ": style not provided"; return false; } - if (!ctx.hasStyle && ctx.setup.style().isEmpty() + if (!ctx.hasStyle && _setup.style().isEmpty() && ctx.defaultStyle.isEmpty()) { _errorString = "Default style not provided"; return false; } - if (!ctx.setup.rest() && !ctx.hasFormat) { - _errorString = ctx.setup.format() + ": format not provided"; + if (!_setup.rest() && !ctx.hasFormat) { + _errorString = _setup.format() + ": format not provided"; return false; } if (!ctx.hasSet) { - _errorString = ctx.setup.set() + ": set not provided"; + _errorString = _setup.set() + ": set not provided"; return false; } if (ctx.crs.isNull()) { @@ -290,74 +290,92 @@ bool WMTS::parseCapabilities(const QString &path, CTX &ctx) _errorString = "No usable tile matrix found"; return false; } - if (ctx.setup.rest() && _tileUrl.isNull()) { + if (_setup.rest() && _tileUrl.isNull()) { _errorString = "Missing tile URL template"; return false; } + _bbox = ctx.bbox; + _cs = (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown) + ? _projection.coordinateSystem() : _setup.coordinateSystem(); return true; } -bool WMTS::downloadCapabilities(const QString &url, const QString &file, - const Authorization &authorization) +bool WMTS::downloadCapabilities(const QString &url) { - Downloader d; - QList dl; - - dl.append(Download(url, file)); - - QEventLoop wait; - QObject::connect(&d, SIGNAL(finished()), &wait, SLOT(quit())); - if (d.get(dl, authorization)) - wait.exec(); - - if (!QFileInfo(file).exists()) { - _errorString = "Error downloading capabilities XML file"; - return false; + if (!_downloader) { + _downloader = new Downloader(this); + connect(_downloader, SIGNAL(finished()), this, + SLOT(capabilitiesReady())); } - return true; + QList dl; + dl.append(Download(url, _path)); + + return _downloader->get(dl, _setup.authorization()); } -WMTS::WMTS(const QString &file, const WMTS::Setup &setup) : _valid(false) +void WMTS::capabilitiesReady() { - QUrl url(setup.rest() ? setup.url() : QString( - "%1%2service=WMTS&Version=1.0.0&request=GetCapabilities").arg(setup.url(), - setup.url().contains('?') ? "&" : "?")); + if (!QFileInfo(_path).exists()) { + _errorString = "Error downloading capabilities XML file"; + _valid = false; + } else { + _ready = true; + _valid = init(); + } - if (!url.isLocalFile() && !QFileInfo(file).exists()) - if (!downloadCapabilities(url.toString(), file, setup.authorization())) - return; + emit downloadFinished(); +} - CTX ctx(setup); - if (!parseCapabilities(url.isLocalFile() ? url.toLocalFile() : file, ctx)) - return; +bool WMTS::init() +{ + CTX ctx; + if (!parseCapabilities(ctx)) + return false; - QString style = setup.style().isEmpty() ? ctx.defaultStyle : setup.style(); - if (!setup.rest()) { + QString style = _setup.style().isEmpty() ? ctx.defaultStyle : _setup.style(); + if (!_setup.rest()) { _tileUrl = QString("%1%2service=WMTS&Version=1.0.0&request=GetTile" "&Format=%3&Layer=%4&Style=%5&TileMatrixSet=%6&TileMatrix=$z" - "&TileRow=$y&TileCol=$x").arg(setup.url(), - setup.url().contains('?') ? "&" : "?" , setup.format(), - setup.layer(), style, setup.set()); - for (int i = 0; i < setup.dimensions().size(); i++) { - const KV &dim = setup.dimensions().at(i); + "&TileRow=$y&TileCol=$x").arg(_setup.url(), + _setup.url().contains('?') ? "&" : "?" , _setup.format(), + _setup.layer(), style, _setup.set()); + for (int i = 0; i < _setup.dimensions().size(); i++) { + const KV &dim = _setup.dimensions().at(i); _tileUrl.append(QString("&%1=%2").arg(dim.key(), dim.value())); } } else { _tileUrl.replace("{Style}", style, Qt::CaseInsensitive); - _tileUrl.replace("{TileMatrixSet}", setup.set(), Qt::CaseInsensitive); + _tileUrl.replace("{TileMatrixSet}", _setup.set(), Qt::CaseInsensitive); _tileUrl.replace("{TileMatrix}", "$z", Qt::CaseInsensitive); _tileUrl.replace("{TileRow}", "$y", Qt::CaseInsensitive); _tileUrl.replace("{TileCol}", "$x", Qt::CaseInsensitive); - for (int i = 0; i < setup.dimensions().size(); i++) { - const KV &dim = setup.dimensions().at(i); + for (int i = 0; i < _setup.dimensions().size(); i++) { + const KV &dim = _setup.dimensions().at(i); _tileUrl.replace(QString("{%1}").arg(dim.key()), dim.value(), Qt::CaseInsensitive); } } - _valid = true; + return true; +} + +WMTS::WMTS(const QString &file, const WMTS::Setup &setup, QObject *parent) + : QObject(parent), _setup(setup), _downloader(0), _valid(false), _ready(false) +{ + QUrl url(setup.rest() ? setup.url() : QString( + "%1%2service=WMTS&Version=1.0.0&request=GetCapabilities").arg(setup.url(), + setup.url().contains('?') ? "&" : "?")); + + _path = url.isLocalFile() ? url.toLocalFile() : file; + + if (!url.isLocalFile() && !QFileInfo(file).exists()) + _valid = downloadCapabilities(url.toString()); + else { + _ready = true; + _valid = init(); + } } #ifndef QT_NO_DEBUG diff --git a/src/map/wmts.h b/src/map/wmts.h index d8ef2b78..66e6ad2e 100644 --- a/src/map/wmts.h +++ b/src/map/wmts.h @@ -14,8 +14,10 @@ class QXmlStreamReader; -class WMTS +class WMTS : public QObject { + Q_OBJECT + public: class Setup { @@ -79,16 +81,24 @@ public: }; - WMTS(const QString &path, const Setup &setup); + WMTS(const QString &path, const Setup &setup, QObject *parent = 0); - const RectC &bounds() const {return _bounds;} + const RectC &bbox() const {return _bbox;} const QList &zooms() const {return _zooms;} const Projection &projection() const {return _projection;} const QString &tileUrl() const {return _tileUrl;} + CoordinateSystem cs() const {return _cs;} + bool isReady() const {return _valid && _ready;} bool isValid() const {return _valid;} const QString &errorString() const {return _errorString;} +signals: + void downloadFinished(); + +private slots: + void capabilitiesReady(); + private: struct TileMatrix { QString id; @@ -118,18 +128,18 @@ private: }; struct CTX { - const Setup &setup; QSet matrixes; QSet limits; QString crs; QString defaultStyle; + RectC bbox; bool hasLayer; bool hasStyle; bool hasFormat; bool hasSet; - CTX(const Setup &setup) : setup(setup), hasLayer(false), hasStyle(false), - hasFormat(false), hasSet(false) {} + CTX() : hasLayer(false), hasStyle(false), hasFormat(false), hasSet(false) + {} }; RectC wgs84BoundingBox(QXmlStreamReader &reader); @@ -142,17 +152,21 @@ private: void layer(QXmlStreamReader &reader, CTX &ctx); void contents(QXmlStreamReader &reader, CTX &ctx); void capabilities(QXmlStreamReader &reader, CTX &ctx); - bool parseCapabilities(const QString &path, CTX &ctx); - bool downloadCapabilities(const QString &url, const QString &file, - const Authorization &authorization); + bool parseCapabilities(CTX &ctx); + bool downloadCapabilities(const QString &url); void createZooms(const CTX &ctx); + bool init(); + WMTS::Setup _setup; + QString _path; + Downloader *_downloader; + RectC _bbox; QList _zooms; - RectC _bounds; Projection _projection; QString _tileUrl; + CoordinateSystem _cs; - bool _valid; + bool _valid, _ready; QString _errorString; friend uint qHash(const WMTS::TileMatrix &key); diff --git a/src/map/wmtsmap.cpp b/src/map/wmtsmap.cpp index f9dba6ac..a70c561f 100644 --- a/src/map/wmtsmap.cpp +++ b/src/map/wmtsmap.cpp @@ -12,70 +12,57 @@ #define CAPABILITIES_FILE "capabilities.xml" -bool WMTSMap::loadWMTS() +WMTSMap::WMTSMap(const QString &name, const WMTS::Setup &setup, qreal tileRatio, + QObject *parent) : Map(parent), _name(name), _tileLoader(0), _zoom(0), + _mapRatio(1.0), _tileRatio(tileRatio) { - QString file = tilesDir() + "/" + CAPABILITIES_FILE; + QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name)); - WMTS wmts(file, _setup); - if (!wmts.isValid()) { - _errorString = wmts.errorString(); - return false; - } + _tileLoader = new TileLoader(tilesDir, this); + _tileLoader->setAuthorization(setup.authorization()); + connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(tilesLoaded())); - _zooms = wmts.zooms(); - _projection = wmts.projection(); - _tileLoader->setUrl(wmts.tileUrl()); - _bounds = RectD(wmts.bounds(), _projection); - - if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown) - _cs = _projection.coordinateSystem(); - else - _cs = _setup.coordinateSystem(); - - updateTransform(); - - return true; + _wmts = new WMTS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this); + connect(_wmts, SIGNAL(downloadFinished()), this, SLOT(wmtsReady())); + if (_wmts->isReady()) + init(); } -WMTSMap::WMTSMap(const QString &name, const WMTS::Setup &setup, qreal tileRatio, - QObject *parent) : Map(parent), _name(name), _setup(setup), _tileLoader(0), - _zoom(0), _mapRatio(1.0), _tileRatio(tileRatio), _valid(false) +void WMTSMap::init() { - _tileLoader = new TileLoader(tilesDir(), this); - _tileLoader->setAuthorization(_setup.authorization()); - connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(loaded())); + _tileLoader->setUrl(_wmts->tileUrl()); + _bounds = RectD(_wmts->bbox(), _wmts->projection()); + updateTransform(); +} - _valid = loadWMTS(); +void WMTSMap::wmtsReady() +{ + if (_wmts->isValid()) + init(); + + emit mapLoaded(); } void WMTSMap::clearCache() { _tileLoader->clearCache(); - _zoom = 0; - - if (!loadWMTS()) - qWarning("%s: %s", qPrintable(_name), qPrintable(_errorString)); -} - -QString WMTSMap::tilesDir() const -{ - return QString(QDir(ProgramPaths::tilesDir()).filePath(_name)); } double WMTSMap::sd2res(double scaleDenominator) const { - return scaleDenominator * 0.28e-3 * _projection.units().fromMeters(1.0); + return scaleDenominator * 0.28e-3 + * _wmts->projection().units().fromMeters(1.0); } void WMTSMap::updateTransform() { - const WMTS::Zoom &z = _zooms.at(_zoom); + const WMTS::Zoom &z = _wmts->zooms().at(_zoom); - PointD topLeft = (_cs.axisOrder() == CoordinateSystem::YX) + PointD topLeft = (_wmts->cs().axisOrder() == CoordinateSystem::YX) ? PointD(z.topLeft().y(), z.topLeft().x()) : z.topLeft(); double pixelSpan = sd2res(z.scaleDenominator()); - if (_projection.isGeographic()) + if (_wmts->projection().isGeographic()) pixelSpan /= deg2rad(WGS84_RADIUS); _transform = Transform(ReferencePoint(PointD(0, 0), topLeft), PointD(pixelSpan, pixelSpan)); @@ -83,7 +70,7 @@ void WMTSMap::updateTransform() QRectF WMTSMap::bounds() { - const WMTS::Zoom &z = _zooms.at(_zoom); + const WMTS::Zoom &z = _wmts->zooms().at(_zoom); QRectF tileBounds, bounds; tileBounds = (z.limits().isNull()) ? @@ -95,29 +82,29 @@ QRectF WMTSMap::bounds() if (_bounds.isValid()) bounds = QRectF(_transform.proj2img(_bounds.topLeft()) - / coordinatesRatio(), _transform.proj2img(_bounds.bottomRight()) - / coordinatesRatio()); + / coordinatesRatio(), _transform.proj2img( + _bounds.bottomRight()) / coordinatesRatio()); return bounds.isValid() ? tileBounds.intersected(bounds) : tileBounds; } int WMTSMap::zoomFit(const QSize &size, const RectC &rect) { if (rect.isValid()) { - RectD prect(rect, _projection); + RectD prect(rect, _wmts->projection()); PointD sc(prect.width() / size.width(), prect.height() / size.height()); double resolution = qMax(qAbs(sc.x()), qAbs(sc.y())); - if (_projection.isGeographic()) + if (_wmts->projection().isGeographic()) resolution *= deg2rad(WGS84_RADIUS); _zoom = 0; - for (int i = 0; i < _zooms.size(); i++) { - if (sd2res(_zooms.at(i).scaleDenominator()) < resolution + for (int i = 0; i < _wmts->zooms().size(); i++) { + if (sd2res(_wmts->zooms().at(i).scaleDenominator()) < resolution / coordinatesRatio()) break; _zoom = i; } } else - _zoom = _zooms.size() - 1; + _zoom = _wmts->zooms().size() - 1; updateTransform(); return _zoom; @@ -131,7 +118,7 @@ void WMTSMap::setZoom(int zoom) int WMTSMap::zoomIn() { - _zoom = qMin(_zoom + 1, _zooms.size() - 1); + _zoom = qMin(_zoom + 1, _wmts->zooms().size() - 1); updateTransform(); return _zoom; } @@ -161,7 +148,7 @@ QSizeF WMTSMap::tileSize(const WMTS::Zoom &zoom) const void WMTSMap::draw(QPainter *painter, const QRectF &rect, Flags flags) { - const WMTS::Zoom &z = _zooms.at(_zoom); + const WMTS::Zoom &z = _wmts->zooms().at(_zoom); QSizeF ts(tileSize(z)); QPoint tl = QPoint(qFloor(rect.left() / ts.width()), @@ -194,10 +181,12 @@ void WMTSMap::draw(QPainter *painter, const QRectF &rect, Flags flags) QPointF WMTSMap::ll2xy(const Coordinates &c) { - return _transform.proj2img(_projection.ll2xy(c)) / coordinatesRatio(); + return _transform.proj2img(_wmts->projection().ll2xy(c)) + / coordinatesRatio(); } Coordinates WMTSMap::xy2ll(const QPointF &p) { - return _projection.xy2ll(_transform.img2proj(p * coordinatesRatio())); + return _wmts->projection().xy2ll(_transform.img2proj(p + * coordinatesRatio())); } diff --git a/src/map/wmtsmap.h b/src/map/wmtsmap.h index e86728fc..64b1327a 100644 --- a/src/map/wmtsmap.h +++ b/src/map/wmtsmap.h @@ -36,31 +36,28 @@ public: {_mapRatio = mapRatio;} void clearCache(); - bool isValid() const {return _valid;} - QString errorString() const {return _errorString;} + bool isReady() const {return _wmts->isReady();} + bool isValid() const {return _wmts->isValid();} + QString errorString() const {return _wmts->errorString();} + +private slots: + void wmtsReady(); private: - bool loadWMTS(); double sd2res(double scaleDenominator) const; - QString tilesDir() const; void updateTransform(); QSizeF tileSize(const WMTS::Zoom &zoom) const; qreal coordinatesRatio() const; qreal imageRatio() const; + void init(); QString _name; - WMTS::Setup _setup; + WMTS *_wmts; TileLoader *_tileLoader; - RectD _bounds; - QList _zooms; - Projection _projection; Transform _transform; - CoordinateSystem _cs; + RectD _bounds; int _zoom; qreal _mapRatio, _tileRatio; - - bool _valid; - QString _errorString; }; #endif // WMTSMAP_H