mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-28 05:34:47 +01:00
Added initial WMTS support
This commit is contained in:
parent
3202fc4c15
commit
1bc4833a81
10
gpxsee.pro
10
gpxsee.pro
@ -116,7 +116,10 @@ HEADERS += src/config.h \
|
|||||||
src/map/primemeridian.h \
|
src/map/primemeridian.h \
|
||||||
src/map/linearunits.h \
|
src/map/linearunits.h \
|
||||||
src/map/ct.h \
|
src/map/ct.h \
|
||||||
src/map/mapsource.h
|
src/map/mapsource.h \
|
||||||
|
src/map/tileloader.h \
|
||||||
|
src/map/wmtsmap.h \
|
||||||
|
src/map/wmts.h
|
||||||
SOURCES += src/main.cpp \
|
SOURCES += src/main.cpp \
|
||||||
src/common/coordinates.cpp \
|
src/common/coordinates.cpp \
|
||||||
src/common/rectc.cpp \
|
src/common/rectc.cpp \
|
||||||
@ -202,7 +205,10 @@ SOURCES += src/main.cpp \
|
|||||||
src/map/angularunits.cpp \
|
src/map/angularunits.cpp \
|
||||||
src/map/primemeridian.cpp \
|
src/map/primemeridian.cpp \
|
||||||
src/map/linearunits.cpp \
|
src/map/linearunits.cpp \
|
||||||
src/map/mapsource.cpp
|
src/map/mapsource.cpp \
|
||||||
|
src/map/tileloader.cpp \
|
||||||
|
src/map/wmtsmap.cpp \
|
||||||
|
src/map/wmts.cpp
|
||||||
RESOURCES += gpxsee.qrc
|
RESOURCES += gpxsee.qrc
|
||||||
TRANSLATIONS = lang/gpxsee_cs.ts \
|
TRANSLATIONS = lang/gpxsee_cs.ts \
|
||||||
lang/gpxsee_sv.ts \
|
lang/gpxsee_sv.ts \
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
#include <QFileOpenEvent>
|
#include <QFileOpenEvent>
|
||||||
#include <QNetworkProxyFactory>
|
#include <QNetworkProxyFactory>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
#include "map/onlinemap.h"
|
#include "map/wmts.h"
|
||||||
|
#include "map/tileloader.h"
|
||||||
#include "map/downloader.h"
|
#include "map/downloader.h"
|
||||||
#include "map/ellipsoid.h"
|
#include "map/ellipsoid.h"
|
||||||
#include "map/gcs.h"
|
#include "map/gcs.h"
|
||||||
@ -36,7 +37,9 @@ App::App(int &argc, char **argv) : QApplication(argc, argv),
|
|||||||
#endif // Q_OS_MAC
|
#endif // Q_OS_MAC
|
||||||
|
|
||||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||||
OnlineMap::setDownloader(new Downloader(this));
|
Downloader *dl = new Downloader(this);
|
||||||
|
TileLoader::setDownloader(dl);
|
||||||
|
WMTS::setDownloader(dl);
|
||||||
OPENGL_SET_SAMPLES(4);
|
OPENGL_SET_SAMPLES(4);
|
||||||
loadDatums();
|
loadDatums();
|
||||||
loadPCSs();
|
loadPCSs();
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
bool isValid() const {return _valid;}
|
bool isValid() const {return _valid;}
|
||||||
const QString &errorString() const {return _errorString;}
|
QString errorString() const {return _errorString;}
|
||||||
|
|
||||||
static bool isAtlas(const QString &path);
|
static bool isAtlas(const QString &path);
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ bool Downloader::saveToDisk(const QString &filename, QIODevice *data)
|
|||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
|
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
qWarning("Error writing map tile: %s: %s\n",
|
qWarning("Error writing file: %s: %s\n",
|
||||||
qPrintable(filename), qPrintable(file.errorString()));
|
qPrintable(filename), qPrintable(file.errorString()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -80,11 +80,11 @@ void Downloader::downloadFinished(QNetworkReply *reply)
|
|||||||
QUrl origin = reply->request().attribute(ATTR_ORIGIN).toUrl();
|
QUrl origin = reply->request().attribute(ATTR_ORIGIN).toUrl();
|
||||||
if (origin.isEmpty()) {
|
if (origin.isEmpty()) {
|
||||||
_errorDownloads.insert(url);
|
_errorDownloads.insert(url);
|
||||||
qWarning("Error downloading map tile: %s: %s\n",
|
qWarning("Error downloading file: %s: %s\n",
|
||||||
url.toEncoded().constData(), qPrintable(reply->errorString()));
|
url.toEncoded().constData(), qPrintable(reply->errorString()));
|
||||||
} else {
|
} else {
|
||||||
_errorDownloads.insert(origin);
|
_errorDownloads.insert(origin);
|
||||||
qWarning("Error downloading map tile: %s -> %s: %s\n",
|
qWarning("Error downloading file: %s -> %s: %s\n",
|
||||||
origin.toEncoded().constData(), url.toEncoded().constData(),
|
origin.toEncoded().constData(), url.toEncoded().constData(),
|
||||||
qPrintable(reply->errorString()));
|
qPrintable(reply->errorString()));
|
||||||
}
|
}
|
||||||
@ -99,11 +99,11 @@ void Downloader::downloadFinished(QNetworkReply *reply)
|
|||||||
|
|
||||||
if (location == url) {
|
if (location == url) {
|
||||||
_errorDownloads.insert(url);
|
_errorDownloads.insert(url);
|
||||||
qWarning("Error downloading map tile: %s: "
|
qWarning("Error downloading file: %s: "
|
||||||
"redirect loop\n", url.toEncoded().constData());
|
"redirect loop\n", url.toEncoded().constData());
|
||||||
} else if (level >= MAX_REDIRECT_LEVEL) {
|
} else if (level >= MAX_REDIRECT_LEVEL) {
|
||||||
_errorDownloads.insert(origin);
|
_errorDownloads.insert(origin);
|
||||||
qWarning("Error downloading map tile: %s: "
|
qWarning("Error downloading file: %s: "
|
||||||
"redirect level limit reached\n",
|
"redirect level limit reached\n",
|
||||||
origin.toEncoded().constData());
|
origin.toEncoded().constData());
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,6 +40,9 @@ public:
|
|||||||
|
|
||||||
void setBackgroundColor(const QColor &color) {_backgroundColor = color;}
|
void setBackgroundColor(const QColor &color) {_backgroundColor = color;}
|
||||||
|
|
||||||
|
virtual bool isValid() const {return true;}
|
||||||
|
virtual QString errorString() const {return QString();}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void loaded();
|
void loaded();
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ bool MapList::loadSource(const QString &path, bool dir)
|
|||||||
MapSource ms;
|
MapSource ms;
|
||||||
Map *map;
|
Map *map;
|
||||||
|
|
||||||
if (!ms.loadFile(path, &map)) {
|
if (!(map = ms.loadFile(path))) {
|
||||||
if (dir)
|
if (dir)
|
||||||
_errorString += path + ": " + ms.errorString() + "\n";
|
_errorString += path + ": " + ms.errorString() + "\n";
|
||||||
else
|
else
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
#include "onlinemap.h"
|
#include "onlinemap.h"
|
||||||
|
#include "wmtsmap.h"
|
||||||
#include "mapsource.h"
|
#include "mapsource.h"
|
||||||
|
|
||||||
|
|
||||||
@ -121,13 +122,17 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
|
|||||||
return RectC(Coordinates(left, top), Coordinates(right, bottom));
|
return RectC(Coordinates(left, top), Coordinates(right, bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapSource::map(QXmlStreamReader &reader, Map **map)
|
Map *MapSource::map(QXmlStreamReader &reader)
|
||||||
{
|
{
|
||||||
QString name, url;
|
QString name, url, format, layer, style, tileMatrixSet;
|
||||||
Range z(ZOOM_MIN, ZOOM_MAX);
|
Range z(ZOOM_MIN, ZOOM_MAX);
|
||||||
RectC b(Coordinates(BOUNDS_LEFT, BOUNDS_TOP),
|
RectC b(Coordinates(BOUNDS_LEFT, BOUNDS_TOP),
|
||||||
Coordinates(BOUNDS_RIGHT, BOUNDS_BOTTOM));
|
Coordinates(BOUNDS_RIGHT, BOUNDS_BOTTOM));
|
||||||
|
|
||||||
|
const QXmlStreamAttributes &attr = reader.attributes();
|
||||||
|
bool wmts = (attr.hasAttribute("type") && attr.value("type") == "WMTS")
|
||||||
|
? true : false;
|
||||||
|
|
||||||
while (reader.readNextStartElement()) {
|
while (reader.readNextStartElement()) {
|
||||||
if (reader.name() == "name")
|
if (reader.name() == "name")
|
||||||
name = reader.readElementText();
|
name = reader.readElementText();
|
||||||
@ -139,34 +144,53 @@ void MapSource::map(QXmlStreamReader &reader, Map **map)
|
|||||||
} else if (reader.name() == "bounds") {
|
} else if (reader.name() == "bounds") {
|
||||||
b = bounds(reader);
|
b = bounds(reader);
|
||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
} else
|
} else if (reader.name() == "format")
|
||||||
|
format = reader.readElementText();
|
||||||
|
else if (reader.name() == "layer")
|
||||||
|
layer = reader.readElementText();
|
||||||
|
else if (reader.name() == "style")
|
||||||
|
style = reader.readElementText();
|
||||||
|
else if (reader.name() == "tilematrixset")
|
||||||
|
tileMatrixSet = reader.readElementText();
|
||||||
|
else
|
||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
*map = reader.error() ? 0 : new OnlineMap(name, url, z, b);
|
if (reader.error())
|
||||||
|
return 0;
|
||||||
|
else if (wmts)
|
||||||
|
return new WMTSMap(name, url, format, layer, style, tileMatrixSet);
|
||||||
|
else
|
||||||
|
return new OnlineMap(name, url, z, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MapSource::loadFile(const QString &path, Map **map)
|
Map *MapSource::loadFile(const QString &path)
|
||||||
{
|
{
|
||||||
QFile file(path);
|
QFile file(path);
|
||||||
QXmlStreamReader reader;
|
QXmlStreamReader reader;
|
||||||
|
Map *map = 0;
|
||||||
|
|
||||||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
_errorString = file.errorString();
|
_errorString = file.errorString();
|
||||||
return false;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.setDevice(&file);
|
reader.setDevice(&file);
|
||||||
|
|
||||||
if (reader.readNextStartElement()) {
|
if (reader.readNextStartElement()) {
|
||||||
if (reader.name() == "map")
|
if (reader.name() == "map")
|
||||||
MapSource::map(reader, map);
|
map = MapSource::map(reader);
|
||||||
else
|
else
|
||||||
reader.raiseError("Not an online map source file");
|
reader.raiseError("Not an online map source file");
|
||||||
}
|
}
|
||||||
|
|
||||||
_errorString = reader.error() ? QString("%1: %2").arg(reader.lineNumber())
|
if (!map)
|
||||||
.arg(reader.errorString()) : QString();
|
_errorString = QString("%1: %2").arg(reader.lineNumber())
|
||||||
|
.arg(reader.errorString());
|
||||||
return !reader.error();
|
else if (!map->isValid()) {
|
||||||
|
_errorString = map->errorString();
|
||||||
|
delete map; map = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,13 @@ class QXmlStreamReader;
|
|||||||
class MapSource
|
class MapSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool loadFile(const QString &path, Map **map);
|
Map *loadFile(const QString &path);
|
||||||
const QString &errorString() const {return _errorString;}
|
const QString &errorString() const {return _errorString;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RectC bounds(QXmlStreamReader &reader);
|
RectC bounds(QXmlStreamReader &reader);
|
||||||
Range zooms(QXmlStreamReader &reader);
|
Range zooms(QXmlStreamReader &reader);
|
||||||
void map(QXmlStreamReader &reader, Map **map);
|
Map *map(QXmlStreamReader &reader);
|
||||||
|
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
};
|
};
|
||||||
|
@ -41,7 +41,7 @@ public:
|
|||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
bool isValid() const {return _valid;}
|
bool isValid() const {return _valid;}
|
||||||
const QString &errorString() const {return _errorString;}
|
QString errorString() const {return _errorString;}
|
||||||
|
|
||||||
QPointF ll2pp(const Coordinates &c) const
|
QPointF ll2pp(const Coordinates &c) const
|
||||||
{return _projection.ll2xy(c);}
|
{return _projection.ll2xy(c);}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#include <QFileInfo>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include "common/coordinates.h"
|
#include "common/coordinates.h"
|
||||||
#include "common/rectc.h"
|
#include "common/rectc.h"
|
||||||
@ -41,45 +39,26 @@ static int scale2zoom(qreal scale)
|
|||||||
return (int)log2(360.0/(scale * (qreal)TILE_SIZE));
|
return (int)log2(360.0/(scale * (qreal)TILE_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool loadTileFile(Tile &tile, const QString &file)
|
|
||||||
{
|
|
||||||
if (!tile.pixmap().load(file)) {
|
|
||||||
qWarning("%s: error loading tile file\n", qPrintable(file));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Downloader *OnlineMap::downloader;
|
|
||||||
|
|
||||||
OnlineMap::OnlineMap(const QString &name, const QString &url,
|
OnlineMap::OnlineMap(const QString &name, const QString &url,
|
||||||
const Range &zooms, const RectC &bounds, QObject *parent)
|
const Range &zooms, const RectC &bounds, QObject *parent)
|
||||||
: Map(parent), _name(name), _url(url), _zooms(zooms), _bounds(bounds)
|
: Map(parent), _name(name), _zooms(zooms), _bounds(bounds)
|
||||||
{
|
{
|
||||||
_block = false;
|
_block = false;
|
||||||
_zoom = _zooms.max();
|
_zoom = _zooms.max();
|
||||||
|
_tileLoader = TileLoader(url, TILES_DIR + "/" + name);
|
||||||
QString path = TILES_DIR + QString("/") + name;
|
|
||||||
if (!QDir().mkpath(path))
|
|
||||||
qWarning("Error creating tiles dir: %s\n", qPrintable(path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnlineMap::load()
|
void OnlineMap::load()
|
||||||
{
|
{
|
||||||
connect(downloader, SIGNAL(finished()), this, SLOT(emitLoaded()));
|
connect(TileLoader::downloader(), SIGNAL(finished()), this,
|
||||||
|
SLOT(emitLoaded()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnlineMap::unload()
|
void OnlineMap::unload()
|
||||||
{
|
{
|
||||||
disconnect(downloader, SIGNAL(finished()), this, SLOT(emitLoaded()));
|
disconnect(TileLoader::downloader(), SIGNAL(finished()), this,
|
||||||
}
|
SLOT(emitLoaded()));
|
||||||
|
|
||||||
void OnlineMap::fillTile(Tile &tile)
|
|
||||||
{
|
|
||||||
tile.pixmap() = QPixmap(TILE_SIZE, TILE_SIZE);
|
|
||||||
tile.pixmap().fill(_backgroundColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnlineMap::emitLoaded()
|
void OnlineMap::emitLoaded()
|
||||||
@ -87,91 +66,6 @@ void OnlineMap::emitLoaded()
|
|||||||
emit loaded();
|
emit loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnlineMap::loadTilesAsync(QList<Tile> &list)
|
|
||||||
{
|
|
||||||
QList<Download> dl;
|
|
||||||
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
Tile &t = list[i];
|
|
||||||
QString file = tileFile(t);
|
|
||||||
QFileInfo fi(file);
|
|
||||||
|
|
||||||
if (!fi.exists()) {
|
|
||||||
fillTile(t);
|
|
||||||
dl.append(Download(tileUrl(t), file));
|
|
||||||
} else
|
|
||||||
loadTileFile(t, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dl.empty())
|
|
||||||
downloader->get(dl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnlineMap::loadTilesSync(QList<Tile> &list)
|
|
||||||
{
|
|
||||||
QList<Download> dl;
|
|
||||||
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
Tile &t = list[i];
|
|
||||||
QString file = tileFile(t);
|
|
||||||
QFileInfo fi(file);
|
|
||||||
|
|
||||||
if (!fi.exists())
|
|
||||||
dl.append(Download(tileUrl(t), file));
|
|
||||||
else
|
|
||||||
loadTileFile(t, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dl.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QEventLoop wait;
|
|
||||||
connect(downloader, SIGNAL(finished()), &wait, SLOT(quit()));
|
|
||||||
if (downloader->get(dl))
|
|
||||||
wait.exec();
|
|
||||||
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
Tile &t = list[i];
|
|
||||||
|
|
||||||
if (t.pixmap().isNull()) {
|
|
||||||
QString file = tileFile(t);
|
|
||||||
QFileInfo fi(file);
|
|
||||||
|
|
||||||
if (!(fi.exists() && loadTileFile(t, file)))
|
|
||||||
fillTile(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OnlineMap::tileUrl(const Tile &tile) const
|
|
||||||
{
|
|
||||||
QString url(_url);
|
|
||||||
|
|
||||||
url.replace("$z", QString::number(tile.zoom()));
|
|
||||||
url.replace("$x", QString::number(tile.xy().x()));
|
|
||||||
url.replace("$y", QString::number(tile.xy().y()));
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OnlineMap::tileFile(const Tile &tile) const
|
|
||||||
{
|
|
||||||
QString file = TILES_DIR + QString("/%1/%2-%3-%4").arg(name())
|
|
||||||
.arg(tile.zoom()).arg(tile.xy().x()).arg(tile.xy().y());
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnlineMap::clearCache()
|
|
||||||
{
|
|
||||||
QString path = TILES_DIR + QString("/") + name();
|
|
||||||
QDir dir = QDir(path);
|
|
||||||
QStringList list = dir.entryList();
|
|
||||||
|
|
||||||
for (int i = 0; i < list.count(); i++)
|
|
||||||
dir.remove(list.at(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
QRectF OnlineMap::bounds() const
|
QRectF OnlineMap::bounds() const
|
||||||
{
|
{
|
||||||
return QRectF(ll2xy(_bounds.topLeft()), ll2xy(_bounds.bottomRight()));
|
return QRectF(ll2xy(_bounds.topLeft()), ll2xy(_bounds.bottomRight()));
|
||||||
@ -245,14 +139,18 @@ void OnlineMap::draw(QPainter *painter, const QRectF &rect)
|
|||||||
tiles.append(Tile(QPoint(tile.x() + i, tile.y() + j), _zoom));
|
tiles.append(Tile(QPoint(tile.x() + i, tile.y() + j), _zoom));
|
||||||
|
|
||||||
if (_block)
|
if (_block)
|
||||||
loadTilesSync(tiles);
|
_tileLoader.loadTilesSync(tiles);
|
||||||
else
|
else
|
||||||
loadTilesAsync(tiles);
|
_tileLoader.loadTilesAsync(tiles);
|
||||||
|
|
||||||
for (int i = 0; i < tiles.count(); i++) {
|
for (int i = 0; i < tiles.count(); i++) {
|
||||||
Tile &t = tiles[i];
|
Tile &t = tiles[i];
|
||||||
QPoint tp(tl.x() + (t.xy().x() - tile.x()) * TILE_SIZE,
|
QPoint tp(tl.x() + (t.xy().x() - tile.x()) * TILE_SIZE,
|
||||||
tl.y() + (t.xy().y() - tile.y()) * TILE_SIZE);
|
tl.y() + (t.xy().y() - tile.y()) * TILE_SIZE);
|
||||||
|
if (t.pixmap().isNull())
|
||||||
|
painter->fillRect(QRect(tp, QSize(TILE_SIZE, TILE_SIZE)),
|
||||||
|
_backgroundColor);
|
||||||
|
else
|
||||||
painter->drawPixmap(tp, t.pixmap());
|
painter->drawPixmap(tp, t.pixmap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,7 @@
|
|||||||
#include "common/range.h"
|
#include "common/range.h"
|
||||||
#include "common/rectc.h"
|
#include "common/rectc.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "tile.h"
|
#include "tileloader.h"
|
||||||
|
|
||||||
class Downloader;
|
|
||||||
|
|
||||||
class OnlineMap : public Map
|
class OnlineMap : public Map
|
||||||
{
|
{
|
||||||
@ -36,10 +34,7 @@ public:
|
|||||||
void draw(QPainter *painter, const QRectF &rect);
|
void draw(QPainter *painter, const QRectF &rect);
|
||||||
|
|
||||||
void setBlockingMode(bool block) {_block = block;}
|
void setBlockingMode(bool block) {_block = block;}
|
||||||
void clearCache();
|
void clearCache() {_tileLoader.clearCache();}
|
||||||
|
|
||||||
static void setDownloader(Downloader *downloader)
|
|
||||||
{OnlineMap::downloader = downloader;}
|
|
||||||
|
|
||||||
void load();
|
void load();
|
||||||
void unload();
|
void unload();
|
||||||
@ -50,22 +45,14 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
QPointF ll2xy(const Coordinates &c) const;
|
QPointF ll2xy(const Coordinates &c) const;
|
||||||
Coordinates xy2ll(const QPointF &p) const;
|
Coordinates xy2ll(const QPointF &p) const;
|
||||||
|
|
||||||
void fillTile(Tile &tile);
|
|
||||||
QString tileUrl(const Tile &tile) const;
|
|
||||||
QString tileFile(const Tile &tile) const;
|
|
||||||
void loadTilesAsync(QList<Tile> &list);
|
|
||||||
void loadTilesSync(QList<Tile> &list);
|
|
||||||
int limitZoom(int zoom) const;
|
int limitZoom(int zoom) const;
|
||||||
|
|
||||||
|
TileLoader _tileLoader;
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _url;
|
|
||||||
Range _zooms;
|
Range _zooms;
|
||||||
RectC _bounds;
|
RectC _bounds;
|
||||||
int _zoom;
|
int _zoom;
|
||||||
bool _block;
|
bool _block;
|
||||||
|
|
||||||
static Downloader *downloader;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ONLINEMAP_H
|
#endif // ONLINEMAP_H
|
||||||
|
@ -77,9 +77,14 @@ public:
|
|||||||
|
|
||||||
Projection &operator=(const Projection &p);
|
Projection &operator=(const Projection &p);
|
||||||
|
|
||||||
|
bool isNull() const {return (_gcs == 0 && _ct == 0 && _units.isNull());}
|
||||||
|
bool isValid() const {return (_gcs == 0 || _ct == 0 || _units.isNull());}
|
||||||
|
|
||||||
QPointF ll2xy(const Coordinates &c) const;
|
QPointF ll2xy(const Coordinates &c) const;
|
||||||
Coordinates xy2ll(const QPointF &p) const;
|
Coordinates xy2ll(const QPointF &p) const;
|
||||||
|
|
||||||
|
const LinearUnits &units() const {return _units;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const GCS * _gcs;
|
const GCS * _gcs;
|
||||||
CT *_ct;
|
CT *_ct;
|
||||||
|
106
src/map/tileloader.cpp
Normal file
106
src/map/tileloader.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include "downloader.h"
|
||||||
|
#include "tileloader.h"
|
||||||
|
|
||||||
|
|
||||||
|
static bool loadTileFile(Tile &tile, const QString &file)
|
||||||
|
{
|
||||||
|
if (!tile.pixmap().load(file)) {
|
||||||
|
qWarning("%s: error loading tile file\n", qPrintable(file));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Downloader *TileLoader::_downloader = 0;
|
||||||
|
|
||||||
|
TileLoader::TileLoader(const QString &url, const QString &dir)
|
||||||
|
: _url(url), _dir(dir)
|
||||||
|
{
|
||||||
|
if (!QDir().mkpath(_dir))
|
||||||
|
qWarning("Error creating tiles dir: %s\n", qPrintable(_dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileLoader::loadTilesAsync(QList<Tile> &list)
|
||||||
|
{
|
||||||
|
QList<Download> dl;
|
||||||
|
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
Tile &t = list[i];
|
||||||
|
QString file = tileFile(t);
|
||||||
|
QFileInfo fi(file);
|
||||||
|
|
||||||
|
if (!fi.exists())
|
||||||
|
dl.append(Download(tileUrl(t), file));
|
||||||
|
else
|
||||||
|
loadTileFile(t, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dl.empty())
|
||||||
|
_downloader->get(dl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileLoader::loadTilesSync(QList<Tile> &list)
|
||||||
|
{
|
||||||
|
QList<Download> dl;
|
||||||
|
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
Tile &t = list[i];
|
||||||
|
QString file = tileFile(t);
|
||||||
|
QFileInfo fi(file);
|
||||||
|
|
||||||
|
if (!fi.exists())
|
||||||
|
dl.append(Download(tileUrl(t), file));
|
||||||
|
else
|
||||||
|
loadTileFile(t, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dl.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QEventLoop wait;
|
||||||
|
QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit()));
|
||||||
|
if (_downloader->get(dl))
|
||||||
|
wait.exec();
|
||||||
|
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
Tile &t = list[i];
|
||||||
|
|
||||||
|
if (t.pixmap().isNull()) {
|
||||||
|
QString file = tileFile(t);
|
||||||
|
if (QFileInfo(file).exists())
|
||||||
|
loadTileFile(t, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileLoader::clearCache()
|
||||||
|
{
|
||||||
|
QDir dir = QDir(_dir);
|
||||||
|
QStringList list = dir.entryList();
|
||||||
|
|
||||||
|
for (int i = 0; i < list.count(); i++)
|
||||||
|
dir.remove(list.at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TileLoader::tileUrl(const Tile &tile) const
|
||||||
|
{
|
||||||
|
QString url(_url);
|
||||||
|
|
||||||
|
url.replace("$z", QString::number(tile.zoom()));
|
||||||
|
url.replace("$x", QString::number(tile.xy().x()));
|
||||||
|
url.replace("$y", QString::number(tile.xy().y()));
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TileLoader::tileFile(const Tile &tile) const
|
||||||
|
{
|
||||||
|
QString file = _dir + QString("/%1-%2-%3").arg(tile.zoom())
|
||||||
|
.arg(tile.xy().x()).arg(tile.xy().y());
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
33
src/map/tileloader.h
Normal file
33
src/map/tileloader.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef TILELOADER_H
|
||||||
|
#define TILELOADER_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include "tile.h"
|
||||||
|
#include "downloader.h"
|
||||||
|
|
||||||
|
class TileLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TileLoader() {}
|
||||||
|
TileLoader(const QString &url, const QString &dir);
|
||||||
|
|
||||||
|
void loadTilesAsync(QList<Tile> &list);
|
||||||
|
void loadTilesSync(QList<Tile> &list);
|
||||||
|
void clearCache();
|
||||||
|
|
||||||
|
static Downloader *downloader() {return _downloader;}
|
||||||
|
static void setDownloader(Downloader *downloader)
|
||||||
|
{_downloader = downloader;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void fillTile(Tile &tile);
|
||||||
|
QString tileUrl(const Tile &tile) const;
|
||||||
|
QString tileFile(const Tile &tile) const;
|
||||||
|
|
||||||
|
QString _url;
|
||||||
|
QString _dir;
|
||||||
|
|
||||||
|
static Downloader *_downloader;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TILELOADER_Honlinemap
|
169
src/map/wmts.cpp
Normal file
169
src/map/wmts.cpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include <QXmlStreamReader>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include "downloader.h"
|
||||||
|
#include "pcs.h"
|
||||||
|
#include "wmts.h"
|
||||||
|
|
||||||
|
|
||||||
|
Downloader *WMTS::_downloader = 0;
|
||||||
|
|
||||||
|
bool WMTS::createProjection(const QString &crs)
|
||||||
|
{
|
||||||
|
QStringList list(crs.split(':'));
|
||||||
|
QString authority, code;
|
||||||
|
const PCS *pcs;
|
||||||
|
|
||||||
|
switch (list.size()) {
|
||||||
|
case 2:
|
||||||
|
authority = list.at(0);
|
||||||
|
code = list.at(1);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
authority = list.at(4);
|
||||||
|
code = list.at(6);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authority != "EPSG")
|
||||||
|
return false;
|
||||||
|
if (!(pcs = PCS::pcs(code.toInt())))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_projection = Projection(pcs->gcs(), pcs->method(), pcs->setup(),
|
||||||
|
pcs->units());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMTS::tileMatrix(QXmlStreamReader &reader)
|
||||||
|
{
|
||||||
|
Zoom zoom;
|
||||||
|
|
||||||
|
while (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "ScaleDenominator")
|
||||||
|
zoom.scaleDenominator = reader.readElementText().toDouble();
|
||||||
|
else if (reader.name() == "TopLeftCorner") {
|
||||||
|
QString str = reader.readElementText();
|
||||||
|
QTextStream(&str) >> zoom.topLeft.rx() >> zoom.topLeft.ry();
|
||||||
|
} else if (reader.name() == "TileWidth")
|
||||||
|
zoom.tile.setWidth(reader.readElementText().toInt());
|
||||||
|
else if (reader.name() == "TileHeight")
|
||||||
|
zoom.tile.setHeight(reader.readElementText().toInt());
|
||||||
|
else if (reader.name() == "MatrixWidth")
|
||||||
|
zoom.matrix.setWidth(reader.readElementText().toInt());
|
||||||
|
else if (reader.name() == "MatrixHeight")
|
||||||
|
zoom.matrix.setHeight(reader.readElementText().toInt());
|
||||||
|
else
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
_zooms.append(zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMTS::tileMatrixSet(QXmlStreamReader &reader, const QString &set)
|
||||||
|
{
|
||||||
|
QString id;
|
||||||
|
|
||||||
|
while (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "Identifier")
|
||||||
|
id = reader.readElementText();
|
||||||
|
else if (reader.name() == "SupportedCRS" && id == set) {
|
||||||
|
if (!createProjection(reader.readElementText()))
|
||||||
|
reader.raiseError("Invalid/unknown CRS");
|
||||||
|
} else if (reader.name() == "TileMatrix" && id == set)
|
||||||
|
tileMatrix(reader);
|
||||||
|
else
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMTS::contents(QXmlStreamReader &reader, const QString &set)
|
||||||
|
{
|
||||||
|
while (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "TileMatrixSet")
|
||||||
|
tileMatrixSet(reader, set);
|
||||||
|
else
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMTS::capabilities(QXmlStreamReader &reader, const QString &set)
|
||||||
|
{
|
||||||
|
while (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "Contents")
|
||||||
|
contents(reader, set);
|
||||||
|
else
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WMTS::parseCapabilities(const QString &path, const QString &tileMatrixSet)
|
||||||
|
{
|
||||||
|
QFile file(path);
|
||||||
|
QXmlStreamReader reader;
|
||||||
|
|
||||||
|
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
|
_errorString = file.errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.setDevice(&file);
|
||||||
|
|
||||||
|
if (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "Capabilities")
|
||||||
|
capabilities(reader, tileMatrixSet);
|
||||||
|
else
|
||||||
|
reader.raiseError("Not a Capabilities XML file");
|
||||||
|
}
|
||||||
|
|
||||||
|
_errorString = reader.error() ? QString("%1:%2: %3").arg(path)
|
||||||
|
.arg(reader.lineNumber()).arg(reader.errorString()) : QString();
|
||||||
|
|
||||||
|
return reader.error() ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WMTS::getCapabilities(const QString &url, const QString &file)
|
||||||
|
{
|
||||||
|
QList<Download> dl;
|
||||||
|
|
||||||
|
QString capabilitiesUrl = QString("%1?service=WMTS&Version=1.0.0"
|
||||||
|
"&request=GetCapabilities").arg(url);
|
||||||
|
dl.append(Download(capabilitiesUrl, file));
|
||||||
|
|
||||||
|
QEventLoop wait;
|
||||||
|
QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit()));
|
||||||
|
if (_downloader->get(dl))
|
||||||
|
wait.exec();
|
||||||
|
|
||||||
|
if (QFileInfo(file).exists())
|
||||||
|
return true;
|
||||||
|
else {
|
||||||
|
_errorString = "Error downloading capabilities XML file";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WMTS::load(const QString &file, const QString &url,
|
||||||
|
const QString &tileMatrixSet)
|
||||||
|
{
|
||||||
|
if (!QFileInfo(file).exists())
|
||||||
|
if (!getCapabilities(url, file))
|
||||||
|
return false;
|
||||||
|
if (!parseCapabilities(file, tileMatrixSet))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_projection.isNull()) {
|
||||||
|
_errorString = "Missing CRS definition";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_zooms.isEmpty()) {
|
||||||
|
_errorString = "No tile matrix found";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
50
src/map/wmts.h
Normal file
50
src/map/wmts.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef WMTS_H
|
||||||
|
#define WMTS_H
|
||||||
|
|
||||||
|
#include <QSize>
|
||||||
|
#include <QList>
|
||||||
|
#include "projection.h"
|
||||||
|
|
||||||
|
class QXmlStreamReader;
|
||||||
|
class Downloader;
|
||||||
|
|
||||||
|
class WMTS
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Zoom {
|
||||||
|
qreal scaleDenominator;
|
||||||
|
QPointF topLeft;
|
||||||
|
QSize tile;
|
||||||
|
QSize matrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool load(const QString &path, const QString &url,
|
||||||
|
const QString &tileMatrixSet);
|
||||||
|
const QString &errorString() const {return _errorString;}
|
||||||
|
|
||||||
|
const QList<Zoom> &zooms() {return _zooms;}
|
||||||
|
const Projection &projection() {return _projection;}
|
||||||
|
|
||||||
|
static Downloader *downloader() {return _downloader;}
|
||||||
|
static void setDownloader(Downloader *downloader)
|
||||||
|
{_downloader = downloader;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool createProjection(const QString &crs);
|
||||||
|
|
||||||
|
void tileMatrix(QXmlStreamReader &reader);
|
||||||
|
void tileMatrixSet(QXmlStreamReader &reader, const QString &set);
|
||||||
|
void contents(QXmlStreamReader &reader, const QString &set);
|
||||||
|
void capabilities(QXmlStreamReader &reader, const QString &set);
|
||||||
|
bool parseCapabilities(const QString &path, const QString &tileMatrixSet);
|
||||||
|
bool getCapabilities(const QString &url, const QString &file);
|
||||||
|
|
||||||
|
QList<Zoom> _zooms;
|
||||||
|
Projection _projection;
|
||||||
|
|
||||||
|
QString _errorString;
|
||||||
|
|
||||||
|
static Downloader *_downloader;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // WMTS_H
|
203
src/map/wmtsmap.cpp
Normal file
203
src/map/wmtsmap.cpp
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
#include <QPainter>
|
||||||
|
#include "common/rectc.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "transform.h"
|
||||||
|
#include "wmts.h"
|
||||||
|
#include "wmtsmap.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define CAPABILITIES_FILE "capabilities.xml"
|
||||||
|
|
||||||
|
WMTSMap::WMTSMap(const QString &name, const QString &url, const QString &format,
|
||||||
|
const QString &layer, const QString &style, const QString &tileMatrixSet,
|
||||||
|
QObject *parent) : Map(parent), _name(name), _url(url),
|
||||||
|
_tileMatrixSet(tileMatrixSet), _zoom(0), _valid(false)
|
||||||
|
{
|
||||||
|
QString dir(TILES_DIR + "/" + _name);
|
||||||
|
QString file = dir + "/" + CAPABILITIES_FILE;
|
||||||
|
|
||||||
|
QString tileUrl = QString("%1?service=WMTS&Version=1.0.0&request=GetTile"
|
||||||
|
"&Format=%2&Layer=%3&Style=%4&TileMatrixSet=%5&TileMatrix=$z&TileRow=$y"
|
||||||
|
"&TileCol=$x").arg(_url).arg(format).arg(layer).arg(style)
|
||||||
|
.arg(_tileMatrixSet);
|
||||||
|
_tileLoader = TileLoader(tileUrl, dir);
|
||||||
|
|
||||||
|
WMTS wmts;
|
||||||
|
if (!wmts.load(file, _url, _tileMatrixSet)) {
|
||||||
|
_errorString = wmts.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_zooms = wmts.zooms();
|
||||||
|
_projection = wmts.projection();
|
||||||
|
|
||||||
|
updateTransform();
|
||||||
|
|
||||||
|
_block = false;
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal WMTSMap::sd2res(qreal scaleDenominator) const
|
||||||
|
{
|
||||||
|
return scaleDenominator * 0.28e-3 * _projection.units().fromMeters(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMTSMap::updateTransform()
|
||||||
|
{
|
||||||
|
const WMTS::Zoom &z = _zooms.at(_zoom);
|
||||||
|
ReferencePoint tl, br;
|
||||||
|
|
||||||
|
qreal pixelSpan = sd2res(z.scaleDenominator);
|
||||||
|
QPointF tileSpan(z.tile.width() * pixelSpan, z.tile.height() * pixelSpan);
|
||||||
|
QPointF bottomRight(z.topLeft.x() + tileSpan.x() * z.matrix.width(),
|
||||||
|
z.topLeft.y() - tileSpan.y() * z.matrix.height());
|
||||||
|
|
||||||
|
tl.xy = QPoint(0, 0);
|
||||||
|
tl.pp = z.topLeft;
|
||||||
|
br.xy = QPoint(z.tile.width() * z.matrix.width(),
|
||||||
|
z.tile.height() * z.matrix.height());
|
||||||
|
br.pp = bottomRight;
|
||||||
|
|
||||||
|
QList<ReferencePoint> points;
|
||||||
|
points << tl << br;
|
||||||
|
Transform tr(points);
|
||||||
|
_transform = tr.transform();
|
||||||
|
_inverted = _transform.inverted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMTSMap::load()
|
||||||
|
{
|
||||||
|
connect(TileLoader::downloader(), SIGNAL(finished()), this,
|
||||||
|
SLOT(emitLoaded()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMTSMap::unload()
|
||||||
|
{
|
||||||
|
disconnect(TileLoader::downloader(), SIGNAL(finished()), this,
|
||||||
|
SLOT(emitLoaded()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMTSMap::clearCache()
|
||||||
|
{
|
||||||
|
QString dir(TILES_DIR + "/" + _name);
|
||||||
|
QString file = dir + "/" + CAPABILITIES_FILE;
|
||||||
|
|
||||||
|
_tileLoader.clearCache();
|
||||||
|
|
||||||
|
WMTS wmts;
|
||||||
|
if (!wmts.load(file, _url, _tileMatrixSet))
|
||||||
|
return;
|
||||||
|
_zooms = wmts.zooms();
|
||||||
|
_projection = wmts.projection();
|
||||||
|
|
||||||
|
if (_zoom >= _zooms.size())
|
||||||
|
_zoom = _zooms.size() - 1;
|
||||||
|
updateTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMTSMap::emitLoaded()
|
||||||
|
{
|
||||||
|
emit loaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF WMTSMap::bounds() const
|
||||||
|
{
|
||||||
|
const WMTS::Zoom &z = _zooms.at(_zoom);
|
||||||
|
return QRectF(QPointF(0, 0), QSize(z.tile.width() * z.matrix.width(),
|
||||||
|
z.tile.height() * z.matrix.height()));
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal WMTSMap::zoomFit(const QSize &size, const RectC &br)
|
||||||
|
{
|
||||||
|
_zoom = 0;
|
||||||
|
|
||||||
|
if (br.isValid()) {
|
||||||
|
QRectF tbr(_projection.ll2xy(br.topLeft()),
|
||||||
|
_projection.ll2xy(br.bottomRight()));
|
||||||
|
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
|
||||||
|
qreal resolution = qMax(qAbs(sc.x()), qAbs(sc.y()));
|
||||||
|
|
||||||
|
for (int i = 0; i < _zooms.size(); i++) {
|
||||||
|
if (sd2res(_zooms.at(i).scaleDenominator) < resolution)
|
||||||
|
break;
|
||||||
|
_zoom = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTransform();
|
||||||
|
return _zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal WMTSMap::zoomFit(qreal resolution, const Coordinates &c)
|
||||||
|
{
|
||||||
|
Q_UNUSED(c);
|
||||||
|
|
||||||
|
_zoom = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < _zooms.size(); i++) {
|
||||||
|
if (sd2res(_zooms.at(i).scaleDenominator) < resolution)
|
||||||
|
break;
|
||||||
|
_zoom = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTransform();
|
||||||
|
return _zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal WMTSMap::resolution(const QPointF &p) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(p);
|
||||||
|
|
||||||
|
return sd2res(_zooms.at(_zoom).scaleDenominator);
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal WMTSMap::zoomIn()
|
||||||
|
{
|
||||||
|
_zoom = qMin(_zoom + 1, _zooms.size() - 1);
|
||||||
|
updateTransform();
|
||||||
|
return _zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal WMTSMap::zoomOut()
|
||||||
|
{
|
||||||
|
_zoom = qMax(_zoom - 1, 0);
|
||||||
|
updateTransform();
|
||||||
|
return _zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMTSMap::draw(QPainter *painter, const QRectF &rect)
|
||||||
|
{
|
||||||
|
const WMTS::Zoom &z = _zooms.at(_zoom);
|
||||||
|
QPoint tl = QPoint((int)floor(rect.left() / (qreal)z.tile.width()),
|
||||||
|
(int)floor(rect.top() / (qreal)z.tile.height()));
|
||||||
|
QPoint br = QPoint((int)floor(rect.right() / (qreal)z.tile.width()),
|
||||||
|
(int)floor(rect.bottom() / (qreal)z.tile.height()));
|
||||||
|
|
||||||
|
QList<Tile> tiles;
|
||||||
|
for (int i = tl.x(); i <= br.x(); i++)
|
||||||
|
for (int j = tl.y(); j <= br.y(); j++)
|
||||||
|
tiles.append(Tile(QPoint(i, j), _zoom));
|
||||||
|
|
||||||
|
if (_block)
|
||||||
|
_tileLoader.loadTilesSync(tiles);
|
||||||
|
else
|
||||||
|
_tileLoader.loadTilesAsync(tiles);
|
||||||
|
|
||||||
|
for (int i = 0; i < tiles.count(); i++) {
|
||||||
|
Tile &t = tiles[i];
|
||||||
|
QPoint tp(t.xy().x() * z.tile.width(), t.xy().y() * z.tile.height());
|
||||||
|
if (t.pixmap().isNull())
|
||||||
|
painter->fillRect(QRect(tp, z.tile), _backgroundColor);
|
||||||
|
else
|
||||||
|
painter->drawPixmap(tp, t.pixmap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF WMTSMap::ll2xy(const Coordinates &c) const
|
||||||
|
{
|
||||||
|
return _transform.map(_projection.ll2xy(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinates WMTSMap::xy2ll(const QPointF &p) const
|
||||||
|
{
|
||||||
|
return _projection.xy2ll(_inverted.map(p));
|
||||||
|
}
|
69
src/map/wmtsmap.h
Normal file
69
src/map/wmtsmap.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#ifndef WMTSMAP_H
|
||||||
|
#define WMTSMAP_H
|
||||||
|
|
||||||
|
#include <QTransform>
|
||||||
|
#include "projection.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "wmts.h"
|
||||||
|
#include "tileloader.h"
|
||||||
|
|
||||||
|
|
||||||
|
class WMTSMap : public Map
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
WMTSMap(const QString &name, const QString &url, const QString &format,
|
||||||
|
const QString &layer, const QString &style, const QString &tileMatrixSet,
|
||||||
|
QObject *parent = 0);
|
||||||
|
|
||||||
|
const QString &name() const {return _name;}
|
||||||
|
|
||||||
|
QRectF bounds() const;
|
||||||
|
qreal resolution(const QPointF &p) const;
|
||||||
|
|
||||||
|
qreal zoom() const {return _zoom;}
|
||||||
|
qreal zoomFit(const QSize &size, const RectC &br);
|
||||||
|
qreal zoomFit(qreal resolution, const Coordinates &c);
|
||||||
|
qreal zoomIn();
|
||||||
|
qreal zoomOut();
|
||||||
|
|
||||||
|
QPointF ll2xy(const Coordinates &c)
|
||||||
|
{return static_cast<const WMTSMap &>(*this).ll2xy(c);}
|
||||||
|
Coordinates xy2ll(const QPointF &p)
|
||||||
|
{return static_cast<const WMTSMap &>(*this).xy2ll(p);}
|
||||||
|
|
||||||
|
void draw(QPainter *painter, const QRectF &rect);
|
||||||
|
|
||||||
|
void setBlockingMode(bool block) {_block = block;}
|
||||||
|
void clearCache();
|
||||||
|
|
||||||
|
void load();
|
||||||
|
void unload();
|
||||||
|
|
||||||
|
bool isValid() const {return _valid;}
|
||||||
|
QString errorString() const {return _errorString;}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void emitLoaded();
|
||||||
|
|
||||||
|
private:
|
||||||
|
qreal sd2res(qreal scaleDenominator) const;
|
||||||
|
void updateTransform();
|
||||||
|
|
||||||
|
QPointF ll2xy(const Coordinates &c) const;
|
||||||
|
Coordinates xy2ll(const QPointF &p) const;
|
||||||
|
|
||||||
|
QString _name, _url, _tileMatrixSet;
|
||||||
|
TileLoader _tileLoader;
|
||||||
|
QList<WMTS::Zoom> _zooms;
|
||||||
|
Projection _projection;
|
||||||
|
QTransform _transform, _inverted;
|
||||||
|
int _zoom;
|
||||||
|
bool _block;
|
||||||
|
|
||||||
|
bool _valid;
|
||||||
|
QString _errorString;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // WMTSMAP_H
|
Loading…
Reference in New Issue
Block a user