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 /src/location/maps/qgeoprojection.cpp | |
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>
Diffstat (limited to 'src/location/maps/qgeoprojection.cpp')
-rw-r--r-- | src/location/maps/qgeoprojection.cpp | 113 |
1 files changed, 104 insertions, 9 deletions
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()); |