diff options
Diffstat (limited to 'src')
53 files changed, 1293 insertions, 458 deletions
diff --git a/src/imports/location/location.cpp b/src/imports/location/location.cpp index 2c2331bf..dbedd1de 100644 --- a/src/imports/location/location.cpp +++ b/src/imports/location/location.cpp @@ -212,6 +212,6 @@ public: } }; -#include "location.moc" - QT_END_NAMESPACE + +#include "location.moc" diff --git a/src/imports/locationlabs/locationlabs.cpp b/src/imports/locationlabs/locationlabs.cpp index cebdf0e4..21c63622 100644 --- a/src/imports/locationlabs/locationlabs.cpp +++ b/src/imports/locationlabs/locationlabs.cpp @@ -80,6 +80,6 @@ public: } }; -#include "locationlabs.moc" - QT_END_NAMESPACE + +#include "locationlabs.moc" diff --git a/src/imports/positioning/locationsingleton.cpp b/src/imports/positioning/locationsingleton.cpp index e355851e..8f810d94 100644 --- a/src/imports/positioning/locationsingleton.cpp +++ b/src/imports/positioning/locationsingleton.cpp @@ -214,6 +214,14 @@ QGeoPath LocationSingleton::path() const return QGeoPath(); } +/*! + \qmlmethod geopath QtPositioning::path(list<coordinate> coordinates, real width) const + + Constructs a geopath from coordinates and width. + + \sa {geopath} + \since 5.9 +*/ QGeoPath LocationSingleton::path(const QJSValue &value, qreal width) const { QList<QGeoCoordinate> pathList; diff --git a/src/imports/positioning/positioning.cpp b/src/imports/positioning/positioning.cpp index a3cb98fa..215fa61a 100644 --- a/src/imports/positioning/positioning.cpp +++ b/src/imports/positioning/positioning.cpp @@ -38,8 +38,8 @@ ****************************************************************************/ -#include <QtPositioning/private/qdeclarativegeoaddress_p.h> -#include <QtPositioning/private/qdeclarativegeolocation_p.h> +#include <QtPositioningQuick/private/qdeclarativegeoaddress_p.h> +#include <QtPositioningQuick/private/qdeclarativegeolocation_p.h> #include <QtPositioning/private/qwebmercator_p.h> #include <QtPositioningQuick/private/qdeclarativepositionsource_p.h> @@ -621,6 +621,6 @@ public: } }; -#include "positioning.moc" - QT_END_NAMESPACE + +#include "positioning.moc" diff --git a/src/location/declarativemaps/qdeclarativegeocodemodel.cpp b/src/location/declarativemaps/qdeclarativegeocodemodel.cpp index 43ce95a9..a73f9341 100644 --- a/src/location/declarativemaps/qdeclarativegeocodemodel.cpp +++ b/src/location/declarativemaps/qdeclarativegeocodemodel.cpp @@ -42,6 +42,7 @@ #include <QtPositioning/QGeoCircle> #include <QtLocation/QGeoServiceProvider> #include <QtLocation/QGeoCodingManager> +#include <QtLocation/private/qgeocodereply_p.h> #include <QtPositioning/QGeoPolygon> QT_BEGIN_NAMESPACE @@ -389,6 +390,7 @@ void QDeclarativeGeocodeModel::geocodeFinished(QGeoCodeReply *reply) reply->deleteLater(); reply_ = 0; int oldCount = declarativeLocations_.count(); + // const QVariantMap &extraData = QGeoCodeReplyPrivate::get(*reply)->extraData(); setLocations(reply->locations()); setError(NoError, QString()); setStatus(QDeclarativeGeocodeModel::Ready); diff --git a/src/location/declarativemaps/qdeclarativegeocodemodel_p.h b/src/location/declarativemaps/qdeclarativegeocodemodel_p.h index 6c8f533b..e2361045 100644 --- a/src/location/declarativemaps/qdeclarativegeocodemodel_p.h +++ b/src/location/declarativemaps/qdeclarativegeocodemodel_p.h @@ -52,8 +52,8 @@ #include <QtLocation/private/qdeclarativegeoserviceprovider_p.h> #include <QtLocation/qgeocodereply.h> -#include <QtPositioning/private/qdeclarativegeoaddress_p.h> -#include <QtPositioning/private/qdeclarativegeolocation_p.h> +#include <QtPositioningQuick/private/qdeclarativegeoaddress_p.h> +#include <QtPositioningQuick/private/qdeclarativegeolocation_p.h> #include <QtQml/qqml.h> #include <QtQml/QQmlParserStatus> diff --git a/src/location/declarativemaps/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp index 63587efe..3c73ca12 100644 --- a/src/location/declarativemaps/qdeclarativegeomap.cpp +++ b/src/location/declarativemaps/qdeclarativegeomap.cpp @@ -1305,7 +1305,7 @@ void QDeclarativeGeoMap::setVisibleRegion(const QGeoShape &shape) return; } - fitViewportToGeoShape(); + fitViewportToGeoShape(m_visibleRegion); } QGeoShape QDeclarativeGeoMap::visibleRegion() const @@ -1445,39 +1445,6 @@ QMargins QDeclarativeGeoMap::mapMargins() const , height() - va.height() - va.y()); } -// TODO: offer the possibility to specify the margins. -void QDeclarativeGeoMap::fitViewportToGeoShape() -{ - if (m_map->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) { - // This case remains handled here, and not inside QGeoMap*::fitViewportToGeoRectangle, - // in order to honor animations on center and zoomLevel - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); - const int borderSize = 10; - const QMargins borders(borderSize, borderSize, borderSize, borderSize); - - if (!m_map || !m_visibleRegion.isValid()) - return; - - const QMargins margins = borders + mapMargins(); - const QPair<QGeoCoordinate, qreal> fitData = p.fitViewportToGeoRectangle(m_visibleRegion, - margins); - if (!fitData.first.isValid()) - return; - - // position camera to the center of bounding box - setProperty("center", QVariant::fromValue(fitData.first)); // not using setCenter(centerCoordinate) to honor a possible animation set on the center property - - if (!qIsFinite(fitData.second)) - return; - double newZoom = qMax<double>(minimumZoomLevel(), fitData.second); - setProperty("zoomLevel", QVariant::fromValue(newZoom)); // not using setZoomLevel(newZoom) to honor a possible animation set on the zoomLevel property - } else if (m_map->capabilities() & QGeoMap::SupportsFittingViewportToGeoRectangle) { - // Animations cannot be honored in this case, as m_map acts as a black box - m_map->fitViewportToGeoRectangle(m_visibleRegion); - } -} - - /*! \qmlproperty list<MapType> QtLocation::Map::supportedMapTypes @@ -1604,6 +1571,64 @@ void QDeclarativeGeoMap::clearData() } /*! + \qmlmethod void QtLocation::Map::fitViewportToGeoShape(geoShape, margins) + + Fits the viewport to a specific geo shape. + The margins are in screen pixels. + + \note If the projection used by the plugin is not WebMercator, and the plugin does not have fitting to + shape capability, this method will do nothing. + + \sa visibleRegion + \since 5.13 +*/ +void QDeclarativeGeoMap::fitViewportToGeoShape(const QGeoShape &shape, QVariant margins) +{ + QMargins m(10, 10, 10, 10); // lets defaults to 10 if margins is invalid + switch (margins.type()) { + case QMetaType::Int: + case QMetaType::Double: { + const int value = int(margins.toDouble()); + m = QMargins(value, value, value, value); + } + break; + // ToDo: Support distinct margins in some QML form. Perhaps QRect? + default: + break; + } + fitViewportToGeoShape(shape, m); +} + +void QDeclarativeGeoMap::fitViewportToGeoShape(const QGeoShape &shape, const QMargins &borders) +{ + if (!m_map || !shape.isValid()) + return; + + if (m_map->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) { + // This case remains handled here, and not inside QGeoMap*::fitViewportToGeoRectangle, + // in order to honor animations on center and zoomLevel + const QMargins margins = borders + mapMargins(); + const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); + const QPair<QGeoCoordinate, qreal> fitData = p.fitViewportToGeoRectangle(shape.boundingGeoRectangle(), + margins); + if (!fitData.first.isValid()) + return; + + // position camera to the center of bounding box + setProperty("center", QVariant::fromValue(fitData.first)); // not using setCenter(centerCoordinate) to honor a possible animation set on the center property + + if (!qIsFinite(fitData.second)) + return; + double newZoom = qMax<double>(minimumZoomLevel(), fitData.second); + setProperty("zoomLevel", QVariant::fromValue(newZoom)); // not using setZoomLevel(newZoom) to honor a possible animation set on the zoomLevel property + } else if (m_map->capabilities() & QGeoMap::SupportsFittingViewportToGeoRectangle) { + // Animations cannot be honored in this case, as m_map acts as a black box + m_map->fitViewportToGeoRectangle(m_visibleRegion, borders); + } + // else out of luck +} + +/*! \qmlproperty string QtLocation::Map::errorString This read-only property holds the textual presentation of the latest mapping provider error. @@ -2205,7 +2230,7 @@ void QDeclarativeGeoMap::geometryChanged(const QRectF &newGeometry, const QRectF Multiple fitViewportTo*() calls replace each other. */ if (m_pendingFitViewport && width() && height()) { - fitViewportToGeoShape(); + fitViewportToGeoShape(m_visibleRegion); m_pendingFitViewport = false; } diff --git a/src/location/declarativemaps/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h index f59f6f54..3cbefe79 100644 --- a/src/location/declarativemaps/qdeclarativegeomap_p.h +++ b/src/location/declarativemaps/qdeclarativegeomap_p.h @@ -198,6 +198,8 @@ public: Q_INVOKABLE void pan(int dx, int dy); Q_INVOKABLE void prefetchData(); // optional hint for prefetch Q_INVOKABLE void clearData(); + Q_INVOKABLE void fitViewportToGeoShape(const QGeoShape &shape, QVariant margins); + void fitViewportToGeoShape(const QGeoShape &shape, const QMargins &borders = QMargins(10, 10, 10, 10)); QString errorString() const; QGeoServiceProvider::Error error() const; @@ -278,7 +280,6 @@ private: void populateMap(); void populateParameters(); void fitViewportToMapItemsRefine(bool refine, bool onlyVisible); - void fitViewportToGeoShape(); bool isInteractive(); void attachCopyrightNotice(bool initialVisibility); void detachCopyrightNotice(bool currentVisibility); diff --git a/src/location/declarativemaps/qdeclarativegeoroute.cpp b/src/location/declarativemaps/qdeclarativegeoroute.cpp index 09ed46ab..64aeb656 100644 --- a/src/location/declarativemaps/qdeclarativegeoroute.cpp +++ b/src/location/declarativemaps/qdeclarativegeoroute.cpp @@ -352,6 +352,35 @@ QList<QObject *> QDeclarativeGeoRoute::legs() } /*! + \qmlproperty Object Route::extendedAttributes + + This property holds the extended attributes of the route and is a map. + These attributes are plugin specific, and can be empty. + + Consult the \l {Qt Location#Plugin References and Parameters}{plugin documentation} + for what attributes are supported and how they should be used. + + Note, due to limitations of the QQmlPropertyMap, it is not possible + to declaratively specify the attributes in QML, assignment of attributes keys + and values can only be accomplished by JavaScript. + + \since QtLocation 5.13 +*/ +QQmlPropertyMap *QDeclarativeGeoRoute::extendedAttributes() const +{ + if (!m_extendedAttributes) { + QDeclarativeGeoRoute *self = const_cast<QDeclarativeGeoRoute *>(this); + self->m_extendedAttributes = new QQmlPropertyMap(self); + // Fill it + const QVariantMap &xAttrs = route_.extendedAttributes(); + const QStringList &keys = xAttrs.keys(); + for (const QString &key: keys) + self->m_extendedAttributes->insert(key, xAttrs.value(key)); + } + return m_extendedAttributes; +} + +/*! \qmlmethod bool QtLocation::Route::equals(Route other) This method performs deep comparison. diff --git a/src/location/declarativemaps/qdeclarativegeoroute_p.h b/src/location/declarativemaps/qdeclarativegeoroute_p.h index 98d08e98..767e21ea 100644 --- a/src/location/declarativemaps/qdeclarativegeoroute_p.h +++ b/src/location/declarativemaps/qdeclarativegeoroute_p.h @@ -69,6 +69,7 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRoute : public QObject Q_PROPERTY(QQmlListProperty<QDeclarativeGeoRouteSegment> segments READ segments CONSTANT) Q_PROPERTY(QDeclarativeGeoRouteQuery *routeQuery READ routeQuery REVISION 11) Q_PROPERTY(QList<QObject *> legs READ legs CONSTANT REVISION 12) + Q_PROPERTY(QObject *extendedAttributes READ extendedAttributes CONSTANT REVISION 12) public: explicit QDeclarativeGeoRoute(QObject *parent = 0); @@ -91,6 +92,7 @@ public: const QGeoRoute &route() const; QDeclarativeGeoRouteQuery *routeQuery(); QList<QObject *> legs(); + QQmlPropertyMap *extendedAttributes() const; Q_INVOKABLE bool equals(QDeclarativeGeoRoute *other) const; @@ -111,6 +113,8 @@ private: QList<QDeclarativeGeoRouteSegment *> segments_; QList<QObject *> legs_; bool segmentsDirty_ = true; + QQmlPropertyMap *m_extendedAttributes = nullptr; + friend class QDeclarativeRouteMapItem; }; diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp index f4cdc6bf..23ea5666 100644 --- a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp +++ b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp @@ -50,6 +50,7 @@ #include <QtPositioning/private/qdoublevector2d_p.h> #include <QtPositioning/private/qclipperutils_p.h> +#include <QtPositioning/private/qgeopolygon_p.h> /* poly2tri triangulator includes */ #include <clip2tri.h> @@ -318,6 +319,7 @@ QDeclarativePolygonMapItem::QDeclarativePolygonMapItem(QQuickItem *parent) : QDeclarativeGeoMapItemBase(parent), border_(this), color_(Qt::transparent), dirtyMaterial_(true), updatingGeometry_(false) { + geopath_ = QGeoPolygonEager(); setFlag(ItemHasContents, true); QObject::connect(&border_, SIGNAL(colorChanged(QColor)), this, SLOT(markSourceDirtyAndUpdate())); @@ -611,7 +613,7 @@ void QDeclarativePolygonMapItem::setGeoShape(const QGeoShape &shape) if (shape == geopath_) return; - geopath_ = shape; + geopath_ = QGeoPathEager(shape); regenerateCache(); geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft()); borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft()); diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp index 2fb3098d..2bed0896 100644 --- a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp +++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp @@ -54,6 +54,7 @@ #include <QtGui/private/qtriangulator_p.h> #include <QtPositioning/private/qclipperutils_p.h> +#include <QtPositioning/private/qgeopath_p.h> #include <array> QT_BEGIN_NAMESPACE @@ -738,6 +739,7 @@ bool QGeoMapPolylineGeometry::contains(const QPointF &point) const QDeclarativePolylineMapItem::QDeclarativePolylineMapItem(QQuickItem *parent) : QDeclarativeGeoMapItemBase(parent), line_(this), dirtyMaterial_(true), updatingGeometry_(false) { + geopath_ = QGeoPathEager(); setFlag(ItemHasContents, true); QObject::connect(&line_, SIGNAL(colorChanged(QColor)), this, SLOT(updateAfterLinePropertiesChanged())); @@ -806,7 +808,7 @@ void QDeclarativePolylineMapItem::setPath(const QGeoPath &path) if (geopath_.path() == path.path()) return; - geopath_ = path; + geopath_ = QGeoPathEager(path); regenerateCache(); geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft()); markSourceDirtyAndUpdate(); @@ -1135,18 +1137,8 @@ const QGeoShape &QDeclarativePolylineMapItem::geoShape() const void QDeclarativePolylineMapItem::setGeoShape(const QGeoShape &shape) { - if (shape == geopath_) - return; - const QGeoPath geopath(shape); // if shape isn't a path, path will be created as a default-constructed path - const bool pathHasChanged = geopath.path() != geopath_.path(); - geopath_ = geopath; - - regenerateCache(); - geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft()); - markSourceDirtyAndUpdate(); - if (pathHasChanged) - emit pathChanged(); + setPath(geopath); } QGeoMap::ItemType QDeclarativePolylineMapItem::itemType() const diff --git a/src/location/declarativeplaces/qdeclarativeplace_p.h b/src/location/declarativeplaces/qdeclarativeplace_p.h index 67d2c8df..309bd64c 100644 --- a/src/location/declarativeplaces/qdeclarativeplace_p.h +++ b/src/location/declarativeplaces/qdeclarativeplace_p.h @@ -55,7 +55,7 @@ #include <QtQml/QQmlPropertyMap> #include <QtLocation/QPlace> -#include <QtPositioning/private/qdeclarativegeolocation_p.h> +#include <QtPositioningQuick/private/qdeclarativegeolocation_p.h> #include <QtLocation/private/qdeclarativecategory_p.h> #include <QtLocation/private/qdeclarativecontactdetail_p.h> #include <QtLocation/private/qdeclarativesupplier_p.h> diff --git a/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp b/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp index b9f782cf..8bbe7f64 100644 --- a/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp +++ b/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp @@ -46,6 +46,8 @@ #include <QtLocation/QPlaceSearchReply> #include <QtPositioning/QGeoCircle> #include <QtPositioning/QGeoPolygon> +#include <QtLocation/private/qdeclarativegeoroute_p.h> +#include <QtLocation/private/qplacesearchrequest_p.h> QT_BEGIN_NAMESPACE @@ -102,18 +104,36 @@ QVariant QDeclarativeSearchModelBase::searchArea() const void QDeclarativeSearchModelBase::setSearchArea(const QVariant &searchArea) { QGeoShape s; - + QDeclarativeGeoRoute *route = nullptr; + bool routeSearchArea = false; if (searchArea.userType() == qMetaTypeId<QGeoRectangle>()) s = searchArea.value<QGeoRectangle>(); else if (searchArea.userType() == qMetaTypeId<QGeoCircle>()) s = searchArea.value<QGeoCircle>(); else if (searchArea.userType() == qMetaTypeId<QGeoShape>()) s = searchArea.value<QGeoShape>(); + else if (searchArea.type() == qMetaTypeId<QObject *>()) { + route = searchArea.value<QDeclarativeGeoRoute *>(); + if (!route) + return; + routeSearchArea = true; + } - if (m_request.searchArea() == s) + QPlaceSearchRequestPrivate *rp = QPlaceSearchRequestPrivate::get(m_request); + // Invalidating the other thing + if (routeSearchArea) + m_request.setSearchArea(QGeoShape()); + else + rp->routeSearchArea = QGeoRoute(); + + if (m_request.searchArea() == s + && (!route || rp->routeSearchArea == route->route())) return; - m_request.setSearchArea(s); + if (routeSearchArea) + rp->routeSearchArea = route->route(); + else + m_request.setSearchArea(s); emit searchAreaChanged(); } diff --git a/src/location/doc/src/plugins/osm.qdoc b/src/location/doc/src/plugins/osm.qdoc index 649d3bed..1fbb7d3e 100644 --- a/src/location/doc/src/plugins/osm.qdoc +++ b/src/location/doc/src/plugins/osm.qdoc @@ -69,6 +69,11 @@ a prefix. \li Url string set when making network requests to the geocoding server. This parameter should be set to a valid server url with the correct osm API. If not specified the default \l {http://nominatim.openstreetmap.org/}{url} will be used. \note The API documentation is available at \l {https://wiki.openstreetmap.org/wiki/Nominatim}{Project OSM Nominatim}. + \li osm.geocoding.debug_query + \li Instructs the plugin to inject the query url to nominatim into the geocode reply, for debugging purposes. + \li osm.geocoding.include_extended_data + \li Instructs the plugin to include Nominatim-specific information (such as geometry and class) into the returned Location + objects, exposed as extendedAttributes. \row \li osm.mapping.cache.directory \li Absolute path to map tile cache directory used as network disk cache. diff --git a/src/location/labs/qdeclarativenavigator.cpp b/src/location/labs/qdeclarativenavigator.cpp index 0bf5035f..86c2b85a 100644 --- a/src/location/labs/qdeclarativenavigator.cpp +++ b/src/location/labs/qdeclarativenavigator.cpp @@ -141,7 +141,7 @@ QT_BEGIN_NAMESPACE /*! \qmlproperty Route Qt.labs.location::Navigator::currentRoute - This read-only property holds the current route the navigator following. + This read-only property holds the current route the navigator is following. This can be the same as \l route, or can be different, if the navigator cannot follow the user-specified route. For example if the position coming from \l positionSource is considerably @@ -152,6 +152,18 @@ QT_BEGIN_NAMESPACE */ /*! + \qmlproperty RouteLeg Qt.labs.location::Navigator::currentRouteLeg + + This read-only property holds the current route leg the navigator is following. + This is always a part of \l currentRoute, and so the property \l RouteLeg::overallRoute + of currentRouteLeg will hold the same route as \l currentRoute. + + \sa RouteLeg + + \since 5.13 +*/ + +/*! \qmlproperty int Qt.labs.location::Navigator::currentSegment This read-only property holds the index of the current RouteSegment in the \l currentRoute. @@ -179,9 +191,29 @@ QDeclarativeNavigatorPrivate::QDeclarativeNavigatorPrivate(QParameterizableObjec { } -void QDeclarativeNavigatorPrivate::updateReadyState() +void QDeclarativeNavigatorPrivate::clearCachedData() { - qobject_cast<QDeclarativeNavigator *>(q)->updateReadyState(); + const bool routeChanged = !m_currentRoute.isNull(); + const bool routeLegChanged = !m_currentRouteLeg.isNull(); + const bool segmentChanged = m_currentSegment != 0; + + if (m_currentRoute) + m_currentRoute->deleteLater(); + m_currentRoute = nullptr; + + if (m_currentRouteLeg) + m_currentRouteLeg->deleteLater(); + m_currentRouteLeg = nullptr; + + m_currentSegment = 0; + + QDeclarativeNavigator *qq = qobject_cast<QDeclarativeNavigator *>(q); + if (routeChanged) + qq->currentRouteChanged(); + if (routeLegChanged) + qq->currentRouteLegChanged(); + if (segmentChanged) + qq->currentSegmentChanged(); } @@ -220,11 +252,10 @@ void QDeclarativeNavigator::setMap(QDeclarativeGeoMap *map) return; d_ptr->m_params->m_map = map; - QDeclarativeNavigatorPrivate *dptr = d_ptr.data(); connect(map, &QObject::destroyed, this, - [this, dptr]() { + [this]() { this->mapChanged(); - dptr->updateReadyState(); + this->updateReadyState(); }); emit mapChanged(); updateReadyState(); @@ -270,11 +301,10 @@ void QDeclarativeNavigator::setPositionSource(QDeclarativePositionSource *positi return; d_ptr->m_params->m_positionSource = positionSource; - QDeclarativeNavigatorPrivate *dptr = d_ptr.data(); QObject::connect(positionSource, &QObject::destroyed, - [this, dptr]() { + [this]() { this->positionSourceChanged(); - dptr->updateReadyState(); + this->updateReadyState(); } ); emit positionSourceChanged(); @@ -316,6 +346,13 @@ QDeclarativeGeoRoute *QDeclarativeNavigator::currentRoute() const return d_ptr->m_currentRoute.data(); } +QDeclarativeGeoRouteLeg *QDeclarativeNavigator::currentRouteLeg() const +{ + if (!d_ptr->m_ready || !d_ptr->m_navigator->active()) + return nullptr; + return d_ptr->m_currentRouteLeg.data(); +} + int QDeclarativeNavigator::currentSegment() const { if (!d_ptr->m_ready || !d_ptr->m_navigator->active()) @@ -379,6 +416,9 @@ void QDeclarativeNavigator::stop() if (d_ptr->m_navigator->active()) d_ptr->m_active = d_ptr->m_navigator->stop(); + + // clear cached data + d_ptr->clearCachedData(); } void QDeclarativeNavigator::pluginReady() @@ -409,6 +449,7 @@ bool QDeclarativeNavigator::ensureEngine() connect(d_ptr->m_navigator.get(), &QAbstractNavigator::waypointReached, this, &QDeclarativeNavigator::waypointReached); connect(d_ptr->m_navigator.get(), &QAbstractNavigator::destinationReached, this, &QDeclarativeNavigator::destinationReached); connect(d_ptr->m_navigator.get(), &QAbstractNavigator::currentRouteChanged, this, &QDeclarativeNavigator::onCurrentRouteChanged); + connect(d_ptr->m_navigator.get(), &QAbstractNavigator::currentRouteLegChanged, this, &QDeclarativeNavigator::onCurrentRouteLegChanged); connect(d_ptr->m_navigator.get(), &QAbstractNavigator::currentSegmentChanged, this, &QDeclarativeNavigator::onCurrentSegmentChanged); connect(d_ptr->m_navigator.get(), &QAbstractNavigator::activeChanged, this, [this](bool active){ d_ptr->m_active = active; @@ -440,6 +481,14 @@ void QDeclarativeNavigator::onCurrentRouteChanged(const QGeoRoute &route) emit currentRouteChanged(); } +void QDeclarativeNavigator::onCurrentRouteLegChanged(const QGeoRouteLeg &routeLeg) +{ + if (d_ptr->m_currentRoute) + d_ptr->m_currentRouteLeg->deleteLater(); + d_ptr->m_currentRouteLeg = new QDeclarativeGeoRouteLeg(routeLeg, this); + emit currentRouteLegChanged(); +} + void QDeclarativeNavigator::onCurrentSegmentChanged(int segment) { d_ptr->m_currentSegment = segment; diff --git a/src/location/labs/qdeclarativenavigator_p.h b/src/location/labs/qdeclarativenavigator_p.h index 13884c41..2a425e70 100644 --- a/src/location/labs/qdeclarativenavigator_p.h +++ b/src/location/labs/qdeclarativenavigator_p.h @@ -59,9 +59,11 @@ class QDeclarativeGeoServiceProvider; class QDeclarativeGeoMap; class QNavigationManager; class QDeclarativeGeoRoute; +class QDeclarativeGeoRouteLeg; class QDeclarativePositionSource; class QDeclarativeGeoWaypoint; class QGeoRoute; +class QGeoRouteLeg; class QGeoRouteSegment; class QDeclarativeNavigatorPrivate; class QDeclarativeGeoRouteSegment; @@ -77,6 +79,7 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeNavigator : public QParameterizableO Q_PROPERTY(bool navigatorReady READ navigatorReady NOTIFY navigatorReadyChanged) Q_PROPERTY(bool trackPositionSource READ trackPositionSource WRITE setTrackPositionSource NOTIFY trackPositionSourceChanged) Q_PROPERTY(QDeclarativeGeoRoute *currentRoute READ currentRoute NOTIFY currentRouteChanged) + Q_PROPERTY(QDeclarativeGeoRouteLeg *currentRouteLeg READ currentRouteLeg NOTIFY currentRouteChanged) Q_PROPERTY(int currentSegment READ currentSegment NOTIFY currentSegmentChanged) Q_INTERFACES(QQmlParserStatus) @@ -113,6 +116,7 @@ public: bool trackPositionSource() const; QDeclarativeGeoRoute *currentRoute() const; + QDeclarativeGeoRouteLeg *currentRouteLeg() const; int currentSegment() const; signals: @@ -127,6 +131,7 @@ signals: void routeChanged(); void positionSourceChanged(); void currentRouteChanged(); + void currentRouteLegChanged(); void currentSegmentChanged(); private: @@ -136,6 +141,7 @@ private: private slots: void onCurrentRouteChanged(const QGeoRoute &route); + void onCurrentRouteLegChanged(const QGeoRouteLeg &routeLeg); void onCurrentSegmentChanged(int segment); private: diff --git a/src/location/labs/qdeclarativenavigator_p_p.h b/src/location/labs/qdeclarativenavigator_p_p.h index 229ead1e..8849ec7a 100644 --- a/src/location/labs/qdeclarativenavigator_p_p.h +++ b/src/location/labs/qdeclarativenavigator_p_p.h @@ -59,6 +59,7 @@ class QDeclarativeGeoServiceProvider; class QDeclarativeGeoMap; class QNavigationManager; class QDeclarativeGeoRoute; +class QDeclarativeGeoRouteLeg; class QDeclarativePositionSource; class QGeoMapParameter; class QDeclarativeGeoRouteSegment; @@ -81,12 +82,14 @@ class QDeclarativeNavigatorPrivate public: QDeclarativeNavigatorPrivate(QParameterizableObject *q_); - void updateReadyState(); + void clearCachedData(); + QParameterizableObject *q = nullptr; QSharedPointer<QDeclarativeNavigatorParams> m_params; QScopedPointer<QAbstractNavigator> m_navigator; QDeclarativeGeoServiceProvider *m_plugin = nullptr; QPointer<QDeclarativeGeoRoute> m_currentRoute; + QPointer<QDeclarativeGeoRouteLeg> m_currentRouteLeg; int m_currentSegment = 0; bool m_active = false; bool m_completed = false; diff --git a/src/location/labs/qmapobjectview.cpp b/src/location/labs/qmapobjectview.cpp index 2ffc27bc..7a7d7d3d 100644 --- a/src/location/labs/qmapobjectview.cpp +++ b/src/location/labs/qmapobjectview.cpp @@ -89,7 +89,8 @@ QGeoMapObject::Type QMapObjectViewPrivate::type() const */ -QMapObjectViewPrivateDefault::QMapObjectViewPrivateDefault(const QMapObjectViewPrivate &other) : QMapObjectViewPrivate(other.q) +QMapObjectViewPrivateDefault::QMapObjectViewPrivateDefault(const QMapObjectViewPrivate &other) +: QMapObjectViewPrivate(other.q), m_model(other.model()), m_delegate(other.delegate()) { } @@ -98,6 +99,26 @@ QMapObjectViewPrivateDefault::~QMapObjectViewPrivateDefault() } +QVariant QMapObjectViewPrivateDefault::model() const +{ + return m_model; +} + +void QMapObjectViewPrivateDefault::setModel(const QVariant &model) +{ + m_model = model; +} + +QQmlComponent *QMapObjectViewPrivateDefault::delegate() const +{ + return m_delegate; +} + +void QMapObjectViewPrivateDefault::setDelegate(QQmlComponent *delegate) +{ + m_delegate = delegate; +} + QMapObjectViewPrivateDefault::QMapObjectViewPrivateDefault(QGeoMapObject *q) : QMapObjectViewPrivate(q) { @@ -108,6 +129,17 @@ QGeoMapObjectPrivate *QMapObjectViewPrivateDefault::clone() return new QMapObjectViewPrivateDefault(*this); } +bool QMapObjectViewPrivateDefault::equals(const QGeoMapObjectPrivate &other) const +{ + if (other.type() != type()) + return false; + + const QMapObjectViewPrivate &o = static_cast<const QMapObjectViewPrivate &>(other); + return (QGeoMapObjectPrivate::equals(o) + && model() == o.model() + && delegate() == o.delegate()); +} + /* QMapObjectView @@ -160,10 +192,11 @@ void QMapObjectView::classBegin() void QMapObjectView::componentComplete() { QGeoMapObject::componentComplete(); - if (m_delegate) - m_delegateModel->setDelegate(m_delegate); - if (m_model.isValid()) - m_delegateModel->setModel(m_model); + QMapObjectViewPrivate *d = static_cast<QMapObjectViewPrivate *>(d_ptr.data()); + if (d->delegate()) + m_delegateModel->setDelegate(d->delegate()); + if (d->model().isValid()) + m_delegateModel->setModel(d->model()); m_delegateModel->componentComplete(); } @@ -175,7 +208,8 @@ void QMapObjectView::componentComplete() */ QVariant QMapObjectView::model() const { - return m_model; + const QMapObjectViewPrivate *d = static_cast<const QMapObjectViewPrivate *>(d_ptr.data()); + return d->model(); } /*! @@ -187,14 +221,16 @@ QVariant QMapObjectView::model() const */ QQmlComponent *QMapObjectView::delegate() const { - return m_delegate; + const QMapObjectViewPrivate *d = static_cast<const QMapObjectViewPrivate *>(d_ptr.data()); + return d->delegate(); } void QMapObjectView::setModel(QVariant model) { - if (m_model == model) + QMapObjectViewPrivate *d = static_cast<QMapObjectViewPrivate *>(d_ptr.data()); + if (d->model() == model) return; - m_model = model; + d->setModel(model); if (d_ptr->m_componentCompleted) m_delegateModel->setModel(model); @@ -204,9 +240,10 @@ void QMapObjectView::setModel(QVariant model) void QMapObjectView::setDelegate(QQmlComponent *delegate) { - if (m_delegate == delegate) + QMapObjectViewPrivate *d = static_cast<QMapObjectViewPrivate *>(d_ptr.data()); + if (d->delegate() == delegate) return; - m_delegate = delegate; + d->setDelegate(delegate); if (d_ptr->m_componentCompleted) m_delegateModel->setDelegate(delegate); diff --git a/src/location/labs/qmapobjectview_p.h b/src/location/labs/qmapobjectview_p.h index 49b80883..5e85aa7a 100644 --- a/src/location/labs/qmapobjectview_p.h +++ b/src/location/labs/qmapobjectview_p.h @@ -103,8 +103,6 @@ protected: void flushDelegateModel(); void flushUserAddedMapObjects(); - QVariant m_model; - QQmlComponent *m_delegate = nullptr; QQmlDelegateModel *m_delegateModel = nullptr; QVector<QPointer<QGeoMapObject>> m_instantiatedMapObjects; QVector<QPointer<QGeoMapObject>> m_pendingMapObjects; diff --git a/src/location/labs/qmapobjectview_p_p.h b/src/location/labs/qmapobjectview_p_p.h index 7550e209..e283f1b0 100644 --- a/src/location/labs/qmapobjectview_p_p.h +++ b/src/location/labs/qmapobjectview_p_p.h @@ -65,6 +65,11 @@ public: QMapObjectViewPrivate(QGeoMapObject *q); ~QMapObjectViewPrivate() override; + virtual QVariant model() const = 0; + virtual void setModel(const QVariant &model) = 0; + virtual QQmlComponent *delegate() const = 0; + virtual void setDelegate(QQmlComponent *delegate) = 0; + virtual QGeoMapObject::Type type() const override final; }; @@ -75,10 +80,18 @@ public: QMapObjectViewPrivateDefault(const QMapObjectViewPrivate &other); ~QMapObjectViewPrivateDefault() override; + virtual QVariant model() const override; + virtual void setModel(const QVariant &model) override; + virtual QQmlComponent *delegate() const override; + virtual void setDelegate(QQmlComponent *delegate) override; // QGeoMapObjectPrivate interface public: QGeoMapObjectPrivate *clone() override; + bool equals(const QGeoMapObjectPrivate &other) const override; + + QVariant m_model; + QQmlComponent *m_delegate = nullptr; }; QT_END_NAMESPACE diff --git a/src/location/location.pro b/src/location/location.pro index 1535a85e..1b541b9e 100644 --- a/src/location/location.pro +++ b/src/location/location.pro @@ -1,5 +1,5 @@ TARGET = QtLocation -QT = core-private positioning-private +QT = core-private positioning-private positioningquick-private android { # adding qtconcurrent dependency here for the osm plugin QT += concurrent diff --git a/src/location/maps/qgeocodereply.cpp b/src/location/maps/qgeocodereply.cpp index 5fefb6fe..9fbede9c 100644 --- a/src/location/maps/qgeocodereply.cpp +++ b/src/location/maps/qgeocodereply.cpp @@ -97,6 +97,13 @@ QGeoCodeReply::QGeoCodeReply(QObject *parent) : QObject(parent), d_ptr(new QGeoCodeReplyPrivate()) {} +QGeoCodeReply::QGeoCodeReply(QGeoCodeReplyPrivate &dd, QObject *parent) + : QObject(parent), + d_ptr(&dd) +{ + +} + /*! Constructs a geocode reply with a given \a error and \a errorString and the specified \a parent. */ @@ -335,4 +342,19 @@ QGeoCodeReplyPrivate::QGeoCodeReplyPrivate(QGeoCodeReply::Error error, const QSt QGeoCodeReplyPrivate::~QGeoCodeReplyPrivate() {} +QVariantMap QGeoCodeReplyPrivate::extraData() const +{ + return QVariantMap(); +} + +const QGeoCodeReplyPrivate *QGeoCodeReplyPrivate::get(const QGeoCodeReply &reply) +{ + return reply.d_ptr; +} + +QGeoCodeReplyPrivate *QGeoCodeReplyPrivate::get(QGeoCodeReply &reply) +{ + return reply.d_ptr; +} + QT_END_NAMESPACE diff --git a/src/location/maps/qgeocodereply.h b/src/location/maps/qgeocodereply.h index c41e740d..c2395f10 100644 --- a/src/location/maps/qgeocodereply.h +++ b/src/location/maps/qgeocodereply.h @@ -85,6 +85,7 @@ Q_SIGNALS: protected: explicit QGeoCodeReply(QObject *parent = nullptr); + explicit QGeoCodeReply(QGeoCodeReplyPrivate &dd, QObject *parent = nullptr); void setError(Error error, const QString &errorString); void setFinished(bool finished); @@ -99,6 +100,7 @@ protected: private: QGeoCodeReplyPrivate *d_ptr; Q_DISABLE_COPY(QGeoCodeReply) + friend class QGeoCodeReplyPrivate; }; QT_END_NAMESPACE diff --git a/src/location/maps/qgeocodereply_p.h b/src/location/maps/qgeocodereply_p.h index fefe7883..3f77497b 100644 --- a/src/location/maps/qgeocodereply_p.h +++ b/src/location/maps/qgeocodereply_p.h @@ -48,22 +48,28 @@ // We mean it. // +#include <QtLocation/private/qlocationglobal_p.h> #include "qgeocodereply.h" #include "qgeoshape.h" #include <QList> +#include <QVariantMap> QT_BEGIN_NAMESPACE class QGeoLocation; -class QGeoCodeReplyPrivate +class Q_LOCATION_PRIVATE_EXPORT QGeoCodeReplyPrivate { public: QGeoCodeReplyPrivate(); QGeoCodeReplyPrivate(QGeoCodeReply::Error error, const QString &errorString); - ~QGeoCodeReplyPrivate(); + virtual ~QGeoCodeReplyPrivate(); + + virtual QVariantMap extraData() const; + static const QGeoCodeReplyPrivate *get(const QGeoCodeReply &reply); + static QGeoCodeReplyPrivate *get(QGeoCodeReply &reply); QGeoCodeReply::Error error; QString errorString; diff --git a/src/location/maps/qgeomap.cpp b/src/location/maps/qgeomap.cpp index 963ef6bd..bf5e557d 100644 --- a/src/location/maps/qgeomap.cpp +++ b/src/location/maps/qgeomap.cpp @@ -135,9 +135,10 @@ bool QGeoMap::anchorCoordinateToPoint(const QGeoCoordinate &coordinate, const QP return false; } -bool QGeoMap::fitViewportToGeoRectangle(const QGeoRectangle &rectangle) +bool QGeoMap::fitViewportToGeoRectangle(const QGeoRectangle &rectangle, const QMargins &borders) { Q_UNUSED(rectangle) + Q_UNUSED(borders) return false; } diff --git a/src/location/maps/qgeomap_p.h b/src/location/maps/qgeomap_p.h index 874b300f..c0af9e10 100644 --- a/src/location/maps/qgeomap_p.h +++ b/src/location/maps/qgeomap_p.h @@ -150,7 +150,7 @@ public: virtual bool setBearing(qreal bearing, const QGeoCoordinate &coordinate); virtual QGeoShape visibleRegion() const; virtual bool anchorCoordinateToPoint(const QGeoCoordinate &coordinate, const QPointF &anchorPoint); - virtual bool fitViewportToGeoRectangle(const QGeoRectangle &rectangle); + virtual bool fitViewportToGeoRectangle(const QGeoRectangle &rectangle, const QMargins &borders); virtual void setCopyrightVisible(bool visible); virtual void removeMapObject(QGeoMapObject *obj); diff --git a/src/location/maps/qgeoroute.cpp b/src/location/maps/qgeoroute.cpp index 799fe7f1..ef54e4aa 100644 --- a/src/location/maps/qgeoroute.cpp +++ b/src/location/maps/qgeoroute.cpp @@ -321,6 +321,26 @@ QList<QGeoRouteLeg> QGeoRoute::routeLegs() const return d_ptr->routeLegs(); } +/*! + Sets the extended attributes \a extendedAttributes associated with this route. + + \since 5.13 +*/ +void QGeoRoute::setExtendedAttributes(const QVariantMap &extendedAttributes) +{ + d_ptr->setExtendedAttributes(extendedAttributes); +} + +/*! + Returns the extended attributes associated with this route. + + \since 5.13 +*/ +QVariantMap QGeoRoute::extendedAttributes() const +{ + return d_ptr->extendedAttributes(); +} + /******************************************************************************* *******************************************************************************/ @@ -361,7 +381,7 @@ bool QGeoRoutePrivate::equals(const QGeoRoutePrivate &other) const s2 = s2.nextRouteSegment(); } - return ((id() == other.id()) + return ( (id() == other.id()) && (request() == other.request()) && (bounds() == other.bounds()) && (travelTime() == other.travelTime()) @@ -369,7 +389,8 @@ bool QGeoRoutePrivate::equals(const QGeoRoutePrivate &other) const && (travelMode() == other.travelMode()) && (path() == other.path()) && (metadata() == other.metadata()) - && (routeLegs() == other.routeLegs())); + && (routeLegs() == other.routeLegs()) + && (extendedAttributes() == other.extendedAttributes()) ); } void QGeoRoutePrivate::setId(const QString &id) @@ -472,6 +493,16 @@ QList<QGeoRouteLeg> QGeoRoutePrivate::routeLegs() const return QList<QGeoRouteLeg>(); } +void QGeoRoutePrivate::setExtendedAttributes(const QVariantMap &/*extendedAttributes*/) +{ + +} + +QVariantMap QGeoRoutePrivate::extendedAttributes() const +{ + return QVariantMap(); +} + void QGeoRoutePrivate::setLegIndex(int /*idx*/) { @@ -514,7 +545,8 @@ QGeoRoutePrivateDefault::QGeoRoutePrivateDefault(const QGeoRoutePrivateDefault & m_path(other.m_path), m_legs(other.m_legs), m_firstSegment(other.m_firstSegment), - m_numSegments(other.m_numSegments){} + m_numSegments(other.m_numSegments), + m_extendedAttributes(other.m_extendedAttributes) {} // Purposedly ignoring legIndex and parentRoute QGeoRoutePrivateDefault::~QGeoRoutePrivateDefault() {} @@ -636,6 +668,16 @@ QList<QGeoRouteLeg> QGeoRoutePrivateDefault::routeLegs() const return m_legs; } +void QGeoRoutePrivateDefault::setExtendedAttributes(const QVariantMap &extendedAttributes) +{ + m_extendedAttributes = extendedAttributes; +} + +QVariantMap QGeoRoutePrivateDefault::extendedAttributes() const +{ + return m_extendedAttributes; +} + void QGeoRoutePrivateDefault::setLegIndex(int idx) { if (idx >= 0) diff --git a/src/location/maps/qgeoroute.h b/src/location/maps/qgeoroute.h index 381152e3..363ca61b 100644 --- a/src/location/maps/qgeoroute.h +++ b/src/location/maps/qgeoroute.h @@ -90,6 +90,9 @@ public: void setRouteLegs(const QList<QGeoRouteLeg> &legs); QList<QGeoRouteLeg> routeLegs() const; + void setExtendedAttributes(const QVariantMap &extendedAttributes); + QVariantMap extendedAttributes() const; + protected: QGeoRoute(const QExplicitlySharedDataPointer<QGeoRoutePrivate> &dd); QExplicitlySharedDataPointer<QGeoRoutePrivate> &d(); diff --git a/src/location/maps/qgeoroute_p.h b/src/location/maps/qgeoroute_p.h index 39f96c48..721d00b9 100644 --- a/src/location/maps/qgeoroute_p.h +++ b/src/location/maps/qgeoroute_p.h @@ -55,6 +55,7 @@ #include "qgeoroutesegment.h" #include <QSharedData> +#include <QVariantMap> #include <QScopedPointer> QT_BEGIN_NAMESPACE @@ -100,6 +101,9 @@ public: virtual void setRouteLegs(const QList<QGeoRouteLeg> &legs); virtual QList<QGeoRouteLeg> routeLegs() const; + virtual void setExtendedAttributes(const QVariantMap &extendedAttributes); + virtual QVariantMap extendedAttributes() const; + virtual QString engineName() const = 0; virtual int segmentsCount() const = 0; @@ -153,6 +157,9 @@ public: virtual void setRouteLegs(const QList<QGeoRouteLeg> &legs) override; virtual QList<QGeoRouteLeg> routeLegs() const override; + void setExtendedAttributes(const QVariantMap &extendedAttributes) override; + QVariantMap extendedAttributes() const override; + // QGeoRouteLeg API virtual void setLegIndex(int idx) override; virtual int legIndex() const override; @@ -175,6 +182,7 @@ public: QGeoRouteSegment m_firstSegment; mutable int m_numSegments; QScopedPointer<QGeoRoute> m_containingRoute; + QVariantMap m_extendedAttributes; int m_legIndex = 0; }; diff --git a/src/location/maps/qgeotilerequestmanager.cpp b/src/location/maps/qgeotilerequestmanager.cpp index d4d94ad0..aa6de94d 100644 --- a/src/location/maps/qgeotilerequestmanager.cpp +++ b/src/location/maps/qgeotilerequestmanager.cpp @@ -240,6 +240,6 @@ void QGeoTileRequestManagerPrivate::tileError(const QGeoTileSpec &tile, const QS } } -#include "qgeotilerequestmanager.moc" - QT_END_NAMESPACE + +#include "qgeotilerequestmanager.moc" diff --git a/src/location/maps/qnavigationmanagerengine_p.h b/src/location/maps/qnavigationmanagerengine_p.h index 0852b3ea..e7b3876c 100644 --- a/src/location/maps/qnavigationmanagerengine_p.h +++ b/src/location/maps/qnavigationmanagerengine_p.h @@ -60,11 +60,18 @@ class QGeoMap; class QGeoMapParameter; class QMapRouteObject; class QGeoRoute; +class QGeoRouteLeg; class QNavigationManager; class QNavigationManagerEnginePrivate; class QDeclarativeNavigatorParams; class QDeclarativeGeoWaypoint; +/* + This class is not supposed to react on QDeclarativeNavigator properties changes. + This class is meant to react only on start, stop and setTrackPosition. + Upon start(), it is supposed to fetch all info from the QDeclarativeNavigatorParams that the engine is supposed + to inject. +*/ class Q_LOCATION_PRIVATE_EXPORT QAbstractNavigator: public QObject { Q_OBJECT @@ -89,6 +96,7 @@ signals: void waypointReached(const QDeclarativeGeoWaypoint *pos); void destinationReached(); void currentRouteChanged(const QGeoRoute &route); + void currentRouteLegChanged(const QGeoRouteLeg &route); void currentSegmentChanged(int segment); private: diff --git a/src/location/places/qplacesearchrequest_p.h b/src/location/places/qplacesearchrequest_p.h index fdff89b8..73360926 100644 --- a/src/location/places/qplacesearchrequest_p.h +++ b/src/location/places/qplacesearchrequest_p.h @@ -56,6 +56,7 @@ #include <QtCore/QList> #include <QtLocation/private/qlocationglobal_p.h> #include <QtCore/QVariant> +#include <QtLocation/QGeoRoute> QT_BEGIN_NAMESPACE @@ -79,6 +80,7 @@ public: QString recommendationId; QLocation::VisibilityScope visibilityScope; QPlaceSearchRequest::RelevanceHint relevanceHint; + QGeoRoute routeSearchArea; int limit; QVariant searchContext; bool related = false; diff --git a/src/plugins/geoservices/osm/qgeocodereplyosm.cpp b/src/plugins/geoservices/osm/qgeocodereplyosm.cpp index a30601d0..e6a487ba 100644 --- a/src/plugins/geoservices/osm/qgeocodereplyosm.cpp +++ b/src/plugins/geoservices/osm/qgeocodereplyosm.cpp @@ -49,8 +49,8 @@ QT_BEGIN_NAMESPACE -QGeoCodeReplyOsm::QGeoCodeReplyOsm(QNetworkReply *reply, QObject *parent) -: QGeoCodeReply(parent) +QGeoCodeReplyOsm::QGeoCodeReplyOsm(QNetworkReply *reply, bool includeExtraData, QObject *parent) +: QGeoCodeReply(*new QGeoCodeReplyOsmPrivate, parent), m_includeExtraData(includeExtraData) { if (!reply) { setError(UnknownError, QStringLiteral("Null reply")); @@ -98,6 +98,27 @@ static QGeoAddress parseAddressObject(const QJsonObject &object) return address; } +static void injectExtra(QGeoLocation &location, const QJsonObject &object) +{ + QVariantMap extra; + static const QList<QString> extraKeys = { QStringLiteral("geojson"), + QStringLiteral("icon"), + QStringLiteral("importance"), + QStringLiteral("type"), + QStringLiteral("osm_id"), + QStringLiteral("osm_type"), + QStringLiteral("licence"), + QStringLiteral("place_id"), + QStringLiteral("class") }; + + for (const auto k: extraKeys) { + if (object.contains(k)) + extra[k] = object.value(k).toVariant(); + } + + location.setExtendedAttributes(extra); +} + void QGeoCodeReplyOsm::networkReplyFinished() { QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); @@ -121,6 +142,8 @@ void QGeoCodeReplyOsm::networkReplyFinished() location.setCoordinate(coordinate); location.setAddress(parseAddressObject(object)); + if (m_includeExtraData) + injectExtra(location, object); locations.append(location); setLocations(locations); @@ -154,6 +177,8 @@ void QGeoCodeReplyOsm::networkReplyFinished() location.setCoordinate(coordinate); location.setBoundingBox(rectangle); location.setAddress(parseAddressObject(object)); + if (m_includeExtraData) + injectExtra(location, object); locations.append(location); } @@ -171,4 +196,21 @@ void QGeoCodeReplyOsm::networkReplyError(QNetworkReply::NetworkError error) setError(QGeoCodeReply::CommunicationError, reply->errorString()); } +QGeoCodeReplyOsmPrivate::QGeoCodeReplyOsmPrivate() +{ + +} + +QGeoCodeReplyOsmPrivate::~QGeoCodeReplyOsmPrivate() +{ + +} + +QVariantMap QGeoCodeReplyOsmPrivate::extraData() const +{ + return m_extraData; +} + QT_END_NAMESPACE + + diff --git a/src/plugins/geoservices/osm/qgeocodereplyosm.h b/src/plugins/geoservices/osm/qgeocodereplyosm.h index 0847f58c..f00a8bb2 100644 --- a/src/plugins/geoservices/osm/qgeocodereplyosm.h +++ b/src/plugins/geoservices/osm/qgeocodereplyosm.h @@ -42,6 +42,7 @@ #include <QtNetwork/QNetworkReply> #include <QtLocation/QGeoCodeReply> +#include <QtLocation/private/qgeocodereply_p.h> QT_BEGIN_NAMESPACE @@ -50,12 +51,25 @@ class QGeoCodeReplyOsm : public QGeoCodeReply Q_OBJECT public: - explicit QGeoCodeReplyOsm(QNetworkReply *reply, QObject *parent = 0); + explicit QGeoCodeReplyOsm(QNetworkReply *reply, bool includeExtraData = false, QObject *parent = 0); ~QGeoCodeReplyOsm(); private Q_SLOTS: void networkReplyFinished(); void networkReplyError(QNetworkReply::NetworkError error); + +private: + bool m_includeExtraData = false; +}; + +class QGeoCodeReplyOsmPrivate : public QGeoCodeReplyPrivate +{ +public: + QGeoCodeReplyOsmPrivate(); + ~QGeoCodeReplyOsmPrivate(); + QVariantMap extraData() const override; + + QVariantMap m_extraData; }; QT_END_NAMESPACE diff --git a/src/plugins/geoservices/osm/qgeocodingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeocodingmanagerengineosm.cpp index d7751287..b2744551 100644 --- a/src/plugins/geoservices/osm/qgeocodingmanagerengineosm.cpp +++ b/src/plugins/geoservices/osm/qgeocodingmanagerengineosm.cpp @@ -38,7 +38,6 @@ ****************************************************************************/ #include "qgeocodingmanagerengineosm.h" -#include "qgeocodereplyosm.h" #include <QtCore/QVariantMap> #include <QtCore/QUrl> @@ -50,6 +49,8 @@ #include <QtPositioning/QGeoAddress> #include <QtPositioning/QGeoShape> #include <QtPositioning/QGeoRectangle> +#include "qgeocodereplyosm.h" + QT_BEGIN_NAMESPACE @@ -85,6 +86,11 @@ QGeoCodingManagerEngineOsm::QGeoCodingManagerEngineOsm(const QVariantMap ¶me else m_urlPrefix = QStringLiteral("https://nominatim.openstreetmap.org"); + if (parameters.contains(QStringLiteral("osm.geocoding.debug_query"))) + m_debugQuery = parameters.value(QStringLiteral("osm.geocoding.debug_query")).toBool(); + if (parameters.contains(QStringLiteral("osm.geocoding.include_extended_data"))) + m_includeExtraData = parameters.value(QStringLiteral("osm.geocoding.include_extended_data")).toBool(); + *error = QGeoServiceProvider::NoError; errorString->clear(); } @@ -125,7 +131,12 @@ QGeoCodeReply *QGeoCodingManagerEngineOsm::geocode(const QString &address, int l QNetworkReply *reply = m_networkManager->get(request); - QGeoCodeReplyOsm *geocodeReply = new QGeoCodeReplyOsm(reply, this); + QGeoCodeReplyOsm *geocodeReply = new QGeoCodeReplyOsm(reply, m_includeExtraData, this); + if (m_debugQuery) { + QGeoCodeReplyOsmPrivate *replyPrivate + = static_cast<QGeoCodeReplyOsmPrivate *>(QGeoCodeReplyPrivate::get(*geocodeReply)); + replyPrivate->m_extraData["request_url"] = url; + } connect(geocodeReply, SIGNAL(finished()), this, SLOT(replyFinished())); connect(geocodeReply, SIGNAL(error(QGeoCodeReply::Error,QString)), @@ -156,7 +167,12 @@ QGeoCodeReply *QGeoCodingManagerEngineOsm::reverseGeocode(const QGeoCoordinate & QNetworkReply *reply = m_networkManager->get(request); - QGeoCodeReplyOsm *geocodeReply = new QGeoCodeReplyOsm(reply, this); + QGeoCodeReplyOsm *geocodeReply = new QGeoCodeReplyOsm(reply, m_includeExtraData, this); + if (m_debugQuery) { + QGeoCodeReplyOsmPrivate *replyPrivate + = static_cast<QGeoCodeReplyOsmPrivate *>(QGeoCodeReplyPrivate::get(*geocodeReply)); + replyPrivate->m_extraData["request_url"] = url; + } connect(geocodeReply, SIGNAL(finished()), this, SLOT(replyFinished())); connect(geocodeReply, SIGNAL(error(QGeoCodeReply::Error,QString)), diff --git a/src/plugins/geoservices/osm/qgeocodingmanagerengineosm.h b/src/plugins/geoservices/osm/qgeocodingmanagerengineosm.h index 0fec49de..7a54fa43 100644 --- a/src/plugins/geoservices/osm/qgeocodingmanagerengineosm.h +++ b/src/plugins/geoservices/osm/qgeocodingmanagerengineosm.h @@ -71,6 +71,8 @@ private: QNetworkAccessManager *m_networkManager; QByteArray m_userAgent; QString m_urlPrefix; + bool m_debugQuery = false; + bool m_includeExtraData = false; }; QT_END_NAMESPACE diff --git a/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm b/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm index 6435963b..421f7743 100644 --- a/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm +++ b/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm @@ -325,6 +325,6 @@ void QGeoPositionInfoSourceCL::setError(QGeoPositionInfoSource::Error positionEr emit QGeoPositionInfoSource::error(positionError); } -#include "moc_qgeopositioninfosource_cl_p.cpp" - QT_END_NAMESPACE + +#include "moc_qgeopositioninfosource_cl_p.cpp" diff --git a/src/positioning/positioning.pro b/src/positioning/positioning.pro index 44de23ea..35e8e9e1 100644 --- a/src/positioning/positioning.pro +++ b/src/positioning/positioning.pro @@ -49,8 +49,6 @@ PRIVATE_HEADERS += \ qnmeapositioninfosource_p.h \ qgeocoordinate_p.h \ qgeopositioninfosource_p.h \ - qdeclarativegeoaddress_p.h \ - qdeclarativegeolocation_p.h \ qdoublevector2d_p.h \ qdoublevector3d_p.h \ qwebmercator_p.h \ @@ -58,6 +56,7 @@ PRIVATE_HEADERS += \ qlocationdata_simulator_p.h \ qdoublematrix4x4_p.h \ qgeopath_p.h \ + qgeopolygon_p.h \ qgeocoordinateobject_p.h \ qgeopositioninfo_p.h \ qclipperutils_p.h @@ -78,8 +77,6 @@ SOURCES += \ qlocationutils.cpp \ qnmeapositioninfosource.cpp \ qgeopositioninfosourcefactory.cpp \ - qdeclarativegeoaddress.cpp \ - qdeclarativegeolocation.cpp \ qdoublevector2d.cpp \ qdoublevector3d.cpp \ qgeopath.cpp \ diff --git a/src/positioning/qgeolocation.cpp b/src/positioning/qgeolocation.cpp index 62e1a6a3..dd34112f 100644 --- a/src/positioning/qgeolocation.cpp +++ b/src/positioning/qgeolocation.cpp @@ -53,6 +53,7 @@ QGeoLocationPrivate::QGeoLocationPrivate(const QGeoLocationPrivate &other) this->address = other.address; this->coordinate = other.coordinate; this->viewport = other.viewport; + this->extendedAttributes = other.extendedAttributes; } QGeoLocationPrivate::~QGeoLocationPrivate() @@ -63,7 +64,8 @@ bool QGeoLocationPrivate::operator==(const QGeoLocationPrivate &other) const { return (this->address == other.address && this->coordinate == other.coordinate - && this->viewport == other.viewport); + && this->viewport == other.viewport + && this->extendedAttributes == other.extendedAttributes); } @@ -72,7 +74,7 @@ bool QGeoLocationPrivate::isEmpty() const return (address.isEmpty() && !coordinate.isValid() && viewport.isEmpty() - ); + && extendedAttributes.isEmpty()); } /*! @@ -193,6 +195,27 @@ void QGeoLocation::setBoundingBox(const QGeoRectangle &boundingBox) } /*! + Returns the extended attributes associated to this location. + Extended attributes are backend-dependent and can be location-dependent. + + \since 5.13 +*/ +QVariantMap QGeoLocation::extendedAttributes() const +{ + return d->extendedAttributes; +} + +/*! + Sets the extended attributes of the location. + + \since 5.13 +*/ +void QGeoLocation::setExtendedAttributes(const QVariantMap &data) +{ + d->extendedAttributes = data; +} + +/*! Returns true if all fields of the location are 0; otherwise returns false. */ bool QGeoLocation::isEmpty() const diff --git a/src/positioning/qgeolocation.h b/src/positioning/qgeolocation.h index 580b2fb3..ff1dbcd9 100644 --- a/src/positioning/qgeolocation.h +++ b/src/positioning/qgeolocation.h @@ -70,8 +70,10 @@ public: void setAddress(const QGeoAddress &address); QGeoCoordinate coordinate() const; void setCoordinate(const QGeoCoordinate &position); - QGeoRectangle boundingBox() const; + QGeoRectangle boundingBox() const; // ### Qt6: change this into QGeoShape geometry void setBoundingBox(const QGeoRectangle &box); + QVariantMap extendedAttributes() const; + void setExtendedAttributes(const QVariantMap &data); bool isEmpty() const; diff --git a/src/positioning/qgeolocation_p.h b/src/positioning/qgeolocation_p.h index a12e4cb4..a9ce639d 100644 --- a/src/positioning/qgeolocation_p.h +++ b/src/positioning/qgeolocation_p.h @@ -55,6 +55,7 @@ #include <QtPositioning/QGeoAddress> #include <QtPositioning/QGeoCoordinate> #include <QtPositioning/QGeoRectangle> +#include <QVariantMap> QT_BEGIN_NAMESPACE @@ -73,6 +74,7 @@ public: QGeoAddress address; QGeoCoordinate coordinate; QGeoRectangle viewport; + QVariantMap extendedAttributes; }; QT_END_NAMESPACE diff --git a/src/positioning/qgeopath.cpp b/src/positioning/qgeopath.cpp index 0c3d0c1c..843b3f1b 100644 --- a/src/positioning/qgeopath.cpp +++ b/src/positioning/qgeopath.cpp @@ -114,7 +114,7 @@ Q_GLOBAL_STATIC(PathVariantConversions, initPathConversions) Constructs a new, empty geo path. */ QGeoPath::QGeoPath() -: QGeoShape(new QGeoPathPrivate(QGeoShape::PathType)) +: QGeoShape(new QGeoPathPrivate()) { initPathConversions(); } @@ -124,7 +124,7 @@ QGeoPath::QGeoPath() (\a path and \a width). */ QGeoPath::QGeoPath(const QList<QGeoCoordinate> &path, const qreal &width) -: QGeoShape(new QGeoPathPrivate(QGeoShape::PathType, path, width)) +: QGeoShape(new QGeoPathPrivate(path, width)) { initPathConversions(); } @@ -146,7 +146,7 @@ QGeoPath::QGeoPath(const QGeoShape &other) { initPathConversions(); if (type() != QGeoShape::PathType) - d_ptr = new QGeoPathPrivate(QGeoShape::PathType); + d_ptr = new QGeoPathPrivate(); } /*! @@ -391,128 +391,70 @@ QString QGeoPath::toString() const } /******************************************************************************* - * QGeoPathPrivate + * + * QGeoPathPrivate & friends + * *******************************************************************************/ -QGeoPathPrivate::QGeoPathPrivate(QGeoShape::ShapeType type) -: QGeoShapePrivate(type), m_width(0), m_clipperDirty(true) +QGeoPathPrivate::QGeoPathPrivate() +: QGeoShapePrivate(QGeoShape::PathType) { + } -QGeoPathPrivate::QGeoPathPrivate(QGeoShape::ShapeType type, const QList<QGeoCoordinate> &path, const qreal width) -: QGeoShapePrivate(type), m_width(0), m_clipperDirty(true) +QGeoPathPrivate::QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width) +: QGeoShapePrivate(QGeoShape::PathType) { setPath(path); setWidth(width); } -QGeoPathPrivate::QGeoPathPrivate(const QGeoPathPrivate &other) -: QGeoShapePrivate(other.type), m_path(other.m_path), - m_deltaXs(other.m_deltaXs), m_minX(other.m_minX), m_maxX(other.m_maxX), m_minLati(other.m_minLati), - m_maxLati(other.m_maxLati), m_bbox(other.m_bbox), m_width(other.m_width), m_clipperDirty(true) +QGeoPathPrivate::~QGeoPathPrivate() { -} -QGeoPathPrivate::~QGeoPathPrivate() {} +} QGeoShapePrivate *QGeoPathPrivate::clone() const { return new QGeoPathPrivate(*this); } -bool QGeoPathPrivate::operator==(const QGeoShapePrivate &other) const -{ - if (!QGeoShapePrivate::operator==(other)) - return false; - - const QGeoPathPrivate &otherPath = static_cast<const QGeoPathPrivate &>(other); - if (m_path.size() != otherPath.m_path.size()) - return false; - - if (type == QGeoShape::PathType) - return m_width == otherPath.m_width && m_path == otherPath.m_path; - else - return m_path == otherPath.m_path; -} - bool QGeoPathPrivate::isValid() const { - if (type == QGeoShape::PathType) - return !isEmpty(); - else - return m_path.size() > 2; - + return !isEmpty(); } bool QGeoPathPrivate::isEmpty() const { - return m_path.isEmpty(); // this should perhaps return geometric emptiness, less than 2 points for line, or empty polygon for polygons -} - -const QList<QGeoCoordinate> &QGeoPathPrivate::path() const -{ - return m_path; -} - -void QGeoPathPrivate::setPath(const QList<QGeoCoordinate> &path) -{ - for (const QGeoCoordinate &c: path) - if (!c.isValid()) - return; - m_path = path; - computeBoundingBox(); -} - -void QGeoPathPrivate::clearPath() -{ - m_path.clear(); - computeBoundingBox(); + return path().isEmpty(); // this should perhaps return geometric emptiness, less than 2 points for line, or empty polygon for polygons } -qreal QGeoPathPrivate::width() const +QGeoCoordinate QGeoPathPrivate::center() const { - return m_width; + return boundingGeoRectangle().center(); } -void QGeoPathPrivate::setWidth(const qreal &width) +void QGeoPathPrivate::extendShape(const QGeoCoordinate &coordinate) { - if (qIsNaN(width) || width < 0.0) + if (!coordinate.isValid() || contains(coordinate)) return; - m_width = width; + addCoordinate(coordinate); } -double QGeoPathPrivate::length(int indexFrom, int indexTo) const +bool QGeoPathPrivate::operator==(const QGeoShapePrivate &other) const { - if (path().isEmpty()) - return 0.0; - - bool wrap = indexTo == -1; - if (indexTo < 0 || indexTo >= path().size()) - indexTo = path().size() - 1; - double len = 0.0; - // TODO: consider calculating the length of the actual rhumb line segments - // instead of the shortest path from A to B. - for (int i = indexFrom; i < indexTo; i++) - len += m_path[i].distanceTo(m_path[i+1]); - if (wrap) - len += m_path.last().distanceTo(m_path.first()); - return len; -} + if (!QGeoShapePrivate::operator==(other)) + return false; -int QGeoPathPrivate::size() const -{ - return m_path.size(); + const QGeoPathPrivate &otherPath = static_cast<const QGeoPathPrivate &>(other); + if (m_path.size() != otherPath.m_path.size()) + return false; + return m_width == otherPath.m_width && m_path == otherPath.m_path; } -/*! - Returns true if coordinate is present in m_path. -*/ -bool QGeoPathPrivate::contains(const QGeoCoordinate &coordinate) const +const QList<QGeoCoordinate> &QGeoPathPrivate::path() const { - if (type == QGeoShape::PathType) - return lineContains(coordinate); - else - return polygonContains(coordinate); + return m_path; } bool QGeoPathPrivate::lineContains(const QGeoCoordinate &coordinate) const @@ -584,54 +526,67 @@ bool QGeoPathPrivate::lineContains(const QGeoCoordinate &coordinate) const return (m_path[0].distanceTo(coordinate) <= lineRadius); } -/*! - modified version of polygonContains with holes support. -*/ -bool QGeoPathPrivate::polygonContains(const QGeoCoordinate &coordinate) const +bool QGeoPathPrivate::contains(const QGeoCoordinate &coordinate) const { - if (m_clipperDirty) - const_cast<QGeoPathPrivate *>(this)->updateClipperPath(); - - // iterates the holes List checking whether the point is contained inside the holes - for (const QList<QGeoCoordinate> &holePath : qAsConst(m_holesList)) { + return lineContains(coordinate); +} - QGeoPolygon holePolygon; - holePolygon.setPath(holePath); - QGeoPath holeBoundary; - holeBoundary.setPath(holePath); +qreal QGeoPathPrivate::width() const +{ + return m_width; +} - if (holePolygon.contains(coordinate) && !(holeBoundary.contains(coordinate))) - return false; - } +void QGeoPathPrivate::setWidth(const qreal &width) +{ + if (qIsNaN(width) || width < 0.0) + return; + m_width = width; +} - QDoubleVector2D coord = QWebMercator::coordToMercator(coordinate); - double tlx = QWebMercator::coordToMercator(m_bbox.topLeft()).x(); - if (coord.x() < tlx) - coord.setX(coord.x() + 1.0); +double QGeoPathPrivate::length(int indexFrom, int indexTo) const +{ + if (path().isEmpty()) + return 0.0; - IntPoint intCoord = QClipperUtils::toIntPoint(coord); - return c2t::clip2tri::pointInPolygon(intCoord, m_clipperPath) != 0; + bool wrap = indexTo == -1; + if (indexTo < 0 || indexTo >= path().size()) + indexTo = path().size() - 1; + double len = 0.0; + // TODO: consider calculating the length of the actual rhumb line segments + // instead of the shortest path from A to B. + for (int i = indexFrom; i < indexTo; i++) + len += m_path[i].distanceTo(m_path[i+1]); + if (wrap) + len += m_path.last().distanceTo(m_path.first()); + return len; } -QGeoCoordinate QGeoPathPrivate::center() const +int QGeoPathPrivate::size() const { - return boundingGeoRectangle().center(); + return m_path.size(); } -QGeoRectangle QGeoPathPrivate::boundingGeoRectangle() const +QGeoCoordinate QGeoPathPrivate::coordinateAt(int index) const { - return m_bbox; + if (index < 0 || index >= m_path.size()) + return QGeoCoordinate(); + + return m_path.at(index); } -void QGeoPathPrivate::extendShape(const QGeoCoordinate &coordinate) +bool QGeoPathPrivate::containsCoordinate(const QGeoCoordinate &coordinate) const { - if (!coordinate.isValid() || contains(coordinate)) - return; - addCoordinate(coordinate); + return m_path.indexOf(coordinate) > -1; } void QGeoPathPrivate::translate(double degreesLatitude, double degreesLongitude) { + // Need min/maxLati, so update bbox + QVector<double> m_deltaXs; + double m_minX, m_maxX, m_minLati, m_maxLati; + m_bboxDirty = false; + computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); + if (degreesLatitude > 0.0) degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati); else @@ -640,17 +595,29 @@ void QGeoPathPrivate::translate(double degreesLatitude, double degreesLongitude) p.setLatitude(p.latitude() + degreesLatitude); p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude)); } - if (!m_holesList.isEmpty()){ - for (QList<QGeoCoordinate> &hole: m_holesList){ - for (QGeoCoordinate &holeVertex: hole){ - holeVertex.setLatitude(holeVertex.latitude() + degreesLatitude); - holeVertex.setLongitude(QLocationUtils::wrapLong(holeVertex.longitude() + degreesLongitude)); - } - } - } m_bbox.translate(degreesLatitude, degreesLongitude); - m_minLati += degreesLatitude; - m_maxLati += degreesLatitude; +} + +QGeoRectangle QGeoPathPrivate::boundingGeoRectangle() const +{ + if (m_bboxDirty) + const_cast<QGeoPathPrivate &>(*this).computeBoundingBox(); + return m_bbox; +} + +void QGeoPathPrivate::setPath(const QList<QGeoCoordinate> &path) +{ + for (const QGeoCoordinate &c: path) + if (!c.isValid()) + return; + m_path = path; + markDirty(); +} + +void QGeoPathPrivate::clearPath() +{ + m_path.clear(); + markDirty(); } void QGeoPathPrivate::addCoordinate(const QGeoCoordinate &coordinate) @@ -658,38 +625,23 @@ void QGeoPathPrivate::addCoordinate(const QGeoCoordinate &coordinate) if (!coordinate.isValid()) return; m_path.append(coordinate); - updateBoundingBox(); + markDirty(); } void QGeoPathPrivate::insertCoordinate(int index, const QGeoCoordinate &coordinate) { if (index < 0 || index > m_path.size() || !coordinate.isValid()) return; - m_path.insert(index, coordinate); - computeBoundingBox(); + markDirty(); } void QGeoPathPrivate::replaceCoordinate(int index, const QGeoCoordinate &coordinate) { if (index < 0 || index >= m_path.size() || !coordinate.isValid()) return; - m_path[index] = coordinate; - computeBoundingBox(); -} - -QGeoCoordinate QGeoPathPrivate::coordinateAt(int index) const -{ - if (index < 0 || index >= m_path.size()) - return QGeoCoordinate(); - - return m_path.at(index); -} - -bool QGeoPathPrivate::containsCoordinate(const QGeoCoordinate &coordinate) const -{ - return m_path.indexOf(coordinate) > -1; + markDirty(); } void QGeoPathPrivate::removeCoordinate(const QGeoCoordinate &coordinate) @@ -702,171 +654,121 @@ void QGeoPathPrivate::removeCoordinate(int index) { if (index < 0 || index >= m_path.size()) return; - m_path.removeAt(index); - computeBoundingBox(); + markDirty(); +} + +void QGeoPathPrivate::markDirty() +{ + m_bboxDirty = true; } void QGeoPathPrivate::computeBoundingBox() { - m_clipperDirty = true; - if (m_path.isEmpty()) { - m_deltaXs.clear(); - m_minX = qInf(); - m_maxX = -qInf(); - m_minLati = qInf(); - m_maxLati = -qInf(); - m_bbox = QGeoRectangle(); - return; - } + QVector<double> m_deltaXs; + double m_minX, m_maxX, m_minLati, m_maxLati; + m_bboxDirty = false; + computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); +} - m_minLati = m_maxLati = m_path.at(0).latitude(); - int minId = 0; - int maxId = 0; - m_deltaXs.resize(m_path.size()); - m_deltaXs[0] = m_minX = m_maxX = 0.0; +QGeoPathPrivateEager::QGeoPathPrivateEager() +: QGeoPathPrivate() +{ + m_bboxDirty = false; // never dirty on the eager version +} - for (int i = 1; i < m_path.size(); i++) { - const QGeoCoordinate &geoFrom = m_path.at(i-1); - const QGeoCoordinate &geoTo = m_path.at(i); - double longiFrom = geoFrom.longitude(); - double longiTo = geoTo.longitude(); - double deltaLongi = longiTo - longiFrom; - if (qAbs(deltaLongi) > 180.0) { - if (longiTo > 0.0) - longiTo -= 360.0; - else - longiTo += 360.0; - deltaLongi = longiTo - longiFrom; - } - m_deltaXs[i] = m_deltaXs[i-1] + deltaLongi; - if (m_deltaXs[i] < m_minX) { - m_minX = m_deltaXs[i]; - minId = i; - } - if (m_deltaXs[i] > m_maxX) { - m_maxX = m_deltaXs[i]; - maxId = i; - } - if (geoTo.latitude() > m_maxLati) - m_maxLati = geoTo.latitude(); - if (geoTo.latitude() < m_minLati) - m_minLati = geoTo.latitude(); - } +QGeoPathPrivateEager::QGeoPathPrivateEager(const QList<QGeoCoordinate> &path, const qreal width) +: QGeoPathPrivate(path, width) +{ + m_bboxDirty = false; // never dirty on the eager version +} + +QGeoPathPrivateEager::~QGeoPathPrivateEager() +{ - m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(minId).longitude()), - QGeoCoordinate(m_minLati, m_path.at(maxId).longitude())); } -void QGeoPathPrivate::updateBoundingBox() +QGeoShapePrivate *QGeoPathPrivateEager::clone() const { - m_clipperDirty = true; - if (m_path.isEmpty()) { - m_deltaXs.clear(); - m_minX = qInf(); - m_maxX = -qInf(); - m_minLati = qInf(); - m_maxLati = -qInf(); - m_bbox = QGeoRectangle(); - return; - } else if (m_path.size() == 1) { // was 0 now is 1 - m_deltaXs.resize(1); - m_deltaXs[0] = m_minX = m_maxX = 0.0; - m_minLati = m_maxLati = m_path.at(0).latitude(); - m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(0).longitude()), - QGeoCoordinate(m_minLati, m_path.at(0).longitude())); - return; - } else if ( m_path.size() != m_deltaXs.size() + 1 ) { // this case should not happen - computeBoundingBox(); // something went wrong - return; - } + return new QGeoPathPrivateEager(*this); +} - const QGeoCoordinate &geoFrom = m_path.at(m_path.size()-2); - const QGeoCoordinate &geoTo = m_path.last(); - double longiFrom = geoFrom.longitude(); - double longiTo = geoTo.longitude(); - double deltaLongi = longiTo - longiFrom; - if (qAbs(deltaLongi) > 180.0) { - if (longiTo > 0.0) - longiTo -= 360.0; - else - longiTo += 360.0; - deltaLongi = longiTo - longiFrom; - } +void QGeoPathPrivateEager::markDirty() +{ + computeBoundingBox(); +} - m_deltaXs.push_back(m_deltaXs.last() + deltaLongi); - double currentMinLongi = m_bbox.topLeft().longitude(); - double currentMaxLongi = m_bbox.bottomRight().longitude(); - if (m_deltaXs.last() < m_minX) { - m_minX = m_deltaXs.last(); - currentMinLongi = geoTo.longitude(); - } - if (m_deltaXs.last() > m_maxX) { - m_maxX = m_deltaXs.last(); - currentMaxLongi = geoTo.longitude(); - } - if (geoTo.latitude() > m_maxLati) - m_maxLati = geoTo.latitude(); - if (geoTo.latitude() < m_minLati) - m_minLati = geoTo.latitude(); - m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, currentMinLongi), - QGeoCoordinate(m_minLati, currentMaxLongi)); -} - -void QGeoPathPrivate::updateClipperPath() -{ - m_clipperDirty = false; - double tlx = QWebMercator::coordToMercator(m_bbox.topLeft()).x(); - QList<QDoubleVector2D> preservedPath; - for (const QGeoCoordinate &c : m_path) { - QDoubleVector2D crd = QWebMercator::coordToMercator(c); - if (crd.x() < tlx) - crd.setX(crd.x() + 1.0); - preservedPath << crd; +void QGeoPathPrivateEager::translate(double degreesLatitude, double degreesLongitude) +{ + if (degreesLatitude > 0.0) + degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati); + else + degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati); + for (QGeoCoordinate &p: m_path) { + p.setLatitude(p.latitude() + degreesLatitude); + p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude)); } - m_clipperPath = QClipperUtils::qListToPath(preservedPath); + m_bbox.translate(degreesLatitude, degreesLongitude); + m_minLati += degreesLatitude; + m_maxLati += degreesLatitude; } - -/*! - Sets the \a path for an Hole inside the polygon.The hole has QList<QGeoCoordinate> type -*/ -void QGeoPathPrivate::addHole(const QList<QGeoCoordinate> &holePath) +void QGeoPathPrivateEager::addCoordinate(const QGeoCoordinate &coordinate) { - for (const QGeoCoordinate &holeVertex: holePath) - if (!holeVertex.isValid()) - return; + if (!coordinate.isValid()) + return; + m_path.append(coordinate); + //m_clipperDirty = true; // clipper not used in polylines + updateBoundingBox(); +} - m_holesList << holePath; +void QGeoPathPrivateEager::QGeoPathPrivateEager::computeBoundingBox() +{ + computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); } -/*! - Returns a QVariant containing a QList<QGeoCoordinate> representing the hole at index -*/ -const QList<QGeoCoordinate> QGeoPathPrivate::holePath(int index) const +void QGeoPathPrivateEager::QGeoPathPrivateEager::updateBoundingBox() { - return m_holesList.at(index); + updateBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); } +QGeoPathEager::QGeoPathEager() : QGeoPath() +{ + initPathConversions(); + d_ptr = new QGeoPathPrivateEager; +} -/*! - Removes element at position \a index from the holes QList. -*/ -void QGeoPathPrivate::removeHole(int index) +QGeoPathEager::QGeoPathEager(const QList<QGeoCoordinate> &path, const qreal &width) : QGeoPath() { - if (index < 0 || index >= m_holesList.size()) - return; + initPathConversions(); + d_ptr = new QGeoPathPrivateEager(path, width); +} - m_holesList.removeAt(index); +QGeoPathEager::QGeoPathEager(const QGeoPath &other) : QGeoPath() +{ + initPathConversions(); + d_ptr = new QGeoPathPrivateEager; + setPath(other.path()); + setWidth(other.width()); } -/*! - Returns the number of holes. -*/ -int QGeoPathPrivate::holesCount() const +QGeoPathEager::QGeoPathEager(const QGeoShape &other) : QGeoPath() { - return m_holesList.size(); + initPathConversions(); + if (other.type() == QGeoShape::PathType) + *this = QGeoPathEager(QGeoPath(other)); + else + d_ptr = new QGeoPathPrivateEager; } +QGeoPathEager::~QGeoPathEager() {} + QT_END_NAMESPACE + + + + + + + diff --git a/src/positioning/qgeopath_p.h b/src/positioning/qgeopath_p.h index d39f0ab2..4fffe61d 100644 --- a/src/positioning/qgeopath_p.h +++ b/src/positioning/qgeopath_p.h @@ -51,73 +51,217 @@ // We mean it. // +#include <QtPositioning/private/qpositioningglobal_p.h> #include "qgeoshape_p.h" #include "qgeocoordinate.h" #include "qlocationutils_p.h" #include <QtPositioning/private/qclipperutils_p.h> - +#include <QtPositioning/qgeopath.h> #include <QtCore/QVector> QT_BEGIN_NAMESPACE -class QGeoPathPrivate : public QGeoShapePrivate +inline static void computeBBox( const QList<QGeoCoordinate> &m_path, + QVector<double> &m_deltaXs, + double &m_minX, + double &m_maxX, + double &m_minLati, + double &m_maxLati, + QGeoRectangle &m_bbox) +{ + if (m_path.isEmpty()) { + m_deltaXs.clear(); + m_minX = qInf(); + m_maxX = -qInf(); + m_minLati = qInf(); + m_maxLati = -qInf(); + m_bbox = QGeoRectangle(); + return; + } + + m_minLati = m_maxLati = m_path.at(0).latitude(); + int minId = 0; + int maxId = 0; + m_deltaXs.resize(m_path.size()); + m_deltaXs[0] = m_minX = m_maxX = 0.0; + + for (int i = 1; i < m_path.size(); i++) { + const QGeoCoordinate &geoFrom = m_path.at(i-1); + const QGeoCoordinate &geoTo = m_path.at(i); + double longiFrom = geoFrom.longitude(); + double longiTo = geoTo.longitude(); + double deltaLongi = longiTo - longiFrom; + if (qAbs(deltaLongi) > 180.0) { + if (longiTo > 0.0) + longiTo -= 360.0; + else + longiTo += 360.0; + deltaLongi = longiTo - longiFrom; + } + m_deltaXs[i] = m_deltaXs[i-1] + deltaLongi; + if (m_deltaXs[i] < m_minX) { + m_minX = m_deltaXs[i]; + minId = i; + } + if (m_deltaXs[i] > m_maxX) { + m_maxX = m_deltaXs[i]; + maxId = i; + } + if (geoTo.latitude() > m_maxLati) + m_maxLati = geoTo.latitude(); + if (geoTo.latitude() < m_minLati) + m_minLati = geoTo.latitude(); + } + + m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(minId).longitude()), + QGeoCoordinate(m_minLati, m_path.at(maxId).longitude())); +} + +inline static void updateBBox( const QList<QGeoCoordinate> &m_path, + QVector<double> &m_deltaXs, + double &m_minX, + double &m_maxX, + double &m_minLati, + double &m_maxLati, + QGeoRectangle &m_bbox) +{ + if (m_path.isEmpty()) { + m_deltaXs.clear(); + m_minX = qInf(); + m_maxX = -qInf(); + m_minLati = qInf(); + m_maxLati = -qInf(); + m_bbox = QGeoRectangle(); + return; + } else if (m_path.size() == 1) { // was 0 now is 1 + m_deltaXs.resize(1); + m_deltaXs[0] = m_minX = m_maxX = 0.0; + m_minLati = m_maxLati = m_path.at(0).latitude(); + m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(0).longitude()), + QGeoCoordinate(m_minLati, m_path.at(0).longitude())); + return; + } else if ( m_path.size() != m_deltaXs.size() + 1 ) { // this case should not happen + computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); // something went wrong + return; + } + + const QGeoCoordinate &geoFrom = m_path.at(m_path.size()-2); + const QGeoCoordinate &geoTo = m_path.last(); + double longiFrom = geoFrom.longitude(); + double longiTo = geoTo.longitude(); + double deltaLongi = longiTo - longiFrom; + if (qAbs(deltaLongi) > 180.0) { + if (longiTo > 0.0) + longiTo -= 360.0; + else + longiTo += 360.0; + deltaLongi = longiTo - longiFrom; + } + + m_deltaXs.push_back(m_deltaXs.last() + deltaLongi); + double currentMinLongi = m_bbox.topLeft().longitude(); + double currentMaxLongi = m_bbox.bottomRight().longitude(); + if (m_deltaXs.last() < m_minX) { + m_minX = m_deltaXs.last(); + currentMinLongi = geoTo.longitude(); + } + if (m_deltaXs.last() > m_maxX) { + m_maxX = m_deltaXs.last(); + currentMaxLongi = geoTo.longitude(); + } + if (geoTo.latitude() > m_maxLati) + m_maxLati = geoTo.latitude(); + if (geoTo.latitude() < m_minLati) + m_minLati = geoTo.latitude(); + m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, currentMinLongi), + QGeoCoordinate(m_minLati, currentMaxLongi)); +} + +// Lazy by default. Eager, within the module, used only in MapItems/MapObjectsQSG +class Q_POSITIONING_PRIVATE_EXPORT QGeoPathPrivate : public QGeoShapePrivate { public: - QGeoPathPrivate(QGeoShape::ShapeType type); - QGeoPathPrivate(QGeoShape::ShapeType type, const QList<QGeoCoordinate> &path, const qreal width = 0.0); - QGeoPathPrivate(const QGeoPathPrivate &other); + QGeoPathPrivate(); + QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width = 0.0); ~QGeoPathPrivate(); - bool isValid() const override; - bool isEmpty() const override; - bool contains(const QGeoCoordinate &coordinate) const override; - bool lineContains(const QGeoCoordinate &coordinate) const; - bool polygonContains(const QGeoCoordinate &coordinate) const; - - QGeoCoordinate center() const override; - QGeoRectangle boundingGeoRectangle() const override; - void extendShape(const QGeoCoordinate &coordinate) override; - void translate(double degreesLatitude, double degreesLongitude); - - QGeoShapePrivate *clone() const override; - - bool operator==(const QGeoShapePrivate &other) const override; - - const QList<QGeoCoordinate> &path() const; - void setPath(const QList<QGeoCoordinate> &path); - void clearPath(); - - qreal width() const; - void setWidth(const qreal &width); - double length(int indexFrom, int indexTo) const; - int size() const; - void addCoordinate(const QGeoCoordinate &coordinate); - void insertCoordinate(int index, const QGeoCoordinate &coordinate); - void replaceCoordinate(int index, const QGeoCoordinate &coordinate); - QGeoCoordinate coordinateAt(int index) const; - bool containsCoordinate(const QGeoCoordinate &coordinate) const; - void removeCoordinate(const QGeoCoordinate &coordinate); - void removeCoordinate(int index); - void computeBoundingBox(); - void updateBoundingBox(); - void updateClipperPath(); - void addHole(const QList<QGeoCoordinate> &holePath); - const QList<QGeoCoordinate> holePath(int index) const; - void removeHole(int index); - int holesCount() const; +// QGeoShape API + virtual QGeoShapePrivate *clone() const override; + virtual bool isValid() const override; + virtual bool isEmpty() const override; + virtual QGeoCoordinate center() const override; + virtual bool operator==(const QGeoShapePrivate &other) const override; + virtual bool contains(const QGeoCoordinate &coordinate) const override; + virtual QGeoRectangle boundingGeoRectangle() const override; + virtual void extendShape(const QGeoCoordinate &coordinate) override; +// QGeoPathPrivate API + virtual const QList<QGeoCoordinate> &path() const; + virtual bool lineContains(const QGeoCoordinate &coordinate) const; + virtual qreal width() const; + virtual double length(int indexFrom, int indexTo) const; + virtual int size() const; + virtual QGeoCoordinate coordinateAt(int index) const; + virtual bool containsCoordinate(const QGeoCoordinate &coordinate) const; + + virtual void setWidth(const qreal &width); + virtual void translate(double degreesLatitude, double degreesLongitude); + virtual void setPath(const QList<QGeoCoordinate> &path); + virtual void clearPath(); + virtual void addCoordinate(const QGeoCoordinate &coordinate); + virtual void insertCoordinate(int index, const QGeoCoordinate &coordinate); + virtual void replaceCoordinate(int index, const QGeoCoordinate &coordinate); + virtual void removeCoordinate(const QGeoCoordinate &coordinate); + virtual void removeCoordinate(int index); + virtual void computeBoundingBox(); + virtual void markDirty(); + +// data members QList<QGeoCoordinate> m_path; - QList<QList<QGeoCoordinate>> m_holesList; - QVector<double> m_deltaXs; // longitude deltas from m_path[0] - double m_minX; // minimum value inside deltaXs - double m_maxX; // maximum value inside deltaXs - double m_minLati; // minimum latitude. paths do not wrap around through the poles - double m_maxLati; // minimum latitude. paths do not wrap around through the poles - QGeoRectangle m_bbox; - qreal m_width; - bool m_clipperDirty; - QtClipperLib::Path m_clipperPath; + qreal m_width = 0; + QGeoRectangle m_bbox; // cached + bool m_bboxDirty = false; +}; + +class Q_POSITIONING_PRIVATE_EXPORT QGeoPathPrivateEager : public QGeoPathPrivate +{ +public: + QGeoPathPrivateEager(); + QGeoPathPrivateEager(const QList<QGeoCoordinate> &path, const qreal width = 0.0); + ~QGeoPathPrivateEager(); + +// QGeoShapePrivate API + virtual QGeoShapePrivate *clone() const override; + virtual void translate(double degreesLatitude, double degreesLongitude) override; + +// QGeoShapePrivate API + virtual void markDirty() override; + virtual void addCoordinate(const QGeoCoordinate &coordinate) override; + virtual void computeBoundingBox() override; + +// *Eager API + void updateBoundingBox(); + +// data members + QVector<double> m_deltaXs; // longitude deltas from m_path[0] + double m_minX = 0; // minimum value inside deltaXs + double m_maxX = 0; // maximum value inside deltaXs + double m_minLati = 0; // minimum latitude. paths do not wrap around through the poles + double m_maxLati = 0; // minimum latitude. paths do not wrap around through the poles +}; + +// This is a mean of creating a QGeoPathPrivateEager and injecting it into QGeoPaths via operator= +class Q_POSITIONING_PRIVATE_EXPORT QGeoPathEager : public QGeoPath +{ + Q_GADGET +public: + + QGeoPathEager(); + QGeoPathEager(const QList<QGeoCoordinate> &path, const qreal &width = 0.0); + QGeoPathEager(const QGeoPath &other); + QGeoPathEager(const QGeoShape &other); + ~QGeoPathEager(); }; QT_END_NAMESPACE diff --git a/src/positioning/qgeopolygon.cpp b/src/positioning/qgeopolygon.cpp index 66659d4b..4e902be5 100644 --- a/src/positioning/qgeopolygon.cpp +++ b/src/positioning/qgeopolygon.cpp @@ -38,7 +38,7 @@ ****************************************************************************/ #include "qgeopolygon.h" -#include "qgeopath_p.h" +#include "qgeopolygon_p.h" #include "qgeocoordinate.h" #include "qnumeric.h" @@ -111,7 +111,7 @@ Q_GLOBAL_STATIC(PolygonVariantConversions, initPolygonConversions) Constructs a new, empty geo polygon. */ QGeoPolygon::QGeoPolygon() -: QGeoShape(new QGeoPolygonPrivate(QGeoShape::PolygonType)) +: QGeoShape(new QGeoPolygonPrivate()) { initPolygonConversions(); } @@ -120,7 +120,7 @@ QGeoPolygon::QGeoPolygon() Constructs a new geo \a polygon from a list of coordinates. */ QGeoPolygon::QGeoPolygon(const QList<QGeoCoordinate> &path) -: QGeoShape(new QGeoPolygonPrivate(QGeoShape::PolygonType, path)) +: QGeoShape(new QGeoPolygonPrivate(path)) { initPolygonConversions(); } @@ -142,7 +142,7 @@ QGeoPolygon::QGeoPolygon(const QGeoShape &other) { initPolygonConversions(); if (type() != QGeoShape::PolygonType) - d_ptr = new QGeoPolygonPrivate(QGeoShape::PolygonType); + d_ptr = new QGeoPolygonPrivate(); } /*! @@ -432,4 +432,255 @@ int QGeoPolygon::holesCount() const return d->holesCount(); } +/******************************************************************************* + * + * QGeoPathPrivate & friends + * +*******************************************************************************/ + +QGeoPolygonPrivate::QGeoPolygonPrivate() +: QGeoPathPrivate() +{ + type = QGeoShape::PolygonType; +} + +QGeoPolygonPrivate::QGeoPolygonPrivate(const QList<QGeoCoordinate> &path) +: QGeoPathPrivate(path) +{ + type = QGeoShape::PolygonType; +} + +QGeoPolygonPrivate::~QGeoPolygonPrivate() {} + +QGeoShapePrivate *QGeoPolygonPrivate::clone() const +{ + return new QGeoPolygonPrivate(*this); +} + +bool QGeoPolygonPrivate::isValid() const +{ + return path().size() > 2; +} + +bool QGeoPolygonPrivate::contains(const QGeoCoordinate &coordinate) const +{ + return polygonContains(coordinate); +} + +inline static void translatePoly( QList<QGeoCoordinate> &m_path, + QList<QList<QGeoCoordinate>> &m_holesList, + QGeoRectangle &m_bbox, + double degreesLatitude, + double degreesLongitude, + double m_maxLati, + double m_minLati) +{ + if (degreesLatitude > 0.0) + degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati); + else + degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati); + for (QGeoCoordinate &p: m_path) { + p.setLatitude(p.latitude() + degreesLatitude); + p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude)); + } + if (!m_holesList.isEmpty()){ + for (QList<QGeoCoordinate> &hole: m_holesList){ + for (QGeoCoordinate &holeVertex: hole){ + holeVertex.setLatitude(holeVertex.latitude() + degreesLatitude); + holeVertex.setLongitude(QLocationUtils::wrapLong(holeVertex.longitude() + degreesLongitude)); + } + } + } + m_bbox.translate(degreesLatitude, degreesLongitude); +} + +void QGeoPolygonPrivate::translate(double degreesLatitude, double degreesLongitude) +{ + // Need min/maxLati, so update bbox + QVector<double> m_deltaXs; + double m_minX, m_maxX, m_minLati, m_maxLati; + m_bboxDirty = false; + computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); + + translatePoly(m_path, m_holesList, m_bbox, degreesLatitude, degreesLongitude, m_maxLati, m_minLati); +} + +bool QGeoPolygonPrivate::operator==(const QGeoShapePrivate &other) const +{ + if (!QGeoShapePrivate::operator==(other)) // checks type + return false; + + const QGeoPolygonPrivate &otherPath = static_cast<const QGeoPolygonPrivate &>(other); + if (m_path.size() != otherPath.m_path.size() + || m_holesList.size() != otherPath.m_holesList.size()) + return false; + return m_path == otherPath.m_path && m_holesList == otherPath.m_holesList; +} + +void QGeoPolygonPrivate::addHole(const QList<QGeoCoordinate> &holePath) +{ + for (const QGeoCoordinate &holeVertex: holePath) + if (!holeVertex.isValid()) + return; + + m_holesList << holePath; + // ToDo: mark clipper dirty when hole caching gets added +} + +const QList<QGeoCoordinate> QGeoPolygonPrivate::holePath(int index) const +{ + return m_holesList.at(index); +} + +void QGeoPolygonPrivate::removeHole(int index) +{ + if (index < 0 || index >= m_holesList.size()) + return; + + m_holesList.removeAt(index); + // ToDo: mark clipper dirty when hole caching gets added +} + +int QGeoPolygonPrivate::holesCount() const +{ + return m_holesList.size(); +} + +bool QGeoPolygonPrivate::polygonContains(const QGeoCoordinate &coordinate) const +{ + if (m_clipperDirty) + const_cast<QGeoPolygonPrivate *>(this)->updateClipperPath(); // this one updates bbox too if needed + + QDoubleVector2D coord = QWebMercator::coordToMercator(coordinate); + double tlx = QWebMercator::coordToMercator(m_bbox.topLeft()).x(); + if (coord.x() < tlx) + coord.setX(coord.x() + 1.0); + + IntPoint intCoord = QClipperUtils::toIntPoint(coord); + if (!c2t::clip2tri::pointInPolygon(intCoord, m_clipperPath)) + return false; + + // else iterates the holes List checking whether the point is contained inside the holes + for (const QList<QGeoCoordinate> &holePath : qAsConst(m_holesList)) { + // ToDo: cache these + QGeoPolygon holePolygon; + holePolygon.setPath(holePath); + // QGeoPath holeBoundary; + // holeBoundary.setPath(holePath); + + if (holePolygon.contains(coordinate) + // && !(holeBoundary.contains(coordinate)) + ) + return false; + } + return true; +} + +void QGeoPolygonPrivate::markDirty() +{ + m_bboxDirty = m_clipperDirty = true; +} + +void QGeoPolygonPrivate::updateClipperPath() +{ + if (m_bboxDirty) + computeBoundingBox(); + m_clipperDirty = false; + double tlx = QWebMercator::coordToMercator(m_bbox.topLeft()).x(); + QList<QDoubleVector2D> preservedPath; + for (const QGeoCoordinate &c : m_path) { + QDoubleVector2D crd = QWebMercator::coordToMercator(c); + if (crd.x() < tlx) + crd.setX(crd.x() + 1.0); + preservedPath << crd; + } + m_clipperPath = QClipperUtils::qListToPath(preservedPath); +} + +QGeoPolygonPrivateEager::QGeoPolygonPrivateEager() : QGeoPolygonPrivate() +{ + m_bboxDirty = false; // never dirty on the eager version +} + +QGeoPolygonPrivateEager::QGeoPolygonPrivateEager(const QList<QGeoCoordinate> &path) : QGeoPolygonPrivate(path) +{ + m_bboxDirty = false; // never dirty on the eager version +} + +QGeoPolygonPrivateEager::~QGeoPolygonPrivateEager() +{ + +} + +QGeoShapePrivate *QGeoPolygonPrivateEager::clone() const +{ + return new QGeoPolygonPrivate(*this); +} + +void QGeoPolygonPrivateEager::translate(double degreesLatitude, double degreesLongitude) +{ + translatePoly(m_path, m_holesList, m_bbox, degreesLatitude, degreesLongitude, m_maxLati, m_minLati); +} + +void QGeoPolygonPrivateEager::markDirty() +{ + m_clipperDirty = true; + computeBoundingBox(); +} + +void QGeoPolygonPrivateEager::addCoordinate(const QGeoCoordinate &coordinate) +{ + if (!coordinate.isValid()) + return; + m_path.append(coordinate); + m_clipperDirty = true; + updateBoundingBox(); // do not markDirty as it uses computeBoundingBox instead +} + +void QGeoPolygonPrivateEager::computeBoundingBox() +{ + computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); +} + +void QGeoPolygonPrivateEager::updateBoundingBox() +{ + updateBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); +} + +QGeoPolygonEager::QGeoPolygonEager() : QGeoPolygon() +{ + initPolygonConversions(); + d_ptr = new QGeoPolygonPrivateEager; +} + +QGeoPolygonEager::QGeoPolygonEager(const QList<QGeoCoordinate> &path) : QGeoPolygon() +{ + initPolygonConversions(); + d_ptr = new QGeoPolygonPrivateEager(path); +} + +QGeoPolygonEager::QGeoPolygonEager(const QGeoPolygon &other) : QGeoPolygon() +{ + initPolygonConversions(); + // without being able to dynamic_cast the d_ptr, only way to be sure is to reconstruct a new QGeoPolygonPrivateEager + d_ptr = new QGeoPolygonPrivateEager; + setPath(other.path()); + for (int i = 0; i < other.holesCount(); i++) + addHole(other.holePath(i)); +} + +QGeoPolygonEager::QGeoPolygonEager(const QGeoShape &other) : QGeoPolygon() +{ + initPolygonConversions(); + if (other.type() == QGeoShape::PolygonType) + *this = QGeoPolygonEager(QGeoPolygon(other)); + else + d_ptr = new QGeoPolygonPrivateEager; +} + +QGeoPolygonEager::~QGeoPolygonEager() +{ + +} + QT_END_NAMESPACE diff --git a/src/positioning/qgeopolygon.h b/src/positioning/qgeopolygon.h index ccc4b98b..8becda8f 100644 --- a/src/positioning/qgeopolygon.h +++ b/src/positioning/qgeopolygon.h @@ -46,8 +46,7 @@ QT_BEGIN_NAMESPACE class QGeoCoordinate; -class QGeoPathPrivate; -typedef QGeoPathPrivate QGeoPolygonPrivate; +class QGeoPolygonPrivate; class Q_POSITIONING_EXPORT QGeoPolygon : public QGeoShape { diff --git a/src/positioning/qgeopolygon_p.h b/src/positioning/qgeopolygon_p.h new file mode 100644 index 00000000..d28fcc6e --- /dev/null +++ b/src/positioning/qgeopolygon_p.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGEOPOLYGON_P_H +#define QGEOPOLYGON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtPositioning/private/qgeopath_p.h> +#include <QtPositioning/qgeopolygon.h> + +QT_BEGIN_NAMESPACE + +class Q_POSITIONING_PRIVATE_EXPORT QGeoPolygonPrivate : public QGeoPathPrivate +{ +public: + QGeoPolygonPrivate(); + QGeoPolygonPrivate(const QList<QGeoCoordinate> &path); + ~QGeoPolygonPrivate(); + +// QGeoShape API + virtual QGeoShapePrivate *clone() const override; + virtual bool isValid() const override; + virtual bool contains(const QGeoCoordinate &coordinate) const override; + virtual void translate(double degreesLatitude, double degreesLongitude) override; + virtual bool operator==(const QGeoShapePrivate &other) const override; + +// QGeoPath API + virtual void markDirty() override; + +// QGeoPolygonPrivate API + int holesCount() const; + bool polygonContains(const QGeoCoordinate &coordinate) const; + const QList<QGeoCoordinate> holePath(int index) const; + + virtual void addHole(const QList<QGeoCoordinate> &holePath); + virtual void removeHole(int index); + virtual void updateClipperPath(); + +// data members + bool m_clipperDirty = true; + QList<QList<QGeoCoordinate>> m_holesList; + QtClipperLib::Path m_clipperPath; +}; + +class Q_POSITIONING_PRIVATE_EXPORT QGeoPolygonPrivateEager : public QGeoPolygonPrivate +{ +public: + QGeoPolygonPrivateEager(); + QGeoPolygonPrivateEager(const QList<QGeoCoordinate> &path); + ~QGeoPolygonPrivateEager(); + +// QGeoShape API + virtual QGeoShapePrivate *clone() const override; + virtual void translate(double degreesLatitude, double degreesLongitude) override; + +// QGeoPath API + virtual void markDirty() override; + virtual void addCoordinate(const QGeoCoordinate &coordinate) override; + virtual void computeBoundingBox() override; + +// QGeoPolygonPrivate API + +// *Eager API + void updateBoundingBox(); + +// data members + QVector<double> m_deltaXs; // longitude deltas from m_path[0] + double m_minX = 0; // minimum value inside deltaXs + double m_maxX = 0; // maximum value inside deltaXs + double m_minLati = 0; // minimum latitude. paths do not wrap around through the poles + double m_maxLati = 0; // minimum latitude. paths do not wrap around through the poles +}; + +// This is a mean of creating a QGeoPolygonPrivateEager and injecting it into QGeoPolygons via operator= +class Q_POSITIONING_PRIVATE_EXPORT QGeoPolygonEager : public QGeoPolygon +{ + Q_GADGET +public: + + QGeoPolygonEager(); + QGeoPolygonEager(const QList<QGeoCoordinate> &path); + QGeoPolygonEager(const QGeoPolygon &other); + QGeoPolygonEager(const QGeoShape &other); + ~QGeoPolygonEager(); +}; + +QT_END_NAMESPACE + +#endif // QGEOPOLYGON_P_H diff --git a/src/positioning/qgeorectangle.cpp b/src/positioning/qgeorectangle.cpp index 337b4c76..bb2debcf 100644 --- a/src/positioning/qgeorectangle.cpp +++ b/src/positioning/qgeorectangle.cpp @@ -804,7 +804,8 @@ void QGeoRectangle::extendRectangle(const QGeoCoordinate &coordinate) QGeoRectangle QGeoRectangle::united(const QGeoRectangle &rectangle) const { QGeoRectangle result(*this); - result |= rectangle; + if (rectangle.isValid()) + result |= rectangle; return result; } diff --git a/src/positioning/qgeoshape.cpp b/src/positioning/qgeoshape.cpp index d17f9eea..b1d310af 100644 --- a/src/positioning/qgeoshape.cpp +++ b/src/positioning/qgeoshape.cpp @@ -449,6 +449,6 @@ QDataStream &operator>>(QDataStream &stream, QGeoShape &shape) } #endif -#include "moc_qgeoshape.cpp" - QT_END_NAMESPACE + +#include "moc_qgeoshape.cpp" diff --git a/src/positioning/qdeclarativegeoaddress.cpp b/src/positioningquick/qdeclarativegeoaddress.cpp index 470a4c12..470a4c12 100644 --- a/src/positioning/qdeclarativegeoaddress.cpp +++ b/src/positioningquick/qdeclarativegeoaddress.cpp diff --git a/src/positioning/qdeclarativegeoaddress_p.h b/src/positioningquick/qdeclarativegeoaddress_p.h index 3285cea9..dd814978 100644 --- a/src/positioning/qdeclarativegeoaddress_p.h +++ b/src/positioningquick/qdeclarativegeoaddress_p.h @@ -53,10 +53,11 @@ #include <QtCore/QObject> #include <QtPositioning/QGeoAddress> +#include <QtPositioningQuick/private/qpositioningquickglobal_p.h> QT_BEGIN_NAMESPACE -class Q_POSITIONING_EXPORT QDeclarativeGeoAddress : public QObject +class Q_POSITIONINGQUICK_PRIVATE_EXPORT QDeclarativeGeoAddress : public QObject { Q_OBJECT diff --git a/src/positioning/qdeclarativegeolocation.cpp b/src/positioningquick/qdeclarativegeolocation.cpp index 9e3b71e5..c06fcff2 100644 --- a/src/positioning/qdeclarativegeolocation.cpp +++ b/src/positioningquick/qdeclarativegeolocation.cpp @@ -75,15 +75,24 @@ QT_USE_NAMESPACE \endcode */ +/*! + \qmlproperty VariantMap QDeclarativeGeoLocation::extendedAttributes + + This property holds the extended attributes for this Location. + Extended attributes are backend-dependent and can be location-dependent. + + \since 5.13 +*/ + QDeclarativeGeoLocation::QDeclarativeGeoLocation(QObject *parent) -: QObject(parent), m_address(0) +: QObject(parent) { setLocation(QGeoLocation()); } QDeclarativeGeoLocation::QDeclarativeGeoLocation(const QGeoLocation &src, QObject *parent) -: QObject(parent), m_address(0) +: QObject(parent) { setLocation(src); } @@ -109,6 +118,7 @@ void QDeclarativeGeoLocation::setLocation(const QGeoLocation &src) setCoordinate(src.coordinate()); setBoundingBox(src.boundingBox()); + setProperty("extendedAttributes", src.extendedAttributes()); } QGeoLocation QDeclarativeGeoLocation::location() const @@ -117,6 +127,7 @@ QGeoLocation QDeclarativeGeoLocation::location() const retValue.setAddress(m_address ? m_address->address() : QGeoAddress()); retValue.setCoordinate(m_coordinate); retValue.setBoundingBox(m_boundingBox); + retValue.setExtendedAttributes(m_extendedAttributes); return retValue; } diff --git a/src/positioning/qdeclarativegeolocation_p.h b/src/positioningquick/qdeclarativegeolocation_p.h index a02d7b45..2d604ea5 100644 --- a/src/positioning/qdeclarativegeolocation_p.h +++ b/src/positioningquick/qdeclarativegeolocation_p.h @@ -52,13 +52,15 @@ // #include <QtCore/QObject> +#include <QtCore/QVariantMap> #include <QtPositioning/QGeoLocation> #include <QtPositioning/qgeorectangle.h> -#include <QtPositioning/private/qdeclarativegeoaddress_p.h> +#include <QtPositioningQuick/private/qdeclarativegeoaddress_p.h> +#include <QtPositioningQuick/private/qpositioningquickglobal_p.h> QT_BEGIN_NAMESPACE -class Q_POSITIONING_EXPORT QDeclarativeGeoLocation : public QObject +class Q_POSITIONINGQUICK_PRIVATE_EXPORT QDeclarativeGeoLocation : public QObject { Q_OBJECT @@ -66,6 +68,7 @@ class Q_POSITIONING_EXPORT QDeclarativeGeoLocation : public QObject Q_PROPERTY(QDeclarativeGeoAddress *address READ address WRITE setAddress NOTIFY addressChanged) Q_PROPERTY(QGeoCoordinate coordinate READ coordinate WRITE setCoordinate NOTIFY coordinateChanged) Q_PROPERTY(QGeoRectangle boundingBox READ boundingBox WRITE setBoundingBox NOTIFY boundingBoxChanged) + Q_PROPERTY(QVariantMap extendedAttributes MEMBER m_extendedAttributes NOTIFY extendedAttributesChanged REVISION 13) public: explicit QDeclarativeGeoLocation(QObject *parent = 0); @@ -87,11 +90,13 @@ Q_SIGNALS: void addressChanged(); void coordinateChanged(); void boundingBoxChanged(); + void extendedAttributesChanged(); private: - QDeclarativeGeoAddress *m_address; + QDeclarativeGeoAddress *m_address = nullptr; QGeoRectangle m_boundingBox; QGeoCoordinate m_coordinate; + QVariantMap m_extendedAttributes; }; QT_END_NAMESPACE |