summaryrefslogtreecommitdiff
path: root/src/location/maps/qgeotiledmapscene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/location/maps/qgeotiledmapscene.cpp')
-rw-r--r--src/location/maps/qgeotiledmapscene.cpp124
1 files changed, 88 insertions, 36 deletions
diff --git a/src/location/maps/qgeotiledmapscene.cpp b/src/location/maps/qgeotiledmapscene.cpp
index 3711841d..422082fc 100644
--- a/src/location/maps/qgeotiledmapscene.cpp
+++ b/src/location/maps/qgeotiledmapscene.cpp
@@ -88,6 +88,7 @@ public:
double m_mapEdgeSize;
QHash<QGeoTileSpec, QSharedPointer<QGeoTileTexture> > m_textures;
+ QVector<QGeoTileSpec> m_updatedTextures;
// tilesToGrid transform
int m_minTileX; // the minimum tile index, i.e. 0 to sideLength which is 1<< zoomLevel
@@ -104,7 +105,7 @@ public:
void setVisibleTiles(const QSet<QGeoTileSpec> &visibleTiles);
void removeTiles(const QSet<QGeoTileSpec> &oldTiles);
- bool buildGeometry(const QGeoTileSpec &spec, QSGImageNode *imageNode);
+ bool buildGeometry(const QGeoTileSpec &spec, QSGImageNode *imageNode, bool &overzooming);
void updateTileBounds(const QSet<QGeoTileSpec> &tiles);
void setupCamera();
inline bool isTiltedOrRotated() { return (m_cameraData.tilt() > 0.0) || (m_cameraData.bearing() > 0.0); }
@@ -125,21 +126,31 @@ void QGeoTiledMapScene::setScreenSize(const QSize &size)
d->m_screenSize = size;
}
+void QGeoTiledMapScene::updateSceneParameters()
+{
+ Q_D(QGeoTiledMapScene);
+ d->m_intZoomLevel = static_cast<int>(std::floor(d->m_cameraData.zoomLevel()));
+ const float delta = d->m_cameraData.zoomLevel() - d->m_intZoomLevel;
+ d->m_linearScaling = qAbs(delta) > 0.05 || d->isTiltedOrRotated();
+ d->m_sideLength = 1 << d->m_intZoomLevel;
+ d->m_mapEdgeSize = std::pow(2.0, d->m_cameraData.zoomLevel()) * d->m_tileSize;
+}
+
void QGeoTiledMapScene::setTileSize(int tileSize)
{
Q_D(QGeoTiledMapScene);
+ if (d->m_tileSize == tileSize)
+ return;
+
d->m_tileSize = tileSize;
+ updateSceneParameters();
}
void QGeoTiledMapScene::setCameraData(const QGeoCameraData &cameraData)
{
Q_D(QGeoTiledMapScene);
d->m_cameraData = cameraData;
- d->m_intZoomLevel = static_cast<int>(std::floor(d->m_cameraData.zoomLevel()));
- float delta = cameraData.zoomLevel() - d->m_intZoomLevel;
- d->m_linearScaling = qAbs(delta) > 0.05 || d->isTiltedOrRotated();
- d->m_sideLength = 1 << d->m_intZoomLevel;
- d->m_mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * d->m_tileSize;
+ updateSceneParameters();
}
void QGeoTiledMapScene::setVisibleTiles(const QSet<QGeoTileSpec> &tiles)
@@ -164,9 +175,9 @@ QSet<QGeoTileSpec> QGeoTiledMapScene::texturedTiles()
{
Q_D(QGeoTiledMapScene);
QSet<QGeoTileSpec> textured;
- foreach (const QGeoTileSpec &tile, d->m_textures.keys()) {
- textured += tile;
- }
+ for (auto it = d->m_textures.cbegin(); it != d->m_textures.cend(); ++it)
+ textured += it.value()->spec;
+
return textured;
}
@@ -197,8 +208,9 @@ QGeoTiledMapScenePrivate::~QGeoTiledMapScenePrivate()
{
}
-bool QGeoTiledMapScenePrivate::buildGeometry(const QGeoTileSpec &spec, QSGImageNode *imageNode)
+bool QGeoTiledMapScenePrivate::buildGeometry(const QGeoTileSpec &spec, QSGImageNode *imageNode, bool &overzooming)
{
+ overzooming = false;
int x = spec.x();
if (x < m_tileXWrapsBelow)
@@ -227,7 +239,25 @@ bool QGeoTiledMapScenePrivate::buildGeometry(const QGeoTileSpec &spec, QSGImageN
imageNode->setRect(QRectF(QPointF(x1, y2), QPointF(x2, y1)));
imageNode->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically);
- imageNode->setSourceRect(QRectF(QPointF(0,0), imageNode->texture()->textureSize()));
+
+ // Calculate the texture mapping, in case we are magnifying some lower ZL tile
+ const auto it = m_textures.find(spec); // This should be always found, but apparently sometimes it isn't, possibly due to memory shortage
+ if (it != m_textures.end()) {
+ if (it.value()->spec.zoom() < spec.zoom()) {
+ // Currently only using lower ZL tiles for the overzoom.
+ const int tilesPerTexture = 1 << (spec.zoom() - it.value()->spec.zoom());
+ const int mappedSize = imageNode->texture()->textureSize().width() / tilesPerTexture;
+ const int x = (spec.x() % tilesPerTexture) * mappedSize;
+ const int y = (spec.y() % tilesPerTexture) * mappedSize;
+ imageNode->setSourceRect(QRectF(x, y, mappedSize, mappedSize));
+ overzooming = true;
+ } else {
+ imageNode->setSourceRect(QRectF(QPointF(0,0), imageNode->texture()->textureSize()));
+ }
+ } else {
+ qWarning() << "!! buildGeometry: tileSpec not present in m_textures !!";
+ imageNode->setSourceRect(QRectF(QPointF(0,0), imageNode->texture()->textureSize()));
+ }
return true;
}
@@ -237,6 +267,8 @@ void QGeoTiledMapScenePrivate::addTile(const QGeoTileSpec &spec, QSharedPointer<
if (!m_visibleTiles.contains(spec)) // Don't add the geometry if it isn't visible
return;
+ if (m_textures.contains(spec))
+ m_updatedTextures.append(spec);
m_textures.insert(spec, texture);
}
@@ -350,7 +382,7 @@ void QGeoTiledMapScenePrivate::updateTileBounds(const QSet<QGeoTileSpec> &tiles)
void QGeoTiledMapScenePrivate::setupCamera()
{
// NOTE: The following instruction is correct only because WebMercator is a square projection!
- double f = 1.0 * qMin(m_screenSize.width(), m_screenSize.height());
+ double f = m_screenSize.height();
// Using fraction of zoom level, z varies between [ m_tileSize , 2 * m_tileSize [
double z = std::pow(2.0, m_cameraData.zoomLevel() - m_intZoomLevel) * m_tileSize;
@@ -431,11 +463,8 @@ void QGeoTiledMapScenePrivate::setupCamera()
double aspectRatio = 1.0 * m_screenSize.width() / m_screenSize.height();
float halfWidth = 1 * apertureSize;
float halfHeight = 1 * apertureSize;
- if (aspectRatio > 1.0) {
- halfWidth *= aspectRatio;
- } else if (aspectRatio > 0.0f && aspectRatio < 1.0f) {
- halfHeight /= aspectRatio;
- }
+ halfWidth *= aspectRatio;
+
m_projectionMatrix.setToIdentity();
m_projectionMatrix.frustum(-halfWidth, halfWidth, -halfHeight, halfHeight, nearPlane, farPlane);
}
@@ -549,19 +578,19 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root,
cameraMatrix.lookAt(toVector3D(eye), toVector3D(center), toVector3D(d->m_cameraUp));
root->setMatrix(d->m_projectionMatrix * cameraMatrix);
- QSet<QGeoTileSpec> tilesInSG = QSet<QGeoTileSpec>::fromList(root->tiles.keys());
- QSet<QGeoTileSpec> toRemove = tilesInSG - d->m_visibleTiles;
- QSet<QGeoTileSpec> toAdd = d->m_visibleTiles - tilesInSG;
+ const QSet<QGeoTileSpec> tilesInSG = QSet<QGeoTileSpec>::fromList(root->tiles.keys());
+ const QSet<QGeoTileSpec> toRemove = tilesInSG - d->m_visibleTiles;
+ const QSet<QGeoTileSpec> toAdd = d->m_visibleTiles - tilesInSG;
- foreach (const QGeoTileSpec &s, toRemove)
+ for (const QGeoTileSpec &s : toRemove)
delete root->tiles.take(s);
bool straight = !d->isTiltedOrRotated();
-
+ bool overzooming;
qreal pixelRatio = window->effectiveDevicePixelRatio();
for (QHash<QGeoTileSpec, QSGImageNode *>::iterator it = root->tiles.begin();
it != root->tiles.end(); ) {
QSGImageNode *node = it.value();
- bool ok = d->buildGeometry(it.key(), node)
+ bool ok = d->buildGeometry(it.key(), node, overzooming)
&& qgeotiledmapscene_isTileInViewport(node->rect(), root->matrix(), straight);
QSGNode::DirtyState dirtyBits = 0;
@@ -575,10 +604,12 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root,
node->setFiltering(QSGTexture::Linear); // With mipmapping QSGTexture::Nearest generates artifacts
node->setMipmapFiltering(QSGTexture::Linear);
} else {
- node->setFiltering(d->m_linearScaling ? QSGTexture::Linear : QSGTexture::Nearest);
+ node->setFiltering((d->m_linearScaling || overzooming) ? QSGTexture::Linear : QSGTexture::Nearest);
}
+#if QT_CONFIG(opengl)
if (ogl)
static_cast<QSGDefaultImageNode *>(node)->setAnisotropyLevel(QSGTexture::Anisotropy16x);
+#endif
dirtyBits |= QSGNode::DirtyMaterial;
}
if (dirtyBits != 0)
@@ -587,23 +618,25 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root,
}
}
- foreach (const QGeoTileSpec &s, toAdd) {
+ for (const QGeoTileSpec &s : toAdd) {
QGeoTileTexture *tileTexture = d->m_textures.value(s).data();
if (!tileTexture || tileTexture->image.isNull())
continue;
QSGImageNode *tileNode = window->createImageNode();
// note: setTexture will update coordinates so do it here, before we buildGeometry
tileNode->setTexture(textures.value(s));
- if (d->buildGeometry(s, tileNode)
+ if (d->buildGeometry(s, tileNode, overzooming)
&& qgeotiledmapscene_isTileInViewport(tileNode->rect(), root->matrix(), straight)) {
if (tileNode->texture()->textureSize().width() > d->m_tileSize * pixelRatio) {
tileNode->setFiltering(QSGTexture::Linear); // with mipmapping QSGTexture::Nearest generates artifacts
tileNode->setMipmapFiltering(QSGTexture::Linear);
} else {
- tileNode->setFiltering(d->m_linearScaling ? QSGTexture::Linear : QSGTexture::Nearest);
+ tileNode->setFiltering((d->m_linearScaling || overzooming) ? QSGTexture::Linear : QSGTexture::Nearest);
}
+#if QT_CONFIG(opengl)
if (ogl)
static_cast<QSGDefaultImageNode *>(tileNode)->setAnisotropyLevel(QSGTexture::Anisotropy16x);
+#endif
root->addChild(s, tileNode);
} else {
delete tileNode;
@@ -636,24 +669,43 @@ QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *win
mapRoot->root->setMatrix(itemSpaceMatrix);
if (d->m_dropTextures) {
- foreach (const QGeoTileSpec &s, mapRoot->tiles->tiles.keys())
+ for (const QGeoTileSpec &s : mapRoot->tiles->tiles.keys())
delete mapRoot->tiles->tiles.take(s);
- foreach (const QGeoTileSpec &s, mapRoot->wrapLeft->tiles.keys())
+ for (const QGeoTileSpec &s : mapRoot->wrapLeft->tiles.keys())
delete mapRoot->wrapLeft->tiles.take(s);
- foreach (const QGeoTileSpec &s, mapRoot->wrapRight->tiles.keys())
+ for (const QGeoTileSpec &s : mapRoot->wrapRight->tiles.keys())
delete mapRoot->wrapRight->tiles.take(s);
- foreach (const QGeoTileSpec &spec, mapRoot->textures.keys())
+ for (const QGeoTileSpec &spec : mapRoot->textures.keys())
mapRoot->textures.take(spec)->deleteLater();
d->m_dropTextures = false;
}
- QSet<QGeoTileSpec> textures = QSet<QGeoTileSpec>::fromList(mapRoot->textures.keys());
- QSet<QGeoTileSpec> toRemove = textures - d->m_visibleTiles;
- QSet<QGeoTileSpec> toAdd = d->m_visibleTiles - textures;
+ // Evicting loZL tiles temporarily used in place of hiZL ones
+ if (d->m_updatedTextures.size()) {
+ const QVector<QGeoTileSpec> &toRemove = d->m_updatedTextures;
+ for (const QGeoTileSpec &s : toRemove) {
+ if (mapRoot->tiles->tiles.contains(s))
+ delete mapRoot->tiles->tiles.take(s);
+
+ if (mapRoot->wrapLeft->tiles.contains(s))
+ delete mapRoot->wrapLeft->tiles.take(s);
+
+ if (mapRoot->wrapRight->tiles.contains(s))
+ delete mapRoot->wrapRight->tiles.take(s);
+
+ if (mapRoot->textures.contains(s))
+ mapRoot->textures.take(s)->deleteLater();
+ }
+ d->m_updatedTextures.clear();
+ }
+
+ const QSet<QGeoTileSpec> textures = QSet<QGeoTileSpec>::fromList(mapRoot->textures.keys());
+ const QSet<QGeoTileSpec> toRemove = textures - d->m_visibleTiles;
+ const QSet<QGeoTileSpec> toAdd = d->m_visibleTiles - textures;
- foreach (const QGeoTileSpec &spec, toRemove)
+ for (const QGeoTileSpec &spec : toRemove)
mapRoot->textures.take(spec)->deleteLater();
- foreach (const QGeoTileSpec &spec, toAdd) {
+ for (const QGeoTileSpec &spec : toAdd) {
QGeoTileTexture *tileTexture = d->m_textures.value(spec).data();
if (!tileTexture || tileTexture->image.isNull())
continue;