diff options
41 files changed, 1025 insertions, 490 deletions
diff --git a/.qmake.conf b/.qmake.conf index 3566a973..0815e3b5 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,3 +2,8 @@ load(qt_build_config) CONFIG += warning_clean MODULE_VERSION = 5.12.0 + +# Adds a way to debug location. The define is needed for multiple subprojects as they +# include the essential headers. +# Alternatively, the define can be passed directly to qmake +# DEFINES+=QT_LOCATION_DEBUG diff --git a/config.tests/winrt/winrt.pro b/config.tests/winrt/winrt.pro index 1476abc9..06c2249e 100644 --- a/config.tests/winrt/winrt.pro +++ b/config.tests/winrt/winrt.pro @@ -1,5 +1,5 @@ SOURCES += main.cpp -win32-msvc201* { +msvc { LIBS += runtimeobject.lib CONFIG += console } diff --git a/src/location/declarativemaps/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp index b0adc54c..63587efe 100644 --- a/src/location/declarativemaps/qdeclarativegeomap.cpp +++ b/src/location/declarativemaps/qdeclarativegeomap.cpp @@ -360,7 +360,7 @@ void QDeclarativeGeoMap::initialize() center.setLatitude(qBound(m_minimumViewportLatitude, center.latitude(), m_maximumViewportLatitude)); cameraData.setCenter(center); - connect(m_map, &QGeoMap::cameraDataChanged, + connect(m_map.data(), &QGeoMap::cameraDataChanged, this, &QDeclarativeGeoMap::onCameraDataChanged); m_map->setCameraData(cameraData); @@ -371,7 +371,7 @@ void QDeclarativeGeoMap::initialize() if (visibleAreaHasChanged) emit visibleAreaChanged(); - connect(m_map, &QGeoMap::visibleAreaChanged, this, &QDeclarativeGeoMap::visibleAreaChanged); + connect(m_map.data(), &QGeoMap::visibleAreaChanged, this, &QDeclarativeGeoMap::visibleAreaChanged); emit mapReadyChanged(true); @@ -657,11 +657,11 @@ void QDeclarativeGeoMap::mappingManagerInitialized() QImage copyrightImage; if (!m_initialized && width() > 0 && height() > 0) { QMetaObject::Connection copyrightStringCatcherConnection = - connect(m_map, + connect(m_map.data(), QOverload<const QString &>::of(&QGeoMap::copyrightsChanged), [©rightString](const QString ©){ copyrightString = copy; }); QMetaObject::Connection copyrightImageCatcherConnection = - connect(m_map, + connect(m_map.data(), QOverload<const QImage &>::of(&QGeoMap::copyrightsChanged), [©rightImage](const QImage ©){ copyrightImage = copy; }); m_map->setViewportSize(QSize(width(), height())); @@ -672,9 +672,9 @@ void QDeclarativeGeoMap::mappingManagerInitialized() /* COPYRIGHT SIGNALS REWIRING */ - connect(m_map, SIGNAL(copyrightsChanged(QImage)), + connect(m_map.data(), SIGNAL(copyrightsChanged(QImage)), this, SIGNAL(copyrightsChanged(QImage))); - connect(m_map, SIGNAL(copyrightsChanged(QString)), + connect(m_map.data(), SIGNAL(copyrightsChanged(QString)), this, SIGNAL(copyrightsChanged(QString))); if (!copyrightString.isEmpty()) emit m_map->copyrightsChanged(copyrightString); @@ -682,8 +682,8 @@ void QDeclarativeGeoMap::mappingManagerInitialized() emit m_map->copyrightsChanged(copyrightImage); - connect(m_map, &QGeoMap::sgNodeChanged, this, &QQuickItem::update); - connect(m_map, &QGeoMap::cameraCapabilitiesChanged, this, &QDeclarativeGeoMap::onCameraCapabilitiesChanged); + connect(m_map.data(), &QGeoMap::sgNodeChanged, this, &QQuickItem::update); + connect(m_map.data(), &QGeoMap::cameraCapabilitiesChanged, this, &QDeclarativeGeoMap::onCameraCapabilitiesChanged); // This prefetches a buffer around the map m_map->prefetchData(); diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp index 4461d2e0..41ab3453 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp @@ -135,8 +135,8 @@ void QDeclarativeGeoMapItemView::classBegin() connect(m_delegateModel, &QQmlInstanceModel::modelUpdated, this, &QDeclarativeGeoMapItemView::modelUpdated); connect(m_delegateModel, &QQmlInstanceModel::createdItem, this, &QDeclarativeGeoMapItemView::createdItem); - connect(m_delegateModel, &QQmlInstanceModel::destroyingItem, this, &QDeclarativeGeoMapItemView::destroyingItem); - connect(m_delegateModel, &QQmlInstanceModel::initItem, this, &QDeclarativeGeoMapItemView::initItem); +// connect(m_delegateModel, &QQmlInstanceModel::destroyingItem, this, &QDeclarativeGeoMapItemView::destroyingItem); +// connect(m_delegateModel, &QQmlInstanceModel::initItem, this, &QDeclarativeGeoMapItemView::initItem); } void QDeclarativeGeoMapItemView::destroyingItem(QObject */*object*/) @@ -156,16 +156,21 @@ void QDeclarativeGeoMapItemView::createdItem(int index, QObject */*object*/) // createdItem is emitted on asynchronous creation. In which case, object has to be invoked again. // See QQmlDelegateModel::object for further info. - if (m_incubationMode == QQmlIncubator::Synchronous) { - qWarning() << "createdItem invoked on Synchronous incubation"; + // DelegateModel apparently triggers this method in any case, that is: + // 1. Synchronous incubation, delegate instantiated on the first object() call (during the object() call!) + // 2. Async incubation, delegate not instantiated on the first object() call + // 3. Async incubation, delegate present in the cache, and returned on the first object() call. + // createdItem also called during the object() call. + if (m_creatingObject) { + // Falling into case 1. or 3. Returning early to prevent double referencing the delegate instance. return; } QQuickItem *item = qobject_cast<QQuickItem *>(m_delegateModel->object(index, m_incubationMode)); if (item) - addDelegateToMap(item, index); + addDelegateToMap(item, index, true); else - qWarning() << "createdItem for " << index << " produced a null item"; + qWarning() << "QQmlDelegateModel:: object called in createdItem for " << index << " produced a null item"; } void QDeclarativeGeoMapItemView::modelUpdated(const QQmlChangeSet &changeSet, bool reset) @@ -189,9 +194,12 @@ void QDeclarativeGeoMapItemView::modelUpdated(const QQmlChangeSet &changeSet, bo } } + QBoolBlocker createBlocker(m_creatingObject, true); for (const QQmlChangeSet::Change &c: changeSet.inserts()) { - for (int idx = c.start(); idx < c.end(); idx++) - addDelegateToMap(qobject_cast<QQuickItem *>(m_delegateModel->object(idx, m_incubationMode)), idx); + for (int idx = c.start(); idx < c.end(); idx++) { + QObject *delegateInstance = m_delegateModel->object(idx, m_incubationMode); + addDelegateToMap(qobject_cast<QQuickItem *>(delegateInstance), idx); + } } fitViewport(); @@ -316,8 +324,11 @@ void QDeclarativeGeoMapItemView::instantiateAllItems() return; // If here, m_delegateModel may contain data, but QQmlInstanceModel::object for each row hasn't been called yet. - for (int i = 0; i < m_delegateModel->count(); i++) - addDelegateToMap(qobject_cast<QQuickItem *>(m_delegateModel->object(i, m_incubationMode)), i); + QBoolBlocker createBlocker(m_creatingObject, true); + for (int i = 0; i < m_delegateModel->count(); i++) { + QObject *delegateInstance = m_delegateModel->object(i, m_incubationMode); + addDelegateToMap(qobject_cast<QQuickItem *>(delegateInstance), i); + } fitViewport(); } @@ -346,15 +357,12 @@ void QDeclarativeGeoMapItemView::removeDelegateFromMap(int index, bool transitio { if (index >= 0 && index < m_instantiatedItems.size()) { QQuickItem *item = m_instantiatedItems.takeAt(index); - if (!item) { - if (m_incubatingItems.contains(index)) { - // cancel request - m_delegateModel->cancel(index); - m_incubatingItems.remove(index); - } + if (!item) { // not yet incubated + // Don't cancel incubation explicitly, as DelegateModel apparently takes care of incubating elements when the model + // remove those indices. return; } - // item can be either a QDeclarativeGeoMapItemBase or a QDeclarativeGeoMapItemGroup + // item can be either a QDeclarativeGeoMapItemBase or a QDeclarativeGeoMapItemGroup (subclass) if (m_exit && m_map && transition) { transitionItemOut(item); } else { @@ -443,16 +451,14 @@ void QDeclarativeGeoMapItemView::exitTransitionFinished() #endif } -void QDeclarativeGeoMapItemView::addItemToMap(QDeclarativeGeoMapItemBase *item, int index) +void QDeclarativeGeoMapItemView::addItemToMap(QDeclarativeGeoMapItemBase *item, int index, bool createdItem) { - if (m_map && item) { // belonging to another map?? - if (item->quickMap() == m_map) - return; - } + if (m_map && item->quickMap() == m_map) // test for *item done in the caller + return; if (m_map) { - insertInstantiatedItem(index, item); + insertInstantiatedItem(index, item, createdItem); item->setParentItem(this); m_map->addMapItem(item); if (m_enter) { @@ -466,23 +472,21 @@ void QDeclarativeGeoMapItemView::addItemToMap(QDeclarativeGeoMapItemBase *item, } } -void QDeclarativeGeoMapItemView::insertInstantiatedItem(int index, QQuickItem *o) +void QDeclarativeGeoMapItemView::insertInstantiatedItem(int index, QQuickItem *o, bool createdItem) { - if (m_incubatingItems.contains(index)) { - m_incubatingItems.remove(index); + if (createdItem) m_instantiatedItems.replace(index, o); - } else { + else m_instantiatedItems.insert(index, o); - } } -void QDeclarativeGeoMapItemView::addItemViewToMap(QDeclarativeGeoMapItemView *item, int index) +void QDeclarativeGeoMapItemView::addItemViewToMap(QDeclarativeGeoMapItemView *item, int index, bool createdItem) { - if (!item || (m_map && item->quickMap() == m_map)) + if (m_map && item->quickMap() == m_map) // test for *item done in the caller return; if (m_map) { - insertInstantiatedItem(index, item); + insertInstantiatedItem(index, item, createdItem); item->setParentItem(this); m_map->addMapItemView(item); if (m_enter) { @@ -496,13 +500,13 @@ void QDeclarativeGeoMapItemView::addItemViewToMap(QDeclarativeGeoMapItemView *it } } -void QDeclarativeGeoMapItemView::addItemGroupToMap(QDeclarativeGeoMapItemGroup *item, int index) +void QDeclarativeGeoMapItemView::addItemGroupToMap(QDeclarativeGeoMapItemGroup *item, int index, bool createdItem) { - if (!item || (m_map && item->quickMap() == m_map)) + if (m_map && item->quickMap() == m_map) // test for *item done in the caller return; if (m_map) { - insertInstantiatedItem(index, item); + insertInstantiatedItem(index, item, createdItem); item->setParentItem(this); m_map->addMapItemGroup(item); if (m_enter) { @@ -516,28 +520,29 @@ void QDeclarativeGeoMapItemView::addItemGroupToMap(QDeclarativeGeoMapItemGroup * } } -void QDeclarativeGeoMapItemView::addDelegateToMap(QQuickItem *object, int index) +void QDeclarativeGeoMapItemView::addDelegateToMap(QQuickItem *object, int index, bool createdItem) { if (!object) { - m_incubatingItems.insert(index); - m_instantiatedItems.insert(index, nullptr); + if (!createdItem) + m_instantiatedItems.insert(index, nullptr); // insert placeholder return; } QDeclarativeGeoMapItemBase *item = qobject_cast<QDeclarativeGeoMapItemBase *>(object); if (item) { // else createdItem will be emitted. - addItemToMap(item, index); + addItemToMap(item, index, createdItem); return; } QDeclarativeGeoMapItemView *view = qobject_cast<QDeclarativeGeoMapItemView *>(object); if (view) { - addItemViewToMap(view, index); + addItemViewToMap(view, index, createdItem); return; } QDeclarativeGeoMapItemGroup *group = qobject_cast<QDeclarativeGeoMapItemGroup *>(object); if (group) { - addItemGroupToMap(group, index); + addItemGroupToMap(group, index, createdItem); return; } + qWarning() << "addDelegateToMap called with a "<< object->metaObject()->className(); } QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h index 58ef2835..43ca685a 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h +++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h @@ -131,11 +131,11 @@ private: void removeDelegateFromMap(QQuickItem *o); void transitionItemOut(QQuickItem *o); - void insertInstantiatedItem(int index, QQuickItem *o); - void addItemToMap(QDeclarativeGeoMapItemBase *item, int index); - void addItemViewToMap(QDeclarativeGeoMapItemView *item, int index); - void addItemGroupToMap(QDeclarativeGeoMapItemGroup *item, int index); - void addDelegateToMap(QQuickItem *object, int index); + void insertInstantiatedItem(int index, QQuickItem *o, bool createdItem); + void addItemToMap(QDeclarativeGeoMapItemBase *item, int index, bool createdItem); + void addItemViewToMap(QDeclarativeGeoMapItemView *item, int index, bool createdItem); + void addItemGroupToMap(QDeclarativeGeoMapItemGroup *item, int index, bool createdItem); + void addDelegateToMap(QQuickItem *object, int index, bool createdItem = false); bool m_componentCompleted; QQmlIncubator::IncubationMode m_incubationMode = QQmlIncubator::Asynchronous; @@ -143,8 +143,8 @@ private: QVariant m_itemModel; QDeclarativeGeoMap *m_map; QList<QQuickItem *> m_instantiatedItems; - QSet<int> m_incubatingItems; bool m_fitViewport; + bool m_creatingObject = false; QQmlDelegateModel *m_delegateModel; QQuickTransition *m_enter = nullptr; QQuickTransition *m_exit = nullptr; diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp index 70b4bc21..2fb3098d 100644 --- a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp +++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp @@ -398,9 +398,13 @@ QList<QList<QDoubleVector2D> > QGeoMapPolylineGeometry::clipPath(const QGeoMap & wrappedPath.append(wrappedProjection); } +#ifdef QT_LOCATION_DEBUG + m_wrappedPath = wrappedPath; +#endif + // 2) QList<QList<QDoubleVector2D> > clippedPaths; - const QList<QDoubleVector2D> &visibleRegion = p.visibleGeometryExpanded(); + const QList<QDoubleVector2D> &visibleRegion = p.projectableGeometry(); if (visibleRegion.size()) { clippedPaths = clipLine(wrappedPath, visibleRegion); @@ -428,6 +432,10 @@ QList<QList<QDoubleVector2D> > QGeoMapPolylineGeometry::clipPath(const QGeoMap & clippedPaths.append(wrappedPath); } +#ifdef QT_LOCATION_DEBUG + m_clippedPaths = clippedPaths; +#endif + return clippedPaths; } @@ -441,14 +449,12 @@ void QGeoMapPolylineGeometry::pathToScreen(const QGeoMap &map, double minY = qInf(); double maxX = -qInf(); double maxY = -qInf(); - srcOrigin_ = p.mapProjectionToGeo(p.unwrapMapProjection(leftBoundWrapped)); QDoubleVector2D origin = p.wrappedMapProjectionToItemPosition(leftBoundWrapped); for (const QList<QDoubleVector2D> &path: clippedPaths) { QDoubleVector2D lastAddedPoint; for (int i = 0; i < path.size(); ++i) { QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(path.at(i)); - point = point - origin; // (0,0) if point == geoLeftBound_ minX = qMin(point.x(), minX); @@ -507,6 +513,120 @@ void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map, pathToScreen(map, clippedPaths, leftBoundWrapped); } +// *** SCREEN CLIPPING *** // + +enum ClipPointType { + InsidePoint = 0x00, + LeftPoint = 0x01, + RightPoint = 0x02, + BottomPoint = 0x04, + TopPoint = 0x08 +}; + +static inline int clipPointType(qreal x, qreal y, const QRectF &rect) +{ + int type = InsidePoint; + if (x < rect.left()) + type |= LeftPoint; + else if (x > rect.right()) + type |= RightPoint; + if (y < rect.top()) + type |= TopPoint; + else if (y > rect.bottom()) + type |= BottomPoint; + return type; +} + +static void clipSegmentToRect(qreal x0, qreal y0, qreal x1, qreal y1, + const QRectF &clipRect, + QVector<qreal> &outPoints, + QVector<QPainterPath::ElementType> &outTypes) +{ + int type0 = clipPointType(x0, y0, clipRect); + int type1 = clipPointType(x1, y1, clipRect); + bool accept = false; + + while (true) { + if (!(type0 | type1)) { + accept = true; + break; + } else if (type0 & type1) { + break; + } else { + qreal x = 0.0; + qreal y = 0.0; + int outsideType = type0 ? type0 : type1; + + if (outsideType & BottomPoint) { + x = x0 + (x1 - x0) * (clipRect.bottom() - y0) / (y1 - y0); + y = clipRect.bottom() - 0.1; + } else if (outsideType & TopPoint) { + x = x0 + (x1 - x0) * (clipRect.top() - y0) / (y1 - y0); + y = clipRect.top() + 0.1; + } else if (outsideType & RightPoint) { + y = y0 + (y1 - y0) * (clipRect.right() - x0) / (x1 - x0); + x = clipRect.right() - 0.1; + } else if (outsideType & LeftPoint) { + y = y0 + (y1 - y0) * (clipRect.left() - x0) / (x1 - x0); + x = clipRect.left() + 0.1; + } + + if (outsideType == type0) { + x0 = x; + y0 = y; + type0 = clipPointType(x0, y0, clipRect); + } else { + x1 = x; + y1 = y; + type1 = clipPointType(x1, y1, clipRect); + } + } + } + + if (accept) { + if (outPoints.size() >= 2) { + qreal lastX, lastY; + lastY = outPoints.at(outPoints.size() - 1); + lastX = outPoints.at(outPoints.size() - 2); + + if (!qFuzzyCompare(lastY, y0) || !qFuzzyCompare(lastX, x0)) { + outTypes << QPainterPath::MoveToElement; + outPoints << x0 << y0; + } + } else { + outTypes << QPainterPath::MoveToElement; + outPoints << x0 << y0; + } + + outTypes << QPainterPath::LineToElement; + outPoints << x1 << y1; + } +} + +static void clipPathToRect(const QVector<qreal> &points, + const QVector<QPainterPath::ElementType> &types, + const QRectF &clipRect, + QVector<qreal> &outPoints, + QVector<QPainterPath::ElementType> &outTypes) +{ + outPoints.clear(); + outPoints.reserve(points.size()); + outTypes.clear(); + outTypes.reserve(types.size()); + + qreal lastX = 0; + qreal lastY = 0; // or else used uninitialized + for (int i = 0; i < types.size(); ++i) { + if (i > 0 && types[i] != QPainterPath::MoveToElement) { + qreal x = points[i * 2], y = points[i * 2 + 1]; + clipSegmentToRect(lastX, lastY, x, y, clipRect, outPoints, outTypes); + } + + lastX = points[i * 2]; + lastY = points[i * 2 + 1]; + } +} + //////////////////////////////////////////////////////////////////////////// /*! @@ -526,9 +646,24 @@ void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map, return; } - // The geometry has already been clipped against the visible region projection in wrapped mercator space. - QVector<qreal> points = srcPoints_; - QVector<QPainterPath::ElementType> types = srcPointTypes_; + // Create the viewport rect in the same coordinate system + // as the actual points + QRectF viewport(0, 0, map.viewportWidth(), map.viewportHeight()); + viewport.adjust(-strokeWidth, -strokeWidth, strokeWidth, strokeWidth); + viewport.translate(-1 * origin); + + QVector<qreal> points; + QVector<QPainterPath::ElementType> types; + + if (clipToViewport_) { + // Although the geometry has already been clipped against the visible region in wrapped mercator space. + // This is currently still needed to prevent a number of artifacts deriving from QTriangulatingStroker processing + // very large lines (that is, polylines that span many pixels in screen space) + clipPathToRect(srcPoints_, srcPointTypes_, viewport, points, types); + } else { + points = srcPoints_; + types = srcPointTypes_; + } QVectorPath vp(points.data(), types.size(), types.data()); QTriangulatingStroker ts; diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h index 392841dd..1105bb13 100644 --- a/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h +++ b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h @@ -48,6 +48,7 @@ // We mean it. // +#include <QtLocation/private/qlocationglobal_p.h> #include <QtLocation/private/qdeclarativegeomapitembase_p.h> #include <QtLocation/private/qgeomapitemgeometry_p.h> @@ -110,10 +111,15 @@ public: const QList<QList<QDoubleVector2D> > &clippedPaths, const QDoubleVector2D &leftBoundWrapped); -private: +public: QVector<qreal> srcPoints_; QVector<QPainterPath::ElementType> srcPointTypes_; +#ifdef QT_LOCATION_DEBUG + QList<QDoubleVector2D> m_wrappedPath; + QList<QList<QDoubleVector2D>> m_clippedPaths; +#endif + friend class QDeclarativeCircleMapItem; friend class QDeclarativePolygonMapItem; friend class QDeclarativeRectangleMapItem; @@ -171,6 +177,9 @@ private: void regenerateCache(); void updateCache(); +#ifdef QT_LOCATION_DEBUG +public: +#endif QGeoPath geopath_; QList<QDoubleVector2D> geopathProjected_; QDeclarativeMapLineProperties line_; diff --git a/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp index b7c6e319..3bc45c4f 100644 --- a/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp +++ b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp @@ -39,6 +39,7 @@ #include "qdeclarativeplaceicon_p.h" #include "qgeoserviceprovider.h" #include "error_messages_p.h" +#include <QtCore/private/qobject_p.h> #include <QCoreApplication> #include <QtQml/QQmlInfo> @@ -121,6 +122,15 @@ QT_BEGIN_NAMESPACE */ /*! + \qmlmethod void QtLocation::CategoryModel::update() + \internal + + Updates the model. + + \note The CategoryModel auto updates automatically when needed. Calling this method explicitly is normally not necessary. +*/ + +/*! \internal \enum QDeclarativeSupportedCategoriesModel::Roles */ @@ -143,6 +153,8 @@ QDeclarativeSupportedCategoriesModel::~QDeclarativeSupportedCategoriesModel() void QDeclarativeSupportedCategoriesModel::componentComplete() { m_complete = true; + if (m_plugin) // do not try to load or change status when trying to update in componentComplete() if the plugin hasn't been set yet even once. + update(); } /*! @@ -255,6 +267,7 @@ void QDeclarativeSupportedCategoriesModel::setPlugin(QDeclarativeGeoServiceProvi //disconnect the manager of the old plugin if we have one if (m_plugin) { + disconnect(m_plugin, nullptr, this, nullptr); QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); if (serviceProvider) { QPlaceManager *placeManager = serviceProvider->placeManager(); @@ -273,14 +286,17 @@ void QDeclarativeSupportedCategoriesModel::setPlugin(QDeclarativeGeoServiceProvi m_plugin = plugin; - // handle plugin name changes -> update categories + // handle plugin attached changes -> update categories if (m_plugin) { - connect(m_plugin, SIGNAL(nameChanged(QString)), this, SLOT(connectNotificationSignals())); - connect(m_plugin, SIGNAL(nameChanged(QString)), this, SLOT(update())); + if (m_plugin->isAttached()) { + connectNotificationSignals(); + update(); + } else { + connect(m_plugin, &QDeclarativeGeoServiceProvider::attached, this, &QDeclarativeSupportedCategoriesModel::update); + connect(m_plugin, &QDeclarativeGeoServiceProvider::attached, this, &QDeclarativeSupportedCategoriesModel::connectNotificationSignals); + } } - connectNotificationSignals(); - if (m_complete) emit pluginChanged(); } @@ -499,6 +515,9 @@ void QDeclarativeSupportedCategoriesModel::connectNotificationSignals() */ void QDeclarativeSupportedCategoriesModel::update() { + if (!m_complete) + return; + if (m_response) return; diff --git a/src/location/doc/src/plugins/mapboxgl.qdoc b/src/location/doc/src/plugins/mapboxgl.qdoc index 51b49f93..b1d721bf 100644 --- a/src/location/doc/src/plugins/mapboxgl.qdoc +++ b/src/location/doc/src/plugins/mapboxgl.qdoc @@ -88,6 +88,11 @@ The following table lists optional parameters that can be passed to the Mapbox p \l{https://www.mapbox.com/tos}{Terms of Services} and must not be used in production. This property has no effect on styles hosted outside the Mapbox servers. \row + \li mapboxgl.china + \li Use Mapbox China API base URLs and styles. + Please notice that Mapbox China requires a specific access token. Contact \l + {https://www.mapbox.com/contact/sales/} {Mapbox sales} for more information. +\row \li mapboxgl.mapping.additional_style_urls \li Additional, comma separated, Mapbox \l{https://www.mapbox.com/help/define-style-url} {style URLs} to be added to the available style URLs. Additional styles will be prepended to diff --git a/src/location/doc/src/qtlocation-qml.qdoc b/src/location/doc/src/qtlocation-qml.qdoc index 38f43ef1..90f19c5a 100644 --- a/src/location/doc/src/qtlocation-qml.qdoc +++ b/src/location/doc/src/qtlocation-qml.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -26,83 +26,103 @@ ****************************************************************************/ /*! - \qmlmodule QtLocation 5.11 + \qmlmodule QtLocation \QtVer \title Qt Location QML Types \ingroup qmlmodules - \brief Provides QML types for mapping and location information + \brief Provides QML types for mapping and location information. -\section1 Overview + \section1 Overview -Provided that a position has been obtained, this module can add a -\l{QtLocation::Map}{Map} with Places of Interest (POI) and -\l{QtLocation::Place}{Places}. The user can be made aware of nearby features -and related information, displayed graphically. Features on the \l Map can be -places of business, entertainment, and so on. They may include paths, roads, -or forms of transport, enabling navigation optimization and assistance. + Provided that a position has been obtained, the Qt Location module + can add a \l{QtLocation::}{Map} with Places of Interest (POI) and + \l{QtLocation::Place}{Places}. The user can be made aware of nearby + features and related information, displayed on the map. These features + can be places of business, entertainment, and so on. They may include + paths, roads, or forms of transport, enabling navigation optimization + and assistance. -To perform navigation we need \l {Route}s from start to destination. These routes -are made up of segments, where each \l {QtLocation::RouteSegment}{RouteSegment} -can be considered a navigation subtask: drive 100 meters, turn left. The beginning and -end of each segment is a \e waypoint, that is, one part of our journey. + To perform navigation we need \l {Route}s from start to destination. + These routes are made up of segments, where each \l {QtLocation::} + {RouteSegment} can be considered a navigation subtask; for example, + "drive 100 meters", or "turn left". The beginning and end of each + segment is a \e waypoint, that is, one part of the journey. -A typical use case for the API is a user looking for a particular type of -place, say a restaurant. The user could enter a search string into the map -application and respond to a list or display of results for restaurants -"near" the device. The application could then be used to navigate to the -restaurant using an optimized route that is aware of features in the -environment that can help or hinder the journey. The navigation then -proceeds with the user's progress monitored by means of the current -\l Location. In the context of this API the map application would be aware -of the location and size of various places and the location of the user. -Plugins would supply the data required by the application to determine routes -and navigation instructions. The \l Place types would hold information about the -destination and surrounding objects including displayable representations. -The \l Map type would enable this information to be displayed, panned, -zoomed and so on. The \l Route would be determined by a plugin with each -\l RouteSegment holding the navigation instructions guided by the updated -current \l Location. + A typical use case for the API is a user looking for a particular type of + place, such as a restaurant; the user enters a search string into the map + application and is presented with a list of results for restaurants + "near" the device. The application can then be used to navigate to the + chosen destination using a route that is optimized according to features + in the environment that may help or hinder the journey. The navigation then + proceeds with the user's progress monitored by means of the current + location. -\l {Plugin}s are a means of specifying which location-based service to use. For -example, a plugin may allow connection to a provider's service that provides -geocoding and routing information, which can be consumed by the application. -There may be various GeoServices plugins for various tasks with some plugins -providing more than one service. One QML \l Plugin must be created for each -required GeoService plugin. Plugins are required for maps, routing and geocoding, -and places, however the default plugin handles all four of these services. A plugin may -require online access or may support on-board maps and data. + In short, the main QML types and their roles are as follows: -\note Plugins may not provide features such as paging or relevance hints. + \list -The following links provide more detailed information about maps and places: + \li The \l [QML] Place instances hold information about the + destination and surrounding objects, including displayable + representations. -\table - \row - \li \l {Maps and Navigation (QML)}{Maps and Navigation} - \li Displaying maps and finding routes. - \row - \li \l {QML PLaces API} {Places} - \li Searching for and managing points of interest. -\endtable + \li The \l [QML] Map enables the information contained in + \l [QML] {Place} objects to be displayed, panned, zoomed, + and so on. -\section1 Common QML Types + \li The \l [QML] Route is be determined by a \e plugin, with each + \l [QML] RouteSegment holding the navigation instructions, + guided by the continuously updated current \l [QML] Location. -\annotatedlist qml-QtLocation5-common + \endlist -\section1 Maps QML Types + \section2 Plugins -\annotatedlist qml-QtLocation5-maps + \l {Plugin}s supply the data required to calculate routes and navigation + instructions, and they are typically tied to a specific location-based + service. For example, a plugin may allow connecting to a service that + provides geocoding and routing information, which can be consumed by the + application. -\section1 Navigation and Routing QML Types + There may be various GeoServices plugins for various tasks, with some + plugins providing more than one service. One QML \l Plugin instance must + be created for each GeoService plugin. Plugins are required for routing + and geocoding, maps, and places, however the default plugin handles all + four of these services. A plugin may require online access or it may + support on-board maps and data. -\annotatedlist qml-QtLocation5-routing + \note Plugins may not provide features such as paging or relevance hints. -\section1 Geocoding QML Types + \section2 Related Information -\annotatedlist qml-QtLocation5-geocoding + The following links provide more information about maps and places: -\section1 Places QML Types + \table + \row + \li \l {Maps and Navigation (QML)}{Maps and Navigation} + \li Displaying maps and finding routes + \row + \li \l {QML Places API} {Places} + \li Searching for and managing points of interest + \endtable -\annotatedlist qml-QtLocation5-places + \section1 Common QML Types -\section1 Alphabetical Listing of All QML Types + \annotatedlist qml-QtLocation5-common + + \section1 Maps QML Types + + \annotatedlist qml-QtLocation5-maps + + \section1 Navigation and Routing QML Types + + \annotatedlist qml-QtLocation5-routing + + \section1 Geocoding QML Types + + \annotatedlist qml-QtLocation5-geocoding + + \section1 Places QML Types + + \annotatedlist qml-QtLocation5-places + + \section1 Alphabetical Listing of All QML Types */ diff --git a/src/location/doc/src/qtlocation.qdoc b/src/location/doc/src/qtlocation.qdoc index 77c2cd99..059d03f2 100644 --- a/src/location/doc/src/qtlocation.qdoc +++ b/src/location/doc/src/qtlocation.qdoc @@ -87,10 +87,10 @@ The Qt Location API enables you to: To load the Qt Location module, add the following statement to your .qml files -\code - import QtPositioning 5.11 - import QtLocation 5.11 -\endcode +\qml \QtVer +import QtPositioning \1 +import QtLocation \1 +\endqml The QtLocation QML module depends on the QtPositioning QML module. Therefore every QML application that imports the QtLocation QML module must always diff --git a/src/location/labs/qdeclarativenavigator.cpp b/src/location/labs/qdeclarativenavigator.cpp index b06681d9..0bf5035f 100644 --- a/src/location/labs/qdeclarativenavigator.cpp +++ b/src/location/labs/qdeclarativenavigator.cpp @@ -296,15 +296,15 @@ bool QDeclarativeNavigator::navigatorReady() const bool QDeclarativeNavigator::trackPositionSource() const { - return d_ptr->m_trackPositionSource; + return d_ptr->m_params->m_trackPositionSource; } void QDeclarativeNavigator::setTrackPositionSource(bool trackPositionSource) { - if (trackPositionSource == d_ptr->m_trackPositionSource) + if (trackPositionSource == d_ptr->m_params->m_trackPositionSource) return; - d_ptr->m_trackPositionSource = trackPositionSource; + d_ptr->m_params->m_trackPositionSource = trackPositionSource; emit trackPositionSourceChanged(trackPositionSource); } @@ -414,6 +414,7 @@ bool QDeclarativeNavigator::ensureEngine() d_ptr->m_active = active; emit activeChanged(active); }); + connect(this, &QDeclarativeNavigator::trackPositionSourceChanged, d_ptr->m_navigator.get(), &QAbstractNavigator::setTrackPosition); emit navigatorReadyChanged(true); return true; } diff --git a/src/location/labs/qdeclarativenavigator_p_p.h b/src/location/labs/qdeclarativenavigator_p_p.h index 6c07a0ca..229ead1e 100644 --- a/src/location/labs/qdeclarativenavigator_p_p.h +++ b/src/location/labs/qdeclarativenavigator_p_p.h @@ -73,6 +73,7 @@ public: QGeoRoute m_geoRoute; QPointer<QDeclarativePositionSource> m_positionSource; QList<QPointer<QGeoMapParameter>> m_parameters; + bool m_trackPositionSource = true; }; class QDeclarativeNavigatorPrivate @@ -90,7 +91,6 @@ public: bool m_active = false; bool m_completed = false; bool m_ready = false; - bool m_trackPositionSource = true; }; QT_END_NAMESPACE diff --git a/src/location/maps/maps.pri b/src/location/maps/maps.pri index b5be4601..68e80442 100644 --- a/src/location/maps/maps.pri +++ b/src/location/maps/maps.pri @@ -62,6 +62,8 @@ PRIVATE_HEADERS += \ maps/qgeoprojection_p.h \ maps/qnavigationmanagerengine_p.h \ maps/qnavigationmanager_p.h \ + maps/qgeocameratiles_p_p.h \ + maps/qgeotiledmapscene_p_p.h \ maps/qcache3q_p.h SOURCES += \ @@ -100,3 +102,4 @@ SOURCES += \ maps/qnavigationmanagerengine.cpp \ maps/qnavigationmanager.cpp \ maps/qgeoprojection.cpp + diff --git a/src/location/maps/qgeocameratiles.cpp b/src/location/maps/qgeocameratiles.cpp index b7eac306..3a2732b2 100644 --- a/src/location/maps/qgeocameratiles.cpp +++ b/src/location/maps/qgeocameratiles.cpp @@ -34,6 +34,7 @@ ** ****************************************************************************/ #include "qgeocameratiles_p.h" +#include "qgeocameratiles_p_p.h" #include "qgeocameradata_p.h" #include "qgeotilespec_p.h" #include "qgeomaptype_p.h" @@ -63,76 +64,6 @@ static QDoubleVector3D toDoubleVector3D(const QVector3D& in) QT_BEGIN_NAMESPACE -struct Frustum -{ - QDoubleVector3D apex; - QDoubleVector3D topLeftNear; - QDoubleVector3D topLeftFar; - QDoubleVector3D topRightNear; - QDoubleVector3D topRightFar; - QDoubleVector3D bottomLeftNear; - QDoubleVector3D bottomLeftFar; - QDoubleVector3D bottomRightNear; - QDoubleVector3D bottomRightFar; -}; - -typedef QVector<QDoubleVector3D> PolygonVector; - -class QGeoCameraTilesPrivate -{ -public: - QGeoCameraTilesPrivate(); - ~QGeoCameraTilesPrivate(); - - QString m_pluginString; - QGeoMapType m_mapType; - int m_mapVersion; - QGeoCameraData m_camera; - QSize m_screenSize; - QRectF m_visibleArea; - int m_tileSize; - QSet<QGeoTileSpec> m_tiles; - - int m_intZoomLevel; - int m_sideLength; - - bool m_dirtyGeometry; - bool m_dirtyMetadata; - - double m_viewExpansion; - void updateMetadata(); - void updateGeometry(); - - Frustum createFrustum(double viewExpansion) const; - - struct ClippedFootprint - { - ClippedFootprint(const PolygonVector &left_, const PolygonVector &mid_, const PolygonVector &right_) - : left(left_), mid(mid_), right(right_) - {} - PolygonVector left; - PolygonVector mid; - PolygonVector right; - }; - - PolygonVector frustumFootprint(const Frustum &frustum) const; - - QPair<PolygonVector, PolygonVector> splitPolygonAtAxisValue(const PolygonVector &polygon, int axis, double value) const; - ClippedFootprint clipFootprintToMap(const PolygonVector &footprint) const; - - QList<QPair<double, int> > tileIntersections(double p1, int t1, double p2, int t2) const; - QSet<QGeoTileSpec> tilesFromPolygon(const PolygonVector &polygon) const; - - struct TileMap - { - TileMap(); - - void add(int tileX, int tileY); - - QMap<int, QPair<int, int> > data; - }; -}; - QGeoCameraTiles::QGeoCameraTiles() : d_ptr(new QGeoCameraTilesPrivate()) {} @@ -277,12 +208,22 @@ void QGeoCameraTilesPrivate::updateGeometry() // Find the frustum from the camera / screen / viewport information // The larger frustum when stationary is a form of prefetching Frustum f = createFrustum(m_viewExpansion); +#ifdef QT_LOCATION_DEBUG + m_frustum = f; +#endif // Find the polygon where the frustum intersects the plane of the map PolygonVector footprint = frustumFootprint(f); +#ifdef QT_LOCATION_DEBUG + m_frustumFootprint = footprint; +#endif // Clip the polygon to the map, split it up if it cross the dateline ClippedFootprint polygons = clipFootprintToMap(footprint); +#ifdef QT_LOCATION_DEBUG + m_clippedFootprint = polygons; +#endif + if (!polygons.left.isEmpty()) { QSet<QGeoTileSpec> tilesLeft = tilesFromPolygon(polygons.left); @@ -306,6 +247,10 @@ Frustum QGeoCameraTilesPrivate::createFrustum(double viewExpansion) const if (m_camera.fieldOfView() != 90.0) //aperture(90 / 2) = 1 apertureSize = tan(QLocationUtils::radians(m_camera.fieldOfView()) * 0.5); QDoubleVector3D center = m_sideLength * QWebMercator::coordToMercator(m_camera.center()); +#ifdef QT_LOCATION_DEBUG + m_createFrustum_center = center; +#endif + double f = m_screenSize.height(); @@ -335,7 +280,7 @@ Frustum QGeoCameraTilesPrivate::createFrustum(double viewExpansion) const side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0)); up = QDoubleVector3D::normal(view, side2); - double nearPlane = 1 / (4.0 * m_tileSize ); + double nearPlane = 1.0 / 32.0; // The denominator used to be (4.0 * m_tileSize ), which produces an extremely narrow and tiny near plane. // farPlane plays a role on how much gets clipped when the map gets tilted. It used to be altitude + 1.0 // The value of 8.0 has been chosen as an acceptable compromise. // TODO: use m_camera.clipDistance(); when this will be introduced @@ -367,6 +312,9 @@ Frustum QGeoCameraTilesPrivate::createFrustum(double viewExpansion) const Frustum frustum; frustum.apex = eye; +#ifdef QT_LOCATION_DEBUG + m_createFrustum_eye = eye; +#endif QRectF va = m_visibleArea; if (va.isNull()) diff --git a/src/location/maps/qgeocameratiles_p.h b/src/location/maps/qgeocameratiles_p.h index f95db44d..4b6f3234 100644 --- a/src/location/maps/qgeocameratiles_p.h +++ b/src/location/maps/qgeocameratiles_p.h @@ -79,6 +79,8 @@ public: protected: QScopedPointer<QGeoCameraTilesPrivate> d_ptr; + + friend class QGeoCameraTilesPrivate; Q_DISABLE_COPY(QGeoCameraTiles) }; diff --git a/src/location/maps/qgeocameratiles_p_p.h b/src/location/maps/qgeocameratiles_p_p.h new file mode 100644 index 00000000..846d95f2 --- /dev/null +++ b/src/location/maps/qgeocameratiles_p_p.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtLocation module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QGEOCAMERATILES_P_P_H +#define QGEOCAMERATILES_P_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 "qgeocameratiles_p.h" +#include <QtPositioning/private/qwebmercator_p.h> +#include <QtPositioning/private/qdoublevector2d_p.h> +#include <QtPositioning/private/qdoublevector3d_p.h> +#include "qgeomaptype_p.h" +#include "qgeocameradata_p.h" +#include "qgeotilespec_p.h" + +#include <QtCore/qvector.h> +#include <QtCore/qset.h> + +QT_BEGIN_NAMESPACE + +struct Q_LOCATION_PRIVATE_EXPORT Frustum +{ + QDoubleVector3D apex; + QDoubleVector3D topLeftNear; + QDoubleVector3D topLeftFar; + QDoubleVector3D topRightNear; + QDoubleVector3D topRightFar; + QDoubleVector3D bottomLeftNear; + QDoubleVector3D bottomLeftFar; + QDoubleVector3D bottomRightNear; + QDoubleVector3D bottomRightFar; +}; + +typedef QVector<QDoubleVector3D> PolygonVector; + +class Q_LOCATION_PRIVATE_EXPORT QGeoCameraTilesPrivate +{ +public: + struct ClippedFootprint + { + ClippedFootprint() + {} + ClippedFootprint(const PolygonVector &left_, const PolygonVector &mid_, const PolygonVector &right_) + : left(left_), mid(mid_), right(right_) + {} + PolygonVector left; + PolygonVector mid; + PolygonVector right; + }; + + struct TileMap + { + TileMap(); + + void add(int tileX, int tileY); + + QMap<int, QPair<int, int> > data; + }; + + QGeoCameraTilesPrivate(); + ~QGeoCameraTilesPrivate(); + + + void updateMetadata(); + void updateGeometry(); + + Frustum createFrustum(double viewExpansion) const; + PolygonVector frustumFootprint(const Frustum &frustum) const; + + QPair<PolygonVector, PolygonVector> splitPolygonAtAxisValue(const PolygonVector &polygon, int axis, double value) const; + ClippedFootprint clipFootprintToMap(const PolygonVector &footprint) const; + + QList<QPair<double, int> > tileIntersections(double p1, int t1, double p2, int t2) const; + QSet<QGeoTileSpec> tilesFromPolygon(const PolygonVector &polygon) const; + + static QGeoCameraTilesPrivate *get(QGeoCameraTiles *o) { + return o->d_ptr.data(); + } + +public: + QString m_pluginString; + QGeoMapType m_mapType; + int m_mapVersion; + QGeoCameraData m_camera; + QSize m_screenSize; + QRectF m_visibleArea; + int m_tileSize; + QSet<QGeoTileSpec> m_tiles; + + int m_intZoomLevel; + int m_sideLength; + bool m_dirtyGeometry; + bool m_dirtyMetadata; + double m_viewExpansion; + +#ifdef QT_LOCATION_DEBUG + // updateGeometry + ClippedFootprint m_clippedFootprint; + PolygonVector m_frustumFootprint; + Frustum m_frustum; + + // createFrustum + mutable QDoubleVector3D m_createFrustum_center; + mutable QDoubleVector3D m_createFrustum_eye; +#endif +}; + +QT_END_NAMESPACE + +#endif // QGEOCAMERATILES_P_P_H diff --git a/src/location/maps/qgeomap_p.h b/src/location/maps/qgeomap_p.h index f19f847a..874b300f 100644 --- a/src/location/maps/qgeomap_p.h +++ b/src/location/maps/qgeomap_p.h @@ -177,7 +177,6 @@ Q_SIGNALS: private: Q_DISABLE_COPY(QGeoMap) friend class QDeclarativeGeoMap; //updateSceneGraph - friend class QGeoMapPrivate; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QGeoMap::ItemTypes) diff --git a/src/location/maps/qgeomap_p_p.h b/src/location/maps/qgeomap_p_p.h index 7bda316d..331697b2 100644 --- a/src/location/maps/qgeomap_p_p.h +++ b/src/location/maps/qgeomap_p_p.h @@ -110,7 +110,11 @@ protected: QRectF clampVisibleArea(const QRectF &visibleArea) const; +#ifdef QT_LOCATION_DEBUG +public: +#else protected: +#endif QSize m_viewportSize; QGeoProjection *m_geoProjection; QPointer<QGeoMappingManagerEngine> m_engine; diff --git a/src/location/maps/qgeoprojection.cpp b/src/location/maps/qgeoprojection.cpp index a456f80e..0fdb5f0b 100644 --- a/src/location/maps/qgeoprojection.cpp +++ b/src/location/maps/qgeoprojection.cpp @@ -164,7 +164,7 @@ QGeoProjectionWebMercator::QGeoProjectionWebMercator() m_viewportHeight(1), m_1_viewportWidth(0), m_1_viewportHeight(0), - m_sideLength(256), + m_sideLengthPixels(256), m_aperture(0.0), m_nearPlane(0.0), m_farPlane(0.0), @@ -389,7 +389,7 @@ QMatrix4x4 QGeoProjectionWebMercator::quickItemTransformation(const QGeoCoordina const QDoubleVector2D anchorMercator = anchorScaled / mapWidth(); const QDoubleVector2D coordAnchored = coordWrapped - anchorMercator; - const QDoubleVector2D coordAnchoredScaled = coordAnchored * m_sideLength; + const QDoubleVector2D coordAnchoredScaled = coordAnchored * m_sideLengthPixels; QDoubleMatrix4x4 matTranslateScale; matTranslateScale.translate(coordAnchoredScaled.x(), coordAnchoredScaled.y(), 0.0); @@ -416,7 +416,7 @@ bool QGeoProjectionWebMercator::isProjectable(const QDoubleVector2D &wrappedProj if (m_cameraData.tilt() == 0.0) return true; - QDoubleVector3D pos = wrappedProjection * m_sideLength; + QDoubleVector3D pos = wrappedProjection * m_sideLengthPixels; // use m_centerNearPlane in order to add an offset to m_eye. QDoubleVector3D p = m_centerNearPlane - pos; double dot = QDoubleVector3D::dotProduct(p , m_viewNormalized); @@ -491,7 +491,7 @@ QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(const QDoubleVector3D ray = m_eye - p; ray.normalize(); - return (xyPlane.lineIntersection(m_eye, ray, s) / m_sideLength).toVector2D(); + return (xyPlane.lineIntersection(m_eye, ray, s) / m_sideLengthPixels).toVector2D(); } /* @@ -552,8 +552,8 @@ void QGeoProjectionWebMercator::setupCamera() m_cameraCenterYMercator = m_centerMercator.y(); int intZoomLevel = static_cast<int>(std::floor(m_cameraData.zoomLevel())); - m_sideLength = (1 << intZoomLevel) * defaultTileSize; - m_center = m_centerMercator * m_sideLength; + m_sideLengthPixels = (1 << intZoomLevel) * defaultTileSize; + m_center = m_centerMercator * m_sideLengthPixels; //aperture(90 / 2) = 1 m_aperture = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5); @@ -624,7 +624,8 @@ void QGeoProjectionWebMercator::setupCamera() m_viewMercator = m_eyeMercator - m_centerMercator; m_upMercator = QDoubleVector3D::normal(m_viewMercator, m_sideMercator); - m_nearPlaneMercator = 1.0 / m_sideLength; + m_nearPlaneMercator = 0.000002; // this value works until ZL 18. Above that, a better progressive formula is needed, or + // else, this clips too much. double aspectRatio = 1.0 * m_viewportWidth / m_viewportHeight; @@ -657,7 +658,7 @@ void QGeoProjectionWebMercator::setupCamera() m_transformation = matScreenTransformation * projectionMatrix * cameraMatrix; m_quickItemTransformation = m_transformation; - m_transformation.scale(m_sideLength, m_sideLength, 1.0); + m_transformation.scale(m_sideLengthPixels, m_sideLengthPixels, 1.0); m_centerNearPlane = m_eye - m_viewNormalized; m_centerNearPlaneMercator = m_eyeMercator - m_viewNormalized * m_nearPlaneMercator; diff --git a/src/location/maps/qgeoprojection_p.h b/src/location/maps/qgeoprojection_p.h index e33ae880..2e1af8c5 100644 --- a/src/location/maps/qgeoprojection_p.h +++ b/src/location/maps/qgeoprojection_p.h @@ -195,7 +195,11 @@ public: QDoubleVector3D m_normal; }; -private: +#ifdef QT_LOCATION_DEBUG +public: +#else +protected: +#endif QGeoCameraData m_cameraData; double m_mapEdgeSize; double m_minimumZoom; @@ -218,7 +222,7 @@ private: QDoubleVector3D m_viewNormalized; QDoubleVector3D m_side; QDoubleVector3D m_centerNearPlane; - double m_sideLength; // map edge size at integer zoom level + double m_sideLengthPixels; // map edge size at integer zoom level double m_aperture; double m_nearPlane; double m_farPlane; diff --git a/src/location/maps/qgeoserviceprovider.cpp b/src/location/maps/qgeoserviceprovider.cpp index 11b1c28d..d25c379a 100644 --- a/src/location/maps/qgeoserviceprovider.cpp +++ b/src/location/maps/qgeoserviceprovider.cpp @@ -362,7 +362,7 @@ template <> QNavigationManagerEngine *createEngine<QNavigationManagerEngine>(QGe { if (!d_ptr->factoryV2) return nullptr; - return d_ptr->factoryV2->createNavigationManagerEngine(d_ptr->cleanedParameterMap, &(d_ptr->placeError), &(d_ptr->placeErrorString)); + return d_ptr->factoryV2->createNavigationManagerEngine(d_ptr->cleanedParameterMap, &(d_ptr->navigationError), &(d_ptr->navigationErrorString)); } /* Template for generating the code for each of the geocodingManager(), @@ -381,11 +381,15 @@ Manager *QGeoServiceProviderPrivate::manager(QGeoServiceProvider::Error *_error, this->loadPlugin(this->parameterMap); } - if (!this->factory || error != QGeoServiceProvider::NoError) + if (!this->factory) { + error = this->error; + errorString = this->errorString; return 0; + } if (!manager) { - Engine *engine = createEngine<Engine>(this); + Engine *engine = createEngine<Engine>(this); // this sets the specific error variables directly, + // from now on the local error, errorString refs should be set. if (engine) { engine->setManagerName( @@ -534,9 +538,13 @@ QPlaceManager *QGeoServiceProvider::placeManager() const */ QNavigationManager *QGeoServiceProvider::navigationManager() const { - return d_ptr->manager<QNavigationManager, QNavigationManagerEngine>( + QNavigationManager * mgr = d_ptr->manager<QNavigationManager, QNavigationManagerEngine>( &(d_ptr->navigationError), &(d_ptr->navigationErrorString), &(d_ptr->navigationManager)); + if (!mgr) { + qDebug() << d_ptr->navigationError << d_ptr->navigationErrorString; + } + return mgr; } /*! @@ -747,6 +755,11 @@ void QGeoServiceProviderPrivate::loadPlugin(const QVariantMap ¶meters) // load the actual plugin QObject *instance = loader()->instance(idx); + if (!instance) { + error = QGeoServiceProvider::LoaderError; + errorString = QLatin1String("loader()->instance(idx) failed to return an instance. Set the environment variable QT_DEBUG_PLUGINS to see more details."); + return; + } factoryV3 = qobject_cast<QGeoServiceProviderFactoryV3 *>(instance); if (!factoryV3) { factoryV2 = qobject_cast<QGeoServiceProviderFactoryV2 *>(instance); diff --git a/src/location/maps/qgeoserviceprovider.h b/src/location/maps/qgeoserviceprovider.h index 8e594977..b2e0be05 100644 --- a/src/location/maps/qgeoserviceprovider.h +++ b/src/location/maps/qgeoserviceprovider.h @@ -69,7 +69,8 @@ public: NotSupportedError, UnknownParameterError, MissingRequiredParameterError, - ConnectionError + ConnectionError, + LoaderError }; enum RoutingFeature { diff --git a/src/location/maps/qgeotiledmap_p_p.h b/src/location/maps/qgeotiledmap_p_p.h index 0ba349ca..80f658e0 100644 --- a/src/location/maps/qgeotiledmap_p_p.h +++ b/src/location/maps/qgeotiledmap_p_p.h @@ -94,7 +94,11 @@ protected: void setVisibleArea(const QRectF &visibleArea) override; QRectF visibleArea() const override; +#ifdef QT_LOCATION_DEBUG +public: +#else protected: +#endif QAbstractGeoTileCache *m_cache; QGeoCameraTiles *m_visibleTiles; QGeoCameraTiles *m_prefetchTiles; diff --git a/src/location/maps/qgeotiledmapscene.cpp b/src/location/maps/qgeotiledmapscene.cpp index 4709a48f..074b67c6 100644 --- a/src/location/maps/qgeotiledmapscene.cpp +++ b/src/location/maps/qgeotiledmapscene.cpp @@ -35,15 +35,14 @@ ** ****************************************************************************/ #include "qgeotiledmapscene_p.h" +#include "qgeotiledmapscene_p_p.h" #include "qgeocameradata_p.h" #include "qabstractgeotilecache_p.h" #include "qgeotilespec_p.h" #include <QtPositioning/private/qdoublevector3d_p.h> #include <QtPositioning/private/qwebmercator_p.h> #include <QtCore/private/qobject_p.h> -#include <QtQuick/QSGImageNode> #include <QtQuick/QQuickWindow> -#include <QtQuick/private/qsgdefaultimagenode_p.h> #include <QtGui/QVector3D> #include <cmath> #include <QtPositioning/private/qlocationutils_p.h> @@ -57,61 +56,6 @@ static QVector3D toVector3D(const QDoubleVector3D& in) QT_BEGIN_NAMESPACE -class QGeoTiledMapScenePrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QGeoTiledMapScene) -public: - QGeoTiledMapScenePrivate(); - ~QGeoTiledMapScenePrivate(); - - QSize m_screenSize; // in pixels - int m_tileSize; // the pixel resolution for each tile - QGeoCameraData m_cameraData; - QRectF m_visibleArea; - QSet<QGeoTileSpec> m_visibleTiles; - - QDoubleVector3D m_cameraUp; - QDoubleVector3D m_cameraEye; - QDoubleVector3D m_cameraCenter; - QMatrix4x4 m_projectionMatrix; - - // scales up the tile geometry and the camera altitude, resulting in no visible effect - // other than to control the accuracy of the render by keeping the values in a sensible range - double m_scaleFactor; - - // rounded down, positive zoom is zooming in, corresponding to reduced altitude - int m_intZoomLevel; - - // mercatorToGrid transform - // the number of tiles in each direction for the whole map (earth) at the current zoom level. - // it is 1<<zoomLevel - int m_sideLength; - double m_mapEdgeSize; - - QHash<QGeoTileSpec, QSharedPointer<QGeoTileTexture> > m_textures; - QVector<QGeoTileSpec> m_updatedTextures; - - // tilesToGrid transform - int m_minTileX; // the minimum tile index, i.e. 0 to sideLength which is 1<< zoomLevel - int m_minTileY; - int m_maxTileX; - int m_maxTileY; - int m_tileXWrapsBelow; // the wrap point as a tile index - - bool m_linearScaling; - - bool m_dropTextures; - - void addTile(const QGeoTileSpec &spec, QSharedPointer<QGeoTileTexture> texture); - - void setVisibleTiles(const QSet<QGeoTileSpec> &visibleTiles); - void removeTiles(const QSet<QGeoTileSpec> &oldTiles); - bool buildGeometry(const QGeoTileSpec &spec, QSGImageNode *imageNode, bool &overzooming); - void updateTileBounds(const QSet<QGeoTileSpec> &tiles); - void setupCamera(); - inline bool isTiltedOrRotated() { return (m_cameraData.tilt() > 0.0) || (m_cameraData.bearing() > 0.0); } -}; - QGeoTiledMapScene::QGeoTiledMapScene(QObject *parent) : QObject(*new QGeoTiledMapScenePrivate(),parent) { @@ -201,7 +145,11 @@ void QGeoTiledMapScene::clearTexturedTiles() QGeoTiledMapScenePrivate::QGeoTiledMapScenePrivate() : QObjectPrivate(), m_tileSize(0), +#ifdef QT_LOCATION_DEBUG + m_scaleFactor(1.0), +#else m_scaleFactor(10.0), +#endif m_intZoomLevel(0), m_sideLength(0), m_minTileX(-1), @@ -503,71 +451,6 @@ void QGeoTiledMapScenePrivate::setupCamera() nearPlane, farPlane); } -class QGeoTiledMapTileContainerNode : public QSGTransformNode -{ -public: - void addChild(const QGeoTileSpec &spec, QSGImageNode *node) - { - tiles.insert(spec, node); - appendChildNode(node); - } - QHash<QGeoTileSpec, QSGImageNode *> tiles; -}; - -class QGeoTiledMapRootNode : public QSGClipNode -{ -public: - QGeoTiledMapRootNode() - : isTextureLinear(false) - , geometry(QSGGeometry::defaultAttributes_Point2D(), 4) - , root(new QSGTransformNode()) - , tiles(new QGeoTiledMapTileContainerNode()) - , wrapLeft(new QGeoTiledMapTileContainerNode()) - , wrapRight(new QGeoTiledMapTileContainerNode()) - { - setIsRectangular(true); - setGeometry(&geometry); - root->appendChildNode(tiles); - root->appendChildNode(wrapLeft); - root->appendChildNode(wrapRight); - appendChildNode(root); - } - - ~QGeoTiledMapRootNode() - { - qDeleteAll(textures); - } - - void setClipRect(const QRect &rect) - { - if (rect != clipRect) { - QSGGeometry::updateRectGeometry(&geometry, rect); - QSGClipNode::setClipRect(rect); - clipRect = rect; - markDirty(DirtyGeometry); - } - } - - void updateTiles(QGeoTiledMapTileContainerNode *root, - QGeoTiledMapScenePrivate *d, - double camAdjust, - QQuickWindow *window, - bool ogl); - - bool isTextureLinear; - - QSGGeometry geometry; - QRect clipRect; - - QSGTransformNode *root; - - QGeoTiledMapTileContainerNode *tiles; // The majority of the tiles - QGeoTiledMapTileContainerNode *wrapLeft; // When zoomed out, the tiles that wrap around on the left. - QGeoTiledMapTileContainerNode *wrapRight; // When zoomed out, the tiles that wrap around on the right - - QHash<QGeoTileSpec, QSGTexture *> textures; -}; - static bool qgeotiledmapscene_isTileInViewport_Straight(const QRectF &tileRect, const QMatrix4x4 &matrix) { const QRectF boundingRect = QRectF(matrix * tileRect.topLeft(), matrix * tileRect.bottomRight()); @@ -621,6 +504,9 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root, bool straight = !d->isTiltedOrRotated(); bool overzooming; qreal pixelRatio = window->effectiveDevicePixelRatio(); +#ifdef QT_LOCATION_DEBUG + QList<QGeoTileSpec> droppedTiles; +#endif for (QHash<QGeoTileSpec, QSGImageNode *>::iterator it = root->tiles.begin(); it != root->tiles.end(); ) { QSGImageNode *node = it.value(); @@ -630,6 +516,9 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root, QSGNode::DirtyState dirtyBits = 0; if (!ok) { +#ifdef QT_LOCATION_DEBUG + droppedTiles.append(it.key()); +#endif it = root->tiles.erase(it); delete node; } else { @@ -656,8 +545,12 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root, for (const QGeoTileSpec &s : toAdd) { QGeoTileTexture *tileTexture = d->m_textures.value(s).data(); - if (!tileTexture || tileTexture->image.isNull()) + if (!tileTexture || tileTexture->image.isNull()) { +#ifdef QT_LOCATION_DEBUG + droppedTiles.append(s); +#endif continue; + } QSGImageNode *tileNode = window->createImageNode(); // note: setTexture will update coordinates so do it here, before we buildGeometry tileNode->setTexture(textures.value(s)); @@ -675,9 +568,16 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root, #endif root->addChild(s, tileNode); } else { +#ifdef QT_LOCATION_DEBUG + droppedTiles.append(s); +#endif delete tileNode; } } + +#ifdef QT_LOCATION_DEBUG + m_droppedTiles[camAdjust] = droppedTiles; +#endif } QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *window) @@ -695,6 +595,11 @@ QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *win if (!mapRoot) mapRoot = new QGeoTiledMapRootNode(); +#ifdef QT_LOCATION_DEBUG + mapRoot->m_droppedTiles.clear(); + d->m_mapRoot = mapRoot; +#endif + // Setting clip rect to fullscreen, as now the map can never be smaller than the viewport. mapRoot->setClipRect(QRect(0, 0, w, h)); @@ -749,6 +654,9 @@ QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *win } double sideLength = d->m_scaleFactor * d->m_tileSize * d->m_sideLength; +#ifdef QT_LOCATION_DEBUG + d->m_sideLengthPixel = sideLength; +#endif mapRoot->updateTiles(mapRoot->tiles, d, 0, window, isOpenGL); mapRoot->updateTiles(mapRoot->wrapLeft, d, +sideLength, window, isOpenGL); mapRoot->updateTiles(mapRoot->wrapRight, d, -sideLength, window, isOpenGL); diff --git a/src/location/maps/qgeotiledmapscene_p_p.h b/src/location/maps/qgeotiledmapscene_p_p.h new file mode 100644 index 00000000..5d98abd5 --- /dev/null +++ b/src/location/maps/qgeotiledmapscene_p_p.h @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtLocation module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QGEOTILEDMAPSCENE_P_P_H +#define QGEOTILEDMAPSCENE_P_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 "qgeotiledmapscene_p.h" +#include <QtCore/private/qobject_p.h> +#include <QtPositioning/private/qdoublevector3d_p.h> +#include <QtQuick/QSGImageNode> +#include <QtQuick/private/qsgdefaultimagenode_p.h> +#include <QtQuick/QQuickWindow> +#include "qgeocameradata_p.h" +#include "qgeotilespec_p.h" + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QGeoTiledMapTileContainerNode : public QSGTransformNode +{ +public: + void addChild(const QGeoTileSpec &spec, QSGImageNode *node) + { + tiles.insert(spec, node); + appendChildNode(node); + } + QHash<QGeoTileSpec, QSGImageNode *> tiles; +}; + +class Q_LOCATION_PRIVATE_EXPORT QGeoTiledMapRootNode : public QSGClipNode +{ +public: + QGeoTiledMapRootNode() + : isTextureLinear(false) + , geometry(QSGGeometry::defaultAttributes_Point2D(), 4) + , root(new QSGTransformNode()) + , tiles(new QGeoTiledMapTileContainerNode()) + , wrapLeft(new QGeoTiledMapTileContainerNode()) + , wrapRight(new QGeoTiledMapTileContainerNode()) + { + setIsRectangular(true); + setGeometry(&geometry); + root->appendChildNode(tiles); + root->appendChildNode(wrapLeft); + root->appendChildNode(wrapRight); + appendChildNode(root); + } + + ~QGeoTiledMapRootNode() + { + qDeleteAll(textures); + } + + void setClipRect(const QRect &rect) + { + if (rect != clipRect) { + QSGGeometry::updateRectGeometry(&geometry, rect); + QSGClipNode::setClipRect(rect); + clipRect = rect; + markDirty(DirtyGeometry); + } + } + + void updateTiles(QGeoTiledMapTileContainerNode *root, + QGeoTiledMapScenePrivate *d, + double camAdjust, + QQuickWindow *window, + bool ogl); + + bool isTextureLinear; + + QSGGeometry geometry; + QRect clipRect; + + QSGTransformNode *root; + + QGeoTiledMapTileContainerNode *tiles; // The majority of the tiles + QGeoTiledMapTileContainerNode *wrapLeft; // When zoomed out, the tiles that wrap around on the left. + QGeoTiledMapTileContainerNode *wrapRight; // When zoomed out, the tiles that wrap around on the right + + QHash<QGeoTileSpec, QSGTexture *> textures; + +#ifdef QT_LOCATION_DEBUG + double m_sideLengthPixel; + QMap<double, QList<QGeoTileSpec>> m_droppedTiles; +#endif +}; + +class Q_LOCATION_PRIVATE_EXPORT QGeoTiledMapScenePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QGeoTiledMapScene) +public: + QGeoTiledMapScenePrivate(); + ~QGeoTiledMapScenePrivate(); + + void addTile(const QGeoTileSpec &spec, QSharedPointer<QGeoTileTexture> texture); + + void setVisibleTiles(const QSet<QGeoTileSpec> &visibleTiles); + void removeTiles(const QSet<QGeoTileSpec> &oldTiles); + bool buildGeometry(const QGeoTileSpec &spec, QSGImageNode *imageNode, bool &overzooming); + void updateTileBounds(const QSet<QGeoTileSpec> &tiles); + void setupCamera(); + inline bool isTiltedOrRotated() { return (m_cameraData.tilt() > 0.0) || (m_cameraData.bearing() > 0.0); } + +public: + + QSize m_screenSize; // in pixels + int m_tileSize; // the pixel resolution for each tile + QGeoCameraData m_cameraData; + QRectF m_visibleArea; + QSet<QGeoTileSpec> m_visibleTiles; + + QDoubleVector3D m_cameraUp; + QDoubleVector3D m_cameraEye; + QDoubleVector3D m_cameraCenter; + QMatrix4x4 m_projectionMatrix; + + // scales up the tile geometry and the camera altitude, resulting in no visible effect + // other than to control the accuracy of the render by keeping the values in a sensible range + double m_scaleFactor; + + // rounded down, positive zoom is zooming in, corresponding to reduced altitude + int m_intZoomLevel; + + // mercatorToGrid transform + // the number of tiles in each direction for the whole map (earth) at the current zoom level. + // it is 1<<zoomLevel + int m_sideLength; + double m_mapEdgeSize; + + QHash<QGeoTileSpec, QSharedPointer<QGeoTileTexture> > m_textures; + QVector<QGeoTileSpec> m_updatedTextures; + + // tilesToGrid transform + int m_minTileX; // the minimum tile index, i.e. 0 to sideLength which is 1<< zoomLevel + int m_minTileY; + int m_maxTileX; + int m_maxTileY; + int m_tileXWrapsBelow; // the wrap point as a tile index + bool m_linearScaling; + bool m_dropTextures; + +#ifdef QT_LOCATION_DEBUG + double m_sideLengthPixel; + QGeoTiledMapRootNode *m_mapRoot = nullptr; +#endif +}; + +QT_END_NAMESPACE + +#endif // QGEOTILEDMAPSCENE_P_P_H diff --git a/src/location/maps/qnavigationmanagerengine.cpp b/src/location/maps/qnavigationmanagerengine.cpp index 1f82b4a1..770e30a6 100644 --- a/src/location/maps/qnavigationmanagerengine.cpp +++ b/src/location/maps/qnavigationmanagerengine.cpp @@ -54,7 +54,6 @@ class QAbstractNavigatorPrivate public: QLocale locale; QLocale::MeasurementSystem measurementSystem; - bool initialized = false; }; QAbstractNavigator::QAbstractNavigator(QObject *parent) diff --git a/src/location/maps/qnavigationmanagerengine_p.h b/src/location/maps/qnavigationmanagerengine_p.h index 62d9eb87..0852b3ea 100644 --- a/src/location/maps/qnavigationmanagerengine_p.h +++ b/src/location/maps/qnavigationmanagerengine_p.h @@ -81,6 +81,7 @@ public: public slots: virtual bool start() = 0; virtual bool stop() = 0; + virtual void setTrackPosition(bool trackPosition) = 0; signals: // These must be emitted by the engine diff --git a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp index 4614de89..ed36cd5f 100644 --- a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp +++ b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp @@ -378,7 +378,7 @@ QString QGeoMapMapboxGL::copyrightsStyleSheet() const return QStringLiteral("* { vertical-align: middle; font-weight: normal }"); } -void QGeoMapMapboxGL::setMapboxGLSettings(const QMapboxGLSettings& settings) +void QGeoMapMapboxGL::setMapboxGLSettings(const QMapboxGLSettings& settings, bool useChinaEndpoint) { Q_D(QGeoMapMapboxGL); @@ -386,8 +386,13 @@ void QGeoMapMapboxGL::setMapboxGLSettings(const QMapboxGLSettings& settings) // If the access token is not set, use the development access token. // This will only affect mapbox:// styles. + // Mapbox China requires a China-specific access token. if (d->m_settings.accessToken().isEmpty()) { - d->m_settings.setAccessToken(developmentToken); + if (useChinaEndpoint) { + qWarning("Mapbox China requires an access token: https://www.mapbox.com/contact/sales"); + } else { + d->m_settings.setAccessToken(developmentToken); + } } } diff --git a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h index 0ffaf4ea..5fc2260e 100644 --- a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h +++ b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h @@ -54,7 +54,7 @@ public: virtual ~QGeoMapMapboxGL(); QString copyrightsStyleSheet() const override; - void setMapboxGLSettings(const QMapboxGLSettings &); + void setMapboxGLSettings(const QMapboxGLSettings &, bool useChinaEndpoint); void setUseFBO(bool); void setMapItemsBefore(const QString &); Capabilities capabilities() const override; diff --git a/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp index cc48afb2..d2463106 100644 --- a/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp +++ b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp @@ -69,30 +69,45 @@ QGeoMappingManagerEngineMapboxGL::QGeoMappingManagerEngineMapboxGL(const QVarian int mapId = 0; const QByteArray pluginName = "mapboxgl"; - mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/streets-v10"), - tr("Streets"), false, false, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/basic-v9"), - tr("Basic"), false, false, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/bright-v9"), - tr("Bright"), false, false, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::TerrainMap, QStringLiteral("mapbox://styles/mapbox/outdoors-v10"), - tr("Outdoors"), false, false, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, QStringLiteral("mapbox://styles/mapbox/satellite-v9"), - tr("Satellite"), false, false, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::HybridMap, QStringLiteral("mapbox://styles/mapbox/satellite-streets-v10"), - tr("Satellite Streets"), false, false, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/light-v9"), - tr("Light"), false, false, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/dark-v9"), - tr("Dark"), false, false, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::TransitMap, QStringLiteral("mapbox://styles/mapbox/navigation-preview-day-v2"), - tr("Navigation Preview Day"), false, false, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::TransitMap, QStringLiteral("mapbox://styles/mapbox/navigation-preview-night-v2"), - tr("Navigation Preview Night"), false, true, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::CarNavigationMap, QStringLiteral("mapbox://styles/mapbox/navigation-guidance-day-v2"), - tr("Navigation Guidance Day"), false, false, ++mapId, pluginName, cameraCaps); - mapTypes << QGeoMapType(QGeoMapType::CarNavigationMap, QStringLiteral("mapbox://styles/mapbox/navigation-guidance-night-v2"), - tr("Navigation Guidance Night"), false, true, ++mapId, pluginName, cameraCaps); + if (parameters.contains(QStringLiteral("mapboxgl.china"))) { + m_useChinaEndpoint = parameters.value(QStringLiteral("mapboxgl.china")).toBool(); + } + + if (m_useChinaEndpoint) { + m_settings.setApiBaseUrl(QStringLiteral("https://api.mapbox.cn")); + + mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/streets-zh-v1"), + tr("China Streets"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/light-zh-v1"), + tr("China Light"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/dark-zh-v1"), + tr("China Dark"), false, false, ++mapId, pluginName, cameraCaps); + } else { + mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/streets-v10"), + tr("Streets"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/basic-v9"), + tr("Basic"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/bright-v9"), + tr("Bright"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::TerrainMap, QStringLiteral("mapbox://styles/mapbox/outdoors-v10"), + tr("Outdoors"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, QStringLiteral("mapbox://styles/mapbox/satellite-v9"), + tr("Satellite"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::HybridMap, QStringLiteral("mapbox://styles/mapbox/satellite-streets-v10"), + tr("Satellite Streets"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/light-v9"), + tr("Light"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/dark-v9"), + tr("Dark"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::TransitMap, QStringLiteral("mapbox://styles/mapbox/navigation-preview-day-v2"), + tr("Navigation Preview Day"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::TransitMap, QStringLiteral("mapbox://styles/mapbox/navigation-preview-night-v2"), + tr("Navigation Preview Night"), false, true, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::CarNavigationMap, QStringLiteral("mapbox://styles/mapbox/navigation-guidance-day-v2"), + tr("Navigation Guidance Day"), false, false, ++mapId, pluginName, cameraCaps); + mapTypes << QGeoMapType(QGeoMapType::CarNavigationMap, QStringLiteral("mapbox://styles/mapbox/navigation-guidance-night-v2"), + tr("Navigation Guidance Night"), false, true, ++mapId, pluginName, cameraCaps); + } if (parameters.contains(QStringLiteral("mapboxgl.mapping.additional_style_urls"))) { const QString ids = parameters.value(QStringLiteral("mapboxgl.mapping.additional_style_urls")).toString(); @@ -156,7 +171,7 @@ QGeoMappingManagerEngineMapboxGL::~QGeoMappingManagerEngineMapboxGL() QGeoMap *QGeoMappingManagerEngineMapboxGL::createMap() { QGeoMapMapboxGL* map = new QGeoMapMapboxGL(this, 0); - map->setMapboxGLSettings(m_settings); + map->setMapboxGLSettings(m_settings, m_useChinaEndpoint); map->setUseFBO(m_useFBO); map->setMapItemsBefore(m_mapItemsBefore); diff --git a/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h index b3afe77b..9ceb8ccc 100644 --- a/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h +++ b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h @@ -59,6 +59,7 @@ public: private: QMapboxGLSettings m_settings; bool m_useFBO = true; + bool m_useChinaEndpoint = false; QString m_mapItemsBefore; }; diff --git a/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp b/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp index ab575463..5094b72e 100644 --- a/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp +++ b/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp @@ -52,6 +52,7 @@ #include <QtCore/QJsonArray> #include <QtCore/QJsonDocument> #include <QtCore/QJsonObject> +#include <QtCore/QRegularExpression> #include <QtCore/QStandardPaths> #include <QtCore/QUrlQuery> #include <QtNetwork/QNetworkProxy> @@ -690,13 +691,14 @@ QPlaceIcon QPlaceManagerEngineNokiaV2::icon(const QString &remotePath, QPlaceIcon icon; QVariantMap params; - QRegExp rx("(.*)(/icons/categories/.*)"); + QRegularExpression rx("(.*)(/icons/categories/.*)"); + QRegularExpressionMatch match = rx.match(remotePath); QString iconPrefix; QString nokiaIcon; - if (rx.indexIn(remotePath) != -1 && !rx.cap(1).isEmpty() && !rx.cap(2).isEmpty()) { - iconPrefix = rx.cap(1); - nokiaIcon = rx.cap(2); + if (match.hasMatch() && !match.capturedRef(1).isEmpty() && !match.capturedRef(2).isEmpty()) { + iconPrefix = match.captured(1); + nokiaIcon = match.captured(2); if (QFile::exists(m_localDataPath + nokiaIcon)) iconPrefix = QString::fromLatin1("file://") + m_localDataPath; diff --git a/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp b/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp index cd514d30..10484e3b 100644 --- a/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp +++ b/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp @@ -264,7 +264,7 @@ void QGeoPositionInfoSourceGeoclue2::createClient() setError(AccessError); delete m_client; } else { - connect(m_client, &OrgFreedesktopGeoClue2ClientInterface::LocationUpdated, + connect(m_client.data(), &OrgFreedesktopGeoClue2ClientInterface::LocationUpdated, this, &QGeoPositionInfoSourceGeoclue2::handleNewLocation); if (configureClient()) diff --git a/src/plugins/position/position.pro b/src/plugins/position/position.pro index 4453b8a3..6800d5a3 100644 --- a/src/plugins/position/position.pro +++ b/src/plugins/position/position.pro @@ -2,8 +2,8 @@ TEMPLATE = subdirs QT_FOR_CONFIG += positioning-private -qtHaveModule(dbus):SUBDIRS += geoclue -qtHaveModule(dbus):SUBDIRS += geoclue2 +linux:qtHaveModule(dbus):SUBDIRS += geoclue +linux:qtHaveModule(dbus):SUBDIRS += geoclue2 qtConfig(gypsy):SUBDIRS += gypsy qtConfig(winrt_geolocation):SUBDIRS += winrt qtHaveModule(simulator):SUBDIRS += simulator diff --git a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp index 046d862e..139a6b3d 100644 --- a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp +++ b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp @@ -36,11 +36,12 @@ #include "qgeopositioninfosource_winrt_p.h" -#include <QCoreApplication> -#include <QMutex> -#include <qfunctions_winrt.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qfunctions_winrt.h> +#include <QtCore/qloggingcategory.h> +#include <QtCore/qmutex.h> #ifdef Q_OS_WINRT -#include <private/qeventdispatcher_winrt_p.h> +#include <QtCore/private/qeventdispatcher_winrt_p.h> #endif #include <functional> @@ -56,10 +57,11 @@ using namespace ABI::Windows::Foundation; using namespace ABI::Windows::Foundation::Collections; typedef ITypedEventHandler<Geolocator *, PositionChangedEventArgs *> GeoLocatorPositionHandler; -typedef ITypedEventHandler<Geolocator *, StatusChangedEventArgs *> GeoLocatorStatusHandler; typedef IAsyncOperationCompletedHandler<Geoposition*> PositionHandler; typedef IAsyncOperationCompletedHandler<GeolocationAccessStatus> AccessHandler; +Q_DECLARE_LOGGING_CATEGORY(lcPositioningWinRT) + QT_BEGIN_NAMESPACE #ifndef Q_OS_WINRT @@ -70,7 +72,36 @@ HRESULT runOnXamlThread(const std::function<HRESULT ()> &delegate, bool waitForR return delegate(); } } -#endif + +static inline HRESULT await(const ComPtr<IAsyncOperation<GeolocationAccessStatus>> &asyncOp, + GeolocationAccessStatus *result) +{ + ComPtr<IAsyncInfo> asyncInfo; + HRESULT hr = asyncOp.As(&asyncInfo); + if (FAILED(hr)) + return hr; + + AsyncStatus status; + while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == AsyncStatus::Started) + QThread::yieldCurrentThread(); + + if (FAILED(hr) || status != AsyncStatus::Completed) { + HRESULT ec; + hr = asyncInfo->get_ErrorCode(&ec); + if (FAILED(hr)) + return hr; + hr = asyncInfo->Close(); + if (FAILED(hr)) + return hr; + return ec; + } + + if (FAILED(hr)) + return hr; + + return asyncOp->GetResults(result); +} +#endif // !Q_OS_WINRT class QGeoPositionInfoSourceWinRTPrivate { public: @@ -83,13 +114,37 @@ public: EventRegistrationToken positionToken; QMutex mutex; bool updatesOngoing; + int minimumUpdateInterval; + + PositionStatus nativeStatus() const; }; +PositionStatus QGeoPositionInfoSourceWinRTPrivate::nativeStatus() const +{ +#ifdef Q_OS_WINRT + qCDebug(lcPositioningWinRT) << __FUNCTION__; + + PositionStatus status; + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, &status]() { + return locator->get_LocationStatus(&status); + }); + if (FAILED(hr)) { + qErrnoWarning(hr, "Could not query status"); + return PositionStatus_NotAvailable; + } + return status; +#else + return PositionStatus_Ready; +#endif +} + QGeoPositionInfoSourceWinRT::QGeoPositionInfoSourceWinRT(QObject *parent) : QGeoPositionInfoSource(parent) , d_ptr(new QGeoPositionInfoSourceWinRTPrivate) { + qCDebug(lcPositioningWinRT) << __FUNCTION__; + CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); Q_D(QGeoPositionInfoSourceWinRT); d->positionError = QGeoPositionInfoSource::NoError; d->updatesOngoing = false; @@ -97,10 +152,13 @@ QGeoPositionInfoSourceWinRT::QGeoPositionInfoSourceWinRT(QObject *parent) QGeoPositionInfoSourceWinRT::~QGeoPositionInfoSourceWinRT() { + qCDebug(lcPositioningWinRT) << __FUNCTION__; + CoUninitialize(); } int QGeoPositionInfoSourceWinRT::init() { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_D(QGeoPositionInfoSourceWinRT); if (!requestAccess()) { qWarning ("Location access failed."); @@ -111,13 +169,11 @@ int QGeoPositionInfoSourceWinRT::init() &d->locator); RETURN_HR_IF_FAILED("Could not initialize native location services."); - hr = d->locator->add_StatusChanged(Callback<GeoLocatorStatusHandler>(this, - &QGeoPositionInfoSourceWinRT::onStatusChanged).Get(), - &d->statusToken); - RETURN_HR_IF_FAILED("Could not add status callback."); - - hr = d->locator->put_ReportInterval(1000); - RETURN_HR_IF_FAILED("Could not initialize report interval."); + UINT32 interval; + hr = d->locator->get_ReportInterval(&interval); + RETURN_HR_IF_FAILED("Could not retrieve report interval."); + d->minimumUpdateInterval = static_cast<int>(interval); + setUpdateInterval(d->minimumUpdateInterval); return hr; }); @@ -137,7 +193,6 @@ int QGeoPositionInfoSourceWinRT::init() d->positionToken.value = 0; d->periodicTimer.setSingleShot(true); - d->periodicTimer.setInterval(minimumUpdateInterval()); connect(&d->periodicTimer, &QTimer::timeout, this, &QGeoPositionInfoSourceWinRT::virtualPositionUpdate); d->singleUpdateTimer.setSingleShot(true); @@ -151,6 +206,7 @@ int QGeoPositionInfoSourceWinRT::init() QGeoPositionInfo QGeoPositionInfoSourceWinRT::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_D(const QGeoPositionInfoSourceWinRT); Q_UNUSED(fromSatellitePositioningMethodsOnly) return d->lastPosition; @@ -160,13 +216,8 @@ QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceWinRT::supporte { Q_D(const QGeoPositionInfoSourceWinRT); - PositionStatus status; - HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([d, &status]() { - HRESULT hr = d->locator->get_LocationStatus(&status); - return hr; - }); - if (FAILED(hr)) - return QGeoPositionInfoSource::NoPositioningMethods; + PositionStatus status = d->nativeStatus(); + qCDebug(lcPositioningWinRT) << __FUNCTION__ << status; switch (status) { case PositionStatus::PositionStatus_NoData: @@ -180,6 +231,7 @@ QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceWinRT::supporte void QGeoPositionInfoSourceWinRT::setPreferredPositioningMethods(QGeoPositionInfoSource::PositioningMethods methods) { + qCDebug(lcPositioningWinRT) << __FUNCTION__ << methods; Q_D(QGeoPositionInfoSourceWinRT); PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods(); @@ -187,7 +239,7 @@ void QGeoPositionInfoSourceWinRT::setPreferredPositioningMethods(QGeoPositionInf if (previousPreferredPositioningMethods == preferredPositioningMethods()) return; - bool needsRestart = d->positionToken.value != 0; + const bool needsRestart = d->positionToken.value != 0; if (needsRestart) stopHandler(); @@ -207,19 +259,20 @@ void QGeoPositionInfoSourceWinRT::setPreferredPositioningMethods(QGeoPositionInf void QGeoPositionInfoSourceWinRT::setUpdateInterval(int msec) { + qCDebug(lcPositioningWinRT) << __FUNCTION__ << msec; Q_D(QGeoPositionInfoSourceWinRT); - // Windows Phone 8.1 and Windows 10 do not support 0 interval -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - if (msec == 0) - msec = minimumUpdateInterval(); -#endif - - // If msec is 0 we send updates as data becomes available, otherwise we force msec to be equal - // to or larger than the minimum update interval. + // minimumUpdateInterval is initialized to the lowest possible update interval in init(). + // Passing 0 will cause an error on Windows 10. + // See https://docs.microsoft.com/en-us/uwp/api/windows.devices.geolocation.geolocator.reportinterval if (msec != 0 && msec < minimumUpdateInterval()) msec = minimumUpdateInterval(); - HRESULT hr = d->locator->put_ReportInterval(msec); + const bool needsRestart = d->positionToken.value != 0; + + if (needsRestart) + stopHandler(); + + HRESULT hr = d->locator->put_ReportInterval(static_cast<UINT32>(msec)); if (FAILED(hr)) { setError(QGeoPositionInfoSource::UnknownSourceError); qErrnoWarning(hr, "Failed to set update interval"); @@ -229,17 +282,20 @@ void QGeoPositionInfoSourceWinRT::setUpdateInterval(int msec) d->periodicTimer.setInterval(qMax(msec, minimumUpdateInterval())); QGeoPositionInfoSource::setUpdateInterval(msec); + + if (needsRestart) + startHandler(); } int QGeoPositionInfoSourceWinRT::minimumUpdateInterval() const { - // We use one second to reduce potential timer events - // in case the platform itself stops reporting - return 1000; + Q_D(const QGeoPositionInfoSourceWinRT); + return d->minimumUpdateInterval; } void QGeoPositionInfoSourceWinRT::startUpdates() { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_D(QGeoPositionInfoSourceWinRT); if (d->updatesOngoing) @@ -253,6 +309,7 @@ void QGeoPositionInfoSourceWinRT::startUpdates() void QGeoPositionInfoSourceWinRT::stopUpdates() { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_D(QGeoPositionInfoSourceWinRT); stopHandler(); @@ -262,6 +319,7 @@ void QGeoPositionInfoSourceWinRT::stopUpdates() bool QGeoPositionInfoSourceWinRT::startHandler() { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_D(QGeoPositionInfoSourceWinRT); // Check if already attached @@ -301,6 +359,7 @@ bool QGeoPositionInfoSourceWinRT::startHandler() void QGeoPositionInfoSourceWinRT::stopHandler() { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_D(QGeoPositionInfoSourceWinRT); if (!d->positionToken.value) @@ -314,6 +373,7 @@ void QGeoPositionInfoSourceWinRT::stopHandler() void QGeoPositionInfoSourceWinRT::requestUpdate(int timeout) { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_D(QGeoPositionInfoSourceWinRT); if (timeout != 0 && timeout < minimumUpdateInterval()) { @@ -330,6 +390,7 @@ void QGeoPositionInfoSourceWinRT::requestUpdate(int timeout) void QGeoPositionInfoSourceWinRT::virtualPositionUpdate() { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_D(QGeoPositionInfoSourceWinRT); QMutexLocker locker(&d->mutex); @@ -367,6 +428,7 @@ void QGeoPositionInfoSourceWinRT::singleUpdateTimeOut() void QGeoPositionInfoSourceWinRT::updateSynchronized(QGeoPositionInfo currentInfo) { + qCDebug(lcPositioningWinRT) << __FUNCTION__ << currentInfo; Q_D(QGeoPositionInfoSourceWinRT); QMutexLocker locker(&d->mutex); @@ -388,11 +450,13 @@ void QGeoPositionInfoSourceWinRT::updateSynchronized(QGeoPositionInfo currentInf QGeoPositionInfoSource::Error QGeoPositionInfoSourceWinRT::error() const { Q_D(const QGeoPositionInfoSourceWinRT); + qCDebug(lcPositioningWinRT) << __FUNCTION__ << d->positionError; return d->positionError; } void QGeoPositionInfoSourceWinRT::setError(QGeoPositionInfoSource::Error positionError) { + qCDebug(lcPositioningWinRT) << __FUNCTION__ << positionError; Q_D(QGeoPositionInfoSourceWinRT); if (positionError == d->positionError) @@ -404,14 +468,9 @@ void QGeoPositionInfoSourceWinRT::setError(QGeoPositionInfoSource::Error positio bool QGeoPositionInfoSourceWinRT::checkNativeState() { Q_D(QGeoPositionInfoSourceWinRT); + qCDebug(lcPositioningWinRT) << __FUNCTION__; - PositionStatus status; - HRESULT hr = d->locator->get_LocationStatus(&status); - if (FAILED(hr)) { - setError(QGeoPositionInfoSource::UnknownSourceError); - qErrnoWarning(hr, "Could not query status"); - return false; - } + PositionStatus status = d->nativeStatus(); bool result = false; switch (status) { @@ -432,41 +491,53 @@ bool QGeoPositionInfoSourceWinRT::checkNativeState() HRESULT QGeoPositionInfoSourceWinRT::onPositionChanged(IGeolocator *locator, IPositionChangedEventArgs *args) { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_UNUSED(locator); HRESULT hr; - ComPtr<IGeoposition> pos; - hr = args->get_Position(&pos); + ComPtr<IGeoposition> position; + hr = args->get_Position(&position); RETURN_HR_IF_FAILED("Could not access position object."); QGeoPositionInfo currentInfo; ComPtr<IGeocoordinate> coord; - hr = pos->get_Coordinate(&coord); + hr = position->get_Coordinate(&coord); if (FAILED(hr)) qErrnoWarning(hr, "Could not access coordinate"); - DOUBLE lat; - hr = coord->get_Latitude(&lat); + ComPtr<IGeocoordinateWithPoint> pointCoordinate; + hr = coord.As(&pointCoordinate); if (FAILED(hr)) - qErrnoWarning(hr, "Could not access latitude"); + qErrnoWarning(hr, "Could not cast coordinate."); - DOUBLE lon; - hr = coord->get_Longitude(&lon); + ComPtr<IGeopoint> point; + hr = pointCoordinate->get_Point(&point); if (FAILED(hr)) - qErrnoWarning(hr, "Could not access longitude"); - - // Depending on data source altitude can - // be identified or not - IReference<double> *alt; - hr = coord->get_Altitude(&alt); - if (SUCCEEDED(hr) && alt) { - double altd; - hr = alt->get_Value(&altd); - currentInfo.setCoordinate(QGeoCoordinate(lat, lon, altd)); - } else { - currentInfo.setCoordinate(QGeoCoordinate(lat, lon)); + qErrnoWarning(hr, "Could not obtain coordinate's point."); + + BasicGeoposition pos; + hr = point->get_Position(&pos); + if (FAILED(hr)) + qErrnoWarning(hr, "Could not obtain point's position."); + + DOUBLE lat = pos.Latitude; + DOUBLE lon = pos.Longitude; + DOUBLE alt = pos.Altitude; + + bool altitudeAvailable = false; + ComPtr<IGeoshape> shape; + hr = point.As(&shape); + if (SUCCEEDED(hr) && shape) { + AltitudeReferenceSystem altitudeSystem; + hr = shape->get_AltitudeReferenceSystem(&altitudeSystem); + if (SUCCEEDED(hr) && altitudeSystem == AltitudeReferenceSystem_Geoid) + altitudeAvailable = true; } + if (altitudeAvailable) + currentInfo.setCoordinate(QGeoCoordinate(lat, lon, alt)); + else + currentInfo.setCoordinate(QGeoCoordinate(lat, lon)); DOUBLE accuracy; hr = coord->get_Accuracy(&accuracy); @@ -477,7 +548,7 @@ HRESULT QGeoPositionInfoSourceWinRT::onPositionChanged(IGeolocator *locator, IPo hr = coord->get_AltitudeAccuracy(&altAccuracy); if (SUCCEEDED(hr) && altAccuracy) { double value; - hr = alt->get_Value(&value); + hr = altAccuracy->get_Value(&value); currentInfo.setAttribute(QGeoPositionInfo::VerticalAccuracy, value); } @@ -525,16 +596,9 @@ HRESULT QGeoPositionInfoSourceWinRT::onPositionChanged(IGeolocator *locator, IPo return S_OK; } -HRESULT QGeoPositionInfoSourceWinRT::onStatusChanged(IGeolocator*, IStatusChangedEventArgs *args) -{ - PositionStatus st; - args->get_Status(&st); - return S_OK; -} - bool QGeoPositionInfoSourceWinRT::requestAccess() const { -#ifdef Q_OS_WINRT + qCDebug(lcPositioningWinRT) << __FUNCTION__; static GeolocationAccessStatus accessStatus = GeolocationAccessStatus_Unspecified; static ComPtr<IGeolocatorStatics> statics; @@ -557,11 +621,12 @@ bool QGeoPositionInfoSourceWinRT::requestAccess() const Q_ASSERT_SUCCEEDED(hr); // We cannot wait inside the XamlThread as that would deadlock +#ifdef Q_OS_WINRT QWinRTFunctions::await(op, &accessStatus); +#else + await(op, &accessStatus); +#endif return accessStatus == GeolocationAccessStatus_Allowed; -#else // Q_OS_WINRT - return true; -#endif // Q_OS_WINRT } QT_END_NAMESPACE diff --git a/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h b/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h index 9f3a1c7f..4319ccae 100644 --- a/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h +++ b/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h @@ -51,7 +51,7 @@ #include "qgeopositioninfosource.h" #include "qgeopositioninfo.h" -#include <QTimer> +#include <QtCore/qtimer.h> #include <EventToken.h> #include <wrl.h> @@ -62,7 +62,6 @@ namespace ABI { namespace Geolocation{ struct IGeolocator; struct IPositionChangedEventArgs; - struct IStatusChangedEventArgs; } } } @@ -76,7 +75,7 @@ class QGeoPositionInfoSourceWinRT : public QGeoPositionInfoSource { Q_OBJECT public: - QGeoPositionInfoSourceWinRT(QObject *parent = 0); + QGeoPositionInfoSourceWinRT(QObject *parent = nullptr); ~QGeoPositionInfoSourceWinRT(); int init(); @@ -92,9 +91,6 @@ public: HRESULT onPositionChanged(ABI::Windows::Devices::Geolocation::IGeolocator *locator, ABI::Windows::Devices::Geolocation::IPositionChangedEventArgs *args); - HRESULT onStatusChanged(ABI::Windows::Devices::Geolocation::IGeolocator*, - ABI::Windows::Devices::Geolocation::IStatusChangedEventArgs *args); - bool requestAccess() const; Q_SIGNALS: void nativePositionUpdate(const QGeoPositionInfo); diff --git a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp index e58744a0..b1ec6fb3 100644 --- a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp +++ b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp @@ -37,24 +37,37 @@ #include "qgeopositioninfosourcefactory_winrt.h" #include "qgeopositioninfosource_winrt_p.h" +#include <QtCore/qloggingcategory.h> + +Q_LOGGING_CATEGORY(lcPositioningWinRT, "qt.positioning.winrt") + +QT_BEGIN_NAMESPACE + QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryWinRT::positionInfoSource(QObject *parent) { + qCDebug(lcPositioningWinRT) << __FUNCTION__; QGeoPositionInfoSourceWinRT *src = new QGeoPositionInfoSourceWinRT(parent); if (src->init() < 0) { + qCDebug(lcPositioningWinRT) << __FUNCTION__ << "Source initialization failed."; delete src; - src = 0; + return nullptr; } + qCDebug(lcPositioningWinRT) << __FUNCTION__ << "Created position info source."; return src; } QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryWinRT::satelliteInfoSource(QObject *parent) { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_UNUSED(parent); - return 0; + return nullptr; } QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryWinRT::areaMonitor(QObject *parent) { + qCDebug(lcPositioningWinRT) << __FUNCTION__; Q_UNUSED(parent); - return 0; + return nullptr; } + +QT_END_NAMESPACE diff --git a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h index 46cd3853..d09ddb64 100644 --- a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h +++ b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h @@ -37,8 +37,8 @@ #ifndef QGEOPOSITIONINFOSOURCEFACTORY_WINRT_H #define QGEOPOSITIONINFOSOURCEFACTORY_WINRT_H -#include <QObject> -#include <QGeoPositionInfoSourceFactory> +#include <QtCore/qobject.h> +#include <QtPositioning/qgeopositioninfosourcefactory.h> QT_BEGIN_NAMESPACE diff --git a/src/positioning/doc/src/qtpositioning-qml.qdoc b/src/positioning/doc/src/qtpositioning-qml.qdoc index 7c9567cb..0c84484b 100644 --- a/src/positioning/doc/src/qtpositioning-qml.qdoc +++ b/src/positioning/doc/src/qtpositioning-qml.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -26,40 +26,46 @@ ****************************************************************************/ /*! - \qmlmodule QtPositioning 5.11 + \qmlmodule QtPositioning \QtVer \title Qt Positioning QML Types \ingroup qmlmodules - \brief Provides QML types for position information + \brief Provides QML types for position information. -\section1 Overview + \section1 Overview -The identifying string for this module is \e QtPositioning. To use include the following import -statement in the QML file. + The identifying string for this module is \e QtPositioning. To use the QML + from this module, include the following import statement in the QML file: -\snippet doc_src_qtpositioning.qml import + \qml \QtVer + import QtPositioning \1 + \endqml -\section2 Positioning QML Concepts + \section2 Positioning QML Concepts -Position information can come from a variety of sources including satellites, -wifi, text files and so on. The position is described by the latitude, -the longitude, and the altitude in meters. For more information see -\l {http://en.wikipedia.org/wiki/Geographic_coordinate}{Geographic Coordinate}. + Position information can come from a variety of sources including + satellites, Wi-Fi, text files and so on. The position is described by the + latitude, longitude, and the altitude in meters. For more information, see + the Wikipedia page on + \l {http://en.wikipedia.org/wiki/Geographic_coordinate} + {Geographic Coordinates}. -The QML position is stored in a \l {coordinate} which contains the -latitude, longitude and altitude of the device. The \l {QtPositioning::Location}{Location} contains -this \l {coordinate} and adds an address, it also has a bounding box which -defines the recommended viewing region when displaying the location. + The QML position is stored in a \l {coordinate} which contains the + latitude, longitude and altitude of the device. The \l {QtPositioning::} + {Location} contains this \l {coordinate} and adds an address, and also has + a bounding box which defines the recommended viewing region when displaying + the location. -Now that the device has a position, with regular updates the API can determine -the speed and heading of the device. It can also define a box or a circle that can -produce a notification when the device either leaves or enters that region. + Now that the device has a position, with regular updates the API can + determine the speed and heading of the device. It can also define a + box-shaped or circular region that triggers notifications when the device + either leaves or enters that region. -More detailed information retrieving the current position can be found under -\l {Positioning (QML)}{Location Positioning via QML} + More detailed information on retrieving the current position can be found + under \l {Positioning (QML)}{Location Positioning via QML}. -\section1 Basic Types + \section1 Basic Types -\annotatedlist qml-QtPositioning5-basictypes + \annotatedlist qml-QtPositioning5-basictypes -\section1 Alphabetical Listing of All QML Types + \section1 Alphabetical Listing of All QML Types */ diff --git a/tests/auto/declarative_core/tst_categorymodel.qml b/tests/auto/declarative_core/tst_categorymodel.qml index 0b6e50a3..86d0fd4c 100644 --- a/tests/auto/declarative_core/tst_categorymodel.qml +++ b/tests/auto/declarative_core/tst_categorymodel.qml @@ -221,7 +221,7 @@ TestCase { //iteration. //try updating with an uninitialized plugin instance. - testModel.plugin = uninitializedPlugin; + testModel.plugin = uninitializedPlugin; // uninitialized does not trigger update on setPlugin testModel.update(); tryCompare(statusChangedSpy, "count", 2); compare(testModel.status, CategoryModel.Error); @@ -229,8 +229,9 @@ TestCase { //try searching with plugin a instance //that has been provided a non-existent name + tryCompare(statusChangedSpy, "count", 0); testModel.plugin = nonExistantPlugin; - testModel.update(); +// testModel.update(); //QTBUG-70254 tryCompare(statusChangedSpy, "count", 2); compare(testModel.status, CategoryModel.Error); } |