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
qmapboxglstylechange.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 Mapbox, Inc.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtCore/QDebug>
7#include <QtCore/QMetaProperty>
8#include <QtCore/QRegularExpression>
9#include <QtCore/QStringList>
10#include <QtPositioning/QGeoPath>
11#include <QtPositioning/QGeoPolygon>
12#include <QtQml/QJSValue>
13#include <QtLocation/private/qdeclarativecirclemapitem_p_p.h>
14
15namespace {
16
17QByteArray formatPropertyName(const QByteArray &name)
18{
19 QString nameAsString = QString::fromLatin1(name);
20 static const QRegularExpression camelCaseRegex(QStringLiteral("([a-z0-9])([A-Z])"));
21 return nameAsString.replace(camelCaseRegex, QStringLiteral("\\1-\\2")).toLower().toLatin1();
22}
23
24bool isImmutableProperty(const QByteArray &name)
25{
26 return name == QStringLiteral("type") || name == QStringLiteral("layer");
27}
28
30{
31 return QStringLiteral("QtLocation-") +
32 ((mapItem->objectName().isEmpty()) ? QString::number(quint64(mapItem)) : mapItem->objectName());
33}
34
35// Mapbox GL supports geometry segments that spans above 180 degrees in
36// longitude. To keep visual expectations in parity with Qt, we need to adapt
37// the coordinates to always use the shortest path when in ambiguity.
38static bool geoRectangleCrossesDateLine(const QGeoRectangle &rect) {
39 return rect.topLeft().longitude() > rect.bottomRight().longitude();
40}
41
42QMapbox::Feature featureFromMapRectangle(QDeclarativeRectangleMapItem *mapItem)
43{
44 const QGeoRectangle *rect = static_cast<const QGeoRectangle *>(&mapItem->geoShape());
45 QMapbox::Coordinate bottomLeft { rect->bottomLeft().latitude(), rect->bottomLeft().longitude() };
46 QMapbox::Coordinate topLeft { rect->topLeft().latitude(), rect->topLeft().longitude() };
47 QMapbox::Coordinate bottomRight { rect->bottomRight().latitude(), rect->bottomRight().longitude() };
48 QMapbox::Coordinate topRight { rect->topRight().latitude(), rect->topRight().longitude() };
49 if (geoRectangleCrossesDateLine(*rect)) {
50 bottomRight.second += 360.0;
51 topRight.second += 360.0;
52 }
53 QMapbox::CoordinatesCollections geometry { { { bottomLeft, bottomRight, topRight, topLeft, bottomLeft } } };
54
55 return QMapbox::Feature(QMapbox::Feature::PolygonType, geometry, {}, getId(mapItem));
56}
57
58QMapbox::Feature featureFromMapCircle(QDeclarativeCircleMapItem *mapItem)
59{
60 static const int circleSamples = 128;
61 const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(mapItem->map()->geoProjection());
62 QList<QGeoCoordinate> path;
63 QGeoCoordinate leftBound;
64 QDeclarativeCircleMapItemPrivate::calculatePeripheralPoints(path, mapItem->center(), mapItem->radius(), circleSamples, leftBound);
65 QList<QDoubleVector2D> pathProjected;
66 for (const QGeoCoordinate &c : std::as_const(path))
67 pathProjected << p.geoToMapProjection(c);
68 if (QDeclarativeCircleMapItemPrivateCPU::crossEarthPole(mapItem->center(), mapItem->radius()))
69 QDeclarativeCircleMapItemPrivateCPU::preserveCircleGeometry(pathProjected, mapItem->center(), mapItem->radius(), p);
70 path.clear();
71 for (const QDoubleVector2D &c : std::as_const(pathProjected))
72 path << p.mapProjectionToGeo(c);
73
74
75 QMapbox::Coordinates coordinates;
76 for (const QGeoCoordinate &coordinate : path) {
77 coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() };
78 }
79 coordinates.append(coordinates.first()); // closing the path
80 QMapbox::CoordinatesCollections geometry { { coordinates } };
81 return QMapbox::Feature(QMapbox::Feature::PolygonType, geometry, {}, getId(mapItem));
82}
83
84static QMapbox::Coordinates qgeocoordinate2mapboxcoordinate(const QList<QGeoCoordinate> &crds, const bool crossesDateline, bool closed = false)
85{
86 QMapbox::Coordinates coordinates;
87 for (const QGeoCoordinate &coordinate : crds) {
88 if (!coordinates.empty() && crossesDateline && qAbs(coordinate.longitude() - coordinates.last().second) > 180.0) {
89 coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() + (coordinate.longitude() >= 0 ? -360.0 : 360.0) };
90 } else {
91 coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() };
92 }
93 }
94 if (closed && !coordinates.empty() && coordinates.last() != coordinates.first())
95 coordinates.append(coordinates.first()); // closing the path
96 return coordinates;
97}
98
99QMapbox::Feature featureFromMapPolygon(QDeclarativePolygonMapItem *mapItem)
100{
101 const QGeoPolygon *polygon = static_cast<const QGeoPolygon *>(&mapItem->geoShape());
102 const bool crossesDateline = geoRectangleCrossesDateLine(polygon->boundingGeoRectangle());
103 QMapbox::CoordinatesCollections geometry;
104 QMapbox::CoordinatesCollection poly;
105 QMapbox::Coordinates coordinates = qgeocoordinate2mapboxcoordinate(polygon->perimeter(), crossesDateline, true);
106 poly.push_back(coordinates);
107 for (int i = 0; i < polygon->holesCount(); ++i) {
108 coordinates = qgeocoordinate2mapboxcoordinate(polygon->holePath(i), crossesDateline, true);
109 poly.push_back(coordinates);
110 }
111
112 geometry.push_back(poly);
113 return QMapbox::Feature(QMapbox::Feature::PolygonType, geometry, {}, getId(mapItem));
114}
115
116QMapbox::Feature featureFromMapPolyline(QDeclarativePolylineMapItem *mapItem)
117{
118 const QGeoPath *path = static_cast<const QGeoPath *>(&mapItem->geoShape());
119 QMapbox::Coordinates coordinates;
120 const bool crossesDateline = geoRectangleCrossesDateLine(path->boundingGeoRectangle());
121 for (const QGeoCoordinate &coordinate : path->path()) {
122 if (!coordinates.empty() && crossesDateline && qAbs(coordinate.longitude() - coordinates.last().second) > 180.0) {
123 coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() + (coordinate.longitude() >= 0 ? -360.0 : 360.0) };
124 } else {
125 coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() };
126 }
127 }
128 QMapbox::CoordinatesCollections geometry { { coordinates } };
129
130 return QMapbox::Feature(QMapbox::Feature::LineStringType, geometry, {}, getId(mapItem));
131}
132
133QMapbox::Feature featureFromMapItem(QDeclarativeGeoMapItemBase *item)
134{
135 switch (item->itemType()) {
137 return featureFromMapRectangle(static_cast<QDeclarativeRectangleMapItem *>(item));
139 return featureFromMapCircle(static_cast<QDeclarativeCircleMapItem *>(item));
141 return featureFromMapPolygon(static_cast<QDeclarativePolygonMapItem *>(item));
143 return featureFromMapPolyline(static_cast<QDeclarativePolylineMapItem *>(item));
144 default:
145 qWarning() << "Unsupported QGeoMap item type: " << item->itemType();
146 return QMapbox::Feature();
147 }
148}
149
150QList<QByteArray> getAllPropertyNamesList(QObject *object)
151{
152 const QMetaObject *metaObject = object->metaObject();
153 QList<QByteArray> propertyNames(object->dynamicPropertyNames());
154 for (int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i) {
155 propertyNames.append(metaObject->property(i).name());
156 }
157 return propertyNames;
158}
159
160} // namespace
161
162
163QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleChange::addMapItem(QDeclarativeGeoMapItemBase *item, const QString &before)
164{
165 QList<QSharedPointer<QMapboxGLStyleChange>> changes;
166
167 switch (item->itemType()) {
172 break;
173 default:
174 qWarning() << "Unsupported QGeoMap item type: " << item->itemType();
175 return changes;
176 }
177
178 QMapbox::Feature feature = featureFromMapItem(item);
179
180 changes << QMapboxGLStyleAddLayer::fromFeature(feature, before);
181 changes << QMapboxGLStyleAddSource::fromFeature(feature);
184
185 return changes;
186}
187
188QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleChange::removeMapItem(QDeclarativeGeoMapItemBase *item)
189{
190 QList<QSharedPointer<QMapboxGLStyleChange>> changes;
191
192 const QString id = getId(item);
193
194 changes << QSharedPointer<QMapboxGLStyleChange>(new QMapboxGLStyleRemoveLayer(id));
195 changes << QSharedPointer<QMapboxGLStyleChange>(new QMapboxGLStyleRemoveSource(id));
196
197 return changes;
198}
199
200// QMapboxGLStyleSetLayoutProperty
201
203{
204 map->setLayoutProperty(m_layer, m_property, m_value);
205}
206
208{
209 QList<QSharedPointer<QMapboxGLStyleChange>> changes;
210
211 switch (item->itemType()) {
213 changes = fromMapItem(static_cast<QDeclarativePolylineMapItem *>(item));
214 default:
215 break;
216 }
217
218 changes << QSharedPointer<QMapboxGLStyleChange>(
219 new QMapboxGLStyleSetLayoutProperty(getId(item), QStringLiteral("visibility"),
220 item->isVisible() ? QStringLiteral("visible") : QStringLiteral("none")));
221
222 return changes;
223}
224
225QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetLayoutProperty::fromMapItem(QDeclarativePolylineMapItem *item)
226{
227 QList<QSharedPointer<QMapboxGLStyleChange>> changes;
228 changes.reserve(2);
229
230 const QString id = getId(item);
231
232 changes << QSharedPointer<QMapboxGLStyleChange>(
233 new QMapboxGLStyleSetLayoutProperty(id, QStringLiteral("line-cap"), QStringLiteral("square")));
234 changes << QSharedPointer<QMapboxGLStyleChange>(
235 new QMapboxGLStyleSetLayoutProperty(id, QStringLiteral("line-join"), QStringLiteral("bevel")));
236
237 return changes;
238}
239
240QMapboxGLStyleSetLayoutProperty::QMapboxGLStyleSetLayoutProperty(const QString& layer, const QString& property, const QVariant &value)
241 : m_layer(layer), m_property(property), m_value(value)
242{
243}
244
245// QMapboxGLStyleSetPaintProperty
246
247QMapboxGLStyleSetPaintProperty::QMapboxGLStyleSetPaintProperty(const QString& layer, const QString& property, const QVariant &value)
248 : m_layer(layer), m_property(property), m_value(value)
249{
250}
251
253{
254 map->setPaintProperty(m_layer, m_property, m_value);
255}
256
258{
259 switch (item->itemType()) {
261 return fromMapItem(static_cast<QDeclarativeRectangleMapItem *>(item));
263 return fromMapItem(static_cast<QDeclarativeCircleMapItem *>(item));
265 return fromMapItem(static_cast<QDeclarativePolygonMapItem *>(item));
267 return fromMapItem(static_cast<QDeclarativePolylineMapItem *>(item));
268 default:
269 qWarning() << "Unsupported QGeoMap item type: " << item->itemType();
270 return QList<QSharedPointer<QMapboxGLStyleChange>>();
271 }
272}
273
274QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetPaintProperty::fromMapItem(QDeclarativeRectangleMapItem *item)
275{
276 QList<QSharedPointer<QMapboxGLStyleChange>> changes;
277 changes.reserve(3);
278
279 const QString id = getId(item);
280
281 changes << QSharedPointer<QMapboxGLStyleChange>(
282 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-opacity"), item->color().alphaF() * item->mapItemOpacity()));
283 changes << QSharedPointer<QMapboxGLStyleChange>(
284 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-color"), item->color()));
285 changes << QSharedPointer<QMapboxGLStyleChange>(
286 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-outline-color"), item->border()->color()));
287
288 return changes;
289}
290
291QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetPaintProperty::fromMapItem(QDeclarativeCircleMapItem *item)
292{
293 QList<QSharedPointer<QMapboxGLStyleChange>> changes;
294 changes.reserve(3);
295
296 const QString id = getId(item);
297
298 changes << QSharedPointer<QMapboxGLStyleChange>(
299 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-opacity"), item->color().alphaF() * item->mapItemOpacity()));
300 changes << QSharedPointer<QMapboxGLStyleChange>(
301 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-color"), item->color()));
302 changes << QSharedPointer<QMapboxGLStyleChange>(
303 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-outline-color"), item->border()->color()));
304
305 return changes;
306}
307
308QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetPaintProperty::fromMapItem(QDeclarativePolygonMapItem *item)
309{
310 QList<QSharedPointer<QMapboxGLStyleChange>> changes;
311 changes.reserve(3);
312
313 const QString id = getId(item);
314
315 changes << QSharedPointer<QMapboxGLStyleChange>(
316 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-opacity"), item->color().alphaF() * item->mapItemOpacity()));
317 changes << QSharedPointer<QMapboxGLStyleChange>(
318 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-color"), item->color()));
319 changes << QSharedPointer<QMapboxGLStyleChange>(
320 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-outline-color"), item->border()->color()));
321
322 return changes;
323}
324
325QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetPaintProperty::fromMapItem(QDeclarativePolylineMapItem *item)
326{
327 QList<QSharedPointer<QMapboxGLStyleChange>> changes;
328 changes.reserve(3);
329
330 const QString id = getId(item);
331
332 changes << QSharedPointer<QMapboxGLStyleChange>(
333 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("line-opacity"), item->line()->color().alphaF() * item->mapItemOpacity()));
334 changes << QSharedPointer<QMapboxGLStyleChange>(
335 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("line-color"), item->line()->color()));
336 changes << QSharedPointer<QMapboxGLStyleChange>(
337 new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("line-width"), item->line()->width()));
338
339 return changes;
340}
341
342// QMapboxGLStyleAddLayer
343
345{
346 map->addLayer(m_params, m_before);
347}
348
349QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleAddLayer::fromFeature(const QMapbox::Feature &feature, const QString &before)
350{
351 auto layer = new QMapboxGLStyleAddLayer();
352 layer->m_params[QStringLiteral("id")] = feature.id;
353 layer->m_params[QStringLiteral("source")] = feature.id;
354
355 switch (feature.type) {
356 case QMapbox::Feature::PointType:
357 layer->m_params[QStringLiteral("type")] = QStringLiteral("circle");
358 break;
359 case QMapbox::Feature::LineStringType:
360 layer->m_params[QStringLiteral("type")] = QStringLiteral("line");
361 break;
362 case QMapbox::Feature::PolygonType:
363 layer->m_params[QStringLiteral("type")] = QStringLiteral("fill");
364 break;
365 }
366
367 layer->m_before = before;
368
369 return QSharedPointer<QMapboxGLStyleChange>(layer);
370}
371
372
373// QMapboxGLStyleRemoveLayer
374
376{
377 map->removeLayer(m_id);
378}
379
383
384
385// QMapboxGLStyleAddSource
386
388{
389 map->updateSource(m_id, m_params);
390}
391
392QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleAddSource::fromFeature(const QMapbox::Feature &feature)
393{
394 auto source = new QMapboxGLStyleAddSource();
395
396 source->m_id = feature.id.toString();
397 source->m_params[QStringLiteral("type")] = QStringLiteral("geojson");
398 source->m_params[QStringLiteral("data")] = QVariant::fromValue<QMapbox::Feature>(feature);
399
400 return QSharedPointer<QMapboxGLStyleChange>(source);
401}
402
404{
405 return fromFeature(featureFromMapItem(item));
406}
407
408
409// QMapboxGLStyleRemoveSource
410
412{
413 map->removeSource(m_id);
414}
415
419
420
421// QMapboxGLStyleSetFilter
422
424{
425 map->setFilter(m_layer, m_filter);
426}
427
428// QMapboxGLStyleAddImage
429
431{
432 map->addImage(m_name, m_sprite);
433}
\inmodule QtCore
Definition qbytearray.h:57
static int crossEarthPole(const QGeoCoordinate &center, qreal distance)
\inmodule QtPositioning
double latitude
This property holds the latitude in decimal degrees.
@ MapRectangle
Definition qgeomap_p.h:48
@ MapPolyline
Definition qgeomap_p.h:50
@ MapPolygon
Definition qgeomap_p.h:51
@ MapCircle
Definition qgeomap_p.h:49
\inmodule QtPositioning
Definition qgeopath.h:16
\inmodule QtPositioning
Definition qgeopolygon.h:16
\inmodule QtPositioning
QGeoCoordinate bottomLeft
This property holds the bottom left coorindate of this geo rectangle.
bool isVisible() const
Returns true if the item is visible; otherwise, false is returned.
void apply(QMapboxGL *map) override
static QSharedPointer< QMapboxGLStyleChange > fromFeature(const QMapbox::Feature &feature, const QString &before)
void apply(QMapboxGL *map) override
static QSharedPointer< QMapboxGLStyleChange > fromMapItem(QDeclarativeGeoMapItemBase *)
static QSharedPointer< QMapboxGLStyleChange > fromFeature(const QMapbox::Feature &feature)
void apply(QMapboxGL *map) override
static QList< QSharedPointer< QMapboxGLStyleChange > > addMapItem(QDeclarativeGeoMapItemBase *, const QString &before)
static QList< QSharedPointer< QMapboxGLStyleChange > > removeMapItem(QDeclarativeGeoMapItemBase *)
QMapboxGLStyleRemoveLayer(const QString &id)
void apply(QMapboxGL *map) override
QMapboxGLStyleRemoveSource(const QString &id)
void apply(QMapboxGL *map) override
void apply(QMapboxGL *map) override
void apply(QMapboxGL *map) override
static QList< QSharedPointer< QMapboxGLStyleChange > > fromMapItem(QDeclarativeGeoMapItemBase *)
static QList< QSharedPointer< QMapboxGLStyleChange > > fromMapItem(QDeclarativeGeoMapItemBase *)
void apply(QMapboxGL *map) override
\inmodule QtCore
Definition qobject.h:103
\inmodule QtCore \reentrant
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
\inmodule QtCore
Definition qvariant.h:65
QMap< QString, QString > map
[6]
rect
[4]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputLayerEXT layer
#define qWarning
Definition qlogging.h:166
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLenum GLuint id
[7]
GLuint object
[3]
GLuint name
GLsizei GLsizei GLchar * source
const GLubyte * c
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
#define QStringLiteral(str)
unsigned long long quint64
Definition qtypes.h:61
const char property[13]
Definition qwizard.cpp:101
obj metaObject() -> className()
QGraphicsItem * item
\inmodule QtCore