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