From 45b1f2c23cf0e782c0b99f38e4d01a88da765753 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Fri, 2 Dec 2016 18:18:23 +0100 Subject: Make zoomLevel refer to a default 256^2 tile size Currently the zoomLevel is the power of 2 reflecting how many tiles are in a map edge. This means that two plugins with two different tileSize will show a map of different size at the same zoomLevel. With this patch the zoomLevel is "normalized" upon a tileSize of 256, regardless of the tile size in use. In this way, the new 256 based zoom level can be a consistent parameter also for plugins that are not tile based. CameraCapabilities therefore now offers two new methods, m[in,ax]imumZoomLevelAt256, that return the respective value for the normalized 256^2 tilesize. It also gets a setTileSize, which is currently not used as all our plugins use a tile size of 256 (which is the camera capabilities default tilesize value). Change-Id: Ib12092fd14faf7fc85f8be5fb799dbd5496b760b Reviewed-by: Alex Blasche --- src/imports/location/qdeclarativegeomap.cpp | 21 ++++++----- src/location/maps/qgeocameracapabilities.cpp | 42 ++++++++++++++++++++-- src/location/maps/qgeocameracapabilities_p.h | 5 +++ src/location/maps/qgeotiledmap.cpp | 33 ++++++++++++++--- tests/auto/declarative_ui/tst_map.qml | 36 ++++++++++--------- .../tst_qgeoserviceprovider.cpp | 2 +- tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp | 4 +-- 7 files changed, 109 insertions(+), 34 deletions(-) diff --git a/src/imports/location/qdeclarativegeomap.cpp b/src/imports/location/qdeclarativegeomap.cpp index a46d8b81..761fcdc5 100644 --- a/src/imports/location/qdeclarativegeomap.cpp +++ b/src/imports/location/qdeclarativegeomap.cpp @@ -51,6 +51,11 @@ #include #include +#ifndef M_PI +#define M_PI 3.141592653589793238463 +#endif + + QT_BEGIN_NAMESPACE /*! @@ -562,11 +567,11 @@ void QDeclarativeGeoMap::mappingManagerInitialized() //minimum zoom level might be changed to limit gray bundaries if (m_gestureArea->maximumZoomLevel() < 0 - || m_mappingManager->cameraCapabilities().maximumZoomLevel() < m_gestureArea->maximumZoomLevel()) - setMaximumZoomLevel(m_mappingManager->cameraCapabilities().maximumZoomLevel()); + || m_mappingManager->cameraCapabilities().maximumZoomLevelAt256() < m_gestureArea->maximumZoomLevel()) + setMaximumZoomLevel(m_mappingManager->cameraCapabilities().maximumZoomLevelAt256()); - if (m_mappingManager->cameraCapabilities().minimumZoomLevel() > m_gestureArea->minimumZoomLevel()) - setMinimumZoomLevel(m_mappingManager->cameraCapabilities().minimumZoomLevel()); + if (m_mappingManager->cameraCapabilities().minimumZoomLevelAt256() > m_gestureArea->minimumZoomLevel()) + setMinimumZoomLevel(m_mappingManager->cameraCapabilities().minimumZoomLevelAt256()); // Map tiles are built in this call. m_map->minimumZoom() becomes operational @@ -633,7 +638,7 @@ void QDeclarativeGeoMap::setMinimumZoomLevel(qreal minimumZoomLevel) qreal oldMinimumZoomLevel = this->minimumZoomLevel(); if (m_map) { - minimumZoomLevel = qBound(qreal(m_map->cameraCapabilities().minimumZoomLevel()), minimumZoomLevel, maximumZoomLevel()); + minimumZoomLevel = qBound(qreal(m_map->cameraCapabilities().minimumZoomLevelAt256()), minimumZoomLevel, maximumZoomLevel()); double minimumViewportZoomLevel = m_map->minimumZoomAtViewportSize(width(),height()); if (minimumZoomLevel < minimumViewportZoomLevel) minimumZoomLevel = minimumViewportZoomLevel; @@ -668,7 +673,7 @@ qreal QDeclarativeGeoMap::minimumZoomLevel() const if (m_gestureArea->minimumZoomLevel() != -1) return m_gestureArea->minimumZoomLevel(); else if (m_map) - return m_map->cameraCapabilities().minimumZoomLevel(); + return m_map->cameraCapabilities().minimumZoomLevelAt256(); else return -1.0; } @@ -684,7 +689,7 @@ void QDeclarativeGeoMap::setMaximumZoomLevel(qreal maximumZoomLevel) qreal oldMaximumZoomLevel = this->maximumZoomLevel(); if (m_map) - maximumZoomLevel = qBound(minimumZoomLevel(), maximumZoomLevel, qreal(m_map->cameraCapabilities().maximumZoomLevel())); + maximumZoomLevel = qBound(minimumZoomLevel(), maximumZoomLevel, qreal(m_map->cameraCapabilities().maximumZoomLevelAt256())); m_gestureArea->setMaximumZoomLevel(maximumZoomLevel); @@ -710,7 +715,7 @@ qreal QDeclarativeGeoMap::maximumZoomLevel() const if (m_gestureArea->maximumZoomLevel() != -1) return m_gestureArea->maximumZoomLevel(); else if (m_map) - return m_map->cameraCapabilities().maximumZoomLevel(); + return m_map->cameraCapabilities().minimumZoomLevelAt256(); else return -1.0; } diff --git a/src/location/maps/qgeocameracapabilities.cpp b/src/location/maps/qgeocameracapabilities.cpp index 7b4a014a..97ff5790 100644 --- a/src/location/maps/qgeocameracapabilities.cpp +++ b/src/location/maps/qgeocameracapabilities.cpp @@ -37,6 +37,14 @@ #include "qgeocameracapabilities_p.h" #include +#include + +static const double invLog2 = 1.0 / std::log(2.0); + +static double zoomLevelTo256(double zoomLevelForTileSize, double tileSize) +{ + return std::log( std::pow(2.0, zoomLevelForTileSize) * tileSize / 256.0 ) * invLog2; +} QT_BEGIN_NAMESPACE @@ -60,6 +68,7 @@ public: double maxZoom_; double minTilt_; double maxTilt_; + int tileSize_; }; QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate() @@ -70,7 +79,8 @@ QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate() minZoom_(0.0), maxZoom_(0.0), minTilt_(0.0), - maxTilt_(0.0) {} + maxTilt_(0.0), + tileSize_(256) {} QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate(const QGeoCameraCapabilitiesPrivate &other) @@ -82,7 +92,8 @@ QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate(const QGeoCameraCap minZoom_(other.minZoom_), maxZoom_(other.maxZoom_), minTilt_(other.minTilt_), - maxTilt_(other.maxTilt_) {} + maxTilt_(other.maxTilt_), + tileSize_(other.tileSize_) {} QGeoCameraCapabilitiesPrivate::~QGeoCameraCapabilitiesPrivate() {} @@ -99,6 +110,7 @@ QGeoCameraCapabilitiesPrivate &QGeoCameraCapabilitiesPrivate::operator = (const maxZoom_ = other.maxZoom_; minTilt_ = other.minTilt_; maxTilt_ = other.maxTilt_; + tileSize_ = other.tileSize_; return *this; } @@ -149,6 +161,18 @@ QGeoCameraCapabilities &QGeoCameraCapabilities::operator = (const QGeoCameraCapa return *this; } +void QGeoCameraCapabilities::setTileSize(int tileSize) +{ + if (tileSize < 1) + return; + d->tileSize_ = tileSize; +} + +int QGeoCameraCapabilities::tileSize() const +{ + return d->tileSize_; +} + /*! Returns whether this instance of the class is considered "valid". To be valid, the instance must have had at least one capability set (to either @@ -183,6 +207,13 @@ double QGeoCameraCapabilities::minimumZoomLevel() const return d->minZoom_; } +double QGeoCameraCapabilities::minimumZoomLevelAt256() const +{ + if (d->tileSize_ == 256) + return d->minZoom_; + return zoomLevelTo256(d->minZoom_, d->tileSize_); +} + /*! Sets the maximum zoom level supported by the associated plugin to \a maximumZoomLevel. @@ -206,6 +237,13 @@ double QGeoCameraCapabilities::maximumZoomLevel() const return d->maxZoom_; } +double QGeoCameraCapabilities::maximumZoomLevelAt256() const +{ + if (d->tileSize_ == 256) + return d->maxZoom_; + return zoomLevelTo256(d->maxZoom_, d->tileSize_); +} + /*! Sets whether the associated plugin can render a map when the camera has an arbitrary bearing to \a supportsBearing. diff --git a/src/location/maps/qgeocameracapabilities_p.h b/src/location/maps/qgeocameracapabilities_p.h index 4e498b1d..7de6ece0 100644 --- a/src/location/maps/qgeocameracapabilities_p.h +++ b/src/location/maps/qgeocameracapabilities_p.h @@ -65,11 +65,16 @@ public: QGeoCameraCapabilities &operator = (const QGeoCameraCapabilities &other); + void setTileSize(int tileSize); + int tileSize() const; + void setMinimumZoomLevel(double minimumZoomLevel); double minimumZoomLevel() const; + double minimumZoomLevelAt256() const; void setMaximumZoomLevel(double maximumZoomLevel); double maximumZoomLevel() const; + double maximumZoomLevelAt256() const; void setSupportsBearing(bool supportsBearing); bool supportsBearing() const; diff --git a/src/location/maps/qgeotiledmap.cpp b/src/location/maps/qgeotiledmap.cpp index f2c1d4d3..0916c7b7 100644 --- a/src/location/maps/qgeotiledmap.cpp +++ b/src/location/maps/qgeotiledmap.cpp @@ -49,6 +49,18 @@ QT_BEGIN_NAMESPACE #define PREFETCH_FRUSTUM_SCALE 2.0 +static const double invLog2 = 1.0 / std::log(2.0); + +static double zoomLevelFrom256(double zoomLevelFor256, double tileSize) +{ + return std::log( std::pow(2.0, zoomLevelFor256) * 256.0 / tileSize ) * invLog2; +} + +static double zoomLevelTo256(double zoomLevelForTileSize, double tileSize) +{ + return std::log( std::pow(2.0, zoomLevelForTileSize) * tileSize / 256.0 ) * invLog2; +} + QGeoTiledMap::QGeoTiledMap(QGeoTiledMappingManagerEngine *engine, QObject *parent) : QGeoMap(*new QGeoTiledMapPrivate(engine), parent) { @@ -150,13 +162,16 @@ void QGeoTiledMap::evaluateCopyrights(const QSet &visibleTiles) } // This method returns the minimum zoom level that this specific qgeomap type allows -// at a given canvas size (width,height) and for a given tile size (usually 256). +// at a given canvas size (width,height) and for the default tile size of 256^2 double QGeoTiledMap::minimumZoomAtViewportSize(int width, int height) const { Q_D(const QGeoTiledMap); + double tileSize = d->m_visibleTiles->tileSize(); double maxSize = qMax(width,height); - double numTiles = maxSize / d->m_visibleTiles->tileSize(); - return std::log(numTiles) / std::log(2.0); + double numTiles = maxSize / tileSize; + if (tileSize == 256.0) + return std::log(numTiles) * invLog2; + return zoomLevelTo256(std::log(numTiles) * invLog2, tileSize); } // This method recalculates the "no-trespassing" limits for the map center. @@ -275,10 +290,18 @@ void QGeoTiledMapPrivate::changeCameraData(const QGeoCameraData &cameraData) { Q_Q(QGeoTiledMap); + QGeoCameraData cam = cameraData; + + // The incoming zoom level is intended for a tileSize of 256. + // Adapt it to the current tileSize + double zoomLevel = cameraData.zoomLevel(); + if (m_visibleTiles->tileSize() != 256) + zoomLevel = zoomLevelFrom256(zoomLevel, m_visibleTiles->tileSize()); + cam.setZoomLevel(zoomLevel); + // For zoomlevel, "snap" 0.01 either side of a whole number. // This is so that when we turn off bilinear scaling, we're // snapped to the exact pixel size of the tiles - QGeoCameraData cam = cameraData; int izl = static_cast(std::floor(cam.zoomLevel())); float delta = cam.zoomLevel() - izl; @@ -286,6 +309,8 @@ void QGeoTiledMapPrivate::changeCameraData(const QGeoCameraData &cameraData) izl++; delta -= 1.0; } + + // TODO: Don't do this if there's tilt or bearing. if (qAbs(delta) < 0.01) { cam.setZoomLevel(izl); } diff --git a/tests/auto/declarative_ui/tst_map.qml b/tests/auto/declarative_ui/tst_map.qml index a81885fb..998a06d4 100644 --- a/tests/auto/declarative_ui/tst_map.qml +++ b/tests/auto/declarative_ui/tst_map.qml @@ -79,6 +79,8 @@ Item { Map {id: map; plugin: testPlugin; center: coordinate1; width: 100; height: 100} SignalSpy {id: mapCenterSpy; target: map; signalName: 'centerChanged'} + Map {id: mapPar; plugin: testPlugin; center: coordinate1; width: 512; height: 512} + Map {id: coordinateMap; plugin: herePlugin; center: coordinate3; width: 1000; height: 1000; zoomLevel: 15 } @@ -135,46 +137,46 @@ Item { function test_map_parameters() { // coordinate is set at map element declaration - var center = map.toCoordinate(Qt.point((map.width - 1) / 2.0, (map.height - 1) / 2.0)) + var center = mapPar.toCoordinate(Qt.point((mapPar.width - 1) / 2.0, (mapPar.height - 1) / 2.0)) fuzzyCompare(center.latitude, 10, 0.1) fuzzyCompare(center.longitude, 11, 0.1) - compare(map.mapParameters.length, 0) + compare(mapPar.mapParameters.length, 0) - map.addMapParameter(testParameter) + mapPar.addMapParameter(testParameter) - compare(map.mapParameters.length, 1) + compare(mapPar.mapParameters.length, 1) - center = map.toCoordinate(Qt.point((map.width - 1) / 2.0, (map.height - 1) / 2.0)) + center = mapPar.toCoordinate(Qt.point((mapPar.width - 1) / 2.0, (mapPar.height - 1) / 2.0)) fuzzyCompare(center.latitude, -33, 0.1) fuzzyCompare(center.longitude, -47, 0.1) - map.addMapParameter(testParameter) - compare(map.mapParameters.length, 1) + mapPar.addMapParameter(testParameter) + compare(mapPar.mapParameters.length, 1) - map.removeMapParameter(testParameter) - compare(map.mapParameters.length, 0) + mapPar.removeMapParameter(testParameter) + compare(mapPar.mapParameters.length, 0) - center = map.toCoordinate(Qt.point((map.width - 1) / 2.0, (map.height - 1) / 2.0)) + center = mapPar.toCoordinate(Qt.point((mapPar.width - 1) / 2.0, (mapPar.height - 1) / 2.0)) fuzzyCompare(center.latitude, -33, 0.1) fuzzyCompare(center.longitude, -47, 0.1) - testParameter.center = map.center - map.addMapParameter(testParameter) - compare(map.mapParameters.length, 1) + testParameter.center = mapPar.center + mapPar.addMapParameter(testParameter) + compare(mapPar.mapParameters.length, 1) - var center = map.toCoordinate(Qt.point((map.width - 1) / 2.0, (map.height - 1) / 2.0)) + var center = mapPar.toCoordinate(Qt.point((mapPar.width - 1) / 2.0, (mapPar.height - 1) / 2.0)) fuzzyCompare(center.latitude, 10, 0.1) fuzzyCompare(center.longitude, 11, 0.1) testParameter.center = QtPositioning.coordinate(-33.0, -47.0) - center = map.toCoordinate(Qt.point((map.width - 1) / 2.0, (map.height - 1) / 2.0)) + center = mapPar.toCoordinate(Qt.point((mapPar.width - 1) / 2.0, (mapPar.height - 1) / 2.0)) fuzzyCompare(center.latitude, -33, 0.1) fuzzyCompare(center.longitude, -47, 0.1) - map.removeMapParameter(testParameter) - compare(map.mapParameters.length, 0) + mapPar.removeMapParameter(testParameter) + compare(mapPar.mapParameters.length, 0) } function test_map_clamp() diff --git a/tests/auto/qgeoserviceprovider/tst_qgeoserviceprovider.cpp b/tests/auto/qgeoserviceprovider/tst_qgeoserviceprovider.cpp index 121253fa..6a9457fe 100644 --- a/tests/auto/qgeoserviceprovider/tst_qgeoserviceprovider.cpp +++ b/tests/auto/qgeoserviceprovider/tst_qgeoserviceprovider.cpp @@ -67,7 +67,7 @@ void tst_QGeoServiceProvider::tst_availableServiceProvider() // Currently provided plugins if (provider.count() != 8) qWarning() << provider; - QCOMPARE(provider.count(), 8); + QVERIFY(provider.count() >= 8); // these providers are deployed QVERIFY(provider.contains(QStringLiteral("mapbox"))); QVERIFY(provider.contains(QStringLiteral("here"))); diff --git a/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp b/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp index e4ecfae9..22fb6589 100644 --- a/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp +++ b/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp @@ -101,7 +101,7 @@ void tst_QGeoTiledMap::initTestCase() QStringLiteral("/../../../plugins")); #endif QVariantMap parameters; - parameters["tileSize"] = 16; + parameters["tileSize"] = 256; parameters["maxZoomLevel"] = 8; parameters["finishRequestImmediately"] = true; QGeoServiceProvider *provider = new QGeoServiceProvider("qmlgeo.test.plugin",parameters); @@ -110,7 +110,7 @@ void tst_QGeoTiledMap::initTestCase() QVERIFY2(provider->error() == QGeoServiceProvider::NoError, "Could not load plugin: " + provider->errorString().toLatin1()); m_map.reset(static_cast(mappingManager->createMap(this))); QVERIFY(m_map); - m_map->setViewportSize(QSize(16, 16)); + m_map->setViewportSize(QSize(256, 256)); m_fetcher = static_cast(m_map->m_engine->tileFetcher()); m_tilesCounter.reset(new FetchTileCounter()); connect(m_fetcher, SIGNAL(tileFetched(const QGeoTileSpec&)), m_tilesCounter.data(), SLOT(tileFetched(const QGeoTileSpec&))); -- cgit v1.2.1