diff options
Diffstat (limited to 'src/location/maps/qgeoprojection.cpp')
-rw-r--r-- | src/location/maps/qgeoprojection.cpp | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/src/location/maps/qgeoprojection.cpp b/src/location/maps/qgeoprojection.cpp index 8cb7a748..cd7e5114 100644 --- a/src/location/maps/qgeoprojection.cpp +++ b/src/location/maps/qgeoprojection.cpp @@ -53,6 +53,14 @@ namespace { QDoubleVector2D(-1.0,1.0) }; } +static QMatrix4x4 toMatrix4x4(const QDoubleMatrix4x4 &m) +{ + return QMatrix4x4(m(0,0), m(0,1), m(0,2), m(0,3), + m(1,0), m(1,1), m(1,2), m(1,3), + m(2,0), m(2,1), m(2,2), m(2,3), + m(3,0), m(3,1), m(3,2), m(3,3)); +} + QT_BEGIN_NAMESPACE QGeoProjection::QGeoProjection() @@ -244,6 +252,44 @@ QGeoCoordinate QGeoProjectionWebMercator::wrappedMapProjectionToGeo(const QDoubl return mapProjectionToGeo(unwrapMapProjection(wrappedProjection)); } +QMatrix4x4 QGeoProjectionWebMercator::quickItemTransformation(const QGeoCoordinate &coordinate, const QPointF &anchorPoint, double zoomLevel) const +{ + const QDoubleVector2D coordWrapped = geoToWrappedMapProjection(coordinate); + double scale = std::pow(0.5, zoomLevel - m_cameraData.zoomLevel()); + const QDoubleVector2D anchorScaled = QDoubleVector2D(anchorPoint.x(), anchorPoint.y()) * scale; + const QDoubleVector2D anchorMercator = anchorScaled / mapWidth(); + + // Check for coord OOB, only coordinate is going to be projected to item position, so + // testing also coordAnchored might be superfluous + if (!isProjectable(coordWrapped)) + return QMatrix4x4(); + + const QDoubleVector2D coordAnchored = coordWrapped - anchorMercator; + const QDoubleVector2D coordAnchoredScaled = coordAnchored * m_sideLength; + QDoubleMatrix4x4 matTranslateScale; + matTranslateScale.translate(coordAnchoredScaled.x(), coordAnchoredScaled.y(), 0.0); + + scale = std::pow(0.5, (zoomLevel - std::floor(zoomLevel)) + + (std::floor(zoomLevel) - std::floor(m_cameraData.zoomLevel()))); + matTranslateScale.scale(scale); + + const QDoubleVector2D coordOnScreen = wrappedMapProjectionToItemPosition(coordWrapped); + QDoubleMatrix4x4 matTransformation; + matTransformation.translate(-coordOnScreen.x(), -coordOnScreen.y(), 0); + matTransformation *= m_quickItemTransformation; + + /* + * The full transformation chain for quickItemTransformation() is: + * matScreenShift * m_quickItemTransformation * matTranslate * matScale + * where: + * matScreenShift = translate(-coordOnScreen.x(), -coordOnScreen.y(), 0) + * matTranslate = translate(coordAnchoredScaled.x(), coordAnchoredScaled.y(), 0.0) + * matScale = scale(scale) + */ + + return toMatrix4x4(matTransformation * matTranslateScale); +} + bool QGeoProjectionWebMercator::isProjectable(const QDoubleVector2D &wrappedProjection) const { if (m_cameraData.tilt() == 0.0) @@ -264,6 +310,9 @@ QList<QDoubleVector2D> QGeoProjectionWebMercator::visibleRegion() const return m_visibleRegion; } +/* + actual implementation of itemPositionToWrappedMapProjection +*/ QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition) const { QDoubleVector2D pos = itemPosition; @@ -395,6 +444,7 @@ void QGeoProjectionWebMercator::setupCamera() matScreenTransformation(1,3) = 0.5 * m_viewportHeight; m_transformation = matScreenTransformation * projectionMatrix * cameraMatrix; + m_quickItemTransformation = m_transformation; m_transformation.scale(m_sideLength, m_sideLength, 1.0); m_centerNearPlane = m_eye + m_viewNormalized; |