summaryrefslogtreecommitdiff
path: root/src/location/maps/qgeoprojection.cpp
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@qt.io>2018-06-19 16:33:44 +0200
committerPaolo Angelelli <paolo.angelelli@qt.io>2018-07-26 13:38:02 +0000
commiteca7cc8a260538fcccde97fe59d9580250600bf1 (patch)
tree6a87cc4391b1e0dbf65ee011d0314cfae4c8b19f /src/location/maps/qgeoprojection.cpp
parentd6fc6ba0f84c4cda0ccc2e1250da4a68441dd6ba (diff)
downloadqtlocation-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.cpp113
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());