Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qgeomapmapboxgl.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// Copyright (C) 2017 Mapbox, Inc.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qgeomapmapboxgl.h"
6#include "qgeomapmapboxgl_p.h"
7#include "qsgmapboxglnode.h"
9
10#include <QtCore/QByteArray>
11#include <QtCore/QCoreApplication>
12#include <QtGui/QOpenGLContext>
13#include <QtOpenGL/QOpenGLFramebufferObject>
14#include <QtLocation/private/qdeclarativecirclemapitem_p.h>
15#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
16#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
17#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
18#include <QtLocation/private/qdeclarativerectanglemapitem_p.h>
19#include <QtLocation/private/qgeoprojection_p.h>
20#include <QtQuick/QQuickWindow>
21#include <QtQuick/QSGImageNode>
22#include <QtQuick/private/qsgcontext_p.h> // for debugging the context name
23
24#include <QMapboxGL>
25
26#include <cmath>
27
28// FIXME: Expose from Mapbox GL constants
29#define MBGL_TILE_SIZE 512.0
30
31namespace {
32
33// WARNING! The development token is subject to Mapbox Terms of Services
34// and must not be used in production.
35static char developmentToken[] =
36 "pk.eyJ1IjoicXRzZGsiLCJhIjoiY2l5azV5MHh5MDAwdTMybzBybjUzZnhxYSJ9.9rfbeqPjX2BusLRDXHCOBA";
37
38static const double invLog2 = 1.0 / std::log(2.0);
39
40static double zoomLevelFrom256(double zoomLevelFor256, double tileSize)
41{
42 return std::log(std::pow(2.0, zoomLevelFor256) * 256.0 / tileSize) * invLog2;
43}
44
45} // namespace
46
51
55
57{
58 Q_Q(QGeoMapMapboxGL);
59
60 if (m_viewportSize.isEmpty()) {
61 delete node;
62 return nullptr;
63 }
64
65 QMapboxGL *map = nullptr;
66 if (!node) {
68 if (!currentCtx) {
69 qWarning("QOpenGLContext is NULL!");
70 qWarning() << "You are running on QSG backend " << QSGContext::backend();
71 qWarning("The MapboxGL plugin works with both Desktop and ES 2.0+ OpenGL versions.");
72 qWarning("Verify that your Qt is built with OpenGL, and what kind of OpenGL.");
73 qWarning("To force using a specific OpenGL version, check QSurfaceFormat::setRenderableType and QSurfaceFormat::setDefaultFormat");
74
75 return node;
76 }
77 if (m_useFBO) {
78 QSGMapboxGLTextureNode *mbglNode = new QSGMapboxGLTextureNode(m_settings, m_viewportSize, window->devicePixelRatio(), q);
79 QObject::connect(mbglNode->map(), &QMapboxGL::mapChanged, q, &QGeoMapMapboxGL::onMapChanged);
81 node = mbglNode;
82 } else {
83 QSGMapboxGLRenderNode *mbglNode = new QSGMapboxGLRenderNode(m_settings, m_viewportSize, window->devicePixelRatio(), q);
84 QObject::connect(mbglNode->map(), &QMapboxGL::mapChanged, q, &QGeoMapMapboxGL::onMapChanged);
86 node = mbglNode;
87 }
88 }
89 map = (m_useFBO) ? static_cast<QSGMapboxGLTextureNode *>(node)->map()
90 : static_cast<QSGMapboxGLRenderNode *>(node)->map();
91
94 && m_settings.accessToken() == developmentToken;
95
96 map->setStyleUrl(m_activeMapType.name());
97 }
98
100 if (m_visibleArea.isEmpty()) {
101 map->setMargins(QMargins());
102 } else {
103 QMargins margins(m_visibleArea.x(), // left
104 m_visibleArea.y(), // top
105 m_viewportSize.width() - m_visibleArea.width() - m_visibleArea.x(), // right
106 m_viewportSize.height() - m_visibleArea.height() - m_visibleArea.y()); // bottom
107 map->setMargins(margins);
108 }
109 }
110
112 map->setZoom(zoomLevelFrom256(m_cameraData.zoomLevel() , MBGL_TILE_SIZE));
113 map->setBearing(m_cameraData.bearing());
114 map->setPitch(m_cameraData.tilt());
115
116 QGeoCoordinate coordinate = m_cameraData.center();
117 map->setCoordinate(QMapbox::Coordinate(coordinate.latitude(), coordinate.longitude()));
118 }
119
121 if (m_useFBO) {
122 static_cast<QSGMapboxGLTextureNode *>(node)->resize(m_viewportSize, window->devicePixelRatio());
123 } else {
124 map->resize(m_viewportSize);
125 }
126 }
127
128 if (m_styleLoaded) {
129 syncStyleChanges(map);
130 }
131
132 if (m_useFBO) {
133 static_cast<QSGMapboxGLTextureNode *>(node)->render(window);
134 }
135
136 threadedRenderingHack(window, map);
137
139
140 return node;
141}
142
147
149{
150 Q_Q(QGeoMapMapboxGL);
151
152 switch (item->itemType()) {
153 case QGeoMap::NoItem:
156 return;
159 QObject::connect(mapItem, &QQuickItem::visibleChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
160 QObject::connect(mapItem, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
161 QObject::connect(mapItem, &QDeclarativeRectangleMapItem::bottomRightChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
162 QObject::connect(mapItem, &QDeclarativeRectangleMapItem::topLeftChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
163 QObject::connect(mapItem, &QDeclarativeRectangleMapItem::colorChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
164 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::colorChanged, q, &QGeoMapMapboxGL::onMapItemSubPropertyChanged);
165 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::widthChanged, q, &QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged);
166 } break;
167 case QGeoMap::MapCircle: {
169 QObject::connect(mapItem, &QQuickItem::visibleChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
170 QObject::connect(mapItem, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
171 QObject::connect(mapItem, &QDeclarativeCircleMapItem::centerChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
172 QObject::connect(mapItem, &QDeclarativeCircleMapItem::radiusChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
173 QObject::connect(mapItem, &QDeclarativeCircleMapItem::colorChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
174 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::colorChanged, q, &QGeoMapMapboxGL::onMapItemSubPropertyChanged);
175 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::widthChanged, q, &QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged);
176 } break;
177 case QGeoMap::MapPolygon: {
179 QObject::connect(mapItem, &QQuickItem::visibleChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
180 QObject::connect(mapItem, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
181 QObject::connect(mapItem, &QDeclarativePolygonMapItem::pathChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
182 QObject::connect(mapItem, &QDeclarativePolygonMapItem::colorChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
183 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::colorChanged, q, &QGeoMapMapboxGL::onMapItemSubPropertyChanged);
184 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::widthChanged, q, &QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged);
185 } break;
188 QObject::connect(mapItem, &QQuickItem::visibleChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
189 QObject::connect(mapItem, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
190 QObject::connect(mapItem, &QDeclarativePolylineMapItem::pathChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
191 QObject::connect(mapItem->line(), &QDeclarativeMapLineProperties::colorChanged, q, &QGeoMapMapboxGL::onMapItemSubPropertyChanged);
192 QObject::connect(mapItem->line(), &QDeclarativeMapLineProperties::widthChanged, q, &QGeoMapMapboxGL::onMapItemSubPropertyChanged);
193 } break;
194 }
195
196 QObject::connect(item, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
197
199
200 emit q->sgNodeChanged();
201}
202
204{
205 Q_Q(QGeoMapMapboxGL);
206
207 switch (item->itemType()) {
208 case QGeoMap::NoItem:
211 return;
213 q->disconnect(static_cast<QDeclarativeRectangleMapItem *>(item)->border());
214 break;
216 q->disconnect(static_cast<QDeclarativeCircleMapItem *>(item)->border());
217 break;
219 q->disconnect(static_cast<QDeclarativePolygonMapItem *>(item)->border());
220 break;
222 q->disconnect(static_cast<QDeclarativePolylineMapItem *>(item)->line());
223 break;
224 }
225
226 q->disconnect(item);
227
229
230 emit q->sgNodeChanged();
231}
232
234{
235 Q_Q(QGeoMapMapboxGL);
236
238 emit q->sgNodeChanged();
239}
240
242{
243 Q_Q(QGeoMapMapboxGL);
244
246 emit q->sgNodeChanged();
247}
248
250{
251 Q_Q(QGeoMapMapboxGL);
252
254 emit q->sgNodeChanged();
255}
256
258{
259 Q_Q(QGeoMapMapboxGL);
261 if (va == m_visibleArea)
262 return;
263
264 m_visibleArea = va;
266
268 emit q->sgNodeChanged();
269}
270
272{
273 return m_visibleArea;
274}
275
276void QGeoMapMapboxGLPrivate::syncStyleChanges(QMapboxGL *map)
277{
278 for (const auto& change : m_styleChanges) {
279 change->apply(map);
280 }
281
283}
284
285void QGeoMapMapboxGLPrivate::threadedRenderingHack(QQuickWindow *window, QMapboxGL *map)
286{
287 // FIXME: Optimal support for threaded rendering needs core changes
288 // in Mapbox GL Native. Meanwhile we need to set a timer to update
289 // the map until all the resources are loaded, which is not exactly
290 // battery friendly, because might trigger more paints than we need.
291 if (!m_warned) {
292 m_threadedRendering = window->openglContext()->thread() != QCoreApplication::instance()->thread();
293
295 qWarning() << "Threaded rendering is not optimal in the Mapbox GL plugin.";
296 }
297
298 m_warned = true;
299 }
300
302 if (!map->isFullyLoaded()) {
304 } else {
306 }
307 }
308}
309
310/*
311 * QGeoMapMapboxGL implementation
312 */
313
315 : QGeoMap(*new QGeoMapMapboxGLPrivate(engine), parent), m_engine(engine)
316{
317 Q_D(QGeoMapMapboxGL);
318
319 connect(&d->m_refresh, &QTimer::timeout, this, &QGeoMap::sgNodeChanged);
320 d->m_refresh.setInterval(250);
321}
322
326
328{
329 return QStringLiteral("* { vertical-align: middle; font-weight: normal }");
330}
331
332void QGeoMapMapboxGL::setMapboxGLSettings(const QMapboxGLSettings& settings, bool useChinaEndpoint)
333{
334 Q_D(QGeoMapMapboxGL);
335
336 d->m_settings = settings;
337
338 // If the access token is not set, use the development access token.
339 // This will only affect mapbox:// styles.
340 // Mapbox China requires a China-specific access token.
341 if (d->m_settings.accessToken().isEmpty()) {
342 if (useChinaEndpoint) {
343 qWarning("Mapbox China requires an access token: https://www.mapbox.com/contact/sales");
344 } else {
345 d->m_settings.setAccessToken(developmentToken);
346 }
347 }
348}
349
351{
352 Q_D(QGeoMapMapboxGL);
353 d->m_useFBO = useFBO;
354}
355
357{
358 Q_D(QGeoMapMapboxGL);
359 d->m_mapItemsBefore = before;
360}
361
362QGeoMap::Capabilities QGeoMapMapboxGL::capabilities() const
363{
364 return Capabilities(SupportsVisibleRegion
368}
369
371{
372 Q_D(QGeoMapMapboxGL);
373 return d->updateSceneGraph(oldNode, window);
374}
375
376void QGeoMapMapboxGL::onMapChanged(QMapboxGL::MapChange change)
377{
378 Q_D(QGeoMapMapboxGL);
379
380 if (change == QMapboxGL::MapChangeDidFinishLoadingStyle || change == QMapboxGL::MapChangeDidFailLoadingMap) {
381 d->m_styleLoaded = true;
382 } else if (change == QMapboxGL::MapChangeWillStartLoadingMap) {
383 d->m_styleLoaded = false;
384 d->m_styleChanges.clear();
385
386 for (QDeclarativeGeoMapItemBase *item : d->m_mapItems)
387 d->m_styleChanges << QMapboxGLStyleChange::addMapItem(item, d->m_mapItemsBefore);
388 }
389}
390
391void QGeoMapMapboxGL::onMapItemPropertyChanged()
392{
393 Q_D(QGeoMapMapboxGL);
394
398
400}
401
402void QGeoMapMapboxGL::onMapItemSubPropertyChanged()
403{
404 Q_D(QGeoMapMapboxGL);
405
408
410}
411
412void QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged()
413{
414 // TODO https://bugreports.qt.io/browse/QTBUG-58872
415 qWarning() << "Unsupported property for managed Map item";
416}
417
418void QGeoMapMapboxGL::onMapItemGeometryChanged()
419{
420 Q_D(QGeoMapMapboxGL);
421
423 d->m_styleChanges << QMapboxGLStyleAddSource::fromMapItem(item);
424
426}
427
429{
430 Q_D(QGeoMapMapboxGL);
431
432 QString copyrightsHtmlFinal = copyrightsHtml;
433
434 if (d->m_developmentMode) {
435 copyrightsHtmlFinal.prepend("<a href='https://www.mapbox.com/pricing'>"
436 + tr("Development access token, do not use in production.") + "</a> - ");
437 }
438
439 if (d->m_activeMapType.name().startsWith("mapbox://")) {
440 copyrightsHtmlFinal = "<table><tr><th><img src='qrc:/mapboxgl/logo.png'/></th><th>"
441 + copyrightsHtmlFinal + "</th></tr></table>";
442 }
443
444 QGeoMap::copyrightsChanged(copyrightsHtmlFinal);
445}
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
void colorChanged(const QColor &color)
void radiusChanged(qreal radius)
void centerChanged(const QGeoCoordinate &center)
void widthChanged(qreal width)
void colorChanged(const QColor &color)
void colorChanged(const QColor &color)
void bottomRightChanged(const QGeoCoordinate &bottomRight)
void topLeftChanged(const QGeoCoordinate &topLeft)
void colorChanged(const QColor &color)
double zoomLevel() const
double tilt() const
double bearing() const
QGeoCoordinate center() const
\inmodule QtPositioning
double longitude
This property holds the longitude in decimal degrees.
double latitude
This property holds the latitude in decimal degrees.
QRectF visibleArea() const override
void setVisibleArea(const QRectF &visibleArea) override
QMapboxGLSettings m_settings
void addMapItem(QDeclarativeGeoMapItemBase *item) override
void changeActiveMapType(const QGeoMapType &mapType) override
QList< QSharedPointer< QMapboxGLStyleChange > > m_styleChanges
QGeoMap::ItemTypes supportedMapItemTypes() const override
void changeCameraData(const QGeoCameraData &oldCameraData) override
void removeMapItem(QDeclarativeGeoMapItemBase *item) override
QGeoMapMapboxGLPrivate(QGeoMappingManagerEngineMapboxGL *engine)
void changeViewportSize(const QSize &size) override
QSGNode * updateSceneGraph(QSGNode *oldNode, QQuickWindow *window)
void setMapboxGLSettings(const QMapboxGLSettings &, bool useChinaEndpoint)
QString copyrightsStyleSheet() const override
Capabilities capabilities() const override
void setMapItemsBefore(const QString &)
void copyrightsChanged(const QString &copyrightsHtml)
QGeoMapMapboxGL(QGeoMappingManagerEngineMapboxGL *engine, QObject *parent)
QSGNode * updateSceneGraph(QSGNode *oldNode, QQuickWindow *window) override
QGeoProjection * m_geoProjection
Definition qgeomap_p_p.h:78
QGeoMapType m_activeMapType
Definition qgeomap_p_p.h:81
QSize m_viewportSize
Definition qgeomap_p_p.h:77
QRectF clampVisibleArea(const QRectF &visibleArea) const
Definition qgeomap.cpp:364
QGeoCameraData m_cameraData
Definition qgeomap_p_p.h:80
@ SupportsVisibleArea
Definition qgeomap_p.h:64
@ SupportsVisibleRegion
Definition qgeomap_p.h:60
@ SupportsAnchoringCoordinate
Definition qgeomap_p.h:62
@ SupportsSetBearing
Definition qgeomap_p.h:61
void sgNodeChanged()
void addMapItem(QDeclarativeGeoMapItemBase *item)
Definition qgeomap.cpp:197
void copyrightsChanged(const QString &copyrightsHtml)
@ MapRectangle
Definition qgeomap_p.h:48
@ MapPolyline
Definition qgeomap_p.h:50
@ MapPolygon
Definition qgeomap_p.h:51
@ MapQuickItem
Definition qgeomap_p.h:52
@ MapCircle
Definition qgeomap_p.h:49
@ CustomMapItem
Definition qgeomap_p.h:53
virtual void setVisibleArea(const QRectF &visibleArea)=0
void clear()
Definition qlist.h:434
static QSharedPointer< QMapboxGLStyleChange > fromMapItem(QDeclarativeGeoMapItemBase *)
static QList< QSharedPointer< QMapboxGLStyleChange > > addMapItem(QDeclarativeGeoMapItemBase *, const QString &before)
static QList< QSharedPointer< QMapboxGLStyleChange > > removeMapItem(QDeclarativeGeoMapItemBase *)
static QList< QSharedPointer< QMapboxGLStyleChange > > fromMapItem(QDeclarativeGeoMapItemBase *)
static QList< QSharedPointer< QMapboxGLStyleChange > > fromMapItem(QDeclarativeGeoMapItemBase *)
\inmodule QtCore
Definition qmargins.h:24
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition qobject.cpp:2658
\inmodule QtGui
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
void visibleChanged()
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:661
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:672
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:669
static QString backend()
QMapboxGL * map() const
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:124
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
QString & prepend(QChar c)
Definition qstring.h:478
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
a resize(100000)
QMap< QString, QString > map
[6]
@ QueuedConnection
#define MBGL_TILE_SIZE
#define qWarning
Definition qlogging.h:166
static QT_BEGIN_NAMESPACE const int tileSize
Definition qmemrotate.cpp:9
GLint GLenum GLsizei GLsizei GLsizei GLint border
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define QStringLiteral(str)
#define tr(X)
#define emit
QSettings settings("MySoft", "Star Runner")
[0]
QGraphicsItem * item
aWidget window() -> setWindowTitle("New Window Title")
[2]
myWidget render(this)
QJSEngine engine
[0]
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...