Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qgeotiledmapscene.cpp
Go to the documentation of this file.
1// Copyright (C) 2015 The Qt Company Ltd.
2// Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
10
11#include <QtQuick/QQuickWindow>
12#include <QtGui/QVector3D>
13
14#include <QtCore/private/qobject_p.h>
15#include <QtPositioning/private/qdoublevector3d_p.h>
16#include <QtPositioning/private/qlocationutils_p.h>
17#include <QtPositioning/private/qdoublematrix4x4_p.h>
18#include <QtPositioning/private/qwebmercator_p.h>
19
20#include <cmath>
21
22static QVector3D toVector3D(const QDoubleVector3D& in)
23{
24 return QVector3D(in.x(), in.y(), in.z());
25}
26
27QT_BEGIN_NAMESPACE
28
29QGeoTiledMapScene::QGeoTiledMapScene(QObject *parent)
30 : QObject(*new QGeoTiledMapScenePrivate(),parent)
31{
32}
33
34QGeoTiledMapScene::~QGeoTiledMapScene()
35{
36}
37
38void QGeoTiledMapScene::setScreenSize(const QSize &size)
39{
40 Q_D(QGeoTiledMapScene);
41 d->m_screenSize = size;
42}
43
44void QGeoTiledMapScene::updateSceneParameters()
45{
46 Q_D(QGeoTiledMapScene);
47 d->m_intZoomLevel = static_cast<int>(std::floor(d->m_cameraData.zoomLevel()));
48 const float delta = d->m_cameraData.zoomLevel() - d->m_intZoomLevel;
49 d->m_linearScaling = qAbs(delta) > 0.05 || d->isTiltedOrRotated();
50 d->m_sideLength = 1 << d->m_intZoomLevel;
51}
52
53void QGeoTiledMapScene::setTileSize(int tileSize)
54{
55 Q_D(QGeoTiledMapScene);
56 if (d->m_tileSize == tileSize)
57 return;
58
59 d->m_tileSize = tileSize;
60 updateSceneParameters();
61}
62
63void QGeoTiledMapScene::setCameraData(const QGeoCameraData &cameraData)
64{
65 Q_D(QGeoTiledMapScene);
66 d->m_cameraData = cameraData;
67 updateSceneParameters();
68}
69
70void QGeoTiledMapScene::setVisibleArea(const QRectF &visibleArea)
71{
72 Q_D(QGeoTiledMapScene);
73 if (d->m_visibleArea == visibleArea)
74 return;
75 d->m_visibleArea = visibleArea;
76 updateSceneParameters();
77}
78
79void QGeoTiledMapScene::setVisibleTiles(const QSet<QGeoTileSpec> &tiles)
80{
81 Q_D(QGeoTiledMapScene);
82 d->setVisibleTiles(tiles);
83}
84
85const QSet<QGeoTileSpec> &QGeoTiledMapScene::visibleTiles() const
86{
87 Q_D(const QGeoTiledMapScene);
88 return d->m_visibleTiles;
89}
90
91void QGeoTiledMapScene::addTile(const QGeoTileSpec &spec, QSharedPointer<QGeoTileTexture> texture)
92{
93 Q_D(QGeoTiledMapScene);
94 d->addTile(spec, texture);
95}
96
97QSet<QGeoTileSpec> QGeoTiledMapScene::texturedTiles()
98{
99 Q_D(QGeoTiledMapScene);
100 QSet<QGeoTileSpec> textured;
101 for (auto it = d->m_textures.cbegin(); it != d->m_textures.cend(); ++it)
102 textured += it.value()->spec;
103
104 return textured;
105}
106
107void QGeoTiledMapScene::clearTexturedTiles()
108{
109 Q_D(QGeoTiledMapScene);
110 d->m_textures.clear();
111 d->m_dropTextures = true;
112}
113
114QGeoTiledMapScenePrivate::QGeoTiledMapScenePrivate()
115 : QObjectPrivate()
116{
117}
118
119QGeoTiledMapScenePrivate::~QGeoTiledMapScenePrivate()
120{
121}
122
123bool QGeoTiledMapScenePrivate::buildGeometry(const QGeoTileSpec &spec, QSGImageNode *imageNode, bool &overzooming)
124{
125 overzooming = false;
126 int x = spec.x();
127
128 if (x < m_tileXWrapsBelow)
129 x += m_sideLength;
130
131 if ((x < m_minTileX)
132 || (m_maxTileX < x)
133 || (spec.y() < m_minTileY)
134 || (m_maxTileY < spec.y())
135 || (spec.zoom() != m_intZoomLevel)) {
136 return false;
137 }
138
139 double edge = m_scaleFactor * m_tileSize;
140
141 double x1 = (x - m_minTileX);
142 double x2 = x1 + 1.0;
143
144 double y1 = (m_minTileY - spec.y());
145 double y2 = y1 - 1.0;
146
147 x1 *= edge;
148 x2 *= edge;
149 y1 *= edge;
150 y2 *= edge;
151
152 imageNode->setRect(QRectF(QPointF(x1, y2), QPointF(x2, y1)));
153 imageNode->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically);
154
155 // Calculate the texture mapping, in case we are magnifying some lower ZL tile
156 const auto it = m_textures.find(spec); // This should be always found, but apparently sometimes it isn't, possibly due to memory shortage
157 if (it != m_textures.end()) {
158 if (it.value()->spec.zoom() < spec.zoom()) {
159 // Currently only using lower ZL tiles for the overzoom.
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));
165 overzooming = true;
166 } else {
167 imageNode->setSourceRect(QRectF(QPointF(0,0), imageNode->texture()->textureSize()));
168 }
169 } else {
170 qWarning() << "!! buildGeometry: tileSpec not present in m_textures !!";
171 imageNode->setSourceRect(QRectF(QPointF(0,0), imageNode->texture()->textureSize()));
172 }
173
174 return true;
175}
176
177void QGeoTiledMapScenePrivate::addTile(const QGeoTileSpec &spec, QSharedPointer<QGeoTileTexture> texture)
178{
179 if (!m_visibleTiles.contains(spec)) // Don't add the geometry if it isn't visible
180 return;
181
182 if (m_textures.contains(spec))
183 m_updatedTextures.append(spec);
184 m_textures.insert(spec, texture);
185}
186
187void QGeoTiledMapScenePrivate::setVisibleTiles(const QSet<QGeoTileSpec> &visibleTiles)
188{
189 // work out the tile bounds for the new scene
190 updateTileBounds(visibleTiles);
191
192 // set up the gl camera for the new scene
193 setupCamera();
194
195 QSet<QGeoTileSpec> toRemove = m_visibleTiles - visibleTiles;
196 if (!toRemove.isEmpty())
197 removeTiles(toRemove);
198
199 m_visibleTiles = visibleTiles;
200}
201
202void QGeoTiledMapScenePrivate::removeTiles(const QSet<QGeoTileSpec> &oldTiles)
203{
204 typedef QSet<QGeoTileSpec>::const_iterator iter;
205 iter i = oldTiles.constBegin();
206 iter end = oldTiles.constEnd();
207
208 for (; i != end; ++i) {
209 QGeoTileSpec tile = *i;
210 m_textures.remove(tile);
211 }
212}
213
214void QGeoTiledMapScenePrivate::updateTileBounds(const QSet<QGeoTileSpec> &tiles)
215{
216 if (tiles.isEmpty()) {
217 m_minTileX = -1;
218 m_minTileY = -1;
219 m_maxTileX = -1;
220 m_maxTileY = -1;
221 return;
222 }
223
224 typedef QSet<QGeoTileSpec>::const_iterator iter;
225 iter i = tiles.constBegin();
226 iter end = tiles.constEnd();
227
228 // determine whether the set of map tiles crosses the dateline.
229 // A gap in the tiles indicates dateline crossing
230 bool hasFarLeft = false;
231 bool hasFarRight = false;
232 bool hasMidLeft = false;
233 bool hasMidRight = false;
234
235 for (; i != end; ++i) {
236 if ((*i).zoom() != m_intZoomLevel)
237 continue;
238 int x = (*i).x();
239 if (x == 0)
240 hasFarLeft = true;
241 else if (x == (m_sideLength - 1))
242 hasFarRight = true;
243 else if (x == ((m_sideLength / 2) - 1)) {
244 hasMidLeft = true;
245 } else if (x == (m_sideLength / 2)) {
246 hasMidRight = true;
247 }
248 }
249
250 // if dateline crossing is detected we wrap all x pos of tiles
251 // that are in the left half of the map.
252 m_tileXWrapsBelow = 0;
253
254 if (hasFarLeft && hasFarRight) {
255 if (!hasMidRight) {
256 m_tileXWrapsBelow = m_sideLength / 2;
257 } else if (!hasMidLeft) {
258 m_tileXWrapsBelow = (m_sideLength / 2) - 1;
259 }
260 }
261
262 // finally, determine the min and max bounds
263 i = tiles.constBegin();
264
265 QGeoTileSpec tile = *i;
266
267 int x = tile.x();
268 if (tile.x() < m_tileXWrapsBelow)
269 x += m_sideLength;
270
271 m_minTileX = x;
272 m_maxTileX = x;
273 m_minTileY = tile.y();
274 m_maxTileY = tile.y();
275
276 ++i;
277
278 for (; i != end; ++i) {
279 tile = *i;
280 if (tile.zoom() != m_intZoomLevel)
281 continue;
282
283 int x = tile.x();
284 if (tile.x() < m_tileXWrapsBelow)
285 x += m_sideLength;
286
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());
291 }
292}
293
294void QGeoTiledMapScenePrivate::setupCamera()
295{
296 // NOTE: The following instruction is correct only because WebMercator is a square projection!
297 double f = m_screenSize.height();
298
299 // Using fraction of zoom level, z varies between [ m_tileSize , 2 * m_tileSize [
300 double z = std::pow(2.0, m_cameraData.zoomLevel() - m_intZoomLevel) * m_tileSize;
301
302 // calculate altitude that allows the visible map tiles
303 // to fit in the screen correctly (note that a larger f will cause
304 // the camera be higher, resulting in gray areas displayed around
305 // the tiles)
306 double altitude = f / (2.0 * z);
307
308 // calculate center
309 double edge = m_scaleFactor * m_tileSize;
310
311 // first calculate the camera center in map space in the range of 0 <-> sideLength (2^z)
312 QDoubleVector2D camCenterMercator = QWebMercator::coordToMercator(m_cameraData.center());
313 QDoubleVector3D center = (m_sideLength * camCenterMercator);
314
315 // wrap the center if necessary (due to dateline crossing)
316 if (center.x() < m_tileXWrapsBelow)
317 center.setX(center.x() + 1.0 * m_sideLength);
318
319 // work out where the camera center is w.r.t minimum tile bounds
320 center.setX(center.x() - 1.0 * m_minTileX);
321 center.setY(1.0 * m_minTileY - center.y());
322
323 // apply necessary scaling to the camera center
324 center *= edge;
325
326 // calculate eye
327 double apertureSize = 1.0;
328 if (m_cameraData.fieldOfView() != 90.0) //aperture(90 / 2) = 1
329 apertureSize = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5);
330 QDoubleVector3D eye = center;
331 eye.setZ(altitude * edge / apertureSize);
332
333 // calculate up
334
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);
338
339 // old bearing, tilt and roll code.
340 // Now using double matrices until distilling the transformation to QMatrix4x4
341 QDoubleMatrix4x4 mBearing;
342 // -1.0 * bearing removed, now map north goes in the bearing direction
343 mBearing.rotate(-1.0 * m_cameraData.bearing(), view);
344 up = mBearing * up;
345
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;
351 }
352
353 view = eye - center;
354 view.normalize();
355 side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
356 up = QDoubleVector3D::normal(view, side2);
357
358 // QMatrix4x4 mRoll;
359 // mRoll.rotate(camera.roll(), view);
360 // up = mRoll * up;
361
362 // near plane and far plane
363
364 double nearPlane = 1.0;
365 // Clip plane. Used to be (altitude + 1.0) * edge. This does not affect the perspective. minimum value would be > 0.0
366 // Since, for some reasons possibly related to how QSG works, this clipping plane is unable to clip part of tiles,
367 // Instead of farPlane = (altitude + m_cameraData.clipDistance()) * edge , we use a fixed large clipDistance, and
368 // leave the clipping only in QGeoCameraTiles::createFrustum
369 double farPlane = (altitude + 10000.0) * edge;
370
371 m_cameraUp = up;
372 m_cameraCenter = center;
373 m_cameraEye = eye;
374
375 double aspectRatio = 1.0 * m_screenSize.width() / m_screenSize.height();
376 float halfWidth = 1 * apertureSize;
377 float halfHeight = 1 * apertureSize;
378 halfWidth *= aspectRatio;
379
380// m_projectionMatrix.setToIdentity();
381// m_projectionMatrix.frustum(-halfWidth, halfWidth, -halfHeight, halfHeight, nearPlane, farPlane);
382
383 QRectF va = m_visibleArea;
384 if (va.isNull())
385 va = QRectF(0, 0, m_screenSize.width(), m_screenSize.height());
386
387 QRectF screen = QRectF(QPointF(0,0),m_screenSize);
388 QPointF vaCenter = va.center();
389
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());
394
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;
400
401 m_projectionMatrix.frustum(l,
402 r,
403 b,
404 t,
405 nearPlane, farPlane);
406}
407
408static bool qgeotiledmapscene_isTileInViewport_Straight(const QRectF &tileRect, const QMatrix4x4 &matrix)
409{
410 const QRectF boundingRect = QRectF(matrix.map(tileRect.topLeft()), matrix.map(tileRect.bottomRight()));
411 return QRectF(-1, -1, 2, 2).intersects(boundingRect);
412}
413
414static bool qgeotiledmapscene_isTileInViewport_rotationTilt(const QRectF &tileRect, const QMatrix4x4 &matrix)
415{
416 // Transformed corners
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());
421
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()))
426 );
427 return QRectF(-1, -1, 2, 2).intersects(boundingRect);
428}
429
430static bool qgeotiledmapscene_isTileInViewport(const QRectF &tileRect, const QMatrix4x4 &matrix, const bool straight)
431{
432 if (straight)
433 return qgeotiledmapscene_isTileInViewport_Straight(tileRect, matrix);
434 return qgeotiledmapscene_isTileInViewport_rotationTilt(tileRect, matrix);
435}
436
437void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root,
438 QGeoTiledMapScenePrivate *d,
439 double camAdjust,
440 QQuickWindow *window)
441{
442 // Set up the matrix...
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);
450
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;
456
457 for (const QGeoTileSpec &s : toRemove)
458 delete root->tiles.take(s);
459 bool straight = !d->isTiltedOrRotated();
460 bool overzooming;
461 qreal pixelRatio = window->effectiveDevicePixelRatio();
462#ifdef QT_LOCATION_DEBUG
463 QList<QGeoTileSpec> droppedTiles;
464#endif
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);
470
471 QSGNode::DirtyState dirtyBits = {};
472
473 if (!ok) {
474#ifdef QT_LOCATION_DEBUG
475 droppedTiles.append(it.key());
476#endif
477 it = root->tiles.erase(it);
478 delete node;
479 } else {
480 if (isTextureLinear != d->m_linearScaling) {
481 if (node->texture()->textureSize().width() > d->m_tileSize * pixelRatio) {
482 node->setFiltering(QSGTexture::Linear); // With mipmapping QSGTexture::Nearest generates artifacts
483 node->setMipmapFiltering(QSGTexture::Linear);
484 } else {
485 node->setFiltering((d->m_linearScaling || overzooming) ? QSGTexture::Linear : QSGTexture::Nearest);
486 }
487 dirtyBits |= QSGNode::DirtyMaterial;
488 }
489 if (dirtyBits != 0)
490 node->markDirty(dirtyBits);
491 it++;
492 }
493 }
494
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);
500#endif
501 continue;
502 }
503 QSGImageNode *tileNode = window->createImageNode();
504 // note: setTexture will update coordinates so do it here, before we buildGeometry
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); // with mipmapping QSGTexture::Nearest generates artifacts
510 tileNode->setMipmapFiltering(QSGTexture::Linear);
511 } else {
512 tileNode->setFiltering((d->m_linearScaling || overzooming) ? QSGTexture::Linear : QSGTexture::Nearest);
513 }
514 root->addChild(s, tileNode);
515 } else {
516#ifdef QT_LOCATION_DEBUG
517 droppedTiles.append(s);
518#endif
519 delete tileNode;
520 }
521 }
522
523#ifdef QT_LOCATION_DEBUG
524 m_droppedTiles[camAdjust] = droppedTiles;
525#endif
526}
527
528QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *window)
529{
530 Q_D(QGeoTiledMapScene);
531 float w = d->m_screenSize.width();
532 float h = d->m_screenSize.height();
533 if (w <= 0 || h <= 0) {
534 delete oldNode;
535 return nullptr;
536 }
537
538 QGeoTiledMapRootNode *mapRoot = static_cast<QGeoTiledMapRootNode *>(oldNode);
539 if (!mapRoot)
540 mapRoot = new QGeoTiledMapRootNode();
541
542#ifdef QT_LOCATION_DEBUG
543 mapRoot->m_droppedTiles.clear();
544 d->m_mapRoot = mapRoot;
545#endif
546
547 // Setting clip rect to fullscreen, as now the map can never be smaller than the viewport.
548 mapRoot->setClipRect(QRect(0, 0, w, h));
549
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);
555
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;
566 }
567
568 // Evicting loZL tiles temporarily used in place of hiZL ones
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);
574
575 if (mapRoot->wrapLeft->tiles.contains(s))
576 delete mapRoot->wrapLeft->tiles.take(s);
577
578 if (mapRoot->wrapRight->tiles.contains(s))
579 delete mapRoot->wrapRight->tiles.take(s);
580
581 if (mapRoot->textures.contains(s))
582 mapRoot->textures.take(s)->deleteLater();
583 }
584 d->m_updatedTextures.clear();
585 }
586
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;
592
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())
598 continue;
599 mapRoot->textures.insert(spec, window->createTextureFromImage(tileTexture->image));
600 }
601
602 double sideLength = d->m_scaleFactor * d->m_tileSize * d->m_sideLength;
603#ifdef QT_LOCATION_DEBUG
604 d->m_sideLengthPixel = sideLength;
605#endif
606 mapRoot->updateTiles(mapRoot->tiles, d, 0, window);
607 mapRoot->updateTiles(mapRoot->wrapLeft, d, +sideLength, window);
608 mapRoot->updateTiles(mapRoot->wrapRight, d, -sideLength, window);
609
610 mapRoot->isTextureLinear = d->m_linearScaling;
611
612 return mapRoot;
613}
614
615QT_END_NAMESPACE
static bool qgeotiledmapscene_isTileInViewport_rotationTilt(const QRectF &tileRect, const QMatrix4x4 &matrix)
static bool qgeotiledmapscene_isTileInViewport(const QRectF &tileRect, const QMatrix4x4 &matrix, const bool straight)
static bool qgeotiledmapscene_isTileInViewport_Straight(const QRectF &tileRect, const QMatrix4x4 &matrix)
static QVector3D toVector3D(const QDoubleVector3D &in)