diff options
author | Paolo Angelelli <paolo.angelelli@qt.io> | 2018-06-19 16:33:44 +0200 |
---|---|---|
committer | Paolo Angelelli <paolo.angelelli@qt.io> | 2018-07-26 13:38:02 +0000 |
commit | eca7cc8a260538fcccde97fe59d9580250600bf1 (patch) | |
tree | 6a87cc4391b1e0dbf65ee011d0314cfae4c8b19f | |
parent | d6fc6ba0f84c4cda0ccc2e1250da4a68441dd6ba (diff) | |
download | qtlocation-eca7cc8a260538fcccde97fe59d9580250600bf1.tar.gz |
Introduce Map.visibleArea
This will allow moving the visible map area to a subregion
of the viewport, allowing to maintain the desired visible
region visible when overlaying controls on top of the map.
Task-number: QTBUG-68966
Change-Id: Idf4b30f7c1e4062e5e1c0ddc01a31bc856c0bc0c
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
26 files changed, 531 insertions, 117 deletions
diff --git a/src/imports/location/location.cpp b/src/imports/location/location.cpp index b632836f..62debb1d 100644 --- a/src/imports/location/location.cpp +++ b/src/imports/location/location.cpp @@ -190,6 +190,7 @@ public: minor = 12; qmlRegisterType<QDeclarativeGeoMapItemView, 12>(uri, major, minor, "MapItemView"); qmlRegisterType<QDeclarativeSearchResultModel, 12>(uri, major, minor, "PlaceSearchModel"); + qmlRegisterType<QDeclarativeGeoMap, 12>(uri, major, minor, "Map"); // Register the latest Qt version as QML type version qmlRegisterModule(uri, QT_VERSION_MAJOR, QT_VERSION_MINOR); diff --git a/src/location/declarativemaps/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp index faa25916..d201b6ab 100644 --- a/src/location/declarativemaps/qdeclarativegeomap.cpp +++ b/src/location/declarativemaps/qdeclarativegeomap.cpp @@ -333,6 +333,7 @@ void QDeclarativeGeoMap::initialize() bool bearingHasChanged = false; bool tiltHasChanged = false; bool fovHasChanged = false; + bool visibleAreaHasChanged = false; QGeoCoordinate center = m_cameraData.center(); @@ -354,6 +355,10 @@ void QDeclarativeGeoMap::initialize() tiltHasChanged = true; } + m_map->setVisibleArea(m_visibleArea); + if (m_map->visibleArea() != m_visibleArea) + visibleAreaHasChanged = true; + m_cameraData.setFieldOfView(qBound(m_cameraCapabilities.minimumFieldOfView(), fov, m_cameraCapabilities.maximumFieldOfView())); @@ -362,8 +367,9 @@ void QDeclarativeGeoMap::initialize() // set latitude boundary check m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData); + m_minimumViewportLatitude = m_map->minimumCenterLatitudeAtZoom(m_cameraData); - center.setLatitude(qBound(-m_maximumViewportLatitude, center.latitude(), m_maximumViewportLatitude)); + center.setLatitude(qBound(m_minimumViewportLatitude, center.latitude(), m_maximumViewportLatitude)); if (center != m_cameraData.center()) { centerHasChanged = true; @@ -389,6 +395,10 @@ void QDeclarativeGeoMap::initialize() if (fovHasChanged) emit fieldOfViewChanged(m_cameraData.fieldOfView()); + if (visibleAreaHasChanged) + emit visibleAreaChanged(); + connect(m_map, &QGeoMap::visibleAreaChanged, this, &QDeclarativeGeoMap::visibleAreaChanged); + emit mapReadyChanged(true); if (m_copyrights) // To not update during initialize() @@ -915,8 +925,9 @@ void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel, bool overzoom) zoomLevel, overzoom ? 30 : maximumZoomLevel())); m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData); + m_minimumViewportLatitude = m_map->minimumCenterLatitudeAtZoom(m_cameraData); QGeoCoordinate coord = m_cameraData.center(); - coord.setLatitude(qBound(-m_maximumViewportLatitude, coord.latitude(), m_maximumViewportLatitude)); + coord.setLatitude(qBound(m_minimumViewportLatitude, coord.latitude(), m_maximumViewportLatitude)); if (coord != m_cameraData.center()) { centerHasChanged = true; m_cameraData.setCenter(coord); @@ -1231,7 +1242,7 @@ void QDeclarativeGeoMap::setCenter(const QGeoCoordinate ¢er) if (m_initialized) { QGeoCoordinate coord(center); - coord.setLatitude(qBound(-m_maximumViewportLatitude, center.latitude(), m_maximumViewportLatitude)); + coord.setLatitude(qBound(m_minimumViewportLatitude, center.latitude(), m_maximumViewportLatitude)); m_cameraData.setCenter(coord); m_map->setCameraData(m_cameraData); } else { @@ -1364,6 +1375,42 @@ QColor QDeclarativeGeoMap::color() const } /*! + \qmlproperty rect QtLocation::Map::visibleArea + + This property holds the visible area inside the Map QML element. + It is a rect whose coordinates are relative to the Map element. + Its size will be clamped to the size of the Map element. + A null visibleArea means that the whole Map is visible. + + \since 5.12 +*/ +QRectF QDeclarativeGeoMap::visibleArea() const +{ + if (m_initialized) + return m_map->visibleArea(); + return m_visibleArea; +} + +void QDeclarativeGeoMap::setVisibleArea(const QRectF &visibleArea) +{ + const QRectF oldVisibleArea = QDeclarativeGeoMap::visibleArea(); + if (visibleArea == oldVisibleArea) + return; + + if (!visibleArea.isValid() && !visibleArea.isEmpty()) // values < 0 + return; + + if (m_initialized) { + m_map->setVisibleArea(visibleArea); + } else { + m_visibleArea = visibleArea; + const QRectF newVisibleArea = QDeclarativeGeoMap::visibleArea(); + if (newVisibleArea != oldVisibleArea) + emit visibleAreaChanged(); + } +} + +/*! \qmlproperty bool QtLocation::Map::mapReady This property holds whether the map has been successfully initialized and is ready to be used. @@ -1378,6 +1425,17 @@ bool QDeclarativeGeoMap::mapReady() const return m_initialized; } +QMargins QDeclarativeGeoMap::mapMargins() const +{ + const QRectF va = m_map->visibleArea(); + if (va.isEmpty()) + return QMargins(); + return QMargins( va.x() + , va.y() + , width() - va.width() - va.x() + , height() - va.height() - va.y()); +} + // TODO: offer the possibility to specify the margins. void QDeclarativeGeoMap::fitViewportToGeoShape() { @@ -1385,34 +1443,24 @@ void QDeclarativeGeoMap::fitViewportToGeoShape() // This case remains handled here, and not inside QGeoMap*::fitViewportToGeoRectangle, // in order to honor animations on center and zoomLevel const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); - const int margins = 10; - if (!m_map || !m_visibleRegion.isValid() || width() <= margins || height() <= margins) - return; + const int borderSize = 10; + const QMargins borders(borderSize, borderSize, borderSize, borderSize); - QDoubleVector2D topLeftPoint = p.geoToMapProjection(m_visibleRegion.topLeft()); - QDoubleVector2D bottomRightPoint = p.geoToMapProjection(m_visibleRegion.bottomRight()); - if (bottomRightPoint.x() < topLeftPoint.x()) // crossing the dateline - bottomRightPoint.setX(bottomRightPoint.x() + 1.0); + if (!m_map || !m_visibleRegion.isValid()) + return; - // find center of the bounding box - QDoubleVector2D center = (topLeftPoint + bottomRightPoint) * 0.5; - center.setX(center.x() > 1.0 ? center.x() - 1.0 : center.x()); - QGeoCoordinate centerCoordinate = p.mapProjectionToGeo(center); + const QMargins margins = borders + mapMargins(); + const QPair<QGeoCoordinate, qreal> fitData = p.fitViewportToGeoRectangle(m_visibleRegion, + margins); + if (!fitData.first.isValid()) + return; // position camera to the center of bounding box - setProperty("center", QVariant::fromValue(centerCoordinate)); // not using setCenter(centerCoordinate) to honor a possible animation set on the center property - - // if the shape is empty we just change center position, not zoom - double bboxWidth = (bottomRightPoint.x() - topLeftPoint.x()) * m_map->mapWidth(); - double bboxHeight = (bottomRightPoint.y() - topLeftPoint.y()) * m_map->mapHeight(); + setProperty("center", QVariant::fromValue(fitData.first)); // not using setCenter(centerCoordinate) to honor a possible animation set on the center property - if (bboxHeight == 0.0 && bboxWidth == 0.0) + if (!qIsFinite(fitData.second)) return; - - double zoomRatio = qMax(bboxWidth / (width() - margins), - bboxHeight / (height() - margins)); - zoomRatio = std::log(zoomRatio) / std::log(2.0); - double newZoom = qMax<double>(minimumZoomLevel(), zoomLevel() - zoomRatio); + double newZoom = qMax<double>(minimumZoomLevel(), fitData.second); setProperty("zoomLevel", QVariant::fromValue(newZoom)); // not using setZoomLevel(newZoom) to honor a possible animation set on the zoomLevel property } else if (m_map->capabilities() & QGeoMap::SupportsFittingViewportToGeoRectangle) { // Animations cannot be honored in this case, as m_map act as a black box @@ -2067,11 +2115,14 @@ void QDeclarativeGeoMap::geometryChanged(const QRectF &newGeometry, const QRectF setMinimumZoomLevel(m_map->minimumZoom(), false); // Update the center latitudinal threshold - double maximumCenterLatitudeAtZoom = m_map->maximumCenterLatitudeAtZoom(m_cameraData); - if (maximumCenterLatitudeAtZoom != m_maximumViewportLatitude) { + const double maximumCenterLatitudeAtZoom = m_map->maximumCenterLatitudeAtZoom(m_cameraData); + const double minimumCenterLatitudeAtZoom = m_map->minimumCenterLatitudeAtZoom(m_cameraData); + if (maximumCenterLatitudeAtZoom != m_maximumViewportLatitude + || minimumCenterLatitudeAtZoom != m_minimumViewportLatitude) { m_maximumViewportLatitude = maximumCenterLatitudeAtZoom; + m_minimumViewportLatitude = minimumCenterLatitudeAtZoom; QGeoCoordinate coord = m_cameraData.center(); - coord.setLatitude(qBound(-m_maximumViewportLatitude, coord.latitude(), m_maximumViewportLatitude)); + coord.setLatitude(qBound(m_minimumViewportLatitude, coord.latitude(), m_maximumViewportLatitude)); if (coord != m_cameraData.center()) { m_cameraData.setCenter(coord); diff --git a/src/location/declarativemaps/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h index 7f1bf7ab..6948b15b 100644 --- a/src/location/declarativemaps/qdeclarativegeomap_p.h +++ b/src/location/declarativemaps/qdeclarativegeomap_p.h @@ -101,6 +101,7 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMap : public QQuickItem Q_PROPERTY(bool copyrightsVisible READ copyrightsVisible WRITE setCopyrightsVisible NOTIFY copyrightsVisibleChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) Q_PROPERTY(bool mapReady READ mapReady NOTIFY mapReadyChanged) + Q_PROPERTY(QRectF visibleArea READ visibleArea WRITE setVisibleArea NOTIFY visibleAreaChanged REVISION 12) Q_INTERFACES(QQmlParserStatus) public: @@ -154,6 +155,9 @@ public: void setColor(const QColor &color); QColor color() const; + QRectF visibleArea() const; + void setVisibleArea(const QRectF &visibleArea); + bool mapReady() const; QQmlListProperty<QDeclarativeGeoMapType> supportedMapTypes(); @@ -226,6 +230,7 @@ Q_SIGNALS: void copyrightsChanged(const QString ©rightsHtml); void mapReadyChanged(bool ready); Q_REVISION(11) void mapObjectsChanged(); + void visibleAreaChanged(); protected: void mousePressEvent(QMouseEvent *event) override ; @@ -266,6 +271,7 @@ private: bool isInteractive(); void attachCopyrightNotice(bool initialVisibility); void detachCopyrightNotice(bool currentVisibility); + QMargins mapMargins() const; private: QDeclarativeGeoServiceProvider *m_plugin; @@ -287,6 +293,7 @@ private: bool m_pendingFitViewport; bool m_copyrightsVisible; double m_maximumViewportLatitude; + double m_minimumViewportLatitude = 0.0; bool m_initialized; QList<QDeclarativeGeoMapParameter *> m_mapParameters; QList<QGeoMapObject*> m_pendingMapObjects; // Used only in the initialization phase @@ -306,6 +313,7 @@ private: int m_copyNoticesVisible = 0; qreal m_maxChildZ = 0; + QRectF m_visibleArea; friend class QDeclarativeGeoMapItem; diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp index faa06fef..366992ed 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp @@ -141,6 +141,8 @@ void QDeclarativeGeoMapItemBase::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *m if (map_ && quickMap_) { connect(map_, SIGNAL(cameraDataChanged(QGeoCameraData)), this, SLOT(baseCameraDataChanged(QGeoCameraData))); + connect(map_, SIGNAL(visibleAreaChanged()), + this, SLOT(visibleAreaChanged())); connect(quickMap, SIGNAL(heightChanged()), this, SLOT(polishAndUpdate())); connect(quickMap, SIGNAL(widthChanged()), this, SLOT(polishAndUpdate())); lastSize_ = QSizeF(quickMap_->width(), quickMap_->height()); @@ -177,6 +179,13 @@ void QDeclarativeGeoMapItemBase::baseCameraDataChanged(const QGeoCameraData &cam afterViewportChanged(evt); } +void QDeclarativeGeoMapItemBase::visibleAreaChanged() +{ + QGeoMapViewportChangeEvent evt; + evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height()); + afterViewportChanged(evt); +} + /*! \internal */ diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h index 7a284e8a..4a2f9282 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h +++ b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h @@ -147,6 +147,7 @@ protected: private Q_SLOTS: void baseCameraDataChanged(const QGeoCameraData &camera); + void visibleAreaChanged(); private: QPointer<QGeoMap> map_; diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp index 62613126..9a86fc8e 100644 --- a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp @@ -441,6 +441,10 @@ void QDeclarativeGeoMapQuickItem::updatePolish() void QDeclarativeGeoMapQuickItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event) { Q_UNUSED(event); + if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0) + return; + + polishAndUpdate(); } /*! diff --git a/src/location/maps/qgeocameratiles.cpp b/src/location/maps/qgeocameratiles.cpp index 327d54b3..b7eac306 100644 --- a/src/location/maps/qgeocameratiles.cpp +++ b/src/location/maps/qgeocameratiles.cpp @@ -89,6 +89,7 @@ public: int m_mapVersion; QGeoCameraData m_camera; QSize m_screenSize; + QRectF m_visibleArea; int m_tileSize; QSet<QGeoTileSpec> m_tiles; @@ -155,6 +156,15 @@ QGeoCameraData QGeoCameraTiles::cameraData() const return d_ptr->m_camera; } +void QGeoCameraTiles::setVisibleArea(const QRectF &visibleArea) +{ + if (d_ptr->m_visibleArea == visibleArea) + return; + + d_ptr->m_visibleArea = visibleArea; + d_ptr->m_dirtyGeometry = true; +} + void QGeoCameraTiles::setScreenSize(const QSize &size) { if (d_ptr->m_screenSize == size) @@ -358,15 +368,32 @@ Frustum QGeoCameraTilesPrivate::createFrustum(double viewExpansion) const frustum.apex = eye; - 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 * hhn) - (right * hwn); - frustum.topRightNear = cn - (up * hhn) + (right * hwn); - frustum.bottomLeftNear = cn + (up * hhn) - (right * hwn); - frustum.bottomRightNear = cn + (up * hhn) + (right * hwn); + QRectF va = m_visibleArea; + if (va.isNull()) + va = QRectF(0, 0, m_screenSize.width(), m_screenSize.height()); + QRectF screen = QRectF(QPointF(0,0),m_screenSize); + QPointF vaCenter = va.center(); + QPointF screenCenter = screen.center(); + QPointF diff = screenCenter - vaCenter; + double xdiffpct = diff.x() / m_screenSize.width(); + double ydiffpct = -(diff.y() / m_screenSize.height()); + + double wn = (2 * hwn) * xdiffpct; + double hn = (2 * hhn) * ydiffpct; + double wf = (2 * hwf) * xdiffpct; + double hf = (2 * hhf) * ydiffpct; + + // TODO: fix eye + + frustum.topLeftFar = cf - (up * (hhf + hf)) - (right * (hwf + wf)); + frustum.topRightFar = cf - (up * (hhf + hf)) + (right * (hwf + wf)); + frustum.bottomLeftFar = cf + (up * (hhf + hf)) - (right * (hwf + wf)); + frustum.bottomRightFar = cf + (up * (hhf + hf)) + (right * (hwf + wf)); + + frustum.topLeftNear = cn - (up * (hhn + hn)) - (right * (hwn + wn)); + frustum.topRightNear = cn - (up * (hhn + hn)) + (right * (hwn + wn)); + frustum.bottomLeftNear = cn + (up * (hhn + hn)) - (right * (hwn + wn)); + frustum.bottomRightNear = cn + (up * (hhn + hn)) + (right * (hwn + wn)); return frustum; } diff --git a/src/location/maps/qgeocameratiles_p.h b/src/location/maps/qgeocameratiles_p.h index 3ff00688..f95db44d 100644 --- a/src/location/maps/qgeocameratiles_p.h +++ b/src/location/maps/qgeocameratiles_p.h @@ -49,6 +49,7 @@ #include <QtLocation/private/qlocationglobal_p.h> #include <QtCore/QScopedPointer> +#include <QRectF> QT_BEGIN_NAMESPACE @@ -65,6 +66,7 @@ public: void setCameraData(const QGeoCameraData &camera); QGeoCameraData cameraData() const; + void setVisibleArea(const QRectF &visibleArea); void setScreenSize(const QSize &size); void setTileSize(int tileSize); int tileSize() const; diff --git a/src/location/maps/qgeomap.cpp b/src/location/maps/qgeomap.cpp index 5f125169..db0df702 100644 --- a/src/location/maps/qgeomap.cpp +++ b/src/location/maps/qgeomap.cpp @@ -42,6 +42,7 @@ #include "qgeomapobject_p.h" #include "qgeomapobject_p_p.h" #include <QDebug> +#include <QRectF> QT_BEGIN_NAMESPACE @@ -109,7 +110,7 @@ bool QGeoMap::handleEvent(QEvent *event) return false; } -bool QGeoMap::setBearing(qreal bearing, const QGeoCoordinate &coordinate) +bool QGeoMap::setBearing(qreal bearing, const QGeoCoordinate &coordinate) //FIXME visibleArea { Q_D(QGeoMap); bool res = d->m_geoProjection->setBearing(bearing, coordinate); @@ -124,7 +125,7 @@ bool QGeoMap::anchorCoordinateToPoint(const QGeoCoordinate &coordinate, const QP { Q_D(QGeoMap); QGeoCoordinate newCenter = geoProjection().anchorCoordinateToPoint(coordinate, anchorPoint); - newCenter.setLatitude(qBound(-d->m_maximumViewportLatitude, newCenter.latitude(), d->m_maximumViewportLatitude)); + newCenter.setLatitude(qBound(d->m_minimumViewportLatitude, newCenter.latitude(), d->m_maximumViewportLatitude)); QGeoCameraData data = cameraData(); if (data.center() != newCenter) { data.setCenter(newCenter); @@ -180,6 +181,12 @@ double QGeoMap::maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) co return d->maximumCenterLatitudeAtZoom(cameraData); } +double QGeoMap::minimumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const +{ + Q_D(const QGeoMap); + return d->minimumCenterLatitudeAtZoom(cameraData); +} + double QGeoMap::mapWidth() const { Q_D(const QGeoMap); @@ -297,6 +304,21 @@ void QGeoMap::removeMapObject(QGeoMapObject * /*obj*/) { } +void QGeoMap::setVisibleArea(const QRectF &visibleArea) +{ + Q_D(QGeoMap); + const QRectF &va = d->visibleArea(); + d->setVisibleArea(visibleArea); + if (va != d->visibleArea()) + emit visibleAreaChanged(); +} + +QRectF QGeoMap::visibleArea() const +{ + Q_D(const QGeoMap); + return d->visibleArea(); +} + QList<QGeoMapObject *> QGeoMap::mapObjects() const { Q_D(const QGeoMap); @@ -429,4 +451,29 @@ double QGeoMapPrivate::maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraD return m_maximumViewportLatitude; } +double QGeoMapPrivate::minimumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const +{ + m_minimumViewportLatitude = m_geoProjection->minimumCenterLatitudeAtZoom(cameraData); + return m_minimumViewportLatitude; +} + +void QGeoMapPrivate::setVisibleArea(const QRectF &/*visibleArea*/) +{ + +} + +QRectF QGeoMapPrivate::visibleArea() const +{ + return QRectF(); +} + +QRectF QGeoMapPrivate::clampVisibleArea(const QRectF &visibleArea) const +{ + qreal xp = qMin<qreal>(visibleArea.x(), qMax(m_viewportSize.width() - 1, 0)); + qreal yp = qMin<qreal>(visibleArea.y(), qMax(m_viewportSize.height() - 1, 0)); + qreal w = qMin<qreal>(visibleArea.width(), qMax<qreal>(m_viewportSize.width() - xp, 0)); + qreal h = qMin<qreal>(visibleArea.height(), qMax<qreal>(m_viewportSize.height() - yp, 0)); + return QRectF(xp, yp, w, h); +} + QT_END_NAMESPACE diff --git a/src/location/maps/qgeomap_p.h b/src/location/maps/qgeomap_p.h index f6be5cae..0c396e16 100644 --- a/src/location/maps/qgeomap_p.h +++ b/src/location/maps/qgeomap_p.h @@ -93,7 +93,8 @@ public: SupportsVisibleRegion = 0x0001, SupportsSetBearing = 0x0002, SupportsAnchoringCoordinate = 0x0004, - SupportsFittingViewportToGeoRectangle = 0x0008 + SupportsFittingViewportToGeoRectangle = 0x0008, + SupportsVisibleArea = 0x0010, }; Q_DECLARE_FLAGS(Capabilities, Capability) @@ -117,6 +118,7 @@ public: // returns the minimum zoom at the current viewport size double minimumZoom() const; double maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const; + double minimumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const; // returns the size of the underlying map, at the current zoom level. Unrelated to width()/height()/size(). double mapWidth() const; @@ -153,6 +155,9 @@ public: virtual void setCopyrightVisible(bool visible); virtual void removeMapObject(QGeoMapObject *obj); + void setVisibleArea(const QRectF &visibleArea); + QRectF visibleArea() const; + protected: QGeoMap(QGeoMapPrivate &dd, QObject *parent = 0); void setCameraData(const QGeoCameraData &cameraData); @@ -167,6 +172,7 @@ Q_SIGNALS: void copyrightsChanged(const QImage ©rightsImage); void copyrightsChanged(const QString ©rightsHtml); void copyrightsStyleSheetChanged(const QString &styleSheet); + void visibleAreaChanged(); private: Q_DISABLE_COPY(QGeoMap) diff --git a/src/location/maps/qgeomap_p_p.h b/src/location/maps/qgeomap_p_p.h index 47780c47..7bda316d 100644 --- a/src/location/maps/qgeomap_p_p.h +++ b/src/location/maps/qgeomap_p_p.h @@ -103,6 +103,12 @@ protected: virtual void setCopyrightVisible(bool visible); virtual bool copyrightVisible() const; virtual double maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const; + virtual double minimumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const; + + virtual void setVisibleArea(const QRectF &visibleArea); + virtual QRectF visibleArea() const; + + QRectF clampVisibleArea(const QRectF &visibleArea) const; protected: QSize m_viewportSize; @@ -115,6 +121,7 @@ protected: QGeoCameraCapabilities m_cameraCapabilities; bool m_copyrightVisible = true; mutable double m_maximumViewportLatitude = 0; + mutable double m_minimumViewportLatitude = 0; }; QT_END_NAMESPACE diff --git a/src/location/maps/qgeoprojection.cpp b/src/location/maps/qgeoprojection.cpp index 74736cef..a456f80e 100644 --- a/src/location/maps/qgeoprojection.cpp +++ b/src/location/maps/qgeoprojection.cpp @@ -39,6 +39,7 @@ #include <QtPositioning/private/qlocationutils_p.h> #include <QtPositioning/private/qclipperutils_p.h> #include <QtPositioning/QGeoPolygon> +#include <QtPositioning/QGeoRectangle> #include <QSize> #include <QtGui/QMatrix4x4> #include <cmath> @@ -62,6 +63,30 @@ static QMatrix4x4 toMatrix4x4(const QDoubleMatrix4x4 &m) m(3,0), m(3,1), m(3,2), m(3,3)); } +static QPointF centerOffset(const QSizeF &screenSize, const QRectF &visibleArea) +{ + QRectF va = visibleArea; + if (va.isNull()) + va = QRectF(0, 0, screenSize.width(), screenSize.height()); + + QRectF screen = QRectF(QPointF(0,0),screenSize); + QPointF vaCenter = va.center(); + + QPointF screenCenter = screen.center(); + QPointF diff = screenCenter - vaCenter; + + return diff; +} + +static QPointF marginsOffset(const QSizeF &screenSize, const QRectF &visibleArea) +{ + QPointF diff = centerOffset(screenSize, visibleArea); + qreal xdiffpct = diff.x() / qMax<double>(screenSize.width() - 1, 1); + qreal ydiffpct = diff.y() / qMax<double>(screenSize.height() - 1, 1); + + return QPointF(-xdiffpct, -ydiffpct); +} + QT_BEGIN_NAMESPACE QGeoProjection::QGeoProjection() @@ -175,14 +200,36 @@ double QGeoProjectionWebMercator::maximumCenterLatitudeAtZoom(const QGeoCameraDa // At init time weird things happen int clampedWindowHeight = (m_viewportHeight > mapEdgeSize) ? mapEdgeSize : m_viewportHeight; + QPointF offsetPct = centerOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea); + double hpct = offsetPct.y() / qMax<double>(m_viewportHeight - 1, 1); // Use the window height divided by 2 as the topmost allowed center, with respect to the map size in pixels - double mercatorTopmost = (clampedWindowHeight * 0.5) / mapEdgeSize ; + double mercatorTopmost = (clampedWindowHeight * (0.5 - hpct)) / mapEdgeSize ; QGeoCoordinate topMost = QWebMercator::mercatorToCoord(QDoubleVector2D(0.0, mercatorTopmost)); - return topMost.latitude(); } +double QGeoProjectionWebMercator::minimumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const +{ + double mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * defaultTileSize; + + // At init time weird things happen + int clampedWindowHeight = (m_viewportHeight > mapEdgeSize) ? mapEdgeSize : m_viewportHeight; + QPointF offsetPct = centerOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea); + double hpct = offsetPct.y() / qMax<double>(m_viewportHeight - 1, 1); + + // Use the window height divided by 2 as the topmost allowed center, with respect to the map size in pixels + double mercatorTopmost = (clampedWindowHeight * (0.5 + hpct)) / mapEdgeSize ; + QGeoCoordinate topMost = QWebMercator::mercatorToCoord(QDoubleVector2D(0.0, mercatorTopmost)); + return -topMost.latitude(); +} + +void QGeoProjectionWebMercator::setVisibleArea(const QRectF &visibleArea) +{ + m_visibleArea = visibleArea; + setupCamera(); +} + double QGeoProjectionWebMercator::mapWidth() const { return m_mapEdgeSize; @@ -258,7 +305,8 @@ QDoubleVector2D QGeoProjectionWebMercator::wrappedMapProjectionToItemPosition(co QDoubleVector2D QGeoProjectionWebMercator::itemPositionToWrappedMapProjection(const QDoubleVector2D &itemPosition) const { - QDoubleVector2D pos = itemPosition; + const QPointF centerOff = centerOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea); + QDoubleVector2D pos = itemPosition + QDoubleVector2D(centerOff); pos *= QDoubleVector2D(m_1_viewportWidth, m_1_viewportHeight); pos *= 2.0; pos -= QDoubleVector2D(1.0,1.0); @@ -434,16 +482,54 @@ QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(const QDoubleVector2D pos = itemPosition; pos *= QDoubleVector2D(m_halfWidth, m_halfHeight); + // determine itemPosition on the near plane QDoubleVector3D p = m_centerNearPlane; p += m_up * pos.y(); p += m_side * pos.x(); + // compute the ray using the eye position QDoubleVector3D ray = m_eye - p; ray.normalize(); return (xyPlane.lineIntersection(m_eye, ray, s) / m_sideLength).toVector2D(); } +/* + Returns a pair of <newCenter, newZoom> +*/ +QPair<QGeoCoordinate, qreal> QGeoProjectionWebMercator::fitViewportToGeoRectangle(const QGeoRectangle &rectangle, + const QMargins &m) const +{ + QPair<QGeoCoordinate, qreal> res; + res.second = qQNaN(); + if (m_viewportWidth <= m.left() + m.right() || m_viewportHeight <= m.top() + m.bottom()) + return res; + + QDoubleVector2D topLeftPoint = geoToMapProjection(rectangle.topLeft()); + QDoubleVector2D bottomRightPoint = geoToMapProjection(rectangle.bottomRight()); + if (bottomRightPoint.x() < topLeftPoint.x()) // crossing the dateline + bottomRightPoint.setX(bottomRightPoint.x() + 1.0); + + // find center of the bounding box + QDoubleVector2D center = (topLeftPoint + bottomRightPoint) * 0.5; + center.setX(center.x() > 1.0 ? center.x() - 1.0 : center.x()); + res.first = mapProjectionToGeo(center); + + // if the shape is empty we just change center position, not zoom + double bboxWidth = (bottomRightPoint.x() - topLeftPoint.x()) * mapWidth(); + double bboxHeight = (bottomRightPoint.y() - topLeftPoint.y()) * mapHeight(); + + if (bboxHeight == 0.0 && bboxWidth == 0.0) + return res; + + double zoomRatio = qMax(bboxWidth / (m_viewportWidth - m.left() - m.right()), + bboxHeight / (m_viewportHeight - m.top() - m.bottom())); + zoomRatio = std::log(zoomRatio) / std::log(2.0); + res.second = m_cameraData.zoomLevel() - zoomRatio; + + return res; +} + QGeoProjection::ProjectionGroup QGeoProjectionWebMercator::projectionGroup() const { return QGeoProjection::ProjectionCylindrical; @@ -563,10 +649,11 @@ void QGeoProjectionWebMercator::setupCamera() * matScreen = scale(m_viewportWidth, m_viewportHeight, 1.0) */ + QPointF offsetPct = marginsOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea); QDoubleMatrix4x4 matScreenTransformation; matScreenTransformation.scale(0.5 * m_viewportWidth, 0.5 * m_viewportHeight, 1.0); - matScreenTransformation(0,3) = 0.5 * m_viewportWidth; - matScreenTransformation(1,3) = 0.5 * m_viewportHeight; + matScreenTransformation(0,3) = (0.5 + offsetPct.x()) * m_viewportWidth; + matScreenTransformation(1,3) = (0.5 + offsetPct.y()) * m_viewportHeight; m_transformation = matScreenTransformation * projectionMatrix * cameraMatrix; m_quickItemTransformation = m_transformation; @@ -597,10 +684,18 @@ void QGeoProjectionWebMercator::updateVisibleRegion() { m_visibleRegionDirty = false; - QDoubleVector2D tl = viewportToWrappedMapProjection(QDoubleVector2D(-1, -1 + m_verticalEstateToSkip )); - QDoubleVector2D tr = viewportToWrappedMapProjection(QDoubleVector2D( 1, -1 + m_verticalEstateToSkip )); - QDoubleVector2D bl = viewportToWrappedMapProjection(QDoubleVector2D(-1, 1 )); - QDoubleVector2D br = viewportToWrappedMapProjection(QDoubleVector2D( 1, 1 )); + double viewportHalfWidth = (!m_visibleArea.isEmpty()) ? m_visibleArea.width() / m_viewportWidth : 1.0; + double viewportHalfHeight = (!m_visibleArea.isEmpty()) ? m_visibleArea.height() / m_viewportHeight : 1.0; + + double top = qMax<double>(-viewportHalfHeight, -1 + m_verticalEstateToSkip); + double bottom = viewportHalfHeight; + double left = -viewportHalfWidth; + double right = viewportHalfWidth; + + QDoubleVector2D tl = viewportToWrappedMapProjection(QDoubleVector2D(left, top )); + QDoubleVector2D tr = viewportToWrappedMapProjection(QDoubleVector2D(right, top )); + QDoubleVector2D bl = viewportToWrappedMapProjection(QDoubleVector2D(left, bottom )); + QDoubleVector2D br = viewportToWrappedMapProjection(QDoubleVector2D(right, bottom )); // To make sure that what is returned can be safely converted back to lat/lon without risking overlaps double mapLeftLongitude = QLocationUtils::mapLeftLongitude(m_cameraData.center().longitude()); diff --git a/src/location/maps/qgeoprojection_p.h b/src/location/maps/qgeoprojection_p.h index b0fffa28..e33ae880 100644 --- a/src/location/maps/qgeoprojection_p.h +++ b/src/location/maps/qgeoprojection_p.h @@ -85,6 +85,7 @@ public: QGeoProjection(); virtual ~QGeoProjection(); + virtual void setVisibleArea(const QRectF &visibleArea) = 0; virtual void setViewportSize(const QSize &size) = 0; virtual void setCameraData(const QGeoCameraData &cameraData, bool force = true) = 0; virtual QGeoCameraData cameraData() const = 0; @@ -92,6 +93,7 @@ public: // returns the minimum zoom at the current viewport size virtual double minimumZoom() const = 0; virtual double maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const = 0; + virtual double minimumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const = 0; virtual QGeoCoordinate itemPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport = true) const = 0; virtual QDoubleVector2D coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport = true) const = 0; @@ -116,7 +118,9 @@ public: // From QGeoProjection double minimumZoom() const override; double maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const override; + double minimumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const override; + void setVisibleArea(const QRectF &visibleArea) override; void setViewportSize(const QSize &size) override; void setCameraData(const QGeoCameraData &cameraData, bool force = true) override; QGeoCameraData cameraData() const override; @@ -158,6 +162,9 @@ public: inline QDoubleVector2D viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition) const; inline QDoubleVector2D viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition, double &s) const; + QPair<QGeoCoordinate, qreal> fitViewportToGeoRectangle(const QGeoRectangle &rectangle, + const QMargins &margins) const; + private: void setupCamera(); void updateVisibleRegion(); @@ -234,6 +241,7 @@ private: QList<QDoubleVector2D> m_visibleRegionExpanded; QList<QDoubleVector2D> m_projectableRegion; bool m_visibleRegionDirty; + QRectF m_visibleArea; Q_DISABLE_COPY(QGeoProjectionWebMercator) }; diff --git a/src/location/maps/qgeotiledmap.cpp b/src/location/maps/qgeotiledmap.cpp index a1231cf4..74346fdb 100644 --- a/src/location/maps/qgeotiledmap.cpp +++ b/src/location/maps/qgeotiledmap.cpp @@ -149,7 +149,8 @@ QGeoMap::Capabilities QGeoTiledMap::capabilities() const { return Capabilities(SupportsVisibleRegion | SupportsSetBearing - | SupportsAnchoringCoordinate); + | SupportsAnchoringCoordinate + | SupportsVisibleArea); } void QGeoTiledMap::setCopyrightVisible(bool visible) @@ -353,6 +354,31 @@ void QGeoTiledMapPrivate::updateScene() emit q->sgNodeChanged(); } +void QGeoTiledMapPrivate::setVisibleArea(const QRectF &visibleArea) +{ + Q_Q(QGeoTiledMap); + const QRectF va = clampVisibleArea(visibleArea); + if (va == m_visibleArea) + return; + + m_visibleArea = va; + m_geoProjection->setVisibleArea(va); + + m_visibleTiles->setVisibleArea(va); + m_prefetchTiles->setVisibleArea(va); + m_mapScene->setVisibleArea(va); + + if (m_copyrightVisible) + q->evaluateCopyrights(m_mapScene->visibleTiles()); + updateScene(); + q->sgNodeChanged(); +} + +QRectF QGeoTiledMapPrivate::visibleArea() const +{ + return m_visibleArea; +} + void QGeoTiledMapPrivate::changeActiveMapType(const QGeoMapType mapType) { m_visibleTiles->setTileSize(m_cameraCapabilities.tileSize()); diff --git a/src/location/maps/qgeotiledmap_p_p.h b/src/location/maps/qgeotiledmap_p_p.h index d3791d49..0ba349ca 100644 --- a/src/location/maps/qgeotiledmap_p_p.h +++ b/src/location/maps/qgeotiledmap_p_p.h @@ -91,12 +91,16 @@ protected: void updateScene(); + void setVisibleArea(const QRectF &visibleArea) override; + QRectF visibleArea() const override; + protected: QAbstractGeoTileCache *m_cache; QGeoCameraTiles *m_visibleTiles; QGeoCameraTiles *m_prefetchTiles; QGeoTiledMapScene *m_mapScene; QGeoTileRequestManager *m_tileRequests; + QRectF m_visibleArea; int m_maxZoomLevel; int m_minZoomLevel; QGeoTiledMap::PrefetchStyle m_prefetchStyle; diff --git a/src/location/maps/qgeotiledmapscene.cpp b/src/location/maps/qgeotiledmapscene.cpp index ab15e37b..4709a48f 100644 --- a/src/location/maps/qgeotiledmapscene.cpp +++ b/src/location/maps/qgeotiledmapscene.cpp @@ -67,6 +67,7 @@ public: QSize m_screenSize; // in pixels int m_tileSize; // the pixel resolution for each tile QGeoCameraData m_cameraData; + QRectF m_visibleArea; QSet<QGeoTileSpec> m_visibleTiles; QDoubleVector3D m_cameraUp; @@ -153,6 +154,15 @@ void QGeoTiledMapScene::setCameraData(const QGeoCameraData &cameraData) updateSceneParameters(); } +void QGeoTiledMapScene::setVisibleArea(const QRectF &visibleArea) +{ + Q_D(QGeoTiledMapScene); + if (d->m_visibleArea == visibleArea) + return; + d->m_visibleArea = visibleArea; + updateSceneParameters(); +} + void QGeoTiledMapScene::setVisibleTiles(const QSet<QGeoTileSpec> &tiles) { Q_D(QGeoTiledMapScene); @@ -465,8 +475,32 @@ void QGeoTiledMapScenePrivate::setupCamera() float halfHeight = 1 * apertureSize; halfWidth *= aspectRatio; +// m_projectionMatrix.setToIdentity(); +// m_projectionMatrix.frustum(-halfWidth, halfWidth, -halfHeight, halfHeight, nearPlane, farPlane); + + QRectF va = m_visibleArea; + if (va.isNull()) + va = QRectF(0, 0, m_screenSize.width(), m_screenSize.height()); + + QRectF screen = QRectF(QPointF(0,0),m_screenSize); + QPointF vaCenter = va.center(); + + QPointF screenCenter = screen.center(); + QPointF diff = screenCenter - vaCenter; + float xdiffpct = diff.x() / m_screenSize.width(); + float ydiffpct = -(diff.y() / m_screenSize.height()); + m_projectionMatrix.setToIdentity(); - m_projectionMatrix.frustum(-halfWidth, halfWidth, -halfHeight, halfHeight, nearPlane, farPlane); + float l = -halfWidth + (2 * halfWidth) * xdiffpct; + float r = halfWidth + (2 * halfWidth) * xdiffpct; + float t = halfHeight + (2 * halfHeight) * ydiffpct; + float b = -halfHeight + (2 * halfHeight) * ydiffpct; + + m_projectionMatrix.frustum(l, + r, + b, + t, + nearPlane, farPlane); } class QGeoTiledMapTileContainerNode : public QSGTransformNode diff --git a/src/location/maps/qgeotiledmapscene_p.h b/src/location/maps/qgeotiledmapscene_p.h index f6a8f714..ac607f41 100644 --- a/src/location/maps/qgeotiledmapscene_p.h +++ b/src/location/maps/qgeotiledmapscene_p.h @@ -72,6 +72,7 @@ public: void setScreenSize(const QSize &size); void setTileSize(int tileSize); void setCameraData(const QGeoCameraData &cameraData); + void setVisibleArea(const QRectF &visibleArea); void setVisibleTiles(const QSet<QGeoTileSpec> &tiles); const QSet<QGeoTileSpec> &visibleTiles() const; diff --git a/src/plugins/geoservices/itemsoverlay/qgeomapitemsoverlay.cpp b/src/plugins/geoservices/itemsoverlay/qgeomapitemsoverlay.cpp index af0e263b..dede9dbc 100644 --- a/src/plugins/geoservices/itemsoverlay/qgeomapitemsoverlay.cpp +++ b/src/plugins/geoservices/itemsoverlay/qgeomapitemsoverlay.cpp @@ -70,10 +70,16 @@ public: #endif void updateObjectsGeometry(); + + void setVisibleArea(const QRectF &visibleArea) override; + QRectF visibleArea() const override; + protected: void changeViewportSize(const QSize &size) override; void changeCameraData(const QGeoCameraData &oldCameraData) override; void changeActiveMapType(const QGeoMapType mapType) override; + + QRectF m_visibleArea; }; QGeoMapItemsOverlay::QGeoMapItemsOverlay(QGeoMappingManagerEngineItemsOverlay *engine, QObject *parent) @@ -131,6 +137,24 @@ void QGeoMapItemsOverlay::removeMapObject(QGeoMapObject *obj) #endif } +void QGeoMapItemsOverlayPrivate::setVisibleArea(const QRectF &visibleArea) +{ + Q_Q(QGeoMapItemsOverlay); + const QRectF va = clampVisibleArea(visibleArea); + if (va == m_visibleArea) + return; + + m_visibleArea = va; + m_geoProjection->setVisibleArea(va); + + q->sgNodeChanged(); +} + +QRectF QGeoMapItemsOverlayPrivate::visibleArea() const +{ + return m_visibleArea; +} + QGeoMapItemsOverlayPrivate::QGeoMapItemsOverlayPrivate(QGeoMappingManagerEngineItemsOverlay *engine, QGeoMapItemsOverlay *map) : QGeoMapPrivate(engine, new QGeoProjectionWebMercator) { diff --git a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp index dfebc20d..575bf3b4 100644 --- a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp +++ b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp @@ -106,12 +106,12 @@ QSGNode *QGeoMapMapboxGLPrivate::updateSceneGraph(QSGNode *node, QQuickWindow *w if (m_useFBO) { QSGMapboxGLTextureNode *mbglNode = new QSGMapboxGLTextureNode(m_settings, m_viewportSize, window->devicePixelRatio(), q); QObject::connect(mbglNode->map(), &QMapboxGL::mapChanged, q, &QGeoMapMapboxGL::onMapChanged); - m_syncState = MapTypeSync | CameraDataSync | ViewportSync; + m_syncState = MapTypeSync | CameraDataSync | ViewportSync | VisibleAreaSync; node = mbglNode; } else { QSGMapboxGLRenderNode *mbglNode = new QSGMapboxGLRenderNode(m_settings, m_viewportSize, window->devicePixelRatio(), q); QObject::connect(mbglNode->map(), &QMapboxGL::mapChanged, q, &QGeoMapMapboxGL::onMapChanged); - m_syncState = MapTypeSync | CameraDataSync | ViewportSync; + m_syncState = MapTypeSync | CameraDataSync | ViewportSync | VisibleAreaSync; node = mbglNode; } } @@ -125,7 +125,15 @@ QSGNode *QGeoMapMapboxGLPrivate::updateSceneGraph(QSGNode *node, QQuickWindow *w map->setStyleUrl(m_activeMapType.name()); } - if (m_syncState & CameraDataSync) { + if (m_syncState & VisibleAreaSync) { + QMargins margins(m_visibleArea.x(), // left + m_visibleArea.y(), // top + m_viewportSize.width() - m_visibleArea.width() - m_visibleArea.x(), // right + m_viewportSize.height() - m_visibleArea.height() - m_visibleArea.y()); // bottom + map->setMargins(margins); + } + + if (m_syncState & CameraDataSync || m_syncState & VisibleAreaSync) { map->setZoom(zoomLevelFrom256(m_cameraData.zoomLevel() , MBGL_TILE_SIZE)); map->setBearing(m_cameraData.bearing()); map->setPitch(m_cameraData.tilt()); @@ -291,6 +299,25 @@ void QGeoMapMapboxGLPrivate::changeActiveMapType(const QGeoMapType) emit q->sgNodeChanged(); } +void QGeoMapMapboxGLPrivate::setVisibleArea(const QRectF &visibleArea) +{ + Q_Q(QGeoMapMapboxGL); + const QRectF va = clampVisibleArea(visibleArea); + if (va == m_visibleArea) + return; + + m_visibleArea = va; + m_geoProjection->setVisibleArea(va); + + m_syncState = m_syncState | VisibleAreaSync; + emit q->sgNodeChanged(); +} + +QRectF QGeoMapMapboxGLPrivate::visibleArea() const +{ + return m_visibleArea; +} + void QGeoMapMapboxGLPrivate::syncStyleChanges(QMapboxGL *map) { for (const auto& change : m_styleChanges) { @@ -376,7 +403,8 @@ QGeoMap::Capabilities QGeoMapMapboxGL::capabilities() const { return Capabilities(SupportsVisibleRegion | SupportsSetBearing - | SupportsAnchoringCoordinate); + | SupportsAnchoringCoordinate + | SupportsVisibleArea ); } QSGNode *QGeoMapMapboxGL::updateSceneGraph(QSGNode *oldNode, QQuickWindow *window) diff --git a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl_p.h b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl_p.h index ffb06208..f07b4c98 100644 --- a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl_p.h +++ b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl_p.h @@ -43,6 +43,7 @@ #include <QtCore/QSharedPointer> #include <QtCore/QTimer> #include <QtCore/QVariant> +#include <QtCore/QRectF> #include <QtLocation/private/qgeomap_p_p.h> #include <QtLocation/private/qgeomapparameter_p.h> @@ -70,9 +71,10 @@ public: /* Data members */ enum SyncState : int { NoSync = 0, - ViewportSync = 1 << 0, - CameraDataSync = 1 << 1, - MapTypeSync = 1 << 2 + ViewportSync = 1 << 0, + CameraDataSync = 1 << 1, + MapTypeSync = 1 << 2, + VisibleAreaSync = 1 << 3 }; Q_DECLARE_FLAGS(SyncStates, SyncState); @@ -96,11 +98,16 @@ protected: void changeCameraData(const QGeoCameraData &oldCameraData) override; void changeActiveMapType(const QGeoMapType mapType) override; + void setVisibleArea(const QRectF &visibleArea) override; + QRectF visibleArea() const override; + private: Q_DISABLE_COPY(QGeoMapMapboxGLPrivate); void syncStyleChanges(QMapboxGL *map); void threadedRenderingHack(QQuickWindow *window, QMapboxGL *map); + + QRectF m_visibleArea; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QGeoMapMapboxGLPrivate::SyncStates) diff --git a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp index 6c47d3ee..d9de5ba9 100644 --- a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp +++ b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp @@ -186,8 +186,7 @@ QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleChange::addMapParamete { static const QStringList acceptedParameterTypes = QStringList() << QStringLiteral("paint") << QStringLiteral("layout") << QStringLiteral("filter") - << QStringLiteral("layer") << QStringLiteral("source") << QStringLiteral("image") - << QStringLiteral("margins"); + << QStringLiteral("layer") << QStringLiteral("source") << QStringLiteral("image"); QList<QSharedPointer<QMapboxGLStyleChange>> changes; @@ -213,9 +212,6 @@ QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleChange::addMapParamete case 5: // image changes << QMapboxGLStyleAddImage::fromMapParameter(param); break; - case 6: // margins - changes << QMapboxGLMapMargins::fromMapParameter(param); - break; } return changes; @@ -641,38 +637,3 @@ QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleAddImage::fromMapParameter(QG return QSharedPointer<QMapboxGLStyleChange>(image); } - -// QMapboxGLMapMargins - -void QMapboxGLMapMargins::apply(QMapboxGL *map) -{ - // FIXME: Qt projection handlers are not yet aware of these margins, - // thus map items placement, {to,from}Coordinate, mouse area, etc. - // will require manual fixups. - map->setMargins(m_margins); -} - -QSharedPointer<QMapboxGLStyleChange> QMapboxGLMapMargins::fromMapParameter(QGeoMapParameter *param) -{ - Q_ASSERT(param->type() == "margins"); - - auto mapMargins = new QMapboxGLMapMargins(); - - QVariant leftMargin = param->property("left"); - if (leftMargin.isValid()) - mapMargins->m_margins.setLeft(leftMargin.toInt()); - - QVariant topMargin = param->property("top"); - if (topMargin.isValid()) - mapMargins->m_margins.setTop(topMargin.toInt()); - - QVariant rightMargin = param->property("right"); - if (rightMargin.isValid()) - mapMargins->m_margins.setRight(rightMargin.toInt()); - - QVariant bottomMargin = param->property("bottom"); - if (bottomMargin.isValid()) - mapMargins->m_margins.setBottom(bottomMargin.toInt()); - - return QSharedPointer<QMapboxGLStyleChange>(mapMargins); -} diff --git a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange_p.h b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange_p.h index 38aa87f8..fd5b9af4 100644 --- a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange_p.h +++ b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange_p.h @@ -190,17 +190,4 @@ private: QImage m_sprite; }; -class QMapboxGLMapMargins : public QMapboxGLStyleChange -{ -public: - static QSharedPointer<QMapboxGLStyleChange> fromMapParameter(QGeoMapParameter *); - - void apply(QMapboxGL *map) override; - -private: - QMapboxGLMapMargins() = default; - - QMargins m_margins; -}; - #endif // QQMAPBOXGLSTYLECHANGE_P_H diff --git a/tests/auto/declarative_ui/tst_map.qml b/tests/auto/declarative_ui/tst_map.qml index f05b2c72..2d35fce0 100644 --- a/tests/auto/declarative_ui/tst_map.qml +++ b/tests/auto/declarative_ui/tst_map.qml @@ -52,6 +52,13 @@ Item { extraTypeName = "SomeString" } } + Plugin { + id: testPluginNoVisibleArea; + name: "qmlgeo.test.plugin"; + allowExperimental: true + PluginParameter { name: "supportVisibleArea"; value: false} + } + Plugin { id: itemsOverlay; name: "itemsoverlay"; } property variant coordinate1: QtPositioning.coordinate(10, 11) property variant coordinate2: QtPositioning.coordinate(12, 13) @@ -127,6 +134,16 @@ Item { property var center: QtPositioning.coordinate(-33.0, -47.0) } + Map { + id: mapVisibleArea + width: 256; height: 256; + } + Map { + id: mapVisibleAreaUnsupported + width: 256; height: 256; + } + SignalSpy { id: visibleAreaSpy; target: mapVisibleArea; signalName: 'visibleAreaChanged'} + SignalSpy { id: visibleAreaUnsupportedSpy; target: mapVisibleAreaUnsupported; signalName: 'visibleAreaChanged'} TestCase { when: windowShown && allMapsReady @@ -684,5 +701,29 @@ Item { verify(isNaN(pos.latitude)) verify(isNaN(pos.longitde)) } + + function test_visible_area() + { + wait(1000) + visibleAreaSpy.clear(); + visibleAreaUnsupportedSpy.clear(); + var defaultRect = Qt.rect(0,0,0,0) + + verify(mapVisibleAreaUnsupported.visibleArea, defaultRect) + mapVisibleAreaUnsupported.visibleArea = Qt.rect(0,0,256,256) + compare(visibleAreaUnsupportedSpy.count, 1) + verify(mapVisibleAreaUnsupported.visibleArea, Qt.rect(0,0,256,256)) + mapVisibleAreaUnsupported.plugin = testPluginNoVisibleArea + tryCompare(visibleAreaUnsupportedSpy, "count", 2) + verify(mapVisibleAreaUnsupported.visibleArea, defaultRect) + + verify(mapVisibleArea.visibleArea, defaultRect) + mapVisibleArea.visibleArea = Qt.rect(0,0,256,256) + compare(visibleAreaSpy.count, 1) + verify(mapVisibleArea.visibleArea, Qt.rect(0,0,256,256)) + mapVisibleArea.plugin = testPlugin + tryCompare(visibleAreaSpy, "count", 1) + verify(mapVisibleAreaUnsupported.visibleArea, Qt.rect(0,0,256,256)) + } } } diff --git a/tests/auto/geotestplugin/qgeotiledmap_test.cpp b/tests/auto/geotestplugin/qgeotiledmap_test.cpp index ef2af7db..62abb313 100644 --- a/tests/auto/geotestplugin/qgeotiledmap_test.cpp +++ b/tests/auto/geotestplugin/qgeotiledmap_test.cpp @@ -36,8 +36,9 @@ class QGeoTiledMapTestPrivate: public QGeoTiledMapPrivate { Q_DECLARE_PUBLIC(QGeoTiledMapTest) public: - QGeoTiledMapTestPrivate(QGeoTiledMappingManagerEngine *engine) - : QGeoTiledMapPrivate(engine) + QGeoTiledMapTestPrivate(QGeoTiledMappingManagerEngine *engine, + const QGeoTiledMapTestOptions &options) + : QGeoTiledMapPrivate(engine), m_options(options) { } @@ -68,10 +69,30 @@ public: Q_Q(QGeoTiledMapTest); param->disconnect(q); } + + virtual void setVisibleArea(const QRectF &visibleArea) override + { + if (m_options.supportVisibleArea) + return QGeoTiledMapPrivate::setVisibleArea(visibleArea); + else + return QGeoMapPrivate::setVisibleArea(visibleArea); + } + + virtual QRectF visibleArea() const override + { + if (m_options.supportVisibleArea) + return QGeoTiledMapPrivate::visibleArea(); + else + return QGeoMapPrivate::visibleArea(); + } + + QGeoTiledMapTestOptions m_options; }; -QGeoTiledMapTest::QGeoTiledMapTest(QGeoTiledMappingManagerEngine *engine, QObject *parent) -: QGeoTiledMap(*new QGeoTiledMapTestPrivate(engine), engine, parent), m_engine(engine) +QGeoTiledMapTest::QGeoTiledMapTest(QGeoTiledMappingManagerEngine *engine, + const QGeoTiledMapTestOptions &options, + QObject *parent) +: QGeoTiledMap(*new QGeoTiledMapTestPrivate(engine, options), engine, parent), m_engine(engine) { } diff --git a/tests/auto/geotestplugin/qgeotiledmap_test.h b/tests/auto/geotestplugin/qgeotiledmap_test.h index 19c7620e..a6299efe 100644 --- a/tests/auto/geotestplugin/qgeotiledmap_test.h +++ b/tests/auto/geotestplugin/qgeotiledmap_test.h @@ -37,12 +37,18 @@ QT_USE_NAMESPACE class QGeoTiledMappingManagerEngineTest; class QGeoTiledMapTestPrivate; +struct QGeoTiledMapTestOptions { + bool supportVisibleArea = true; +}; + class QGeoTiledMapTest: public QGeoTiledMap { Q_OBJECT Q_DECLARE_PRIVATE(QGeoTiledMapTest) public: - QGeoTiledMapTest(QGeoTiledMappingManagerEngine *engine, QObject *parent = 0); + QGeoTiledMapTest(QGeoTiledMappingManagerEngine *engine, + const QGeoTiledMapTestOptions &options, + QObject *parent = 0); protected slots: void onCameraCenter_testChanged(QGeoMapParameter *param, const char *propertyName); diff --git a/tests/auto/geotestplugin/qgeotiledmappingmanagerengine_test.h b/tests/auto/geotestplugin/qgeotiledmappingmanagerengine_test.h index 297be0d5..0db78336 100644 --- a/tests/auto/geotestplugin/qgeotiledmappingmanagerengine_test.h +++ b/tests/auto/geotestplugin/qgeotiledmappingmanagerengine_test.h @@ -100,6 +100,10 @@ public: double maxZoomLevel = parameters.value(QStringLiteral("maxZoomLevel")).toDouble(); capabilities.setMaximumZoomLevel(maxZoomLevel); } + if (parameters.contains(QStringLiteral("supportVisibleArea"))) { + bool supportVisibleArea = parameters.value(QStringLiteral("supportVisibleArea")).toBool(); + m_supportVisibleArea = supportVisibleArea; + } setCameraCapabilities(capabilities); fetcher->setTileSize(tileSize()); @@ -108,8 +112,12 @@ public: QGeoMap *createMap() override { - return new QGeoTiledMapTest(this); + QGeoTiledMapTestOptions opts; + opts.supportVisibleArea = m_supportVisibleArea; + return new QGeoTiledMapTest(this, opts); } + + bool m_supportVisibleArea = true; }; #endif |