From be43310b6ff5465e6717128b577f6e61c0335c44 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 24 Jan 2017 18:05:22 +0200 Subject: [PATCH] [Qt] Refactor QMapbox Annotations API --- platform/qt/app/mapwindow.cpp | 55 +++++++++++++ platform/qt/app/mapwindow.hpp | 5 ++ platform/qt/include/qmapbox.hpp | 70 ++++++++++++++-- platform/qt/include/qmapboxgl.hpp | 7 +- platform/qt/resources/common.qrc | 1 + platform/qt/src/qmapboxgl.cpp | 132 ++++++++++++++++++++++-------- 6 files changed, 222 insertions(+), 48 deletions(-) diff --git a/platform/qt/app/mapwindow.cpp b/platform/qt/app/mapwindow.cpp index 0b453406f..3e6a14736 100644 --- a/platform/qt/app/mapwindow.cpp +++ b/platform/qt/app/mapwindow.cpp @@ -203,6 +203,61 @@ void MapWindow::keyPressEvent(QKeyEvent *ev) m_map->setLayoutProperty("road-label-small", "text-size", 30.0); } break; + case Qt::Key_1: { + if (m_symbolAnnotationId.isNull()) { + QMapbox::Coordinate coordinate = m_map->coordinate(); + QMapbox::SymbolAnnotation symbol { coordinate, "default_marker" }; + m_map->addAnnotationIcon("default_marker", QImage(":default_marker.svg")); + m_symbolAnnotationId = m_map->addAnnotation(QVariant::fromValue(symbol)); + } else { + m_map->removeAnnotation(m_symbolAnnotationId.toUInt()); + m_symbolAnnotationId.clear(); + } + } + break; + case Qt::Key_2: { + if (m_lineAnnotationId.isNull()) { + QMapbox::Coordinate topLeft = m_map->coordinateForPixel({ 0, 0 }); + QMapbox::Coordinate bottomRight = m_map->coordinateForPixel({ qreal(size().width()), qreal(size().height()) }); + QMapbox::CoordinatesCollections geometry { { { topLeft, bottomRight } } }; + QMapbox::LineAnnotation line { { QMapbox::ShapeAnnotationGeometry::Type::LineStringType, geometry }, 0.5f, 1.0f, Qt::red }; + m_lineAnnotationId = m_map->addAnnotation(QVariant::fromValue(line)); + } else { + m_map->removeAnnotation(m_lineAnnotationId.toUInt()); + m_lineAnnotationId.clear(); + } + } + break; + case Qt::Key_3: { + if (m_fillAnnotationId.isNull()) { + QMapbox::Coordinate topLeft = m_map->coordinateForPixel({ 0, 0 }); + QMapbox::Coordinate topRight = m_map->coordinateForPixel({ 0, qreal(size().height()) }); + QMapbox::Coordinate bottomLeft = m_map->coordinateForPixel({ qreal(size().width()), 0 }); + QMapbox::Coordinate bottomRight = m_map->coordinateForPixel({ qreal(size().width()), qreal(size().height()) }); + QMapbox::CoordinatesCollections geometry { { { bottomLeft, bottomRight, topRight, topLeft, bottomLeft } } }; + QMapbox::FillAnnotation fill { { QMapbox::ShapeAnnotationGeometry::Type::PolygonType, geometry }, 0.5f, Qt::green, QVariant::fromValue(QColor(Qt::black)) }; + m_fillAnnotationId = m_map->addAnnotation(QVariant::fromValue(fill)); + } else { + m_map->removeAnnotation(m_fillAnnotationId.toUInt()); + m_fillAnnotationId.clear(); + } + } + break; + case Qt::Key_4: { + if (m_styleSourcedAnnotationId.isNull()) { + QMapbox::Coordinate topLeft = m_map->coordinateForPixel({ 0, 0 }); + QMapbox::Coordinate topRight = m_map->coordinateForPixel({ 0, qreal(size().height()) }); + QMapbox::Coordinate bottomLeft = m_map->coordinateForPixel({ qreal(size().width()), 0 }); + QMapbox::Coordinate bottomRight = m_map->coordinateForPixel({ qreal(size().width()), qreal(size().height()) }); + QMapbox::CoordinatesCollections geometry { { { bottomLeft, bottomRight, topRight, topLeft, bottomLeft } } }; + QMapbox::StyleSourcedAnnotation styleSourced { { QMapbox::ShapeAnnotationGeometry::Type::PolygonType, geometry }, "water" }; + m_styleSourcedAnnotationId = m_map->addAnnotation(QVariant::fromValue(styleSourced)); + } else { + m_map->removeAnnotation(m_styleSourcedAnnotationId.toUInt()); + m_styleSourcedAnnotationId.clear(); + } + } + break; case Qt::Key_Tab: m_map->cycleDebugOptions(); break; diff --git a/platform/qt/app/mapwindow.hpp b/platform/qt/app/mapwindow.hpp index 23880902d..6b4b7fd1c 100644 --- a/platform/qt/app/mapwindow.hpp +++ b/platform/qt/app/mapwindow.hpp @@ -61,6 +61,11 @@ private: unsigned m_animationTicks = 0; unsigned m_frameDraws = 0; + QVariant m_symbolAnnotationId; + QVariant m_lineAnnotationId; + QVariant m_fillAnnotationId; + QVariant m_styleSourcedAnnotationId; + bool m_sourceAdded = false; }; diff --git a/platform/qt/include/qmapbox.hpp b/platform/qt/include/qmapbox.hpp index 3aaacb84e..1388c0f51 100644 --- a/platform/qt/include/qmapbox.hpp +++ b/platform/qt/include/qmapbox.hpp @@ -1,6 +1,7 @@ #ifndef QMAPBOX_H #define QMAPBOX_H +#include #include #include #include @@ -10,19 +11,65 @@ namespace QMapbox { +// Reflects mapbox::geometry::point. typedef QPair Coordinate; -typedef QList LineString; - typedef QPair CoordinateZoom; +// Reflects mapbox::geometry::line_string and mapbox::geometry::linear_ring. +typedef QList Coordinates; + +// Reflects mapbox::geometry::multi_line_string and mapbox::geometry::polygon. +typedef QList CoordinatesCollection; + +// Reflects mapbox::geometry::multi_polygon. +typedef QList CoordinatesCollections; + +// Reflects mbgl::ShapeAnnotationGeometry. +struct Q_DECL_EXPORT ShapeAnnotationGeometry { + enum Type { + LineStringType, + PolygonType, + MultiLineStringType, + MultiPolygonType + }; + Type type; + CoordinatesCollections geometry; +}; + +// Reflects mbgl::SymbolAnnotation. +struct Q_DECL_EXPORT SymbolAnnotation { + Coordinate geometry; + QString icon; +}; + +// Reflects mbgl::LineAnnotation. +struct Q_DECL_EXPORT LineAnnotation { + ShapeAnnotationGeometry geometry; + float opacity = 1.0f; + float width = 1.0f; + QColor color = Qt::black; +}; + +// Reflects mbgl::FillAnnotation. +struct Q_DECL_EXPORT FillAnnotation { + ShapeAnnotationGeometry geometry; + float opacity = 1.0f; + QColor color = Qt::black; + QVariant outlineColor; +}; + +// Reflects mbgl::StyleSourcedAnnotation. +struct Q_DECL_EXPORT StyleSourcedAnnotation { + ShapeAnnotationGeometry geometry; + QString layerID; +}; + +// SymbolAnnotation, LineAnnotation, FillAnnotation, StyleSourcedAnnotation. +typedef QVariant Annotation; + typedef quint32 AnnotationID; typedef QList AnnotationIDs; -typedef QPair PointAnnotation; - -// FIXME: We need to add support for custom style properties -typedef QPair ShapeAnnotation; - // Reflects mbgl::NetworkStatus::Status. enum NetworkMode { Online, // Default @@ -55,5 +102,14 @@ Q_DECL_EXPORT void initializeGLExtensions(); } // namespace QMapbox Q_DECLARE_METATYPE(QMapbox::Coordinate); +Q_DECLARE_METATYPE(QMapbox::Coordinates); +Q_DECLARE_METATYPE(QMapbox::CoordinatesCollection); +Q_DECLARE_METATYPE(QMapbox::CoordinatesCollections); + +Q_DECLARE_METATYPE(QMapbox::SymbolAnnotation); +Q_DECLARE_METATYPE(QMapbox::ShapeAnnotationGeometry); +Q_DECLARE_METATYPE(QMapbox::LineAnnotation); +Q_DECLARE_METATYPE(QMapbox::FillAnnotation); +Q_DECLARE_METATYPE(QMapbox::StyleSourcedAnnotation); #endif // QMAPBOX_H diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp index be2d60608..0f1ab7c29 100644 --- a/platform/qt/include/qmapboxgl.hpp +++ b/platform/qt/include/qmapboxgl.hpp @@ -183,11 +183,8 @@ public: void addAnnotationIcon(const QString &name, const QImage &sprite); - QMapbox::AnnotationID addPointAnnotation(const QMapbox::PointAnnotation &); - QMapbox::AnnotationID addShapeAnnotation(const QMapbox::ShapeAnnotation &); - - void updatePointAnnotation(QMapbox::AnnotationID, const QMapbox::PointAnnotation &); - + QMapbox::AnnotationID addAnnotation(const QMapbox::Annotation &); + void updateAnnotation(QMapbox::AnnotationID, const QMapbox::Annotation &); void removeAnnotation(QMapbox::AnnotationID); void setLayoutProperty(const QString &layer, const QString &property, const QVariant &value); diff --git a/platform/qt/resources/common.qrc b/platform/qt/resources/common.qrc index d02c04a3c..4c792b057 100644 --- a/platform/qt/resources/common.qrc +++ b/platform/qt/resources/common.qrc @@ -1,6 +1,7 @@ ../../../common/icon.png + ../../../platform/default/resources/default_marker.svg source1.geojson source2.geojson label-arrow.svg diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 86604a945..fb56c4d99 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -17,8 +17,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -85,20 +87,6 @@ QThreadStorage> loop; // Conversion helper functions. -auto fromQMapboxGLShapeAnnotation(const ShapeAnnotation &shapeAnnotation) { - const LineString &lineString = shapeAnnotation.first; - const QString &styleLayer = shapeAnnotation.second; - - mbgl::LineString mbglLineString; - mbglLineString.reserve(lineString.size()); - - for (const Coordinate &coordinate : lineString) { - mbglLineString.emplace_back(mbgl::Point { coordinate.first, coordinate.second }); - } - - return mbgl::StyleSourcedAnnotation { std::move(mbglLineString), styleLayer.toStdString() }; -} - auto fromQStringList(const QStringList &list) { std::vector strings; @@ -848,42 +836,114 @@ void QMapboxGL::setTransitionOptions(qint64 duration, qint64 delay) { d_ptr->mapObj->setTransitionOptions(mbgl::style::TransitionOptions{ convert(duration), convert(delay) }); } -mbgl::Annotation fromPointAnnotation(const PointAnnotation &pointAnnotation) { - const Coordinate &coordinate = pointAnnotation.first; - const QString &icon = pointAnnotation.second; - return mbgl::SymbolAnnotation { mbgl::Point { coordinate.second, coordinate.first }, icon.toStdString() }; +mbgl::ShapeAnnotationGeometry asMapboxGLGeometry(const QMapbox::ShapeAnnotationGeometry &geometry) { + auto asMapboxGLLineString = [&](const QMapbox::Coordinates &lineString) { + mbgl::LineString mbglLineString; + mbglLineString.reserve(lineString.size()); + for (const auto &coordinate : lineString) { + mbglLineString.emplace_back(mbgl::Point { coordinate.second, coordinate.first }); + } + return mbglLineString; + }; + + auto asMapboxGLMultiLineString = [&](const QMapbox::CoordinatesCollection &multiLineString) { + mbgl::MultiLineString mbglMultiLineString; + mbglMultiLineString.reserve(multiLineString.size()); + for (const auto &lineString : multiLineString) { + mbglMultiLineString.emplace_back(std::forward>(asMapboxGLLineString(lineString))); + } + return mbglMultiLineString; + }; + + auto asMapboxGLPolygon = [&](const QMapbox::CoordinatesCollection &polygon) { + mbgl::Polygon mbglPolygon; + mbglPolygon.reserve(polygon.size()); + for (const auto &linearRing : polygon) { + mbgl::LinearRing mbglLinearRing; + mbglLinearRing.reserve(linearRing.size()); + for (const auto &coordinate: linearRing) { + mbglLinearRing.emplace_back(mbgl::Point { coordinate.second, coordinate.first }); + } + mbglPolygon.emplace_back(std::move(mbglLinearRing)); + } + return mbglPolygon; + }; + + auto asMapboxGLMultiPolygon = [&](const QMapbox::CoordinatesCollections &multiPolygon) { + mbgl::MultiPolygon mbglMultiPolygon; + mbglMultiPolygon.reserve(multiPolygon.size()); + for (const auto &polygon : multiPolygon) { + mbglMultiPolygon.emplace_back(std::forward>(asMapboxGLPolygon(polygon))); + } + return mbglMultiPolygon; + }; + + mbgl::ShapeAnnotationGeometry result; + switch (geometry.type) { + case QMapbox::ShapeAnnotationGeometry::LineStringType: + result = { asMapboxGLLineString(geometry.geometry.first().first()) }; + break; + case QMapbox::ShapeAnnotationGeometry::PolygonType: + result = { asMapboxGLPolygon(geometry.geometry.first()) }; + break; + case QMapbox::ShapeAnnotationGeometry::MultiLineStringType: + result = { asMapboxGLMultiLineString(geometry.geometry.first()) }; + break; + case QMapbox::ShapeAnnotationGeometry::MultiPolygonType: + result = { asMapboxGLMultiPolygon(geometry.geometry) }; + break; + } + + return result; +} + +mbgl::Annotation asMapboxGLAnnotation(const QMapbox::Annotation & annotation) { + if (annotation.canConvert()) { + QMapbox::SymbolAnnotation symbolAnnotation = annotation.value(); + QMapbox::Coordinate& pair = symbolAnnotation.geometry; + return mbgl::SymbolAnnotation { mbgl::Point { pair.second, pair.first }, symbolAnnotation.icon.toStdString() }; + } else if (annotation.canConvert()) { + QMapbox::LineAnnotation lineAnnotation = annotation.value(); + auto color = mbgl::Color::parse(lineAnnotation.color.name().toStdString()); + return mbgl::LineAnnotation { asMapboxGLGeometry(lineAnnotation.geometry), lineAnnotation.opacity, lineAnnotation.width, { *color } }; + } else if (annotation.canConvert()) { + QMapbox::FillAnnotation fillAnnotation = annotation.value(); + auto color = mbgl::Color::parse(fillAnnotation.color.name().toStdString()); + if (fillAnnotation.outlineColor.canConvert()) { + auto outlineColor = mbgl::Color::parse(fillAnnotation.outlineColor.value().name().toStdString()); + return mbgl::FillAnnotation { asMapboxGLGeometry(fillAnnotation.geometry), fillAnnotation.opacity, { *color }, { *outlineColor } }; + } else { + return mbgl::FillAnnotation { asMapboxGLGeometry(fillAnnotation.geometry), fillAnnotation.opacity, { *color }, {} }; + } + } else if (annotation.canConvert()) { + QMapbox::StyleSourcedAnnotation styleSourcedAnnotation = annotation.value(); + return mbgl::StyleSourcedAnnotation { asMapboxGLGeometry(styleSourcedAnnotation.geometry), styleSourcedAnnotation.layerID.toStdString() }; + } + + qWarning() << "Unable to convert annotation:" << annotation; + return {}; } /*! - Adds a \a point annotation to the map. + Adds an \a annotation to the map. Returns the unique identifier for the new annotation. \sa addAnnotationIcon() */ -QMapbox::AnnotationID QMapboxGL::addPointAnnotation(const QMapbox::PointAnnotation &point) +QMapbox::AnnotationID QMapboxGL::addAnnotation(const QMapbox::Annotation &annotation) { - return d_ptr->mapObj->addAnnotation(fromPointAnnotation(point)); + return d_ptr->mapObj->addAnnotation(asMapboxGLAnnotation(annotation)); } /*! - Updates an existing \a point annotation referred by \a id. + Updates an existing \a annotation referred by \a id. \sa addAnnotationIcon() */ -void QMapboxGL::updatePointAnnotation(QMapbox::AnnotationID id, const QMapbox::PointAnnotation &point) +void QMapboxGL::updateAnnotation(QMapbox::AnnotationID id, const QMapbox::Annotation &annotation) { - d_ptr->mapObj->updateAnnotation(id, fromPointAnnotation(point)); -} - -/*! - Adds a \a shape annotation to the map. - - Returns the unique identifier for the new annotation. -*/ -QMapbox::AnnotationID QMapboxGL::addShapeAnnotation(const QMapbox::ShapeAnnotation &shape) -{ - return d_ptr->mapObj->addAnnotation(fromQMapboxGLShapeAnnotation(shape)); + d_ptr->mapObj->updateAnnotation(id, asMapboxGLAnnotation(annotation)); } /*! @@ -1087,10 +1147,10 @@ void QMapboxGL::resize(const QSize& size, const QSize& framebufferSize) Adds an \a icon to the annotation icon pool. This can be later used by the annotation functions to shown any drawing on the map by referencing its \a name. - Unlike using addIcon() for runtime styling, annotations added with addPointAnnotation() + Unlike using addIcon() for runtime styling, annotations added with addAnnotation() will survive style changes. - \sa addPointAnnotation() + \sa addAnnotation() */ void QMapboxGL::addAnnotationIcon(const QString &name, const QImage &icon) {