Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdeclarativegeomapitembase.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include <QtQml/QQmlInfo>
8#include <QtQuick/QSGOpacityNode>
9
10#include <QtQuick/private/qquickmousearea_p.h>
11#include <QtQuick/private/qquickitem_p.h>
12#include <QtPositioning/private/qdoublevector2d_p.h>
13#include <QtLocation/private/qgeomap_p.h>
14#include <QtLocation/private/qgeoprojection_p.h>
15
16#include <QtQuickShapes/private/qquickshape_p_p.h>
17
18QT_BEGIN_NAMESPACE
19
20QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent)
21 : QQuickItem(parent)
22{
23 connect(this, &QDeclarativeGeoMapItemBase::childrenChanged,
24 this, &QDeclarativeGeoMapItemBase::afterChildrenChanged);
25 // Changing opacity on a mapItemGroup should affect also the opacity on the children.
26 // This must be notified to plugins, if they are to render the item.
27 connect(this, &QQuickItem::opacityChanged, this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
28}
29
30QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase()
31{
32 disconnect(this, &QDeclarativeGeoMapItemBase::childrenChanged,
33 this, &QDeclarativeGeoMapItemBase::afterChildrenChanged);
34 if (quickMap_)
35 quickMap_->removeMapItem(this);
36}
37
38/*!
39 \internal
40*/
41void QDeclarativeGeoMapItemBase::afterChildrenChanged()
42{
43 const QList<QQuickItem *> kids = childItems();
44 if (kids.size() > 0) {
45 bool printedWarning = false;
46 for (auto *i : kids) {
47 if (i->flags() & QQuickItem::ItemHasContents
48 && !qobject_cast<QQuickMouseArea *>(i)
49 && i->objectName() != QStringLiteral("_qt_map_item_shape"))
50 {
51 if (!printedWarning) {
52 qmlWarning(this) << "Geographic map items do not support child items";
53 printedWarning = true;
54 }
55
56 qmlWarning(i) << "deleting this child";
57 i->deleteLater();
58 }
59 }
60 }
61}
62
63/*!
64 \internal
65*/
66void QDeclarativeGeoMapItemBase::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
67{
68 if (quickMap == quickMap_)
69 return;
70 if (quickMap && quickMap_)
71 return; // don't allow association to more than one map
72
73 quickMap_ = quickMap;
74 map_ = map;
75
76 if (map_ && quickMap_) {
77 // For performance reasons we're not connecting map_'s and quickMap_'s signals to this.
78 // Rather, the handling of cameraDataChanged, visibleAreaChanged, heightChanged and widthChanged is done explicitly in QDeclarativeGeoMap by directly calling methods on the items.
79 // See QTBUG-76950
80 lastMapSize_ = QSizeF(quickMap_->width(), quickMap_->height());
81 lastCameraData_ = map_->cameraData();
82 }
83}
84
85/*!
86 \internal
87*/
88void QDeclarativeGeoMapItemBase::baseCameraDataChanged(const QGeoCameraData &cameraData)
89{
90 QGeoMapViewportChangeEvent evt;
91 evt.cameraData = cameraData;
92 evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height());
93
94 if (evt.mapSize != lastMapSize_)
95 evt.mapSizeChanged = true;
96
97 if (cameraData.bearing() != lastCameraData_.bearing())
98 evt.bearingChanged = true;
99 if (cameraData.center() != lastCameraData_.center())
100 evt.centerChanged = true;
101 if (cameraData.roll() != lastCameraData_.roll())
102 evt.rollChanged = true;
103 if (cameraData.tilt() != lastCameraData_.tilt())
104 evt.tiltChanged = true;
105 if (cameraData.zoomLevel() != lastCameraData_.zoomLevel())
106 evt.zoomLevelChanged = true;
107
108 lastMapSize_ = evt.mapSize;
109 lastCameraData_ = cameraData;
110
111 afterViewportChanged(evt);
112}
113
114void QDeclarativeGeoMapItemBase::visibleAreaChanged()
115{
116 QGeoMapViewportChangeEvent evt;
117 evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height());
118 afterViewportChanged(evt);
119}
120
121/*!
122 \internal
123*/
124void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset)
125{
126 if (!map_ || !quickMap_)
127 return;
128
129 QDoubleVector2D pos;
130 if (map()->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) {
131 const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
132 QDoubleVector2D wrappedProjection = p.geoToWrappedMapProjection(coordinate);
133 if (!p.isProjectable(wrappedProjection))
134 return;
135 pos = p.wrappedMapProjectionToItemPosition(wrappedProjection);
136 } else {
137 pos = map()->geoProjection().coordinateToItemPosition(coordinate, false);
138 if (qIsNaN(pos.x()))
139 return;
140 }
141
142 QPointF topLeft = pos.toPointF() - offset;
143
144 setPosition(topLeft);
145}
146
147bool QDeclarativeGeoMapItemBase::autoFadeIn() const
148{
149 return m_autoFadeIn;
150}
151
152static const double opacityRampMin = 1.5;
153static const double opacityRampMax = 2.5;
154
155void QDeclarativeGeoMapItemBase::setAutoFadeIn(bool fadeIn)
156{
157 if (fadeIn == m_autoFadeIn)
158 return;
159 m_autoFadeIn = fadeIn;
160 if (quickMap_ && quickMap_->zoomLevel() < opacityRampMax)
161 polishAndUpdate();
162}
163
164QLocation::ReferenceSurface QDeclarativeGeoMapItemBase::referenceSurface() const
165{
166 return m_referenceSurface;
167}
168
169void QDeclarativeGeoMapItemBase::setReferenceSurface(QLocation::ReferenceSurface referenceSurface)
170{
171 if (referenceSurface == m_referenceSurface)
172 return;
173 m_referenceSurface = referenceSurface;
174 emit referenceSurfaceChanged();
175 updatePolish();
176}
177
178int QDeclarativeGeoMapItemBase::lodThreshold() const
179{
180 return m_lodThreshold;
181}
182
183void QDeclarativeGeoMapItemBase::setLodThreshold(int lt)
184{
185 if (lt == m_lodThreshold)
186 return;
187 m_lodThreshold = lt;
188 update();
189}
190
191/*!
192 \internal
193
194 This returns the zoom level to be used when requesting the LOD.
195 Essentially it clamps to m_lodThreshold, and if above, it selects
196 a ZL higher than the maximum LODable level.
197*/
198unsigned int QDeclarativeGeoMapItemBase::zoomForLOD(int zoom) const
199{
200 if (zoom >= m_lodThreshold)
201 return 30; // some arbitrarily large zoom
202 return uint(zoom);
203}
204
205/*!
206 \internal
207*/
208float QDeclarativeGeoMapItemBase::zoomLevelOpacity() const
209{
210 if (!m_autoFadeIn) // Consider skipping the opacity node instead.
211 return 1.0;
212 else if (quickMap_->zoomLevel() > opacityRampMax)
213 return 1.0;
214 else if (quickMap_->zoomLevel() > opacityRampMin)
215 return quickMap_->zoomLevel() - opacityRampMin;
216 else
217 return 0.0;
218}
219
220void QDeclarativeGeoMapItemBase::setShapeTriangulationScale(QQuickShape *shape, qreal maxCoord) const
221{
222 const qreal zoom = qMax(0.01, quickMap_->zoomLevel());
223 qreal scale = 1 / zoom;
224
225 // cater also for QTriangulator's 65536 coordinate limit due to the fixed point math
226 qint64 coord = qint64(maxCoord);
227 const qint64 COORD_LIMIT = (1 << 21) / 32; // 65536 (where 32 is Q_FIXED_POINT_SCALE)
228 while (coord > COORD_LIMIT) {
229 coord /= COORD_LIMIT;
230 scale /= COORD_LIMIT;
231 }
232
233 QQuickShapePrivate::get(shape)->triangulationScale = scale;
234}
235
236/*!
237 \internal
238*/
239QSGNode *QDeclarativeGeoMapItemBase::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *pd)
240{
241 if (!map_ || !quickMap_ || map_->supportedMapItemTypes() & itemType()) {
242 if (oldNode)
243 delete oldNode;
244 oldNode = nullptr;
245 return nullptr;
246 }
247
248 QSGOpacityNode *opn = static_cast<QSGOpacityNode *>(oldNode);
249 if (!opn)
250 opn = new QSGOpacityNode();
251
252 opn->setOpacity(zoomLevelOpacity());
253
254 QSGNode *oldN = opn->childCount() ? opn->firstChild() : 0;
255 opn->removeAllChildNodes();
256 if (opn->opacity() > 0.0) {
257 QSGNode *n = this->updateMapItemPaintNode(oldN, pd);
258 if (n)
259 opn->appendChildNode(n);
260 } else {
261 delete oldN;
262 }
263
264 return opn;
265}
266
267/*!
268 \internal
269*/
270QSGNode *QDeclarativeGeoMapItemBase::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
271{
272 delete oldNode;
273 return nullptr;
274}
275
276/*!
277 \internal
278
279 The actual combined opacity of the item. Needed by custom renderer to look like
280 the scene-graph one.
281*/
282qreal QDeclarativeGeoMapItemBase::mapItemOpacity() const
283{
284 if (parentGroup_)
285 return parentGroup_->mapItemOpacity() * opacity();
286 return opacity();
287}
288
289void QDeclarativeGeoMapItemBase::setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup)
290{
291 parentGroup_ = &parentGroup;
292 if (parentGroup_) {
293 connect(parentGroup_, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged,
294 this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
295 }
296}
297
298bool QDeclarativeGeoMapItemBase::isPolishScheduled() const
299{
300 return QQuickItemPrivate::get(this)->polishScheduled;
301}
302
303void QDeclarativeGeoMapItemBase::polishAndUpdate()
304{
305 polish();
306 update();
307}
308
309QT_END_NAMESPACE
static const double opacityRampMin
static const double opacityRampMax