summaryrefslogtreecommitdiff
path: root/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
diff options
context:
space:
mode:
authorThiago Marcos P. Santos <tmpsantos@gmail.com>2017-02-14 16:05:15 +0200
committerPaolo Angelelli <paolo.angelelli@qt.io>2017-02-17 17:06:22 +0000
commit85c5a6f68a801250bf40eba9546bbd342633327d (patch)
treead2d7f06202333b99c3d33ba0a4d224fa439daf1 /src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
parent6e5eead48216dc0dceb94235436133e47563b553 (diff)
downloadqtlocation-85c5a6f68a801250bf40eba9546bbd342633327d.tar.gz
Fix support for MapParameters on Mapbox GL plugin
Mapbox GL plugin can now accept MapParameters, such as MapParameters used for the Mapbox runtime style API, allowing runtime changes on the map, not restricted only to style, but also adding new geometries and features. Change-Id: If0394bd044a2d3058fe5480966880a1055614ea2 Reviewed-by: Paolo Angelelli <paolo.angelelli@qt.io>
Diffstat (limited to 'src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp')
-rw-r--r--src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp501
1 files changed, 501 insertions, 0 deletions
diff --git a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
new file mode 100644
index 00000000..2d3850e1
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
@@ -0,0 +1,501 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Mapbox, Inc.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmapboxglstylechange_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QMetaProperty>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QStringList>
+#include <QtPositioning/QGeoPath>
+#include <QtQml/QJSValue>
+
+namespace {
+
+QString formatPropertyName(QString *name)
+{
+ static const QRegularExpression camelCaseRegex(QStringLiteral("([a-z0-9])([A-Z])"));
+
+ return name->replace(camelCaseRegex, QStringLiteral("\\1-\\2")).toLower();
+}
+
+bool isImmutableProperty(const QString &name)
+{
+ return name == QStringLiteral("type") || name == QStringLiteral("layer") || name == QStringLiteral("class");
+}
+
+QString getId(QDeclarativeGeoMapItemBase *mapItem)
+{
+ return QStringLiteral("QDeclarativeGeoMapItemBase-") + QString::number(quint64(mapItem));
+}
+
+QMapbox::Feature featureFromMapRectangle(QDeclarativeRectangleMapItem *mapItem)
+{
+ const QGeoRectangle *rect = static_cast<const QGeoRectangle *>(&mapItem->geoShape());
+ QMapbox::Coordinate bottomLeft { rect->bottomLeft().latitude(), rect->bottomLeft().longitude() };
+ QMapbox::Coordinate bottomRight { rect->bottomRight().latitude(), rect->bottomRight().longitude() };
+ QMapbox::Coordinate topLeft { rect->topLeft().latitude(), rect->topLeft().longitude() };
+ QMapbox::Coordinate topRight { rect->topRight().latitude(), rect->topRight().longitude() };
+ QMapbox::CoordinatesCollections geometry { { { bottomLeft, bottomRight, topRight, topLeft, bottomLeft } } };
+
+ return QMapbox::Feature(QMapbox::Feature::PolygonType, geometry, {}, getId(mapItem));
+}
+
+QMapbox::Feature featureFromMapPolygon(QDeclarativePolygonMapItem *mapItem)
+{
+ const QGeoPath *path = static_cast<const QGeoPath *>(&mapItem->geoShape());
+ QMapbox::Coordinates coordinates;
+ for (const QGeoCoordinate &coordinate : path->path()) {
+ coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() };
+ }
+ coordinates.append(coordinates.first());
+ QMapbox::CoordinatesCollections geometry { { coordinates } };
+
+ return QMapbox::Feature(QMapbox::Feature::PolygonType, geometry, {}, getId(mapItem));
+}
+
+QMapbox::Feature featureFromMapPolyline(QDeclarativePolylineMapItem *mapItem)
+{
+ const QGeoPath *path = static_cast<const QGeoPath *>(&mapItem->geoShape());
+ QMapbox::Coordinates coordinates;
+ for (const QGeoCoordinate &coordinate : path->path()) {
+ coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() };
+ }
+ QMapbox::CoordinatesCollections geometry { { coordinates } };
+
+ return QMapbox::Feature(QMapbox::Feature::LineStringType, geometry, {}, getId(mapItem));
+}
+
+QMapbox::Feature featureFromMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ switch (item->itemType()) {
+ case QGeoMap::MapRectangle:
+ return featureFromMapRectangle(static_cast<QDeclarativeRectangleMapItem *>(item));
+ case QGeoMap::MapPolygon:
+ return featureFromMapPolygon(static_cast<QDeclarativePolygonMapItem *>(item));
+ case QGeoMap::MapPolyline:
+ return featureFromMapPolyline(static_cast<QDeclarativePolylineMapItem *>(item));
+ default:
+ qWarning() << "Unsupported QGeoMap item type: " << item->itemType();
+ return QMapbox::Feature();
+ }
+}
+
+} // namespace
+
+
+// QMapboxGLStyleChange
+
+QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleChange::addMapParameter(QGeoMapParameter *param)
+{
+ static const QStringList acceptedParameterTypes = QStringList()
+ << QStringLiteral("paint") << QStringLiteral("layout") << QStringLiteral("filter")
+ << QStringLiteral("layer") << QStringLiteral("source") << QStringLiteral("image");
+
+ QList<QSharedPointer<QMapboxGLStyleChange>> changes;
+
+ switch (acceptedParameterTypes.indexOf(param->type())) {
+ case -1:
+ qWarning() << "Invalid value for property 'type': " + param->type();
+ break;
+ case 0: // paint
+ changes << QMapboxGLStyleSetPaintProperty::fromMapParameter(param);
+ break;
+ case 1: // layout
+ changes << QMapboxGLStyleSetLayoutProperty::fromMapParameter(param);
+ break;
+ case 2: // filter
+ changes << QMapboxGLStyleSetFilter::fromMapParameter(param);
+ break;
+ case 3: // layer
+ changes << QMapboxGLStyleAddLayer::fromMapParameter(param);
+ break;
+ case 4: // source
+ changes << QMapboxGLStyleAddSource::fromMapParameter(param);
+ break;
+ case 5: // image
+ changes << QMapboxGLStyleAddImage::fromMapParameter(param);
+ break;
+ }
+
+ return changes;
+}
+
+QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleChange::addMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ QList<QSharedPointer<QMapboxGLStyleChange>> changes;
+
+ switch (item->itemType()) {
+ case QGeoMap::MapRectangle:
+ case QGeoMap::MapPolygon:
+ case QGeoMap::MapPolyline:
+ break;
+ default:
+ qWarning() << "Unsupported QGeoMap item type: " << item->itemType();
+ return changes;
+ }
+
+ QMapbox::Feature feature = featureFromMapItem(item);
+
+ changes << QMapboxGLStyleAddLayer::fromFeature(feature);
+ changes << QMapboxGLStyleAddSource::fromFeature(feature);
+ changes << QMapboxGLStyleSetPaintProperty::fromMapItem(item);
+
+ return changes;
+}
+
+QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleChange::removeMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ QList<QSharedPointer<QMapboxGLStyleChange>> changes;
+
+ const QString id = getId(item);
+
+ changes << QSharedPointer<QMapboxGLStyleChange>(new QMapboxGLStyleRemoveLayer(id));
+ changes << QSharedPointer<QMapboxGLStyleChange>(new QMapboxGLStyleRemoveSource(id));
+
+ return changes;
+}
+
+// QMapboxGLStyleSetLayoutProperty
+
+void QMapboxGLStyleSetLayoutProperty::apply(QMapboxGL *map)
+{
+ map->setLayoutProperty(m_layer, m_property, m_value);
+}
+
+QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetLayoutProperty::fromMapParameter(QGeoMapParameter *param)
+{
+ Q_ASSERT(param->type() == "layout");
+
+ QList<QSharedPointer<QMapboxGLStyleChange>> changes;
+
+ // Offset objectName and type properties.
+ for (int i = 2; i < param->metaObject()->propertyCount(); ++i) {
+ QString name = param->metaObject()->property(i).name();
+
+ if (isImmutableProperty(name))
+ continue;
+
+ auto layout = new QMapboxGLStyleSetLayoutProperty();
+
+ layout->m_value = param->property(name.toLatin1());
+ if (layout->m_value.canConvert<QJSValue>()) {
+ layout->m_value = layout->m_value.value<QJSValue>().toVariant();
+ }
+
+ layout->m_layer = param->property("layer").toString();
+ layout->m_property = formatPropertyName(&name);
+
+ changes << QSharedPointer<QMapboxGLStyleChange>(layout);
+ }
+
+ return changes;
+}
+
+
+// QMapboxGLStyleSetPaintProperty
+
+QMapboxGLStyleSetPaintProperty::QMapboxGLStyleSetPaintProperty(const QString& layer, const QString& property, const QVariant &value)
+ : m_layer(layer), m_property(property), m_value(value)
+{
+}
+
+void QMapboxGLStyleSetPaintProperty::apply(QMapboxGL *map)
+{
+ map->setPaintProperty(m_layer, m_property, m_value, m_class);
+}
+
+QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetPaintProperty::fromMapParameter(QGeoMapParameter *param)
+{
+ Q_ASSERT(param->type() == "paint");
+
+ QList<QSharedPointer<QMapboxGLStyleChange>> changes;
+
+ // Offset objectName and type properties.
+ for (int i = 2; i < param->metaObject()->propertyCount(); ++i) {
+ QString name = param->metaObject()->property(i).name();
+
+ if (isImmutableProperty(name))
+ continue;
+
+ auto paint = new QMapboxGLStyleSetPaintProperty();
+
+ paint->m_value = param->property(name.toLatin1());
+ if (paint->m_value.canConvert<QJSValue>()) {
+ paint->m_value = paint->m_value.value<QJSValue>().toVariant();
+ }
+
+ paint->m_layer = param->property("layer").toString();
+ paint->m_property = formatPropertyName(&name);
+ paint->m_class = param->property("class").toString();
+
+ changes << QSharedPointer<QMapboxGLStyleChange>(paint);
+ }
+
+ return changes;
+}
+
+QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetPaintProperty::fromMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ switch (item->itemType()) {
+ case QGeoMap::MapRectangle:
+ return fromMapItem(static_cast<QDeclarativeRectangleMapItem *>(item));
+ case QGeoMap::MapPolygon:
+ return fromMapItem(static_cast<QDeclarativePolygonMapItem *>(item));
+ case QGeoMap::MapPolyline:
+ return fromMapItem(static_cast<QDeclarativePolylineMapItem *>(item));
+ default:
+ qWarning() << "Unsupported QGeoMap item type: " << item->itemType();
+ return QList<QSharedPointer<QMapboxGLStyleChange>>();
+ }
+}
+
+QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetPaintProperty::fromMapItem(QDeclarativeRectangleMapItem *item)
+{
+ QList<QSharedPointer<QMapboxGLStyleChange>> changes;
+ changes.reserve(3);
+
+ const QString id = getId(item);
+
+ changes << QSharedPointer<QMapboxGLStyleChange>(
+ new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-opacity"), item->mapItemOpacity()));
+ changes << QSharedPointer<QMapboxGLStyleChange>(
+ new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-color"), item->color()));
+ changes << QSharedPointer<QMapboxGLStyleChange>(
+ new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-outline-color"), item->border()->color()));
+
+ return changes;
+}
+
+QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetPaintProperty::fromMapItem(QDeclarativePolygonMapItem *item)
+{
+ QList<QSharedPointer<QMapboxGLStyleChange>> changes;
+ changes.reserve(3);
+
+ const QString id = getId(item);
+
+ changes << QSharedPointer<QMapboxGLStyleChange>(
+ new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-opacity"), item->mapItemOpacity()));
+ changes << QSharedPointer<QMapboxGLStyleChange>(
+ new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-color"), item->color()));
+ changes << QSharedPointer<QMapboxGLStyleChange>(
+ new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("fill-outline-color"), item->border()->color()));
+
+ return changes;
+}
+
+QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleSetPaintProperty::fromMapItem(QDeclarativePolylineMapItem *item)
+{
+ QList<QSharedPointer<QMapboxGLStyleChange>> changes;
+ changes.reserve(3);
+
+ const QString id = getId(item);
+
+ changes << QSharedPointer<QMapboxGLStyleChange>(
+ new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("line-opacity"), item->mapItemOpacity()));
+ changes << QSharedPointer<QMapboxGLStyleChange>(
+ new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("line-color"), item->line()->color()));
+ changes << QSharedPointer<QMapboxGLStyleChange>(
+ new QMapboxGLStyleSetPaintProperty(id, QStringLiteral("line-width"), item->line()->width()));
+
+ return changes;
+}
+
+// QMapboxGLStyleAddLayer
+
+void QMapboxGLStyleAddLayer::apply(QMapboxGL *map)
+{
+ map->addLayer(m_params);
+}
+
+QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleAddLayer::fromMapParameter(QGeoMapParameter *param)
+{
+ Q_ASSERT(param->type() == "layer");
+
+ auto layer = new QMapboxGLStyleAddLayer();
+ layer->m_params[QStringLiteral("id")] = param->property("name");
+ layer->m_params[QStringLiteral("source")] = param->property("source");
+ layer->m_params[QStringLiteral("type")] = param->property("layerType");
+
+ if (param->property("sourceLayer").isValid()) {
+ layer->m_params[QStringLiteral("source-layer")] = param->property("sourceLayer");
+ }
+
+ return QSharedPointer<QMapboxGLStyleChange>(layer);
+}
+
+QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleAddLayer::fromFeature(const QMapbox::Feature &feature)
+{
+ auto layer = new QMapboxGLStyleAddLayer();
+ layer->m_params[QStringLiteral("id")] = feature.id;
+ layer->m_params[QStringLiteral("source")] = feature.id;
+
+ switch (feature.type) {
+ case QMapbox::Feature::PointType:
+ layer->m_params[QStringLiteral("type")] = QStringLiteral("circle");
+ break;
+ case QMapbox::Feature::LineStringType:
+ layer->m_params[QStringLiteral("type")] = QStringLiteral("line");
+ break;
+ case QMapbox::Feature::PolygonType:
+ layer->m_params[QStringLiteral("type")] = QStringLiteral("fill");
+ break;
+ }
+
+ return QSharedPointer<QMapboxGLStyleChange>(layer);
+}
+
+
+// QMapboxGLStyleRemoveLayer
+
+void QMapboxGLStyleRemoveLayer::apply(QMapboxGL *map)
+{
+ map->removeLayer(m_id);
+}
+
+QMapboxGLStyleRemoveLayer::QMapboxGLStyleRemoveLayer(const QString &id) : m_id(id)
+{
+}
+
+
+// QMapboxGLStyleAddSource
+
+void QMapboxGLStyleAddSource::apply(QMapboxGL *map)
+{
+ map->updateSource(m_id, m_params);
+}
+
+QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleAddSource::fromMapParameter(QGeoMapParameter *param)
+{
+ Q_ASSERT(param->type() == "source");
+
+ static const QStringList acceptedSourceTypes = QStringList()
+ << QStringLiteral("vector") << QStringLiteral("raster") << QStringLiteral("geojson");
+
+ QString sourceType = param->property("sourceType").toString();
+
+ auto source = new QMapboxGLStyleAddSource();
+ source->m_id = param->property("name").toString();
+ source->m_params[QStringLiteral("type")] = sourceType;
+
+ switch (acceptedSourceTypes.indexOf(sourceType)) {
+ case -1:
+ qWarning() << "Invalid value for property 'sourceType': " + sourceType;
+ break;
+ case 0: // vector
+ case 1: // raster
+ source->m_params[QStringLiteral("url")] = param->property("url");
+ break;
+ case 2: { // geojson
+ auto data = param->property("data").toString();
+ if (data.startsWith(':')) {
+ QFile geojson(data);
+ geojson.open(QIODevice::ReadOnly);
+ source->m_params[QStringLiteral("data")] = geojson.readAll();
+ } else {
+ source->m_params[QStringLiteral("data")] = data.toUtf8();
+ }
+ } break;
+ }
+
+ return QSharedPointer<QMapboxGLStyleChange>(source);
+}
+
+QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleAddSource::fromFeature(const QMapbox::Feature &feature)
+{
+ auto source = new QMapboxGLStyleAddSource();
+
+ source->m_id = feature.id.toString();
+ source->m_params[QStringLiteral("type")] = QStringLiteral("geojson");
+ source->m_params[QStringLiteral("data")] = QVariant::fromValue<QMapbox::Feature>(feature);
+
+ return QSharedPointer<QMapboxGLStyleChange>(source);
+}
+
+QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleAddSource::fromMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ return fromFeature(featureFromMapItem(item));
+}
+
+
+// QMapboxGLStyleRemoveSource
+
+void QMapboxGLStyleRemoveSource::apply(QMapboxGL *map)
+{
+ map->removeSource(m_id);
+}
+
+QMapboxGLStyleRemoveSource::QMapboxGLStyleRemoveSource(const QString &id) : m_id(id)
+{
+}
+
+
+// QMapboxGLStyleSetFilter
+
+void QMapboxGLStyleSetFilter::apply(QMapboxGL *map)
+{
+ map->setFilter(m_layer, m_filter);
+}
+
+QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleSetFilter::fromMapParameter(QGeoMapParameter *param)
+{
+ Q_ASSERT(param->type() == "filter");
+
+ auto filter = new QMapboxGLStyleSetFilter();
+ filter->m_layer = param->property("layer").toString();
+ filter->m_filter = param->property("filter");
+
+ return QSharedPointer<QMapboxGLStyleChange>(filter);
+}
+
+
+// QMapboxGLStyleAddImage
+
+void QMapboxGLStyleAddImage::apply(QMapboxGL *map)
+{
+ map->addImage(m_name, m_sprite);
+}
+
+QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleAddImage::fromMapParameter(QGeoMapParameter *param)
+{
+ Q_ASSERT(param->type() == "image");
+
+ auto image = new QMapboxGLStyleAddImage();
+ image->m_name = param->property("name").toString();
+ image->m_sprite = QImage(param->property("sprite").toString());
+
+ return QSharedPointer<QMapboxGLStyleChange>(image);
+}