diff options
Diffstat (limited to 'src/location/maps')
-rw-r--r-- | src/location/maps/qgeocameratiles.cpp | 91 | ||||
-rw-r--r-- | src/location/maps/qgeocameratiles_p.h | 1 | ||||
-rw-r--r-- | src/location/maps/qgeomap.cpp | 5 | ||||
-rw-r--r-- | src/location/maps/qgeomap_p.h | 1 | ||||
-rw-r--r-- | src/location/maps/qgeomapdata.cpp | 9 | ||||
-rw-r--r-- | src/location/maps/qgeomapdata_p.h | 1 | ||||
-rw-r--r-- | src/location/maps/qgeomapscene.cpp | 12 | ||||
-rw-r--r-- | src/location/maps/qgeomapscene_p.h | 1 | ||||
-rw-r--r-- | src/location/maps/qgeotiledmapdata.cpp | 37 | ||||
-rw-r--r-- | src/location/maps/qgeotiledmapdata_p.h | 4 | ||||
-rw-r--r-- | src/location/maps/qgeotiledmapdata_p_p.h | 5 | ||||
-rw-r--r-- | src/location/maps/qgeotiledmappingmanagerengine.cpp | 4 | ||||
-rw-r--r-- | src/location/maps/qgeotilerequestmanager.cpp | 27 | ||||
-rw-r--r-- | src/location/maps/qgeotilerequestmanager_p.h | 2 |
14 files changed, 155 insertions, 45 deletions
diff --git a/src/location/maps/qgeocameratiles.cpp b/src/location/maps/qgeocameratiles.cpp index 9258661b..a63420ed 100644 --- a/src/location/maps/qgeocameratiles.cpp +++ b/src/location/maps/qgeocameratiles.cpp @@ -58,6 +58,11 @@ #include <cmath> QT_BEGIN_NAMESPACE +#define ENABLE_PREFETCHING +// larger values fetch a bigger set when the camera stops +#define PREFETCH_FRUSTUM_SCALE 2.0 +// #define PREFETCH_NEIGHBOUR_LAYER +#define PREFETCH_TWO_NEIGHBOUR_LAYERS struct Frustum { @@ -91,9 +96,9 @@ public: int sideLength_; void updateMetadata(); - void updateGeometry(); + void updateGeometry(double viewExpansion = 1.0); - Frustum frustum() const; + Frustum frustum(double fieldOfViewGradient) const; class LengthSorter { @@ -132,18 +137,78 @@ QGeoCameraTiles::~QGeoCameraTiles() delete d_ptr; } +void QGeoCameraTiles::findPrefetchTiles() +{ +#if defined(ENABLE_PREFETCHING) + Q_D(QGeoCameraTiles); + + d->tiles_.clear(); + + // qDebug() << "prefetch called"; + int zoom = static_cast<int>(floor(d->camera_.zoomLevel())); + d->intZoomLevel_ = zoom; + d->sideLength_ = 1 << d->intZoomLevel_; + d->updateGeometry(PREFETCH_FRUSTUM_SCALE); + +#if defined(PREFETCH_NEIGHBOUR_LAYER) + double zoomFraction = d->camera_.zoomLevel() - zoom; + int nearestNeighbourLayer = zoomFraction > 0.5 ? zoom + 1 : zoom - 1; + if (nearestNeighbourLayer <= d->maxZoom_ && nearestNeighbourLayer >= 0) + { + double oldZoom = d->camera_.zoomLevel(); + d->intZoomLevel_ = nearestNeighbourLayer; + d->sideLength_ = 1 << d->intZoomLevel_; + d->camera_.setZoomLevel(d->intZoomLevel_); + + // Approx heuristic, keeping total # prefetched tiles roughly independent of the + // fractional zoom level. + double neighbourScale = (1.0 + zoomFraction)/2.0; + + d->updateGeometry(PREFETCH_FRUSTUM_SCALE * neighbourScale); + d->camera_.setZoomLevel(oldZoom); + } +#elif defined(PREFETCH_TWO_NEIGHBOUR_LAYERS) + // int size1 = d->tiles_.size(); + + // This is a simpler strategy, we just prefetch from layer above and below + // for the layer below we only use half the size as this fills the screen + double oldZoom = d->camera_.zoomLevel(); + if (zoom > 0) + { + d->intZoomLevel_ = zoom-1; + d->sideLength_ = 1 << d->intZoomLevel_; + d->camera_.setZoomLevel(d->intZoomLevel_); + d->updateGeometry(0.5); + } + // int size2 = d->tiles_.size(); + if (zoom < d->maxZoom_) + { + d->intZoomLevel_ = zoom+1; + d->sideLength_ = 1 << d->intZoomLevel_; + d->camera_.setZoomLevel(d->intZoomLevel_); + d->updateGeometry(1.0); + } + // qDebug() << "prefetched main tiles: " << size1 << " higher detail layer: " << d->tiles_.size() - size2 << " low detail layer: " << size2 - size1; + d->intZoomLevel_ = zoom; + d->sideLength_ = 1 << d->intZoomLevel_; + d->camera_.setZoomLevel(oldZoom); +#endif +#endif +} + + void QGeoCameraTiles::setCamera(const QGeoCameraData &camera) { Q_D(QGeoCameraTiles); if (d->camera_ == camera) return; - d->camera_ = camera; d->intZoomLevel_ = static_cast<int>(floor(d->camera_.zoomLevel())); d->sideLength_ = 1 << d->intZoomLevel_; + d->tiles_.clear(); d->updateGeometry(); } @@ -155,6 +220,7 @@ void QGeoCameraTiles::setScreenSize(const QSize &size) return; d->screenSize_ = size; + d->tiles_.clear(); d->updateGeometry(); } @@ -188,6 +254,7 @@ void QGeoCameraTiles::setTileSize(int tileSize) return; d->tileSize_ = tileSize; + d->tiles_.clear(); d->updateGeometry(); } @@ -205,6 +272,7 @@ void QGeoCameraTiles::setMaximumZoomLevel(int maxZoom) return; d->maxZoom_ = maxZoom; + d->tiles_.clear(); d->updateGeometry(); } @@ -239,12 +307,11 @@ void QGeoCameraTilesPrivate::updateMetadata() tiles_ = newTiles; } -void QGeoCameraTilesPrivate::updateGeometry() +void QGeoCameraTilesPrivate::updateGeometry(double viewExpansion) { - tiles_.clear(); - // Find the frustum from the camera / screen / viewport information - Frustum f = frustum(); + // The larger frustum when stationary is a form of prefetching + Frustum f = frustum(viewExpansion); // Find the polygon where the frustum intersects the plane of the map Polygon footprint = frustumFootprint(f); @@ -263,7 +330,7 @@ void QGeoCameraTilesPrivate::updateGeometry() } } -Frustum QGeoCameraTilesPrivate::frustum() const +Frustum QGeoCameraTilesPrivate::frustum(double fieldOfViewGradient) const { QDoubleVector3D center = sideLength_ * QGeoProjection::coordToMercator(camera_.center()); center.setZ(0.0); @@ -294,16 +361,16 @@ Frustum QGeoCameraTilesPrivate::frustum() const // this assumes that viewSize = 2*nearPlane x 2*nearPlane if (aspectRatio > 1.0) { - hn = 2 * nearPlane; + hn = 2 * fieldOfViewGradient * nearPlane; wn = hn * aspectRatio; - hf = 2 * farPlane; + hf = 2 * fieldOfViewGradient * farPlane; wf = hf * aspectRatio; } else { - wn = 2 * nearPlane; + wn = 2 * fieldOfViewGradient * nearPlane; hn = wn / aspectRatio; - wf = 2 * farPlane; + wf = 2 * fieldOfViewGradient * farPlane; hf = wf / aspectRatio; } diff --git a/src/location/maps/qgeocameratiles_p.h b/src/location/maps/qgeocameratiles_p.h index dfc8cdf3..30571f72 100644 --- a/src/location/maps/qgeocameratiles_p.h +++ b/src/location/maps/qgeocameratiles_p.h @@ -82,6 +82,7 @@ public: void setMapType(const QGeoMapType &mapType); QSet<QGeoTileSpec> tiles() const; + void findPrefetchTiles(); private: QGeoCameraTilesPrivate *d_ptr; diff --git a/src/location/maps/qgeomap.cpp b/src/location/maps/qgeomap.cpp index 7001c7c7..ad81fd13 100644 --- a/src/location/maps/qgeomap.cpp +++ b/src/location/maps/qgeomap.cpp @@ -129,6 +129,11 @@ void QGeoMap::setCameraData(const QGeoCameraData &cameraData) mapData_->setCameraData(cameraData); } +void QGeoMap::cameraStopped() +{ + mapData_->prefetchData(); +} + QGeoCameraData QGeoMap::cameraData() const { return mapData_->cameraData(); diff --git a/src/location/maps/qgeomap_p.h b/src/location/maps/qgeomap_p.h index 34771fe4..a16ad7d6 100644 --- a/src/location/maps/qgeomap_p.h +++ b/src/location/maps/qgeomap_p.h @@ -108,6 +108,7 @@ public: public Q_SLOTS: void update(); + void cameraStopped(); // optional hint for prefetch Q_SIGNALS: void cameraDataChanged(const QGeoCameraData &cameraData); diff --git a/src/location/maps/qgeomapdata.cpp b/src/location/maps/qgeomapdata.cpp index 955b426b..1f0d5cc6 100644 --- a/src/location/maps/qgeomapdata.cpp +++ b/src/location/maps/qgeomapdata.cpp @@ -119,7 +119,6 @@ int QGeoMapData::height() const void QGeoMapData::setCameraData(const QGeoCameraData &cameraData) { Q_D(QGeoMapData); - if (cameraData == d->cameraData()) return; @@ -270,7 +269,13 @@ void QGeoMapDataPrivate::setCameraData(const QGeoCameraData &cameraData) } cameraData_.setCoordinateInterpolator(coordinateInterpolator_.toWeakRef()); - map_->changeCameraData(oldCameraData); + + // Do not call this expensive function if the width is 0, since it will get called + // anyway when it is resized to a width > 0. + // this is mainly an optimisation to the initalization of the geomap, which would otherwise + // call changeCameraData four or more times + if (width() > 0) + map_->changeCameraData(oldCameraData); } QGeoCameraData QGeoMapDataPrivate::cameraData() const diff --git a/src/location/maps/qgeomapdata_p.h b/src/location/maps/qgeomapdata_p.h index 42367ced..f1304ff9 100644 --- a/src/location/maps/qgeomapdata_p.h +++ b/src/location/maps/qgeomapdata_p.h @@ -106,6 +106,7 @@ public: QString pluginString(); QGeoCameraCapabilities cameraCapabilities(); QGeoMappingManagerEngine *engine(); + virtual void prefetchData() = 0; protected: void setCoordinateInterpolator(QSharedPointer<QGeoCoordinateInterpolator> interpolator); diff --git a/src/location/maps/qgeomapscene.cpp b/src/location/maps/qgeomapscene.cpp index c8b39232..7aea014d 100644 --- a/src/location/maps/qgeomapscene.cpp +++ b/src/location/maps/qgeomapscene.cpp @@ -231,6 +231,16 @@ void QGeoMapScene::paintGL(QGLPainter *painter) d->paintGL(painter); } +QSet<QGeoTileSpec> QGeoMapScene::texturedTiles() +{ + Q_D(QGeoMapScene); + QSet<QGeoTileSpec> textured; + foreach (const QGeoTileSpec &tile, d->textures_.keys()) { + textured += tile; + } + return textured; +} + QGeoMapScenePrivate::QGeoMapScenePrivate(QGeoMapScene *scene) : tileSize_(0), camera_(new QGLCamera()), @@ -400,6 +410,8 @@ void QGeoMapScenePrivate::setScalingOnTextures() void QGeoMapScenePrivate::addTile(const QGeoTileSpec &spec, QSharedPointer<QGeoTileTexture> texture) { + if (!visibleTiles_.contains(spec)) // Don't add the geometry if it isn't visible + return; if (linearScaling_) { texture->texture->setBindOptions(texture->texture->bindOptions() | (QGLTexture2D::LinearFilteringBindOption)); diff --git a/src/location/maps/qgeomapscene_p.h b/src/location/maps/qgeomapscene_p.h index 9ff7969d..d2baa99e 100644 --- a/src/location/maps/qgeomapscene_p.h +++ b/src/location/maps/qgeomapscene_p.h @@ -101,6 +101,7 @@ public: void paintGL(QGLPainter *painter); bool verticalLock() const; + QSet<QGeoTileSpec> texturedTiles(); Q_SIGNALS: void newTilesVisible(const QSet<QGeoTileSpec> &newTiles); diff --git a/src/location/maps/qgeotiledmapdata.cpp b/src/location/maps/qgeotiledmapdata.cpp index 0d331625..c1a6bdff 100644 --- a/src/location/maps/qgeotiledmapdata.cpp +++ b/src/location/maps/qgeotiledmapdata.cpp @@ -149,10 +149,10 @@ QGeoTileRequestManager *QGeoTiledMapData::getRequestManager() return d->tileRequests_; } -void QGeoTiledMapData::newTileFetched(QSharedPointer<QGeoTileTexture> texture) +void QGeoTiledMapData::newTileFetched(const QGeoTileSpec &spec) { Q_D(QGeoTiledMapData); - d->newTileFetched(texture); + d->newTileFetched(spec); } QGeoTileCache *QGeoTiledMapData::tileCache() @@ -180,6 +180,12 @@ void QGeoTiledMapData::changeCameraData(const QGeoCameraData &oldCameraData) d->changeCameraData(oldCameraData); } +void QGeoTiledMapData::prefetchData() +{ + Q_D(QGeoTiledMapData); + d->prefetchTiles(); +} + void QGeoTiledMapData::changeActiveMapType(const QGeoMapType mapType) { Q_D(QGeoTiledMapData); @@ -263,6 +269,14 @@ QGeoTiledMappingManagerEngine *QGeoTiledMapDataPrivate::engine() const return engine_; } +void QGeoTiledMapDataPrivate::prefetchTiles() +{ + cameraTiles_->findPrefetchTiles(); + + if (tileRequests_) + tileRequests_->requestTiles(cameraTiles_->tiles() - mapScene_->texturedTiles()); +} + void QGeoTiledMapDataPrivate::changeCameraData(const QGeoCameraData &oldCameraData) { double lat = oldCameraData.center().latitude(); @@ -288,14 +302,14 @@ void QGeoTiledMapDataPrivate::changeCameraData(const QGeoCameraData &oldCameraDa } cameraTiles_->setCamera(cam); - visibleTiles_ = cameraTiles_->tiles(); mapScene_->setCameraData(cam); - mapScene_->setVisibleTiles(visibleTiles_); + mapScene_->setVisibleTiles(cameraTiles_->tiles()); if (tileRequests_) { + // don't request tiles that are already built and textured QList<QSharedPointer<QGeoTileTexture> > cachedTiles = - tileRequests_->requestTiles(visibleTiles_); + tileRequests_->requestTiles(cameraTiles_->tiles() - mapScene_->texturedTiles()); foreach (const QSharedPointer<QGeoTileTexture> &tex, cachedTiles) { mapScene_->addTile(tex->spec, tex); @@ -303,14 +317,12 @@ void QGeoTiledMapDataPrivate::changeCameraData(const QGeoCameraData &oldCameraDa if (!cachedTiles.isEmpty()) map_->update(); - } } void QGeoTiledMapDataPrivate::changeActiveMapType(const QGeoMapType mapType) { cameraTiles_->setMapType(mapType); - visibleTiles_ = cameraTiles_->tiles(); } void QGeoTiledMapDataPrivate::resized(int width, int height) @@ -337,15 +349,18 @@ void QGeoTiledMapDataPrivate::resized(int width, int height) } } -void QGeoTiledMapDataPrivate::newTileFetched(QSharedPointer<QGeoTileTexture> texture) +void QGeoTiledMapDataPrivate::newTileFetched(const QGeoTileSpec &spec) { - mapScene_->addTile(texture->spec, texture); - map_->update(); + // Only promote the texture up to GPU if it is visible + if (cameraTiles_->tiles().contains(spec)){ + mapScene_->addTile(spec, engine_->getTileTexture(spec)); + map_->update(); + } } QSet<QGeoTileSpec> QGeoTiledMapDataPrivate::visibleTiles() { - return visibleTiles_; + return cameraTiles_->tiles(); } void QGeoTiledMapDataPrivate::paintGL(QGLPainter *painter) diff --git a/src/location/maps/qgeotiledmapdata_p.h b/src/location/maps/qgeotiledmapdata_p.h index 73fde8f1..db160fe9 100644 --- a/src/location/maps/qgeotiledmapdata_p.h +++ b/src/location/maps/qgeotiledmapdata_p.h @@ -82,10 +82,11 @@ public: void paintGL(QGLPainter *painter); - void newTileFetched(QSharedPointer<QGeoTileTexture> texture); + void newTileFetched(const QGeoTileSpec &spec); QGeoCoordinate screenPositionToCoordinate(const QPointF &pos, bool clipToViewport = true) const; QPointF coordinateToScreenPosition(const QGeoCoordinate &coordinate, bool clipToViewport = true) const; + void prefetchTiles(); // Alternative to exposing this is to make tileFetched a slot, but then requestManager would // need to be a QObject @@ -94,6 +95,7 @@ protected: void mapResized(int width, int height); void changeCameraData(const QGeoCameraData &oldCameraData); void changeActiveMapType(const QGeoMapType mapType); + void prefetchData(); protected Q_SLOTS: virtual void evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles); diff --git a/src/location/maps/qgeotiledmapdata_p_p.h b/src/location/maps/qgeotiledmapdata_p_p.h index e1d2d716..79af86fb 100644 --- a/src/location/maps/qgeotiledmapdata_p_p.h +++ b/src/location/maps/qgeotiledmapdata_p_p.h @@ -101,18 +101,17 @@ public: QGeoCoordinate screenPositionToCoordinate(const QPointF &pos) const; QPointF coordinateToScreenPosition(const QGeoCoordinate &coordinate) const; - void newTileFetched(QSharedPointer<QGeoTileTexture> texture); + void newTileFetched(const QGeoTileSpec &spec); QSet<QGeoTileSpec> visibleTiles(); QGeoTiledMappingManagerEngine *engine() const; + void prefetchTiles(); private: QGeoTiledMapData *map_; QGeoTileCache *cache_; QGeoTiledMappingManagerEngine *engine_; - QSet<QGeoTileSpec> visibleTiles_; - QGeoCameraTiles *cameraTiles_; QGeoMapScene *mapScene_; Q_DISABLE_COPY(QGeoTiledMapDataPrivate) diff --git a/src/location/maps/qgeotiledmappingmanagerengine.cpp b/src/location/maps/qgeotiledmappingmanagerengine.cpp index 0a7b11b7..3dafc302 100644 --- a/src/location/maps/qgeotiledmappingmanagerengine.cpp +++ b/src/location/maps/qgeotiledmappingmanagerengine.cpp @@ -239,12 +239,10 @@ void QGeoTiledMappingManagerEngine::engineTileFinished(const QGeoTileSpec &spec, tileCache()->insert(spec, bytes, format, d->cacheHint_); - QSharedPointer<QGeoTileTexture> tile = tileCache()->get(spec); - map = maps.constBegin(); mapEnd = maps.constEnd(); for (; map != mapEnd; ++map) { - (*map)->getRequestManager()->tileFetched(tile); + (*map)->getRequestManager()->tileFetched(spec); } } diff --git a/src/location/maps/qgeotilerequestmanager.cpp b/src/location/maps/qgeotilerequestmanager.cpp index 563df456..431a3c26 100644 --- a/src/location/maps/qgeotilerequestmanager.cpp +++ b/src/location/maps/qgeotilerequestmanager.cpp @@ -41,6 +41,7 @@ #include "qgeotilerequestmanager_p.h" #include <QSharedPointer> +#include <QDebug> #include "qgeotilespec.h" #include "qgeotiledmapdata_p.h" #include "qgeotiledmappingmanagerengine.h" @@ -64,10 +65,9 @@ public: QHash<QGeoTileSpec, int> retries_; QHash<QGeoTileSpec, QSharedPointer<RetryFuture> > futures_; - QSet<QGeoTileSpec> visible_; QSet<QGeoTileSpec> requested_; - void tileFetched(QSharedPointer<QGeoTileTexture> texture); + void tileFetched(const QGeoTileSpec &spec); }; QGeoTileRequestManager::QGeoTileRequestManager(QGeoTiledMapData *map) @@ -86,10 +86,10 @@ QList<QSharedPointer<QGeoTileTexture> > QGeoTileRequestManager::requestTiles(con return d->requestTiles(tiles); } -void QGeoTileRequestManager::tileFetched(QSharedPointer<QGeoTileTexture> texture) +void QGeoTileRequestManager::tileFetched(const QGeoTileSpec &spec) { Q_D(QGeoTileRequestManager); - d->tileFetched(texture); + d->tileFetched(spec); } void QGeoTileRequestManager::tileError(const QGeoTileSpec &tile, const QString &errorString) @@ -110,8 +110,10 @@ QGeoTileRequestManagerPrivate::~QGeoTileRequestManagerPrivate() QList<QSharedPointer<QGeoTileTexture> > QGeoTileRequestManagerPrivate::requestTiles(const QSet<QGeoTileSpec> &tiles) { QSet<QGeoTileSpec> cancelTiles = requested_ - tiles; - QSet<QGeoTileSpec> requestTiles = tiles - visible_ - requested_; + QSet<QGeoTileSpec> requestTiles = tiles - requested_; QSet<QGeoTileSpec> cached; +// int tileSize = tiles.size(); +// int newTiles = requestTiles.size(); typedef QSet<QGeoTileSpec>::const_iterator iter; @@ -136,13 +138,14 @@ QList<QSharedPointer<QGeoTileTexture> > QGeoTileRequestManagerPrivate::requestTi requestTiles -= cached; - visible_ = tiles; - requested_ -= cancelTiles; requested_ += requestTiles; +// qDebug() << "required # tiles: " << tileSize << ", new tiles: " << newTiles << ", total server requests: " << requested_.size(); + if (!requestTiles.isEmpty() || !cancelTiles.isEmpty()) { if (engine) { +// qDebug() << "new server requests: " << requestTiles.size() << ", server cancels: " << cancelTiles.size(); engine->updateTileRequests(map_, requestTiles, cancelTiles); // Remove any cancelled tiles from the error retry hash to avoid @@ -159,12 +162,12 @@ QList<QSharedPointer<QGeoTileTexture> > QGeoTileRequestManagerPrivate::requestTi return cachedTex; } -void QGeoTileRequestManagerPrivate::tileFetched(QSharedPointer<QGeoTileTexture> texture) +void QGeoTileRequestManagerPrivate::tileFetched(const QGeoTileSpec &spec) { - map_->newTileFetched(texture); - requested_.remove(texture->spec); - retries_.remove(texture->spec); - futures_.remove(texture->spec); + map_->newTileFetched(spec); + requested_.remove(spec); + retries_.remove(spec); + futures_.remove(spec); } // Represents a tile that needs to be retried after a certain period of time diff --git a/src/location/maps/qgeotilerequestmanager_p.h b/src/location/maps/qgeotilerequestmanager_p.h index 3f394de8..47d1b08a 100644 --- a/src/location/maps/qgeotilerequestmanager_p.h +++ b/src/location/maps/qgeotilerequestmanager_p.h @@ -76,7 +76,7 @@ public: QList<QSharedPointer<QGeoTileTexture> > requestTiles(const QSet<QGeoTileSpec> &tiles); void tileError(const QGeoTileSpec &tile, const QString &errorString); - void tileFetched(QSharedPointer<QGeoTileTexture> texture); + void tileFetched(const QGeoTileSpec &spec); private: QGeoTileRequestManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QGeoTileRequestManager) |