From f586ea00feb414fb0776aa2bc6fbbb356ac61c32 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Tue, 17 Jan 2017 18:16:41 +0100 Subject: Add rotation/tilting support to QGeoTiledMapScene/QGeoCameraTiles This patch adds rotation and tilting support to QGeoTiledMapScene and QGeoCameraTiles. It also adds the related capabilities to the geoservice plugins mapping managers QML Api is added in a separate patch Change-Id: I3de1b52a9928c4856f6ee57ad39191acebe0f770 Reviewed-by: Alex Blasche --- src/location/maps/qgeocameratiles.cpp | 188 +++++++++++++++------ src/location/maps/qgeotiledmapscene.cpp | 140 ++++++++------- .../esri/geotiledmappingmanagerengine_esri.cpp | 7 +- .../mapbox/qgeotiledmappingmanagerenginemapbox.cpp | 6 + .../nokia/qgeotiledmappingmanagerengine_nokia.cpp | 7 +- .../osm/qgeotiledmappingmanagerengineosm.cpp | 6 + tests/auto/declarative_ui/tst_map.qml | 8 +- 7 files changed, 243 insertions(+), 119 deletions(-) diff --git a/src/location/maps/qgeocameratiles.cpp b/src/location/maps/qgeocameratiles.cpp index 0eaa4668..27044ee0 100644 --- a/src/location/maps/qgeocameratiles.cpp +++ b/src/location/maps/qgeocameratiles.cpp @@ -41,12 +41,25 @@ #include #include #include +#include +#include #include #include #include #include #include #include +#include + +static QVector3D toVector3D(const QDoubleVector3D& in) +{ + return QVector3D(in.x(), in.y(), in.z()); +} + +static QDoubleVector3D toDoubleVector3D(const QVector3D& in) +{ + return QDoubleVector3D(in.x(), in.y(), in.z()); +} QT_BEGIN_NAMESPACE @@ -88,7 +101,7 @@ public: void updateMetadata(); void updateGeometry(); - Frustum createFrustum(double fieldOfViewGradient) const; + Frustum createFrustum(double viewExpansion) const; class LengthSorter { @@ -100,11 +113,21 @@ public: } }; + struct ClippedFootprint + { + ClippedFootprint(const PolygonVector &left_, const PolygonVector &mid_, const PolygonVector &right_) + : left(left_), mid(mid_), right(right_) + {} + PolygonVector left; + PolygonVector mid; + PolygonVector right; + }; + void appendZIntersects(const QDoubleVector3D &start, const QDoubleVector3D &end, double z, QVector &results) const; PolygonVector frustumFootprint(const Frustum &frustum) const; QPair splitPolygonAtAxisValue(const PolygonVector &polygon, int axis, double value) const; - QPair clipFootprintToMap(const PolygonVector &footprint) const; + ClippedFootprint clipFootprintToMap(const PolygonVector &footprint) const; QList > tileIntersections(double p1, int t1, double p2, int t2) const; QSet tilesFromPolygon(const PolygonVector &polygon) const; @@ -259,29 +282,36 @@ void QGeoCameraTilesPrivate::updateGeometry() PolygonVector footprint = frustumFootprint(f); // Clip the polygon to the map, split it up if it cross the dateline - QPair polygons = clipFootprintToMap(footprint); + ClippedFootprint polygons = clipFootprintToMap(footprint); - if (!polygons.first.isEmpty()) { - QSet tilesLeft = tilesFromPolygon(polygons.first); + if (!polygons.left.isEmpty()) { + QSet tilesLeft = tilesFromPolygon(polygons.left); m_tiles.unite(tilesLeft); } - if (!polygons.second.isEmpty()) { - QSet tilesRight = tilesFromPolygon(polygons.second); + if (!polygons.right.isEmpty()) { + QSet tilesRight = tilesFromPolygon(polygons.right); + m_tiles.unite(tilesRight); + } + + if (!polygons.mid.isEmpty()) { + QSet tilesRight = tilesFromPolygon(polygons.mid); m_tiles.unite(tilesRight); } } -Frustum QGeoCameraTilesPrivate::createFrustum(double fieldOfViewGradient) const +Frustum QGeoCameraTilesPrivate::createFrustum(double viewExpansion) const { + double apertureSize = 1.0; + if (m_camera.fieldOfView() != 90.0) //aperture(90 / 2) = 1 + apertureSize = tan(QLocationUtils::radians(m_camera.fieldOfView()) * 0.5); QDoubleVector3D center = m_sideLength * QWebMercator::coordToMercator(m_camera.center()); - center.setZ(0.0); double f = qMin(m_screenSize.width(), m_screenSize.height()); - double z = std::pow(2.0, m_camera.zoomLevel() - m_intZoomLevel) * m_tileSize; + double z = std::pow(2.0, m_camera.zoomLevel() - m_intZoomLevel) * m_tileSize; // between 1 and 2 * m_tileSize - double altitude = f / (2.0 * z); + double altitude = (f / (2.0 * z)) / apertureSize; QDoubleVector3D eye = center; eye.setZ(altitude); @@ -289,28 +319,48 @@ Frustum QGeoCameraTilesPrivate::createFrustum(double fieldOfViewGradient) const QDoubleVector3D side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0)); QDoubleVector3D up = QDoubleVector3D::normal(side, view); + QMatrix4x4 mBearing; + // The rotation direction here is the opposite of QGeoTiledMapScene::setupCamera, + // as this is basically rotating the map against a fixed view frustum. + mBearing.rotate(1.0 * m_camera.bearing(), toVector3D(view)); + up = toDoubleVector3D(mBearing * toVector3D(up)); + + // same for tilting + QDoubleVector3D side2 = QDoubleVector3D::normal(up, view); + QMatrix4x4 mTilt; + mTilt.rotate(-1.0 * m_camera.tilt(), toVector3D(side2)); + eye = toDoubleVector3D((mTilt * toVector3D(view)) + toVector3D(center)); + + view = eye - center; + side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0)); + up = QDoubleVector3D::normal(view, side2); + double nearPlane = 1 / (4.0 * m_tileSize ); - double farPlane = altitude + 1.0; + // farPlane plays a role on how much gets clipped when the map gets tilted. It used to be altitude + 1.0 + // The value of 8.0 has been chosen as an acceptable compromise. + // TODO: use m_camera.clipDistance(); when this will be introduced + double farPlane = altitude + 8.0; double aspectRatio = 1.0 * m_screenSize.width() / m_screenSize.height(); - double hn,wn,hf,wf = 0.0; - - // fixes field of view at 45 degrees - // this assumes that viewSize = 2*nearPlane x 2*nearPlane + // Half values. Half width near, far, height near, far. + double hhn,hwn,hhf,hwf = 0.0; + // This used to fix the (half) field of view at 45 degrees + // half because this assumed that viewSize = 2*nearPlane x 2*nearPlane + viewExpansion *= apertureSize; if (aspectRatio > 1.0) { - hn = 2 * fieldOfViewGradient * nearPlane; - wn = hn * aspectRatio; + hhn = viewExpansion * nearPlane; + hwn = hhn * aspectRatio; - hf = 2 * fieldOfViewGradient * farPlane; - wf = hf * aspectRatio; + hhf = viewExpansion * farPlane; + hwf = hhf * aspectRatio; } else { - wn = 2 * fieldOfViewGradient * nearPlane; - hn = wn / aspectRatio; + hwn = viewExpansion * nearPlane; + hhn = hwn / aspectRatio; - wf = 2 * fieldOfViewGradient * farPlane; - hf = wf / aspectRatio; + hwf = viewExpansion * farPlane; + hhf = hwf / aspectRatio; } QDoubleVector3D d = center - eye; @@ -323,15 +373,15 @@ Frustum QGeoCameraTilesPrivate::createFrustum(double fieldOfViewGradient) const Frustum frustum; - frustum.topLeftFar = cf + (up * hf / 2) - (right * wf / 2); - frustum.topRightFar = cf + (up * hf / 2) + (right * wf / 2); - frustum.bottomLeftFar = cf - (up * hf / 2) - (right * wf / 2); - frustum.bottomRightFar = cf - (up * hf / 2) + (right * wf / 2); + frustum.topLeftFar = cf + (up * hhf) - (right * hwf); + frustum.topRightFar = cf + (up * hhf) + (right * hwf); + frustum.bottomLeftFar = cf - (up * hhf) - (right * hwf); + frustum.bottomRightFar = cf - (up * hhf) + (right * hwf); - frustum.topLeftNear = cn + (up * hn / 2) - (right * wn / 2); - frustum.topRightNear = cn + (up * hn / 2) + (right * wn / 2); - frustum.bottomLeftNear = cn - (up * hn / 2) - (right * wn / 2); - frustum.bottomRightNear = cn - (up * hn / 2) + (right * wn / 2); + frustum.topLeftNear = cn + (up * hhn) - (right * hwn); + frustum.topRightNear = cn + (up * hhn) + (right * hwn); + frustum.bottomLeftNear = cn - (up * hhn) - (right * hwn); + frustum.bottomRightNear = cn - (up * hhn) + (right * hwn); return frustum; } @@ -579,8 +629,13 @@ QPair QGeoCameraTilesPrivate::splitPolygonAtAxisVa return QPair(polygonBelow, polygonAbove); } +static void addXOffset(PolygonVector &footprint, double xoff) +{ + for (QDoubleVector3D &v: footprint) + v.setX(v.x() + xoff); +} -QPair QGeoCameraTilesPrivate::clipFootprintToMap(const PolygonVector &footprint) const +QGeoCameraTilesPrivate::ClippedFootprint QGeoCameraTilesPrivate::clipFootprintToMap(const PolygonVector &footprint) const { bool clipX0 = false; bool clipX1 = false; @@ -588,20 +643,13 @@ QPair QGeoCameraTilesPrivate::clipFootprintToMap(c bool clipY1 = false; double side = 1.0 * m_sideLength; + double minX = std::numeric_limits::max(); + double maxX = std::numeric_limits::lowest(); - typedef PolygonVector::const_iterator const_iter; - - const_iter i = footprint.constBegin(); - const_iter end = footprint.constEnd(); - for (; i != end; ++i) { - QDoubleVector3D p = *i; - if ((p.x() < 0.0) || (qFuzzyIsNull(p.x()))) - clipX0 = true; - if ((side < p.x()) || (qFuzzyCompare(side, p.x()))) - clipX1 = true; + for (const QDoubleVector3D &p: footprint) { if (p.y() < 0.0) clipY0 = true; - if (side < p.y()) + if (p.y() > side) clipY1 = true; } @@ -615,11 +663,39 @@ QPair QGeoCameraTilesPrivate::clipFootprintToMap(c results = splitPolygonAtAxisValue(results, 1, side).first; } + for (const QDoubleVector3D &p: results) { + if ((p.x() < 0.0) || (qFuzzyIsNull(p.x()))) + clipX0 = true; + if ((p.x() > side) || (qFuzzyCompare(side, p.x()))) + clipX1 = true; + } + + for (const QDoubleVector3D &v : results) { + minX = qMin(v.x(), minX); + maxX = qMax(v.x(), maxX); + } + + double footprintWidth = maxX - minX; + if (clipX0) { if (clipX1) { - results = splitPolygonAtAxisValue(results, 0, 0.0).second; - results = splitPolygonAtAxisValue(results, 0, side).first; - return QPair(results, PolygonVector()); + if (footprintWidth > side) { + PolygonVector rightPart = splitPolygonAtAxisValue(results, 0, side).second; + addXOffset(rightPart, -side); + rightPart = splitPolygonAtAxisValue(rightPart, 0, side).first; // clip it again, should it tend to infinite or so + + PolygonVector leftPart = splitPolygonAtAxisValue(results, 0, 0).first; + addXOffset(leftPart, side); + leftPart = splitPolygonAtAxisValue(leftPart, 0, 0).second; // same here + + results = splitPolygonAtAxisValue(results, 0, 0.0).second; + results = splitPolygonAtAxisValue(results, 0, side).first; + return ClippedFootprint(leftPart, results, rightPart); + } else { // fitting the WebMercator square exactly? + results = splitPolygonAtAxisValue(results, 0, 0.0).second; + results = splitPolygonAtAxisValue(results, 0, side).first; + return ClippedFootprint(PolygonVector(), results, PolygonVector()); + } } else { QPair pair = splitPolygonAtAxisValue(results, 0, 0.0); if (pair.first.isEmpty()) { @@ -649,11 +725,11 @@ QPair QGeoCameraTilesPrivate::clipFootprintToMap(c pair.first.append(QDoubleVector3D(side, y - 0.001, 0.0)); } } else { - for (int i = 0; i < pair.first.size(); ++i) { - pair.first[i].setX(pair.first.at(i).x() + side); - } + addXOffset(pair.first, side); + if (footprintWidth > side) + pair.first = splitPolygonAtAxisValue(pair.first, 0, 0).second; } - return pair; + return ClippedFootprint(pair.first, pair.second, PolygonVector()); } } else { if (clipX1) { @@ -685,13 +761,13 @@ QPair QGeoCameraTilesPrivate::clipFootprintToMap(c pair.second.append(QDoubleVector3D(0.0, y + 0.001, 0.0)); } } else { - for (int i = 0; i < pair.second.size(); ++i) { - pair.second[i].setX(pair.second.at(i).x() - side); - } + addXOffset(pair.second, -side); + if (footprintWidth > side) + pair.second = splitPolygonAtAxisValue(pair.second, 0, side).first; } - return pair; + return ClippedFootprint(PolygonVector(), pair.first, pair.second); } else { - return QPair(results, PolygonVector()); + return ClippedFootprint(PolygonVector(), results, PolygonVector()); } } diff --git a/src/location/maps/qgeotiledmapscene.cpp b/src/location/maps/qgeotiledmapscene.cpp index 3e75cece..fbd05645 100644 --- a/src/location/maps/qgeotiledmapscene.cpp +++ b/src/location/maps/qgeotiledmapscene.cpp @@ -43,7 +43,16 @@ #include #include #include +#include #include +#include +#include +#include + +static QVector3D toVector3D(const QDoubleVector3D& in) +{ + return QVector3D(in.x(), in.y(), in.z()); +} QT_BEGIN_NAMESPACE @@ -75,6 +84,7 @@ public: // the number of tiles in each direction for the whole map (earth) at the current zoom level. // it is 1< > m_textures; @@ -85,31 +95,16 @@ public: int m_maxTileY; int m_tileXWrapsBelow; // the wrap point as a tile index - // cameraToScreen transform - double m_screenWidth; // in pixels - double m_screenHeight; // in pixels bool m_linearScaling; bool m_dropTextures; void addTile(const QGeoTileSpec &spec, QSharedPointer texture); - QDoubleVector2D itemPositionToMercator(const QDoubleVector2D &pos) const; - QDoubleVector2D mercatorToItemPosition(const QDoubleVector2D &mercator) const; - - QDoubleVector2D geoToMapProjection(const QGeoCoordinate &coordinate) const; - QGeoCoordinate mapProjectionToGeo(const QDoubleVector2D &projection) const; - - QDoubleVector2D wrapMapProjection(const QDoubleVector2D &projection) const; - QDoubleVector2D unwrapMapProjection(const QDoubleVector2D &wrappedProjection) const; - - QDoubleVector2D wrappedMapProjectionToItemPosition(const QDoubleVector2D &wrappedProjection) const; - QDoubleVector2D itemPositionToWrappedMapProjection(const QDoubleVector2D &itemPosition) const; - - void setVisibleTiles(const QSet &tiles); + void setVisibleTiles(const QSet &visibleTiles); void removeTiles(const QSet &oldTiles); bool buildGeometry(const QGeoTileSpec &spec, QSGImageNode *imageNode); - void setTileBounds(const QSet &tiles); + void updateTileBounds(const QSet &tiles); void setupCamera(); inline bool isTiltedOrRotated() { return (m_cameraData.tilt() > 0.0) || (m_cameraData.bearing() > 0.0); } }; @@ -143,6 +138,7 @@ void QGeoTiledMapScene::setCameraData(const QGeoCameraData &cameraData) 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; } void QGeoTiledMapScene::setVisibleTiles(const QSet &tiles) @@ -191,8 +187,6 @@ QGeoTiledMapScenePrivate::QGeoTiledMapScenePrivate() m_maxTileX(-1), m_maxTileY(-1), m_tileXWrapsBelow(0), - m_screenWidth(0.0), - m_screenHeight(0.0), m_linearScaling(false), m_dropTextures(false) { @@ -245,19 +239,19 @@ void QGeoTiledMapScenePrivate::addTile(const QGeoTileSpec &spec, QSharedPointer< m_textures.insert(spec, texture); } -void QGeoTiledMapScenePrivate::setVisibleTiles(const QSet &tiles) +void QGeoTiledMapScenePrivate::setVisibleTiles(const QSet &visibleTiles) { // work out the tile bounds for the new scene - setTileBounds(tiles); + updateTileBounds(visibleTiles); // set up the gl camera for the new scene setupCamera(); - QSet toRemove = m_visibleTiles - tiles; + QSet toRemove = m_visibleTiles - visibleTiles; if (!toRemove.isEmpty()) removeTiles(toRemove); - m_visibleTiles = tiles; + m_visibleTiles = visibleTiles; } void QGeoTiledMapScenePrivate::removeTiles(const QSet &oldTiles) @@ -272,7 +266,7 @@ void QGeoTiledMapScenePrivate::removeTiles(const QSet &oldTiles) } } -void QGeoTiledMapScenePrivate::setTileBounds(const QSet &tiles) +void QGeoTiledMapScenePrivate::updateTileBounds(const QSet &tiles) { if (tiles.isEmpty()) { m_minTileX = -1; @@ -354,26 +348,24 @@ void QGeoTiledMapScenePrivate::setTileBounds(const QSet &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()); - // fraction of zoom level + // 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; - // Maps smaller than screen size are NOT supported. But we can't simply return here, as this call - // might be invoked also before a valid zoom level is set. - // calculate altitude that allows the visible map tiles - // to fit in the screen correctly (note that a larger f would cause - // the camera be higher, resulting in empty areas displayed around - // the tiles or repeated tiles) - double altitude = f / (2.0 * z) ; + // to fit in the screen correctly (note that a larger f will cause + // the camera be higher, resulting in gray areas displayed around + // the tiles) + double altitude = f / (2.0 * z); // calculate center double edge = m_scaleFactor * m_tileSize; // first calculate the camera center in map space in the range of 0 <-> sideLength (2^z) QDoubleVector2D camCenterMercator = QWebMercator::coordToMercator(m_cameraData.center()); - QDoubleVector3D center = m_sideLength * camCenterMercator; + QDoubleVector3D center = (m_sideLength * camCenterMercator); // wrap the center if necessary (due to dateline crossing) if (center.x() < m_tileXWrapsBelow) @@ -383,16 +375,15 @@ void QGeoTiledMapScenePrivate::setupCamera() center.setX(center.x() - 1.0 * m_minTileX); center.setY(1.0 * m_minTileY - center.y()); - m_screenHeight = m_screenSize.height(); - m_screenWidth = m_screenSize.width(); - // apply necessary scaling to the camera center center *= edge; // calculate eye - + double apertureSize = 1.0; + if (m_cameraData.fieldOfView() != 90.0) //aperture(90 / 2) = 1 + apertureSize = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5); QDoubleVector3D eye = center; - eye.setZ(altitude * edge); + eye.setZ(altitude * edge / apertureSize); // calculate up @@ -400,19 +391,24 @@ void QGeoTiledMapScenePrivate::setupCamera() QDoubleVector3D side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0)); QDoubleVector3D up = QDoubleVector3D::normal(side, view); - // old bearing, tilt and roll code - // QMatrix4x4 mBearing; - // mBearing.rotate(-1.0 * camera.bearing(), view); - // up = mBearing * up; - - // QDoubleVector3D side2 = QDoubleVector3D::normal(up, view); - // QMatrix4x4 mTilt; - // mTilt.rotate(camera.tilt(), side2); - // eye = (mTilt * view) + center; + // old bearing, tilt and roll code. + // Now using double matrices until distilling the transformation to QMatrix4x4 + QDoubleMatrix4x4 mBearing; + // -1.0 * bearing removed, now map north goes in the bearing direction + mBearing.rotate(-1.0 * m_cameraData.bearing(), view); + up = mBearing * up; + + QDoubleVector3D side2 = QDoubleVector3D::normal(up, view); + if (m_cameraData.tilt() > 0.01) { + QDoubleMatrix4x4 mTilt; + mTilt.rotate(m_cameraData.tilt(), side2); + eye = mTilt * view + center; + } - // view = eye - center; - // side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0)); - // up = QDoubleVector3D::normal(view, side2); + view = eye - center; + view.normalize(); + side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0)); + up = QDoubleVector3D::normal(view, side2); // QMatrix4x4 mRoll; // mRoll.rotate(camera.roll(), view); @@ -421,15 +417,19 @@ void QGeoTiledMapScenePrivate::setupCamera() // near plane and far plane double nearPlane = 1.0; - double farPlane = (altitude + 1.0) * edge; + // Clip plane. Used to be (altitude + 1.0) * edge. This does not affect the perspective. minimum value would be > 0.0 + // Since, for some reasons possibly related to how QSG works, this clipping plane is unable to clip part of tiles, + // Instead of farPlane = (altitude + m_cameraData.clipDistance()) * edge , we use a fixed large clipDistance, and + // leave the clipping only in QGeoCameraTiles::createFrustum + double farPlane = (altitude + 10000.0) * edge; m_cameraUp = up; m_cameraCenter = center; m_cameraEye = eye; double aspectRatio = 1.0 * m_screenSize.width() / m_screenSize.height(); - float halfWidth = 1; - float halfHeight = 1; + float halfWidth = 1 * apertureSize; + float halfHeight = 1 * apertureSize; if (aspectRatio > 1.0) { halfWidth *= aspectRatio; } else if (aspectRatio > 0.0f && aspectRatio < 1.0f) { @@ -503,14 +503,33 @@ public: QHash textures; }; -static bool qgeotiledmapscene_isTileInViewport(const QRectF &tileRect, const QMatrix4x4 &matrix) { +static bool qgeotiledmapscene_isTileInViewport_Straight(const QRectF &tileRect, const QMatrix4x4 &matrix) +{ const QRectF boundingRect = QRectF(matrix * tileRect.topLeft(), matrix * tileRect.bottomRight()); return QRectF(-1, -1, 2, 2).intersects(boundingRect); } -static QVector3D toVector3D(const QDoubleVector3D& in) +static bool qgeotiledmapscene_isTileInViewport_rotationTilt(const QRectF &tileRect, const QMatrix4x4 &matrix) { - return QVector3D(in.x(), in.y(), in.z()); + // Transformed corners + const QPointF tlt = matrix * tileRect.topLeft(); + const QPointF trt = matrix * tileRect.topRight(); + const QPointF blt = matrix * tileRect.bottomLeft(); + const QPointF brt = matrix * tileRect.bottomRight(); + + const QRectF boundingRect = QRectF(QPointF(qMin(qMin(qMin(tlt.x(), trt.x()), blt.x()), brt.x()) + ,qMax(qMax(qMax(tlt.y(), trt.y()), blt.y()), brt.y())) + ,QPointF(qMax(qMax(qMax(tlt.x(), trt.x()), blt.x()), brt.x()) + ,qMin(qMin(qMin(tlt.y(), trt.y()), blt.y()), brt.y())) + ); + return QRectF(-1, -1, 2, 2).intersects(boundingRect); +} + +static bool qgeotiledmapscene_isTileInViewport(const QRectF &tileRect, const QMatrix4x4 &matrix, const bool straight) +{ + if (straight) + return qgeotiledmapscene_isTileInViewport_Straight(tileRect, matrix); + return qgeotiledmapscene_isTileInViewport_rotationTilt(tileRect, matrix); } void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root, @@ -533,11 +552,13 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root, foreach (const QGeoTileSpec &s, toRemove) delete root->tiles.take(s); + bool straight = !d->isTiltedOrRotated(); for (QHash::iterator it = root->tiles.begin(); it != root->tiles.end(); ) { QSGImageNode *node = it.value(); - bool ok = d->buildGeometry(it.key(), node) && qgeotiledmapscene_isTileInViewport(node->rect(), root->matrix()); + bool ok = d->buildGeometry(it.key(), node) + && qgeotiledmapscene_isTileInViewport(node->rect(), root->matrix(), straight); QSGNode::DirtyState dirtyBits = 0; @@ -567,7 +588,8 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root, 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) && qgeotiledmapscene_isTileInViewport(tileNode->rect(), root->matrix())) { + if (d->buildGeometry(s, tileNode) + && qgeotiledmapscene_isTileInViewport(tileNode->rect(), root->matrix(), straight)) { if (tileNode->texture()->textureSize().width() > d->m_tileSize) { tileNode->setFiltering(QSGTexture::Linear); // with mipmapping QSGTexture::Nearest generates artifacts tileNode->setMipmapFiltering(QSGTexture::Linear); @@ -596,7 +618,7 @@ QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *win mapRoot = new QGeoTiledMapRootNode(); // Setting clip rect to fullscreen, as now the map can never be smaller than the viewport. - mapRoot->setClipRect(QRect(0, 0, d->m_screenWidth, d->m_screenHeight)); + mapRoot->setClipRect(QRect(0, 0, w, h)); QMatrix4x4 itemSpaceMatrix; itemSpaceMatrix.scale(w / 2, h / 2); diff --git a/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp b/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp index abcb3779..a0f00615 100644 --- a/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp +++ b/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp @@ -95,7 +95,12 @@ GeoTiledMappingManagerEngineEsri::GeoTiledMappingManagerEngineEsri(const QVarian cameraCaps.setMinimumZoomLevel(minimumZoomLevel); cameraCaps.setMaximumZoomLevel(maximumZoomLevel); - + cameraCaps.setSupportsBearing(true); + cameraCaps.setSupportsTilting(true); + cameraCaps.setMinimumTilt(0); + cameraCaps.setMaximumTilt(80); + cameraCaps.setMinimumFieldOfView(20.0); + cameraCaps.setMaximumFieldOfView(120.0); setCameraCapabilities(cameraCaps); setTileSize(QSize(256, 256)); diff --git a/src/plugins/geoservices/mapbox/qgeotiledmappingmanagerenginemapbox.cpp b/src/plugins/geoservices/mapbox/qgeotiledmappingmanagerenginemapbox.cpp index 5404eb30..4b62aece 100644 --- a/src/plugins/geoservices/mapbox/qgeotiledmappingmanagerenginemapbox.cpp +++ b/src/plugins/geoservices/mapbox/qgeotiledmappingmanagerenginemapbox.cpp @@ -50,6 +50,12 @@ QGeoTiledMappingManagerEngineMapbox::QGeoTiledMappingManagerEngineMapbox(const Q QGeoCameraCapabilities cameraCaps; cameraCaps.setMinimumZoomLevel(0.0); cameraCaps.setMaximumZoomLevel(19.0); + cameraCaps.setSupportsBearing(true); + cameraCaps.setSupportsTilting(true); + cameraCaps.setMinimumTilt(0); + cameraCaps.setMaximumTilt(80); + cameraCaps.setMinimumFieldOfView(20.0); + cameraCaps.setMaximumFieldOfView(120.0); setCameraCapabilities(cameraCaps); setTileSize(QSize(256, 256)); diff --git a/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp b/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp index 3a9ac277..e5809018 100644 --- a/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp +++ b/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp @@ -67,7 +67,12 @@ QGeoTiledMappingManagerEngineNokia::QGeoTiledMappingManagerEngineNokia( capabilities.setMinimumZoomLevel(0.0); capabilities.setMaximumZoomLevel(20.0); - + capabilities.setSupportsBearing(true); + capabilities.setSupportsTilting(true); + capabilities.setMinimumTilt(0); + capabilities.setMaximumTilt(80); + capabilities.setMinimumFieldOfView(20.0); + capabilities.setMaximumFieldOfView(120.0); setCameraCapabilities(capabilities); setTileSize(QSize(256, 256)); diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp index 3228b31b..e9e48008 100644 --- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp +++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp @@ -57,6 +57,12 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian QGeoCameraCapabilities cameraCaps; cameraCaps.setMinimumZoomLevel(0.0); cameraCaps.setMaximumZoomLevel(19.0); + cameraCaps.setSupportsBearing(true); + cameraCaps.setSupportsTilting(true); + cameraCaps.setMinimumTilt(0); + cameraCaps.setMaximumTilt(80); + cameraCaps.setMinimumFieldOfView(20.0); + cameraCaps.setMaximumFieldOfView(120.0); setCameraCapabilities(cameraCaps); setTileSize(QSize(256, 256)); diff --git a/tests/auto/declarative_ui/tst_map.qml b/tests/auto/declarative_ui/tst_map.qml index 1c0f4719..ab1ddd8c 100644 --- a/tests/auto/declarative_ui/tst_map.qml +++ b/tests/auto/declarative_ui/tst_map.qml @@ -361,8 +361,8 @@ Item { compare(map.tilt, 0.0) compare(mapTiltBearing.bearing, 45.0) compare(mapTiltBearing.tilt, 25.0) - compare(mapTiltBearingHere.bearing, 0.0) - compare(mapTiltBearingHere.tilt, 0.0) + compare(mapTiltBearingHere.bearing, 45.0) + compare(mapTiltBearingHere.tilt, 25.0) mapTiltBearing.bearing = 0.0 mapTiltBearing.tilt = 0.0 @@ -379,6 +379,10 @@ Item { mapTiltBearingHere.bearing = 45.0 mapTiltBearingHere.tilt = 25.0 + compare(mapTiltBearingHere.bearing, 45.0) + compare(mapTiltBearingHere.tilt, 25.0) + mapTiltBearingHere.bearing = 0.0 + mapTiltBearingHere.tilt = 0.0 compare(mapTiltBearingHere.bearing, 0.0) compare(mapTiltBearingHere.tilt, 0.0) -- cgit v1.2.1