diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-11-27 03:01:30 +0100 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-11-27 03:01:30 +0100 |
commit | 181f1d8eac0af6e508ed483cbffb28cd2066b961 (patch) | |
tree | ce9ecf4878562ea35ddd6afd5efa040107d739af /src/location/declarativemaps | |
parent | 355a82e3d3aeb470b1d3d257afd2cce24f05b110 (diff) | |
parent | fb23882d5bc697b2dfdd22c27d34c52d889d1200 (diff) | |
download | qtlocation-181f1d8eac0af6e508ed483cbffb28cd2066b961.tar.gz |
Merge remote-tracking branch 'origin/5.12' into dev
Change-Id: I79898ba40dcce8054a105867ab2a88f1fba72c1f
Diffstat (limited to 'src/location/declarativemaps')
3 files changed, 184 insertions, 50 deletions
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..aeb7b718 100644 --- a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp +++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp @@ -400,7 +400,7 @@ QList<QList<QDoubleVector2D> > QGeoMapPolylineGeometry::clipPath(const QGeoMap & // 2) QList<QList<QDoubleVector2D> > clippedPaths; - const QList<QDoubleVector2D> &visibleRegion = p.visibleGeometryExpanded(); + const QList<QDoubleVector2D> &visibleRegion = p.projectableGeometry(); if (visibleRegion.size()) { clippedPaths = clipLine(wrappedPath, visibleRegion); @@ -507,6 +507,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 +640,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; |