summaryrefslogtreecommitdiff
path: root/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
diff options
context:
space:
mode:
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);
+}