diff options
-rw-r--r-- | src/location/declarativemaps/qdeclarativegeomapquickitem.cpp | 41 | ||||
-rw-r--r-- | src/location/declarativemaps/qdeclarativegeomapquickitem_p.h | 12 | ||||
-rw-r--r-- | src/location/maps/qgeoprojection.cpp | 50 | ||||
-rw-r--r-- | src/location/maps/qgeoprojection_p.h | 3 |
4 files changed, 101 insertions, 5 deletions
diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp index 4fab18cb..5a10f39f 100644 --- a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp @@ -115,9 +115,25 @@ QT_BEGIN_NAMESPACE \image api-mapquickitem.png */ +QMapQuickItemMatrix4x4::QMapQuickItemMatrix4x4(QObject *parent) : QQuickTransform(parent) { } + +void QMapQuickItemMatrix4x4::setMatrix(const QMatrix4x4 &matrix) +{ + if (m_matrix == matrix) + return; + m_matrix = matrix; + update(); +} + +void QMapQuickItemMatrix4x4::applyTo(QMatrix4x4 *matrix) const +{ + *matrix *= m_matrix; +} + + QDeclarativeGeoMapQuickItem::QDeclarativeGeoMapQuickItem(QQuickItem *parent) : QDeclarativeGeoMapItemBase(parent), zoomLevel_(0.0), - mapAndSourceItemSet_(false), updatingGeometry_(false) + mapAndSourceItemSet_(false), updatingGeometry_(false), matrix_(nullptr) { setFlag(ItemHasContents, true); opacityContainer_ = new QQuickItem(this); @@ -177,7 +193,13 @@ void QDeclarativeGeoMapQuickItem::geometryChanged(const QRectF &newGeometry, con return; } - QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(x(), y()) + (scaleFactor() * QDoubleVector2D(anchorPoint_)), false); + QGeoCoordinate newCoordinate; + // with zoomLevel set the anchorPoint has to be factored into the transformation to properly transform around it. + if (zoomLevel_ != 0.0) + newCoordinate = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(x(), y()), false); + else + newCoordinate = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(x(), y()) + QDoubleVector2D(anchorPoint_), false); + if (newCoordinate.isValid()) setCoordinate(newCoordinate); @@ -337,11 +359,20 @@ void QDeclarativeGeoMapQuickItem::updatePolish() opacityContainer_->setOpacity(zoomLevelOpacity()); - sourceItem_.data()->setScale(scaleFactor()); - sourceItem_.data()->setPosition(QPointF(0,0)); setWidth(sourceItem_.data()->width()); setHeight(sourceItem_.data()->height()); - setPositionOnMap(coordinate(), scaleFactor() * anchorPoint_); + if (zoomLevel_ != 0.0) { // zoom level initialized to 0.0. If it's different, it has been set explicitly. + if (!matrix_) { + matrix_ = new QMapQuickItemMatrix4x4(this); + matrix_->appendToItem(opacityContainer_); + } + matrix_->setMatrix(map()->geoProjection().quickItemTransformation(coordinate(), anchorPoint_, zoomLevel_)); + setPositionOnMap(coordinate(), QPointF(0,0)); + } else { + if (matrix_) + matrix_->setMatrix(QMatrix4x4()); + setPositionOnMap(coordinate(), anchorPoint_); + } } /*! diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h b/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h index 23de8861..cce94d85 100644 --- a/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h +++ b/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h @@ -59,6 +59,17 @@ QT_BEGIN_NAMESPACE +class QMapQuickItemMatrix4x4 : public QQuickTransform +{ +public: + QMapQuickItemMatrix4x4(QObject *parent = nullptr); + + void setMatrix(const QMatrix4x4& matrix); + void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE; + + QMatrix4x4 m_matrix; +}; + class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapQuickItem : public QDeclarativeGeoMapItemBase { Q_OBJECT @@ -112,6 +123,7 @@ private: qreal zoomLevel_; bool mapAndSourceItemSet_; bool updatingGeometry_; + QMapQuickItemMatrix4x4 *matrix_; }; QT_END_NAMESPACE 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; diff --git a/src/location/maps/qgeoprojection_p.h b/src/location/maps/qgeoprojection_p.h index 6ea8fd6e..b17392b1 100644 --- a/src/location/maps/qgeoprojection_p.h +++ b/src/location/maps/qgeoprojection_p.h @@ -90,6 +90,7 @@ public: virtual QDoubleVector2D coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport = true) const = 0; virtual QDoubleVector2D geoToWrappedMapProjection(const QGeoCoordinate &coordinate) const = 0; virtual QGeoCoordinate wrappedMapProjectionToGeo(const QDoubleVector2D &wrappedProjection) const = 0; + virtual QMatrix4x4 quickItemTransformation(const QGeoCoordinate &coordinate, const QPointF &anchorPoint, qreal zoomLevel) const = 0; }; class Q_LOCATION_PRIVATE_EXPORT QGeoProjectionWebMercator : public QGeoProjection @@ -121,6 +122,7 @@ public: QDoubleVector2D coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport = true) const Q_DECL_OVERRIDE; QDoubleVector2D geoToWrappedMapProjection(const QGeoCoordinate &coordinate) const Q_DECL_OVERRIDE; QGeoCoordinate wrappedMapProjectionToGeo(const QDoubleVector2D &wrappedProjection) const Q_DECL_OVERRIDE; + QMatrix4x4 quickItemTransformation(const QGeoCoordinate &coordinate, const QPointF &anchorPoint, qreal zoomLevel) const Q_DECL_OVERRIDE; bool isProjectable(const QDoubleVector2D &wrappedProjection) const Q_DECL_OVERRIDE; QList<QDoubleVector2D> visibleRegion() const Q_DECL_OVERRIDE; @@ -170,6 +172,7 @@ private: double m_1_viewportHeight; QDoubleMatrix4x4 m_transformation; + QDoubleMatrix4x4 m_quickItemTransformation; QDoubleVector3D m_eye; QDoubleVector3D m_up; QDoubleVector3D m_center; |