QGeoShape QDeclarativeGeoMap::visibleRegion() const { if (!m_map || !width() || !height()) return m_region; QGeoCoordinate tl = m_map->itemPositionToCoordinate(QDoubleVector2D(0, 0)); QGeoCoordinate br = m_map->itemPositionToCoordinate(QDoubleVector2D(width(), height())); return QGeoRectangle(tl, br); }
/*! \internal */ void QDeclarativeCircleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { if (updatingGeometry_ || newGeometry == oldGeometry) { QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry); return; } QDoubleVector2D newPoint = QDoubleVector2D(x(),y()) + QDoubleVector2D(width(), height()) / 2; QGeoCoordinate newCoordinate = map()->itemPositionToCoordinate(newPoint, false); if (newCoordinate.isValid()) setCenter(newCoordinate); // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested // call to this function. }
/*! \qmlmethod coordinate QtLocation::Map::toCoordinate(QPointF position, bool clipToViewPort) Returns the coordinate which corresponds to the \a position relative to the map item. If \a cliptoViewPort is \c true, or not supplied then returns an invalid coordinate if \a position is not within the current viewport. */ QGeoCoordinate QDeclarativeGeoMap::toCoordinate(const QPointF &position, bool clipToViewPort) const { if (m_map) return m_map->itemPositionToCoordinate(QDoubleVector2D(position), clipToViewPort); else return QGeoCoordinate(); }
QGeoCoordinate QDeclarativeGeoMap::toCoordinate(const QPointF &screenPosition) const { if (map_) return map_->screenPositionToCoordinate(QDoubleVector2D(screenPosition)); else return QGeoCoordinate(); }
QGeoCoordinate QGeoProjection::coordinateInterpolation(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress) { QDoubleVector2D s = QGeoProjection::coordToMercator(from); QDoubleVector2D e = QGeoProjection::coordToMercator(to); double x = s.x(); if (0.5 < qAbs(e.x() - s.x())) { // handle dateline crossing double ex = e.x(); double sx = s.x(); if (ex < sx) sx -= 1.0; else if (sx < ex) ex -= 1.0; x = (1.0 - progress) * sx + progress * ex; if (!qFuzzyIsNull(x) && (x < 0.0)) x += 1.0; } else { x = (1.0 - progress) * s.x() + progress * e.x(); } double y = (1.0 - progress) * s.y() + progress * e.y(); QGeoCoordinate result = QGeoProjection::mercatorToCoord(QDoubleVector2D(x, y)); result.setAltitude((1.0 - progress) * from.altitude() + progress * to.altitude()); return result; }
/*! \internal */ void QDeclarativeGeoMapGestureArea::touchPointStateMachine() { // Transitions: switch (touchPointState_) { case touchPoints0: if (touchPoints_.count() == 1) { clearTouchData(); startOneTouchPoint(); touchPointState_ = touchPoints1; } else if (touchPoints_.count() >= 2) { clearTouchData(); startTwoTouchPoints(); touchPointState_ = touchPoints2; } break; case touchPoints1: if (touchPoints_.count() == 0) { touchPointState_ = touchPoints0; } else if (touchPoints_.count() >= 2) { touchCenterCoord_ = map_->screenPositionToCoordinate(QDoubleVector2D(sceneCenter_), false); startTwoTouchPoints(); touchPointState_ = touchPoints2; } break; case touchPoints2: if (touchPoints_.count() == 0) { touchPointState_ = touchPoints0; } else if (touchPoints_.count() == 1) { touchCenterCoord_ = map_->screenPositionToCoordinate(QDoubleVector2D(sceneCenter_), false); startOneTouchPoint(); touchPointState_ = touchPoints1; } break; }; // Update switch (touchPointState_) { case touchPoints0: break; // do nothing if no touch points down case touchPoints1: updateOneTouchPoint(); break; case touchPoints2: updateTwoTouchPoints(); break; } }
/*! \internal */ void QDeclarativePolylineMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { if (updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) { QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry); return; } QDoubleVector2D newPoint = QDoubleVector2D(x(),y()) + QDoubleVector2D(geometry_.firstPointOffset()); QGeoCoordinate newCoordinate = map()->screenPositionToCoordinate(newPoint, false); if (newCoordinate.isValid()) { double firstLongitude = path_.at(0).longitude(); double firstLatitude = path_.at(0).latitude(); double minMaxLatitude = firstLatitude; // prevent dragging over valid min and max latitudes for (int i = 0; i < path_.count(); ++i) { double newLatitude = path_.at(i).latitude() + newCoordinate.latitude() - firstLatitude; if (!QLocationUtils::isValidLat(newLatitude)) { if (qAbs(newLatitude) > qAbs(minMaxLatitude)) { minMaxLatitude = newLatitude; } } } // calculate offset needed to re-position the item within map border double offsetLatitude = minMaxLatitude - QLocationUtils::clipLat(minMaxLatitude); for (int i = 0; i < path_.count(); ++i) { QGeoCoordinate coord = path_.at(i); // handle dateline crossing coord.setLongitude(QLocationUtils::wrapLong(coord.longitude() + newCoordinate.longitude() - firstLongitude)); coord.setLatitude(coord.latitude() + newCoordinate.latitude() - firstLatitude - offsetLatitude); path_.replace(i, coord); } QGeoCoordinate leftBoundCoord = geometry_.geoLeftBound(); leftBoundCoord.setLongitude(QLocationUtils::wrapLong(leftBoundCoord.longitude() + newCoordinate.longitude() - firstLongitude)); geometry_.setPreserveGeometry(true, leftBoundCoord); geometry_.markSourceDirty(); updateMapItem(); emit pathChanged(); } // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested // call to this function. }
/*! \internal */ void QDeclarativeGeoMapGestureArea::updatePan() { QPointF startPoint = map_->coordinateToScreenPosition(startCoord_, false).toPointF(); int dx = static_cast<int>(sceneCenter_.x() - startPoint.x()); int dy = static_cast<int>(sceneCenter_.y() - startPoint.y()); QPointF mapCenterPoint; mapCenterPoint.setY(map_->height() / 2.0 - dy); mapCenterPoint.setX(map_->width() / 2.0 - dx); QGeoCoordinate animationStartCoordinate = map_->screenPositionToCoordinate(QDoubleVector2D(mapCenterPoint), false); map_->mapController()->setCenter(animationStartCoordinate); }
QDoubleVector2D QDoubleVector2D::normalized() const { // Need some extra precision if the length is very small. double len = double(xp) * double(xp) + double(yp) * double(yp); if (qFuzzyIsNull(len - 1.0)) return *this; else if (!qFuzzyIsNull(len)) return *this / (double)qSqrt(len); else return QDoubleVector2D(); }
/*! \internal */ void QDeclarativeGeoMapGestureArea::startOneTouchPoint() { sceneStartPoint1_ = touchPoints_.at(0).scenePos(); lastPos_ = sceneStartPoint1_; lastPosTime_.start(); QGeoCoordinate startCoord = map_->screenPositionToCoordinate(QDoubleVector2D(sceneStartPoint1_), false); // ensures a smooth transition for panning startCoord_.setLongitude(startCoord_.longitude() + startCoord.longitude() - touchCenterCoord_.longitude()); startCoord_.setLatitude(startCoord_.latitude() + startCoord.latitude() - touchCenterCoord_.latitude()); }
/*! \internal */ void QDeclarativeGeoMapGestureArea::startTwoTouchPoints() { sceneStartPoint1_ = touchPoints_.at(0).scenePos(); sceneStartPoint2_ = touchPoints_.at(1).scenePos(); QPointF startPos = (sceneStartPoint1_ + sceneStartPoint2_) * 0.5; lastPos_ = startPos; lastPosTime_.start(); QGeoCoordinate startCoord = map_->screenPositionToCoordinate(QDoubleVector2D(startPos), false); startCoord_.setLongitude(startCoord_.longitude() + startCoord.longitude() - touchCenterCoord_.longitude()); startCoord_.setLatitude(startCoord_.latitude() + startCoord.latitude() - touchCenterCoord_.latitude()); }
QT_BEGIN_NAMESPACE QDoubleVector2D QGeoProjection::coordToMercator(const QGeoCoordinate &coord) { const double pi = M_PI; double lon = coord.longitude() / 360.0 + 0.5; double lat = coord.latitude(); lat = 0.5 - (std::log(std::tan((pi / 4.0) + (pi / 2.0) * lat / 180.0)) / pi) / 2.0; lat = qBound(0.0, lat, 1.0); return QDoubleVector2D(lon, lat); }
QDoubleVector2D QGeoTiledMapData::coordinateToScreenPosition(const QGeoCoordinate &coordinate, bool clipToViewport) const { Q_D(const QGeoTiledMapData); QDoubleVector2D pos = d->coordinateToScreenPosition(coordinate); if (clipToViewport) { int w = width(); int h = height(); if ((pos.x() < 0) || (w < pos.x()) || (pos.y() < 0) || (h < pos.y())) return QDoubleVector2D(qQNaN(), qQNaN()); } return pos; }
/*! \internal */ void QDeclarativeGeoMapQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { if (!mapAndSourceItemSet_ || updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) { QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry); return; } QGeoCoordinate newCoordinate = map()->itemPositionToCoordinate(QDoubleVector2D(x(), y()) + (scaleFactor() * QDoubleVector2D(anchorPoint_)), false); if (newCoordinate.isValid()) setCoordinate(newCoordinate); // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested // call to this function. }
/*! \internal */ void QDeclarativeGeoMapGestureArea::panStateMachine() { PanState lastState = panState_; // Transitions switch (panState_) { case panInactive: if (canStartPan()) { // Update startCoord_ to ensure smooth start for panning when going over startDragDistance QGeoCoordinate newStartCoord = map_->screenPositionToCoordinate(QDoubleVector2D(lastPos_), false); startCoord_.setLongitude(newStartCoord.longitude()); startCoord_.setLatitude(newStartCoord.latitude()); panState_ = panActive; } break; case panActive: if (touchPoints_.count() == 0) { panState_ = panFlick; if (!tryStartFlick()) { panState_ = panInactive; // mark as inactive for use by camera if (pinchState_ == pinchInactive) emit movementStopped(); } } break; case panFlick: if (touchPoints_.count() > 0) { // re touched before movement ended endFlick(); panState_ = panActive; } break; } // Update switch (panState_) { case panInactive: // do nothing break; case panActive: updatePan(); // this ensures 'panStarted' occurs after the pan has actually started if (lastState != panActive) emit panStarted(); break; case panFlick: break; } }
void QGeoMapController::pan(qreal dx, qreal dy) { if (dx == 0 && dy == 0) return; QGeoCameraData cd = map_->cameraData(); QGeoCoordinate coord = map_->itemPositionToCoordinate( QDoubleVector2D(map_->width() / 2 + dx, map_->height() / 2 + dy)); // keep altitude as it was coord.setAltitude(cd.center().altitude()); if (coord.isValid()) { cd.setCenter(coord); map_->setCameraData(cd); } }
void tst_doubleVectors::constructor2dTest() { // empty constructor, since it sets to 0, we should check, in case people rely on it QDoubleVector2D v1; QCOMPARE(v1.x(), 0.0); QCOMPARE(v1.y(), 0.0); QCOMPARE(v1.isNull(), true); v1 = QDoubleVector2D(1.1, -2.5); // assignment and constructor QCOMPARE(v1.x(), 1.1); QCOMPARE(v1.y(), -2.5); QDoubleVector2D v2(v1); // copy constructor QCOMPARE(v2.x(), 1.1); QCOMPARE(v2.y(), -2.5); const QDoubleVector3D v3d(2.2, 3.3, 4.4); QDoubleVector2D v3(v3d); // constructor from 3d vector, just copies x and y QCOMPARE(v3.x(), 2.2); QCOMPARE(v3.y(), 3.3); QCOMPARE(v3.isNull(), false); }
QGeoCoordinate QGeoCoordinateInterpolator2D::interpolate(const QGeoCoordinate &start, const QGeoCoordinate &end, qreal progress) { if (start == end) { if (progress < 0.5) { return start; } else { return end; } } QGeoCoordinate s2 = start; QGeoCoordinate e2 = end; QDoubleVector2D s = QGeoProjection::coordToMercator(s2); QDoubleVector2D e = QGeoProjection::coordToMercator(e2); double x = s.x(); if (0.5 < qAbs(e.x() - s.x())) { // handle dateline crossing double ex = e.x(); double sx = s.x(); if (ex < sx) sx -= 1.0; else if (sx < ex) ex -= 1.0; x = (1.0 - progress) * sx + progress * ex; if (!qFuzzyIsNull(x) && (x < 0.0)) x += 1.0; } else { x = (1.0 - progress) * s.x() + progress * e.x(); } double y = (1.0 - progress) * s.y() + progress * e.y(); QGeoCoordinate result = QGeoProjection::mercatorToCoord(QDoubleVector2D(x, y)); result.setAltitude((1.0 - progress) * start.altitude() + progress * end.altitude()); return result; }
/*! \internal */ void QDeclarativeRectangleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { if (updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) { QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry); return; } QDoubleVector2D newTopLeftPoint = QDoubleVector2D(x(),y()); QGeoCoordinate newTopLeft = map()->itemPositionToCoordinate(newTopLeftPoint, false); if (newTopLeft.isValid()) { // calculate new geo width while checking for dateline crossing const double lonW = bottomRight_.longitude() > topLeft_.longitude() ? bottomRight_.longitude() - topLeft_.longitude() : bottomRight_.longitude() + 360 - topLeft_.longitude(); const double latH = qAbs(bottomRight_.latitude() - topLeft_.latitude()); QGeoCoordinate newBottomRight; // prevent dragging over valid min and max latitudes if (QLocationUtils::isValidLat(newTopLeft.latitude() - latH)) { newBottomRight.setLatitude(newTopLeft.latitude() - latH); } else { newBottomRight.setLatitude(QLocationUtils::clipLat(newTopLeft.latitude() - latH)); newTopLeft.setLatitude(newBottomRight.latitude() + latH); } // handle dateline crossing newBottomRight.setLongitude(QLocationUtils::wrapLong(newTopLeft.longitude() + lonW)); newBottomRight.setAltitude(newTopLeft.altitude()); topLeft_ = newTopLeft; bottomRight_ = newBottomRight; geometry_.setPreserveGeometry(true, newTopLeft); borderGeometry_.setPreserveGeometry(true, newTopLeft); markSourceDirtyAndUpdate(); emit topLeftChanged(topLeft_); emit bottomRightChanged(bottomRight_); } // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested // call to this function. }
QDoubleVector2D QGeoTiledMapGoogle::coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport) const { QGeoCoordinate coor = coordinate; //WGS84 to GCJ-02 if("cn" == m_szLocale) { //qDebug() << "transformFromWGSToGCJ:"; //qDebug() << "lat:" << coor.latitude() << ";lng:" << coor.longitude(); coor = QCoordTrans::WGSToGCJ(coor); //qDebug() << "lat:" << coor.latitude() << ";lng:" << coor.longitude(); } QDoubleVector2D pos = QGeoTiledMap::coordinateToItemPosition(coor, clipToViewport); if (clipToViewport) { int w = width(); int h = height(); if ((pos.x() < 0) || (w < pos.x()) || (pos.y() < 0) || (h < pos.y())) return QDoubleVector2D(qQNaN(), qQNaN()); } return pos; }
/*! \internal */ void QGeoMapCircleGeometry::updateScreenPointsInvert(const QGeoMap &map) { if (!screenDirty_) return; if (map.width() == 0 || map.height() == 0) { clear(); return; } QPointF origin = map.coordinateToItemPosition(srcOrigin_, false).toPointF(); QPainterPath ppi = srcPath_; clear(); // a circle requires at least 3 points; if (ppi.elementCount() < 3) return; // translate the path into top-left-centric coordinates QRectF bb = ppi.boundingRect(); ppi.translate(-bb.left(), -bb.top()); firstPointOffset_ = -1 * bb.topLeft(); ppi.closeSubpath(); // calculate actual width of map on screen in pixels QGeoCoordinate mapCenter(0, map.cameraData().center().longitude()); QDoubleVector2D midPoint = map.coordinateToItemPosition(mapCenter, false); QDoubleVector2D midPointPlusOne = QDoubleVector2D(midPoint.x() + 1.0, midPoint.y()); QGeoCoordinate coord1 = map.itemPositionToCoordinate(midPointPlusOne, false); double geoDistance = coord1.longitude() - map.cameraData().center().longitude(); if ( geoDistance < 0 ) geoDistance += 360.0; double mapWidth = 360.0 / geoDistance; qreal leftOffset = origin.x() - (map.width()/2.0 - mapWidth/2.0) - firstPointOffset_.x(); qreal topOffset = origin.y() - (midPoint.y() - mapWidth/2.0) - firstPointOffset_.y(); QPainterPath ppiBorder; ppiBorder.moveTo(QPointF(-leftOffset, -topOffset)); ppiBorder.lineTo(QPointF(mapWidth - leftOffset, -topOffset)); ppiBorder.lineTo(QPointF(mapWidth - leftOffset, mapWidth - topOffset)); ppiBorder.lineTo(QPointF(-leftOffset, mapWidth - topOffset)); screenOutline_ = ppiBorder; std::vector<p2t::Point*> borderPts; borderPts.reserve(4); std::vector<p2t::Point*> curPts; curPts.reserve(ppi.elementCount()); for (int i = 0; i < ppi.elementCount(); ++i) { const QPainterPath::Element e = ppi.elementAt(i); if (e.isMoveTo() || i == ppi.elementCount() - 1 || (qAbs(e.x - curPts.front()->x) < 0.1 && qAbs(e.y - curPts.front()->y) < 0.1)) { if (curPts.size() > 2) { for (int j = 0; j < 4; ++j) { const QPainterPath::Element e2 = ppiBorder.elementAt(j); borderPts.push_back(new p2t::Point(e2.x, e2.y)); } p2t::CDT *cdt = new p2t::CDT(borderPts); cdt->AddHole(curPts); cdt->Triangulate(); std::vector<p2t::Triangle*> tris = cdt->GetTriangles(); screenVertices_.reserve(screenVertices_.size() + int(tris.size())); for (size_t i = 0; i < tris.size(); ++i) { p2t::Triangle *t = tris.at(i); for (int j = 0; j < 3; ++j) { p2t::Point *p = t->GetPoint(j); screenVertices_ << QPointF(p->x, p->y); } } delete cdt; } curPts.clear(); curPts.reserve(ppi.elementCount() - i); curPts.push_back(new p2t::Point(e.x, e.y)); } else if (e.isLineTo()) { curPts.push_back(new p2t::Point(e.x, e.y)); } else { qWarning("Unhandled element type in circle painterpath"); } } if (curPts.size() > 0) { qDeleteAll(curPts.begin(), curPts.end()); curPts.clear(); } if (borderPts.size() > 0) { qDeleteAll(borderPts.begin(), borderPts.end()); borderPts.clear(); } screenBounds_ = ppiBorder.boundingRect(); }
/*! \internal */ void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map, const QList<QGeoCoordinate> &path) { bool foundValid = false; double minX = -1.0; double minY = -1.0; double maxX = -1.0; double maxY = -1.0; if (!sourceDirty_) return; // clear the old data and reserve enough memory srcPoints_.clear(); srcPoints_.reserve(path.size() * 2); srcPointTypes_.clear(); srcPointTypes_.reserve(path.size()); QDoubleVector2D origin, lastPoint, lastAddedPoint; double unwrapBelowX = 0; if (preserveGeometry_) unwrapBelowX = map.coordinateToScreenPosition(geoLeftBound_, false).x(); for (int i = 0; i < path.size(); ++i) { const QGeoCoordinate &coord = path.at(i); if (!coord.isValid()) continue; QDoubleVector2D point = map.coordinateToScreenPosition(coord, false); // We can get NaN if the map isn't set up correctly, or the projection // is faulty -- probably best thing to do is abort if (!qIsFinite(point.x()) || !qIsFinite(point.y())) return; // unwrap x to preserve geometry if moved to border of map if (preserveGeometry_ && point.x() < unwrapBelowX && !qFuzzyCompare(point.x(), unwrapBelowX)) point.setX(unwrapBelowX + geoDistanceToScreenWidth(map, geoLeftBound_, coord)); if (!foundValid) { foundValid = true; srcOrigin_ = coord; origin = point; point = QDoubleVector2D(0,0); minX = point.x(); maxX = minX; minY = point.y(); maxY = minY; srcPoints_ << point.x() << point.y(); srcPointTypes_ << QPainterPath::MoveToElement; lastAddedPoint = point; } else { point -= origin; minX = qMin(point.x(), minX); minY = qMin(point.y(), minY); maxX = qMax(point.x(), maxX); maxY = qMax(point.y(), maxY); if ((point - lastAddedPoint).manhattanLength() > 3 || i == path.size() - 1) { srcPoints_ << point.x() << point.y(); srcPointTypes_ << QPainterPath::LineToElement; lastAddedPoint = point; } } lastPoint = point; } sourceBounds_ = QRectF(QPointF(minX, minY), QPointF(maxX, maxY)); geoLeftBound_ = map.screenPositionToCoordinate( QDoubleVector2D(minX + origin.x(), minY + origin.y()), false); }
/*! \internal */ void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine) { if (mapItems_.size() == 0) return; double minX = 0; double maxX = 0; double minY = 0; double maxY = 0; double topLeftX = 0; double topLeftY = 0; double bottomRightX = 0; double bottomRightY = 0; bool haveQuickItem = false; // find bounds of all map items int itemCount = 0; for (int i = 0; i < mapItems_.count(); ++i) { if (!mapItems_.at(i)) continue; QDeclarativeGeoMapItemBase *item = mapItems_.at(i).data(); if (!item) continue; // skip quick items in the first pass and refine the fit later if (refine) { QDeclarativeGeoMapQuickItem *quickItem = qobject_cast<QDeclarativeGeoMapQuickItem*>(item); if (quickItem) { haveQuickItem = true; continue; } } topLeftX = item->position().x(); topLeftY = item->position().y(); bottomRightX = topLeftX + item->width(); bottomRightY = topLeftY + item->height(); if (itemCount == 0) { minX = topLeftX; maxX = bottomRightX; minY = topLeftY; maxY = bottomRightY; } else { minX = qMin(minX, topLeftX); maxX = qMax(maxX, bottomRightX); minY = qMin(minY, topLeftY); maxY = qMax(maxY, bottomRightY); } ++itemCount; } if (itemCount == 0) { if (haveQuickItem) fitViewportToMapItemsRefine(false); return; } double bboxWidth = maxX - minX; double bboxHeight = maxY - minY; double bboxCenterX = minX + (bboxWidth / 2.0); double bboxCenterY = minY + (bboxHeight / 2.0); // position camera to the center of bounding box QGeoCoordinate coordinate; coordinate = map_->screenPositionToCoordinate(QDoubleVector2D(bboxCenterX, bboxCenterY), false); setProperty("center", QVariant::fromValue(coordinate)); // adjust zoom double bboxWidthRatio = bboxWidth / (bboxWidth + bboxHeight); double mapWidthRatio = width() / (width() + height()); double zoomRatio; if (bboxWidthRatio > mapWidthRatio) zoomRatio = bboxWidth / width(); else zoomRatio = bboxHeight / height(); qreal newZoom = log10(zoomRatio) / log10(0.5); newZoom = floor(qMax(minimumZoomLevel(), (map_->mapController()->zoom() + newZoom))); setProperty("zoomLevel", QVariant::fromValue(newZoom)); // as map quick items retain the same screen size after the camera zooms in/out // we refine the viewport again to achieve better results if (refine) fitViewportToMapItemsRefine(false); }