summaryrefslogtreecommitdiffstats
path: root/src/location
diff options
context:
space:
mode:
Diffstat (limited to 'src/location')
-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;