123bool QGeoTiledMapScenePrivate::buildGeometry(
const QGeoTileSpec &spec, QSGImageNode *imageNode,
bool &overzooming)
128 if (x < m_tileXWrapsBelow)
133 || (spec.y() < m_minTileY)
134 || (m_maxTileY < spec.y())
135 || (spec.zoom() != m_intZoomLevel)) {
139 double edge = m_scaleFactor * m_tileSize;
141 double x1 = (x - m_minTileX);
142 double x2 = x1 + 1.0;
144 double y1 = (m_minTileY - spec.y());
145 double y2 = y1 - 1.0;
152 imageNode->setRect(QRectF(QPointF(x1, y2), QPointF(x2, y1)));
153 imageNode->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically);
156 const auto it = m_textures.find(spec);
157 if (it != m_textures.end()) {
158 if (it.value()->spec.zoom() < spec.zoom()) {
160 const int tilesPerTexture = 1 << (spec.zoom() - it.value()->spec.zoom());
161 const int mappedSize = imageNode->texture()->textureSize().width() / tilesPerTexture;
162 const int x = (spec.x() % tilesPerTexture) * mappedSize;
163 const int y = (spec.y() % tilesPerTexture) * mappedSize;
164 imageNode->setSourceRect(QRectF(x, y, mappedSize, mappedSize));
167 imageNode->setSourceRect(QRectF(QPointF(0,0), imageNode->texture()->textureSize()));
170 qWarning() <<
"!! buildGeometry: tileSpec not present in m_textures !!";
171 imageNode->setSourceRect(QRectF(QPointF(0,0), imageNode->texture()->textureSize()));
214void QGeoTiledMapScenePrivate::updateTileBounds(
const QSet<QGeoTileSpec> &tiles)
216 if (tiles.isEmpty()) {
224 typedef QSet<QGeoTileSpec>::const_iterator iter;
225 iter i = tiles.constBegin();
226 iter end = tiles.constEnd();
230 bool hasFarLeft =
false;
231 bool hasFarRight =
false;
232 bool hasMidLeft =
false;
233 bool hasMidRight =
false;
235 for (; i != end; ++i) {
236 if ((*i).zoom() != m_intZoomLevel)
241 else if (x == (m_sideLength - 1))
243 else if (x == ((m_sideLength / 2) - 1)) {
245 }
else if (x == (m_sideLength / 2)) {
252 m_tileXWrapsBelow = 0;
254 if (hasFarLeft && hasFarRight) {
256 m_tileXWrapsBelow = m_sideLength / 2;
257 }
else if (!hasMidLeft) {
258 m_tileXWrapsBelow = (m_sideLength / 2) - 1;
263 i = tiles.constBegin();
265 QGeoTileSpec tile = *i;
268 if (tile.x() < m_tileXWrapsBelow)
273 m_minTileY = tile.y();
274 m_maxTileY = tile.y();
278 for (; i != end; ++i) {
280 if (tile.zoom() != m_intZoomLevel)
284 if (tile.x() < m_tileXWrapsBelow)
287 m_minTileX = qMin(m_minTileX, x);
288 m_maxTileX = qMax(m_maxTileX, x);
289 m_minTileY = qMin(m_minTileY, tile.y());
290 m_maxTileY = qMax(m_maxTileY, tile.y());
294void QGeoTiledMapScenePrivate::setupCamera()
297 double f = m_screenSize.height();
300 double z = std::pow(2.0, m_cameraData.zoomLevel() - m_intZoomLevel) * m_tileSize;
306 double altitude = f / (2.0 * z);
309 double edge = m_scaleFactor * m_tileSize;
312 QDoubleVector2D camCenterMercator = QWebMercator::coordToMercator(m_cameraData.center());
313 QDoubleVector3D center = (m_sideLength * camCenterMercator);
316 if (center.x() < m_tileXWrapsBelow)
317 center.setX(center.x() + 1.0 * m_sideLength);
320 center.setX(center.x() - 1.0 * m_minTileX);
321 center.setY(1.0 * m_minTileY - center.y());
327 double apertureSize = 1.0;
328 if (m_cameraData.fieldOfView() != 90.0)
329 apertureSize = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5);
330 QDoubleVector3D eye = center;
331 eye.setZ(altitude * edge / apertureSize);
335 QDoubleVector3D view = eye - center;
336 QDoubleVector3D side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
337 QDoubleVector3D up = QDoubleVector3D::normal(side, view);
341 QDoubleMatrix4x4 mBearing;
343 mBearing.rotate(-1.0 * m_cameraData.bearing(), view);
346 QDoubleVector3D side2 = QDoubleVector3D::normal(up, view);
347 if (m_cameraData.tilt() > 0.01) {
348 QDoubleMatrix4x4 mTilt;
349 mTilt.rotate(m_cameraData.tilt(), side2);
350 eye = mTilt * view + center;
355 side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
356 up = QDoubleVector3D::normal(view, side2);
364 double nearPlane = 1.0;
369 double farPlane = (altitude + 10000.0) * edge;
372 m_cameraCenter = center;
375 double aspectRatio = 1.0 * m_screenSize.width() / m_screenSize.height();
376 float halfWidth = 1 * apertureSize;
377 float halfHeight = 1 * apertureSize;
378 halfWidth *= aspectRatio;
383 QRectF va = m_visibleArea;
385 va = QRectF(0, 0, m_screenSize.width(), m_screenSize.height());
387 QRectF screen = QRectF(QPointF(0,0),m_screenSize);
388 QPointF vaCenter = va.center();
390 QPointF screenCenter = screen.center();
391 QPointF diff = screenCenter - vaCenter;
392 float xdiffpct = diff.x() / m_screenSize.width();
393 float ydiffpct = -(diff.y() / m_screenSize.height());
395 m_projectionMatrix.setToIdentity();
396 float l = -halfWidth + (2 * halfWidth) * xdiffpct;
397 float r = halfWidth + (2 * halfWidth) * xdiffpct;
398 float t = halfHeight + (2 * halfHeight) * ydiffpct;
399 float b = -halfHeight + (2 * halfHeight) * ydiffpct;
401 m_projectionMatrix.frustum(l,
405 nearPlane, farPlane);
417 const QPointF tlt = matrix.map(tileRect.topLeft());
418 const QPointF trt = matrix.map(tileRect.topRight());
419 const QPointF blt = matrix.map(tileRect.bottomLeft());
420 const QPointF brt = matrix.map(tileRect.bottomRight());
422 const QRectF boundingRect = QRectF(QPointF(qMin(qMin(qMin(tlt.x(), trt.x()), blt.x()), brt.x())
423 ,qMax(qMax(qMax(tlt.y(), trt.y()), blt.y()), brt.y()))
424 ,QPointF(qMax(qMax(qMax(tlt.x(), trt.x()), blt.x()), brt.x())
425 ,qMin(qMin(qMin(tlt.y(), trt.y()), blt.y()), brt.y()))
427 return QRectF(-1, -1, 2, 2).intersects(boundingRect);
437void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root,
438 QGeoTiledMapScenePrivate *d,
440 QQuickWindow *window)
443 QDoubleVector3D eye = d->m_cameraEye;
444 eye.setX(eye.x() + camAdjust);
445 QDoubleVector3D center = d->m_cameraCenter;
446 center.setX(center.x() + camAdjust);
447 QMatrix4x4 cameraMatrix;
448 cameraMatrix.lookAt(toVector3D(eye), toVector3D(center), toVector3D(d->m_cameraUp));
449 root->setMatrix(d->m_projectionMatrix * cameraMatrix);
451 QSet<QGeoTileSpec> tilesInSG;
452 for (
auto it = root->tiles.cbegin(), end = root->tiles.cend(); it != end; ++it)
453 tilesInSG.insert(it.key());
454 const QSet<QGeoTileSpec> toRemove = tilesInSG - d->m_visibleTiles;
455 const QSet<QGeoTileSpec> toAdd = d->m_visibleTiles - tilesInSG;
457 for (
const QGeoTileSpec &s : toRemove)
458 delete root->tiles.take(s);
459 bool straight = !d->isTiltedOrRotated();
461 qreal pixelRatio = window->effectiveDevicePixelRatio();
462#ifdef QT_LOCATION_DEBUG
463 QList<QGeoTileSpec> droppedTiles;
465 for (QHash<QGeoTileSpec, QSGImageNode *>::iterator it = root->tiles.begin();
466 it != root->tiles.end(); ) {
467 QSGImageNode *node = it.value();
468 bool ok = d->buildGeometry(it.key(), node, overzooming)
469 && qgeotiledmapscene_isTileInViewport(node->rect(), root->matrix(), straight);
471 QSGNode::DirtyState dirtyBits = {};
474#ifdef QT_LOCATION_DEBUG
475 droppedTiles.append(it.key());
477 it = root->tiles.erase(it);
480 if (isTextureLinear != d->m_linearScaling) {
481 if (node->texture()->textureSize().width() > d->m_tileSize * pixelRatio) {
482 node->setFiltering(QSGTexture::Linear);
483 node->setMipmapFiltering(QSGTexture::Linear);
485 node->setFiltering((d->m_linearScaling || overzooming) ? QSGTexture::Linear : QSGTexture::Nearest);
487 dirtyBits |= QSGNode::DirtyMaterial;
490 node->markDirty(dirtyBits);
495 for (
const QGeoTileSpec &s : toAdd) {
496 QGeoTileTexture *tileTexture = d->m_textures.value(s).data();
497 if (!tileTexture || tileTexture->image.isNull()) {
498#ifdef QT_LOCATION_DEBUG
499 droppedTiles.append(s);
503 QSGImageNode *tileNode = window->createImageNode();
505 tileNode->setTexture(textures.value(s));
506 if (d->buildGeometry(s, tileNode, overzooming)
507 && qgeotiledmapscene_isTileInViewport(tileNode->rect(), root->matrix(), straight)) {
508 if (tileNode->texture()->textureSize().width() > d->m_tileSize * pixelRatio) {
509 tileNode->setFiltering(QSGTexture::Linear);
510 tileNode->setMipmapFiltering(QSGTexture::Linear);
512 tileNode->setFiltering((d->m_linearScaling || overzooming) ? QSGTexture::Linear : QSGTexture::Nearest);
514 root->addChild(s, tileNode);
516#ifdef QT_LOCATION_DEBUG
517 droppedTiles.append(s);
523#ifdef QT_LOCATION_DEBUG
524 m_droppedTiles[camAdjust] = droppedTiles;
528QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *window)
530 Q_D(QGeoTiledMapScene);
531 float w = d->m_screenSize.width();
532 float h = d->m_screenSize.height();
533 if (w <= 0 || h <= 0) {
538 QGeoTiledMapRootNode *mapRoot =
static_cast<QGeoTiledMapRootNode *>(oldNode);
540 mapRoot =
new QGeoTiledMapRootNode();
542#ifdef QT_LOCATION_DEBUG
543 mapRoot->m_droppedTiles.clear();
544 d->m_mapRoot = mapRoot;
548 mapRoot->setClipRect(QRect(0, 0, w, h));
550 QMatrix4x4 itemSpaceMatrix;
551 itemSpaceMatrix.scale(w / 2, h / 2);
552 itemSpaceMatrix.translate(1, 1);
553 itemSpaceMatrix.scale(1, -1);
554 mapRoot->root->setMatrix(itemSpaceMatrix);
556 if (d->m_dropTextures) {
557 for (
const QGeoTileSpec &s : mapRoot->tiles->tiles.keys())
558 delete mapRoot->tiles->tiles.take(s);
559 for (
const QGeoTileSpec &s : mapRoot->wrapLeft->tiles.keys())
560 delete mapRoot->wrapLeft->tiles.take(s);
561 for (
const QGeoTileSpec &s : mapRoot->wrapRight->tiles.keys())
562 delete mapRoot->wrapRight->tiles.take(s);
563 for (
const QGeoTileSpec &spec : mapRoot->textures.keys())
564 mapRoot->textures.take(spec)->deleteLater();
565 d->m_dropTextures =
false;
569 if (d->m_updatedTextures.size()) {
570 const QList<QGeoTileSpec> &toRemove = d->m_updatedTextures;
571 for (
const QGeoTileSpec &s : toRemove) {
572 if (mapRoot->tiles->tiles.contains(s))
573 delete mapRoot->tiles->tiles.take(s);
575 if (mapRoot->wrapLeft->tiles.contains(s))
576 delete mapRoot->wrapLeft->tiles.take(s);
578 if (mapRoot->wrapRight->tiles.contains(s))
579 delete mapRoot->wrapRight->tiles.take(s);
581 if (mapRoot->textures.contains(s))
582 mapRoot->textures.take(s)->deleteLater();
584 d->m_updatedTextures.clear();
587 QSet<QGeoTileSpec> textures;
588 for (
auto it = mapRoot->textures.cbegin(), end = mapRoot->textures.cend(); it != end; ++it)
589 textures.insert(it.key());
590 const QSet<QGeoTileSpec> toRemove = textures - d->m_visibleTiles;
591 const QSet<QGeoTileSpec> toAdd = d->m_visibleTiles - textures;
593 for (
const QGeoTileSpec &spec : toRemove)
594 mapRoot->textures.take(spec)->deleteLater();
595 for (
const QGeoTileSpec &spec : toAdd) {
596 QGeoTileTexture *tileTexture = d->m_textures.value(spec).data();
597 if (!tileTexture || tileTexture->image.isNull())
599 mapRoot->textures.insert(spec, window->createTextureFromImage(tileTexture->image));
602 double sideLength = d->m_scaleFactor * d->m_tileSize * d->m_sideLength;
603#ifdef QT_LOCATION_DEBUG
604 d->m_sideLengthPixel = sideLength;
606 mapRoot->updateTiles(mapRoot->tiles, d, 0, window);
607 mapRoot->updateTiles(mapRoot->wrapLeft, d, +sideLength, window);
608 mapRoot->updateTiles(mapRoot->wrapRight, d, -sideLength, window);
610 mapRoot->isTextureLinear = d->m_linearScaling;