124bool QGeoTiledMapScenePrivate::buildGeometry(
const QGeoTileSpec &spec, QSGImageNode *imageNode,
bool &overzooming)
129 if (x < m_tileXWrapsBelow)
134 || (spec.y() < m_minTileY)
135 || (m_maxTileY < spec.y())
136 || (spec.zoom() != m_intZoomLevel)) {
140 double edge = m_scaleFactor * m_tileSize;
142 double x1 = (x - m_minTileX);
143 double x2 = x1 + 1.0;
145 double y1 = (m_minTileY - spec.y());
146 double y2 = y1 - 1.0;
153 imageNode->setRect(QRectF(QPointF(x1, y2), QPointF(x2, y1)));
154 imageNode->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically);
157 const auto it = m_textures.find(spec);
158 if (it != m_textures.end()) {
159 if (it.value()->spec.zoom() < spec.zoom()) {
161 const int tilesPerTexture = 1 << (spec.zoom() - it.value()->spec.zoom());
162 const int mappedSize = imageNode->texture()->textureSize().width() / tilesPerTexture;
163 const int x = (spec.x() % tilesPerTexture) * mappedSize;
164 const int y = (spec.y() % tilesPerTexture) * mappedSize;
165 imageNode->setSourceRect(QRectF(x, y, mappedSize, mappedSize));
168 imageNode->setSourceRect(QRectF(QPointF(0,0), imageNode->texture()->textureSize()));
171 qWarning() <<
"!! buildGeometry: tileSpec not present in m_textures !!";
172 imageNode->setSourceRect(QRectF(QPointF(0,0), imageNode->texture()->textureSize()));
215void QGeoTiledMapScenePrivate::updateTileBounds(
const QSet<QGeoTileSpec> &tiles)
217 if (tiles.isEmpty()) {
225 typedef QSet<QGeoTileSpec>::const_iterator iter;
226 iter i = tiles.constBegin();
227 iter end = tiles.constEnd();
231 bool hasFarLeft =
false;
232 bool hasFarRight =
false;
233 bool hasMidLeft =
false;
234 bool hasMidRight =
false;
236 for (; i != end; ++i) {
237 if ((*i).zoom() != m_intZoomLevel)
242 else if (x == (m_sideLength - 1))
244 else if (x == ((m_sideLength / 2) - 1)) {
246 }
else if (x == (m_sideLength / 2)) {
253 m_tileXWrapsBelow = 0;
255 if (hasFarLeft && hasFarRight) {
257 m_tileXWrapsBelow = m_sideLength / 2;
258 }
else if (!hasMidLeft) {
259 m_tileXWrapsBelow = (m_sideLength / 2) - 1;
264 i = tiles.constBegin();
266 QGeoTileSpec tile = *i;
269 if (tile.x() < m_tileXWrapsBelow)
274 m_minTileY = tile.y();
275 m_maxTileY = tile.y();
279 for (; i != end; ++i) {
281 if (tile.zoom() != m_intZoomLevel)
285 if (tile.x() < m_tileXWrapsBelow)
288 m_minTileX = qMin(m_minTileX, x);
289 m_maxTileX = qMax(m_maxTileX, x);
290 m_minTileY = qMin(m_minTileY, tile.y());
291 m_maxTileY = qMax(m_maxTileY, tile.y());
295void QGeoTiledMapScenePrivate::setupCamera()
298 double f = m_screenSize.height();
301 double z = std::pow(2.0, m_cameraData.zoomLevel() - m_intZoomLevel) * m_tileSize;
307 double altitude = f / (2.0 * z);
310 double edge = m_scaleFactor * m_tileSize;
313 QDoubleVector2D camCenterMercator = QWebMercator::coordToMercator(m_cameraData.center());
314 QDoubleVector3D center = (m_sideLength * camCenterMercator);
317 if (center.x() < m_tileXWrapsBelow)
318 center.setX(center.x() + 1.0 * m_sideLength);
321 center.setX(center.x() - 1.0 * m_minTileX);
322 center.setY(1.0 * m_minTileY - center.y());
328 double apertureSize = 1.0;
329 if (m_cameraData.fieldOfView() != 90.0)
330 apertureSize = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5);
331 QDoubleVector3D eye = center;
332 eye.setZ(altitude * edge / apertureSize);
336 QDoubleVector3D view = eye - center;
337 QDoubleVector3D side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
338 QDoubleVector3D up = QDoubleVector3D::normal(side, view);
342 QDoubleMatrix4x4 mBearing;
344 mBearing.rotate(-1.0 * m_cameraData.bearing(), view);
347 QDoubleVector3D side2 = QDoubleVector3D::normal(up, view);
348 if (m_cameraData.tilt() > 0.01) {
349 QDoubleMatrix4x4 mTilt;
350 mTilt.rotate(m_cameraData.tilt(), side2);
351 eye = mTilt * view + center;
356 side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
357 up = QDoubleVector3D::normal(view, side2);
365 double nearPlane = 1.0;
370 double farPlane = (altitude + 10000.0) * edge;
373 m_cameraCenter = center;
376 double aspectRatio = 1.0 * m_screenSize.width() / m_screenSize.height();
377 float halfWidth = 1 * apertureSize;
378 float halfHeight = 1 * apertureSize;
379 halfWidth *= aspectRatio;
384 QRectF va = m_visibleArea;
386 va = QRectF(0, 0, m_screenSize.width(), m_screenSize.height());
388 QRectF screen = QRectF(QPointF(0,0),m_screenSize);
389 QPointF vaCenter = va.center();
391 QPointF screenCenter = screen.center();
392 QPointF diff = screenCenter - vaCenter;
393 float xdiffpct = diff.x() / m_screenSize.width();
394 float ydiffpct = -(diff.y() / m_screenSize.height());
396 m_projectionMatrix.setToIdentity();
397 float l = -halfWidth + (2 * halfWidth) * xdiffpct;
398 float r = halfWidth + (2 * halfWidth) * xdiffpct;
399 float t = halfHeight + (2 * halfHeight) * ydiffpct;
400 float b = -halfHeight + (2 * halfHeight) * ydiffpct;
402 m_projectionMatrix.frustum(l,
406 nearPlane, farPlane);
418 const QPointF tlt = matrix.map(tileRect.topLeft());
419 const QPointF trt = matrix.map(tileRect.topRight());
420 const QPointF blt = matrix.map(tileRect.bottomLeft());
421 const QPointF brt = matrix.map(tileRect.bottomRight());
423 const QRectF boundingRect = QRectF(QPointF(qMin(qMin(qMin(tlt.x(), trt.x()), blt.x()), brt.x())
424 ,qMax(qMax(qMax(tlt.y(), trt.y()), blt.y()), brt.y()))
425 ,QPointF(qMax(qMax(qMax(tlt.x(), trt.x()), blt.x()), brt.x())
426 ,qMin(qMin(qMin(tlt.y(), trt.y()), blt.y()), brt.y()))
428 return QRectF(-1, -1, 2, 2).intersects(boundingRect);
438void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root,
439 QGeoTiledMapScenePrivate *d,
441 QQuickWindow *window)
444 QDoubleVector3D eye = d->m_cameraEye;
445 eye.setX(eye.x() + camAdjust);
446 QDoubleVector3D center = d->m_cameraCenter;
447 center.setX(center.x() + camAdjust);
448 QMatrix4x4 cameraMatrix;
449 cameraMatrix.lookAt(toVector3D(eye), toVector3D(center), toVector3D(d->m_cameraUp));
450 root->setMatrix(d->m_projectionMatrix * cameraMatrix);
452 QSet<QGeoTileSpec> tilesInSG;
453 for (
auto it = root->tiles.cbegin(), end = root->tiles.cend(); it != end; ++it)
454 tilesInSG.insert(it.key());
455 const QSet<QGeoTileSpec> toRemove = tilesInSG - d->m_visibleTiles;
456 const QSet<QGeoTileSpec> toAdd = d->m_visibleTiles - tilesInSG;
458 for (
const QGeoTileSpec &s : toRemove)
459 delete root->tiles.take(s);
460 bool straight = !d->isTiltedOrRotated();
462 qreal pixelRatio = window->effectiveDevicePixelRatio();
463#ifdef QT_LOCATION_DEBUG
464 QList<QGeoTileSpec> droppedTiles;
466 for (QHash<QGeoTileSpec, QSGImageNode *>::iterator it = root->tiles.begin();
467 it != root->tiles.end(); ) {
468 QSGImageNode *node = it.value();
469 bool ok = d->buildGeometry(it.key(), node, overzooming)
470 && qgeotiledmapscene_isTileInViewport(node->rect(), root->matrix(), straight);
472 QSGNode::DirtyState dirtyBits = {};
475#ifdef QT_LOCATION_DEBUG
476 droppedTiles.append(it.key());
478 it = root->tiles.erase(it);
481 if (isTextureLinear != d->m_linearScaling) {
482 if (node->texture()->textureSize().width() > d->m_tileSize * pixelRatio) {
483 node->setFiltering(QSGTexture::Linear);
484 node->setMipmapFiltering(QSGTexture::Linear);
486 node->setFiltering((d->m_linearScaling || overzooming) ? QSGTexture::Linear : QSGTexture::Nearest);
488 dirtyBits |= QSGNode::DirtyMaterial;
491 node->markDirty(dirtyBits);
496 for (
const QGeoTileSpec &s : toAdd) {
497 QGeoTileTexture *tileTexture = d->m_textures.value(s).data();
498 if (!tileTexture || tileTexture->image.isNull()) {
499#ifdef QT_LOCATION_DEBUG
500 droppedTiles.append(s);
504 QSGImageNode *tileNode = window->createImageNode();
506 tileNode->setTexture(textures.value(s));
507 if (d->buildGeometry(s, tileNode, overzooming)
508 && qgeotiledmapscene_isTileInViewport(tileNode->rect(), root->matrix(), straight)) {
509 if (tileNode->texture()->textureSize().width() > d->m_tileSize * pixelRatio) {
510 tileNode->setFiltering(QSGTexture::Linear);
511 tileNode->setMipmapFiltering(QSGTexture::Linear);
513 tileNode->setFiltering((d->m_linearScaling || overzooming) ? QSGTexture::Linear : QSGTexture::Nearest);
515 root->addChild(s, tileNode);
517#ifdef QT_LOCATION_DEBUG
518 droppedTiles.append(s);
524#ifdef QT_LOCATION_DEBUG
525 m_droppedTiles[camAdjust] = droppedTiles;
529QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *window)
531 Q_D(QGeoTiledMapScene);
532 float w = d->m_screenSize.width();
533 float h = d->m_screenSize.height();
534 if (w <= 0 || h <= 0) {
539 QGeoTiledMapRootNode *mapRoot =
static_cast<QGeoTiledMapRootNode *>(oldNode);
541 mapRoot =
new QGeoTiledMapRootNode();
543#ifdef QT_LOCATION_DEBUG
544 mapRoot->m_droppedTiles.clear();
545 d->m_mapRoot = mapRoot;
549 mapRoot->setClipRect(QRect(0, 0, w, h));
551 QMatrix4x4 itemSpaceMatrix;
552 itemSpaceMatrix.scale(w / 2, h / 2);
553 itemSpaceMatrix.translate(1, 1);
554 itemSpaceMatrix.scale(1, -1);
555 mapRoot->root->setMatrix(itemSpaceMatrix);
557 if (d->m_dropTextures) {
558 for (
const QGeoTileSpec &s : mapRoot->tiles->tiles.keys())
559 delete mapRoot->tiles->tiles.take(s);
560 for (
const QGeoTileSpec &s : mapRoot->wrapLeft->tiles.keys())
561 delete mapRoot->wrapLeft->tiles.take(s);
562 for (
const QGeoTileSpec &s : mapRoot->wrapRight->tiles.keys())
563 delete mapRoot->wrapRight->tiles.take(s);
564 for (
const QGeoTileSpec &spec : mapRoot->textures.keys())
565 mapRoot->textures.take(spec)->deleteLater();
566 d->m_dropTextures =
false;
570 if (d->m_updatedTextures.size()) {
571 const QList<QGeoTileSpec> &toRemove = d->m_updatedTextures;
572 for (
const QGeoTileSpec &s : toRemove) {
573 if (mapRoot->tiles->tiles.contains(s))
574 delete mapRoot->tiles->tiles.take(s);
576 if (mapRoot->wrapLeft->tiles.contains(s))
577 delete mapRoot->wrapLeft->tiles.take(s);
579 if (mapRoot->wrapRight->tiles.contains(s))
580 delete mapRoot->wrapRight->tiles.take(s);
582 if (mapRoot->textures.contains(s))
583 mapRoot->textures.take(s)->deleteLater();
585 d->m_updatedTextures.clear();
588 QSet<QGeoTileSpec> textures;
589 for (
auto it = mapRoot->textures.cbegin(), end = mapRoot->textures.cend(); it != end; ++it)
590 textures.insert(it.key());
591 const QSet<QGeoTileSpec> toRemove = textures - d->m_visibleTiles;
592 const QSet<QGeoTileSpec> toAdd = d->m_visibleTiles - textures;
594 for (
const QGeoTileSpec &spec : toRemove)
595 mapRoot->textures.take(spec)->deleteLater();
596 for (
const QGeoTileSpec &spec : toAdd) {
597 QGeoTileTexture *tileTexture = d->m_textures.value(spec).data();
598 if (!tileTexture || tileTexture->image.isNull())
600 mapRoot->textures.insert(spec, window->createTextureFromImage(tileTexture->image));
603 double sideLength = d->m_scaleFactor * d->m_tileSize * d->m_sideLength;
604#ifdef QT_LOCATION_DEBUG
605 d->m_sideLengthPixel = sideLength;
607 mapRoot->updateTiles(mapRoot->tiles, d, 0, window);
608 mapRoot->updateTiles(mapRoot->wrapLeft, d, +sideLength, window);
609 mapRoot->updateTiles(mapRoot->wrapRight, d, -sideLength, window);
611 mapRoot->isTextureLinear = d->m_linearScaling;