summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@qt.io>2017-02-24 00:01:08 +0100
committerPaolo Angelelli <paolo.angelelli@qt.io>2017-03-08 10:00:49 +0000
commit919c4415d0dc06177d8f3c2a300549d62a8dcdd4 (patch)
tree4dae16cee274abc4910474f8a8c4be0fda09a0bc
parent34c474703f6761a2dafecb219da51c66ebd4709a (diff)
downloadqtlocation-919c4415d0dc06177d8f3c2a300549d62a8dcdd4.tar.gz
Fix MapQuickItem when zoomLevel is set
This patch fixes the behavior of MapQuickItem when the zoomLevel is set, that is it makes behave the qquickitem as if it would be on the map, instead of on the screen. Change-Id: Ibb8a6000e2f6a37a68c32df001fc8565079a6f70 Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapquickitem.cpp41
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapquickitem_p.h12
-rw-r--r--src/location/maps/qgeoprojection.cpp50
-rw-r--r--src/location/maps/qgeoprojection_p.h3
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;