diff options
Diffstat (limited to 'src/location')
-rw-r--r-- | src/location/declarativemaps/qdeclarativecirclemapitem.cpp | 29 | ||||
-rw-r--r-- | src/location/declarativemaps/qdeclarativecirclemapitem_p.h | 1 | ||||
-rw-r--r-- | src/location/declarativemaps/qdeclarativegeomap.cpp | 63 | ||||
-rw-r--r-- | src/location/declarativemaps/qdeclarativegeomap_p.h | 2 | ||||
-rw-r--r-- | src/location/declarativemaps/qdeclarativegeomapquickitem.cpp | 9 | ||||
-rw-r--r-- | src/location/declarativemaps/qdeclarativepolygonmapitem.cpp | 89 | ||||
-rw-r--r-- | src/location/declarativemaps/qdeclarativepolylinemapitem.cpp | 115 | ||||
-rw-r--r-- | src/location/declarativemaps/qquickgeomapgesturearea.cpp | 2 | ||||
-rw-r--r-- | src/location/declarativemaps/qquickgeomapgesturearea_p.h | 4 | ||||
-rw-r--r-- | src/location/location.pro | 1 | ||||
-rw-r--r-- | src/location/maps/qgeomappingmanager.cpp | 6 | ||||
-rw-r--r-- | src/location/maps/qgeoprojection.cpp | 114 | ||||
-rw-r--r-- | src/location/maps/qgeoprojection_p.h | 7 | ||||
-rw-r--r-- | src/location/maps/qgeoroute.cpp | 4 |
14 files changed, 214 insertions, 232 deletions
diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem.cpp b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp index 274225c0..5f002bf9 100644 --- a/src/location/declarativemaps/qdeclarativecirclemapitem.cpp +++ b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp @@ -278,7 +278,8 @@ static bool crossEarthPole(const QGeoCoordinate ¢er, qreal distance) static void calculatePeripheralPoints(QList<QGeoCoordinate> &path, const QGeoCoordinate ¢er, qreal distance, - int steps) + int steps, + QGeoCoordinate &leftBound) { // Calculate points based on great-circle distance // Calculation is the same as GeoCoordinate's atDistanceAndAzimuth function @@ -287,15 +288,17 @@ static void calculatePeripheralPoints(QList<QGeoCoordinate> &path, // pre-calculations steps = qMax(steps, 3); qreal centerLon = center.longitude(); + qreal minLon = centerLon; qreal latRad = QLocationUtils::radians(center.latitude()); qreal lonRad = QLocationUtils::radians(centerLon); qreal cosLatRad = std::cos(latRad); qreal sinLatRad = std::sin(latRad); - qreal ratio = (distance / (QLocationUtils::earthMeanRadius())); + qreal ratio = (distance / QLocationUtils::earthMeanRadius()); qreal cosRatio = std::cos(ratio); qreal sinRatio = std::sin(ratio); qreal sinLatRad_x_cosRatio = sinLatRad * cosRatio; qreal cosLatRad_x_sinRatio = cosLatRad * sinRatio; + int idx = 0; for (int i = 0; i < steps; ++i) { qreal azimuthRad = 2 * M_PI * i / steps; qreal resultLatRad = std::asin(sinLatRad_x_cosRatio @@ -306,7 +309,17 @@ static void calculatePeripheralPoints(QList<QGeoCoordinate> &path, qreal lon2 = QLocationUtils::wrapLong(QLocationUtils::degrees(resultLonRad)); path << QGeoCoordinate(lat2, lon2, center.altitude()); + // Consider only points in the left half of the circle for the left bound. + if (azimuthRad > M_PI) { + if (lon2 > centerLon) // if point and center are on different hemispheres + lon2 -= 360; + if (lon2 < minLon) { + minLon = lon2; + idx = i; + } + } } + leftBound = path.at(idx); } QDeclarativeCircleMapItem::QDeclarativeCircleMapItem(QQuickItem *parent) @@ -480,8 +493,10 @@ void QDeclarativeCircleMapItem::updatePolish() int pathCount = circlePath.size(); bool preserve = preserveCircleGeometry(circlePath, circle_.center(), circle_.radius()); - geometry_.setPreserveGeometry(true, circle_.boundingGeoRectangle().topLeft()); // to set the geoLeftBound_ - geometry_.setPreserveGeometry(preserve, circle_.boundingGeoRectangle().topLeft()); + // using leftBound_ instead of the analytically calculated circle_.boundingGeoRectangle().topLeft()); + // to fix QTBUG-62154 + geometry_.setPreserveGeometry(true, leftBound_); // to set the geoLeftBound_ + geometry_.setPreserveGeometry(preserve, leftBound_); bool invertedCircle = false; if (crossEarthPole(circle_.center(), circle_.radius()) && circlePath.size() == pathCount) { @@ -506,8 +521,8 @@ void QDeclarativeCircleMapItem::updatePolish() std::reverse(closedPath.begin(), closedPath.end()); } - borderGeometry_.setPreserveGeometry(true, circle_.boundingGeoRectangle().topLeft()); // to set the geoLeftBound_ - borderGeometry_.setPreserveGeometry(preserve, circle_.boundingGeoRectangle().topLeft()); + borderGeometry_.setPreserveGeometry(true, leftBound_); + borderGeometry_.setPreserveGeometry(preserve, leftBound_); // Use srcOrigin_ from fill geometry after clipping to ensure that translateToCommonOrigin won't fail. const QGeoCoordinate &geometryOrigin = geometry_.origin(); @@ -553,7 +568,7 @@ void QDeclarativeCircleMapItem::updateCirclePath() if (!map()) return; QList<QGeoCoordinate> path; - calculatePeripheralPoints(path, circle_.center(), circle_.radius(), CircleSamples); + calculatePeripheralPoints(path, circle_.center(), circle_.radius(), CircleSamples, leftBound_); circlePath_.clear(); for (const QGeoCoordinate &c : path) circlePath_ << map()->geoProjection().geoToMapProjection(c); diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem_p.h b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h index 511e3b17..15774427 100644 --- a/src/location/declarativemaps/qdeclarativecirclemapitem_p.h +++ b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h @@ -121,6 +121,7 @@ private: QDeclarativeMapLineProperties border_; QColor color_; QList<QDoubleVector2D> circlePath_; + QGeoCoordinate leftBound_; bool dirtyMaterial_; QGeoMapCircleGeometry geometry_; QGeoMapPolylineGeometry borderGeometry_; diff --git a/src/location/declarativemaps/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp index 19bc57ce..37cfc303 100644 --- a/src/location/declarativemaps/qdeclarativegeomap.cpp +++ b/src/location/declarativemaps/qdeclarativegeomap.cpp @@ -255,6 +255,8 @@ QDeclarativeGeoMap::~QDeclarativeGeoMap() delete m_copyrights.data(); m_copyrights.clear(); + + delete m_map; } /*! @@ -293,17 +295,17 @@ void QDeclarativeGeoMap::onMapChildrenChanged() copyrights = m_copyrights.data(); - connect(m_map.data(), SIGNAL(copyrightsChanged(QImage)), + connect(m_map, SIGNAL(copyrightsChanged(QImage)), copyrights, SLOT(copyrightsChanged(QImage))); - connect(m_map.data(), SIGNAL(copyrightsChanged(QImage)), + connect(m_map, SIGNAL(copyrightsChanged(QImage)), this, SIGNAL(copyrightsChanged(QImage))); - connect(m_map.data(), SIGNAL(copyrightsChanged(QString)), + connect(m_map, SIGNAL(copyrightsChanged(QString)), copyrights, SLOT(copyrightsChanged(QString))); - connect(m_map.data(), SIGNAL(copyrightsChanged(QString)), + connect(m_map, SIGNAL(copyrightsChanged(QString)), this, SIGNAL(copyrightsChanged(QString))); - connect(m_map.data(), SIGNAL(copyrightsStyleSheetChanged(QString)), + connect(m_map, SIGNAL(copyrightsStyleSheetChanged(QString)), copyrights, SLOT(onCopyrightsStyleSheetChanged(QString))); connect(copyrights, SIGNAL(linkActivated(QString)), @@ -739,7 +741,7 @@ void QDeclarativeGeoMap::onCameraCapabilitiesChanged(const QGeoCameraCapabilitie */ void QDeclarativeGeoMap::mappingManagerInitialized() { - m_map = QPointer<QGeoMap>(m_mappingManager->createMap(this)); + m_map = m_mappingManager->createMap(this); if (!m_map) return; @@ -784,11 +786,11 @@ void QDeclarativeGeoMap::mappingManagerInitialized() QImage copyrightImage; if (!m_initialized && width() > 0 && height() > 0) { QMetaObject::Connection copyrightStringCatcherConnection = - connect(m_map.data(), + connect(m_map, QOverload<const QString &>::of(&QGeoMap::copyrightsChanged), [©rightString](const QString ©){ copyrightString = copy; }); QMetaObject::Connection copyrightImageCatcherConnection = - connect(m_map.data(), + connect(m_map, QOverload<const QImage &>::of(&QGeoMap::copyrightsChanged), [©rightImage](const QImage ©){ copyrightImage = copy; }); m_map->setViewportSize(QSize(width(), height())); @@ -800,28 +802,28 @@ void QDeclarativeGeoMap::mappingManagerInitialized() m_copyrights = new QDeclarativeGeoMapCopyrightNotice(this); m_copyrights->onCopyrightsStyleSheetChanged(m_map->copyrightsStyleSheet()); - connect(m_map.data(), SIGNAL(copyrightsChanged(QImage)), + connect(m_map, SIGNAL(copyrightsChanged(QImage)), m_copyrights.data(), SLOT(copyrightsChanged(QImage))); - connect(m_map.data(), SIGNAL(copyrightsChanged(QImage)), + connect(m_map, SIGNAL(copyrightsChanged(QImage)), this, SIGNAL(copyrightsChanged(QImage))); - connect(m_map.data(), SIGNAL(copyrightsChanged(QString)), + connect(m_map, SIGNAL(copyrightsChanged(QString)), m_copyrights.data(), SLOT(copyrightsChanged(QString))); - connect(m_map.data(), SIGNAL(copyrightsChanged(QString)), + connect(m_map, SIGNAL(copyrightsChanged(QString)), this, SIGNAL(copyrightsChanged(QString))); if (!copyrightString.isEmpty()) - emit m_map.data()->copyrightsChanged(copyrightString); + emit m_map->copyrightsChanged(copyrightString); else if (!copyrightImage.isNull()) - emit m_map.data()->copyrightsChanged(copyrightImage); + emit m_map->copyrightsChanged(copyrightImage); - connect(m_map.data(), SIGNAL(copyrightsStyleSheetChanged(QString)), + connect(m_map, SIGNAL(copyrightsStyleSheetChanged(QString)), m_copyrights.data(), SLOT(onCopyrightsStyleSheetChanged(QString))); connect(m_copyrights.data(), SIGNAL(linkActivated(QString)), this, SIGNAL(copyrightLinkActivated(QString))); - connect(m_map.data(), &QGeoMap::sgNodeChanged, this, &QQuickItem::update); - connect(m_map.data(), &QGeoMap::cameraCapabilitiesChanged, this, &QDeclarativeGeoMap::onCameraCapabilitiesChanged); + connect(m_map, &QGeoMap::sgNodeChanged, this, &QQuickItem::update); + connect(m_map, &QGeoMap::cameraCapabilitiesChanged, this, &QDeclarativeGeoMap::onCameraCapabilitiesChanged); // set visibility of copyright notice m_copyrights->setCopyrightsVisible(m_copyrightsVisible); @@ -1340,20 +1342,21 @@ QGeoShape QDeclarativeGeoMap::visibleRegion() const const QList<QDoubleVector2D> &visibleRegion = m_map->geoProjection().visibleRegion(); QGeoPath path; - for (const QDoubleVector2D &c: visibleRegion) + for (int i = 0; i < visibleRegion.size(); ++i) { + const QDoubleVector2D &c = visibleRegion.at(i); + // If a segment spans more than half of the map longitudinally, split in 2. + if (i && qAbs(visibleRegion.at(i-1).x() - c.x()) >= 0.5) { // This assumes a segment is never >= 1.0 (whole map span) + QDoubleVector2D extraPoint = (visibleRegion.at(i-1) + c) * 0.5; + path.addCoordinate(m_map->geoProjection().wrappedMapProjectionToGeo(extraPoint)); + } path.addCoordinate(m_map->geoProjection().wrappedMapProjectionToGeo(c)); - - QGeoRectangle vr = path.boundingGeoRectangle(); - - bool empty = vr.topLeft().latitude() == vr.bottomRight().latitude() || - qFuzzyCompare(vr.topLeft().longitude(), vr.bottomRight().longitude()); // QTBUG-57690 - - if (empty) { - vr.setTopLeft(QGeoCoordinate(vr.topLeft().latitude(), -180)); - vr.setBottomRight(QGeoCoordinate(vr.bottomRight().latitude(), 180)); + } + if (visibleRegion.size() >= 2 && qAbs(visibleRegion.last().x() - visibleRegion.first().x()) >= 0.5) { + QDoubleVector2D extraPoint = (visibleRegion.last() + visibleRegion.first()) * 0.5; + path.addCoordinate(m_map->geoProjection().wrappedMapProjectionToGeo(extraPoint)); } - return vr; + return path.boundingGeoRectangle(); } /*! @@ -1440,7 +1443,7 @@ void QDeclarativeGeoMap::fitViewportToGeoShape() QGeoCoordinate centerCoordinate = m_map->geoProjection().mapProjectionToGeo(center); // position camera to the center of bounding box - setCenter(centerCoordinate); + setProperty("center", QVariant::fromValue(centerCoordinate)); // not using setCenter(centerCoordinate) to honor a possible animation set on the center property // if the shape is empty we just change center position, not zoom double bboxWidth = (bottomRightPoint.x() - topLeftPoint.x()) * m_map->mapWidth(); @@ -1453,7 +1456,7 @@ void QDeclarativeGeoMap::fitViewportToGeoShape() bboxHeight / (height() - margins)); zoomRatio = std::log(zoomRatio) / std::log(2.0); double newZoom = qMax<double>(minimumZoomLevel(), zoomLevel() - zoomRatio); - setZoomLevel(newZoom); + setProperty("zoomLevel", QVariant::fromValue(newZoom)); // not using setZoomLevel(newZoom) to honor a possible animation set on the zoomLevel property } diff --git a/src/location/declarativemaps/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h index 90e73420..5c568d8f 100644 --- a/src/location/declarativemaps/qdeclarativegeomap_p.h +++ b/src/location/declarativemaps/qdeclarativegeomap_p.h @@ -258,7 +258,7 @@ private: QList<QDeclarativeGeoMapType *> m_supportedMapTypes; QList<QDeclarativeGeoMapItemView *> m_mapViews; QQuickGeoMapGestureArea *m_gestureArea; - QPointer<QGeoMap> m_map; + QGeoMap* m_map = nullptr; QPointer<QDeclarativeGeoMapCopyrightNotice> m_copyrights; QList<QPointer<QDeclarativeGeoMapItemBase> > m_mapItems; QList<QPointer<QDeclarativeGeoMapItemGroup> > m_mapItemGroups; diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp index 86d67cf8..7c0764aa 100644 --- a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp @@ -159,7 +159,7 @@ QDeclarativeGeoMapQuickItem::~QDeclarativeGeoMapQuickItem() {} */ void QDeclarativeGeoMapQuickItem::setCoordinate(const QGeoCoordinate &coordinate) { - if (coordinate_ == coordinate || !coordinate.isValid()) + if (coordinate_ == coordinate) return; coordinate_ = coordinate; @@ -378,6 +378,13 @@ void QDeclarativeGeoMapQuickItem::updatePolish() this, SLOT(polishAndUpdate())); } + if (!coordinate_.isValid()) { + opacityContainer_->setVisible(false); + return; + } else { + opacityContainer_->setVisible(true); + } + QScopedValueRollback<bool> rollback(updatingGeometry_); updatingGeometry_ = true; diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp index daa1a9fc..48f66423 100644 --- a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp +++ b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp @@ -53,6 +53,8 @@ /* poly2tri triangulator includes */ #include <clip2tri.h> +#include <earcut.hpp> +#include <array> QT_BEGIN_NAMESPACE @@ -185,7 +187,7 @@ void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map, // 2) QList<QList<QDoubleVector2D> > clippedPaths; - const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion(); + const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().projectableRegion(); if (visibleRegion.size()) { c2t::clip2tri clipper; clipper.addSubjectPath(QClipperUtils::qListToPath(wrappedPath), true); @@ -254,16 +256,6 @@ void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map) return; } - QDoubleVector2D origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false); - - // Create the viewport rect in the same coordinate system - // as the actual points - QRectF viewport(0, 0, map.viewportWidth(), map.viewportHeight()); - viewport.translate(-1 * origin.toPointF()); - - QPainterPath vpPath; - vpPath.addRect(viewport); - // The geometry has already been clipped against the visible region projection in wrapped mercator space. QPainterPath ppi = srcPath_; clear(); @@ -272,57 +264,50 @@ void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map) if (ppi.elementCount() < 3) return; - // Intersection between the viewport and a concave polygon can create multiple polygons - // joined by a line at the viewport border, and poly2tri does not triangulate this very well - // so use the full src path if the resulting polygon is concave. - if (clipToViewport_) { - int changeInX = 0; - int changeInY = 0; - QPainterPath::Element e1 = ppi.elementAt(1); - QPainterPath::Element e = ppi.elementAt(0); - QVector2D edgeA(e1.x - e.x ,e1.y - e.y); - for (int i = 2; i <= ppi.elementCount(); ++i) { - e = ppi.elementAt(i % ppi.elementCount()); - if (e.x == e1.x && e.y == e1.y) - continue; - QVector2D edgeB(e.x - e1.x, e.y - e1.y); - if ((edgeA.x() < 0) == (edgeB.x() >= 0)) - changeInX++; - if ((edgeA.y() < 0) == (edgeB.y() >= 0)) - changeInY++; - edgeA = edgeB; - e1 = e; - } - if (changeInX > 2 || changeInY > 2) // polygon is concave - ppi = srcPath_; - } - // translate the path into top-left-centric coordinates QRectF bb = ppi.boundingRect(); ppi.translate(-bb.left(), -bb.top()); firstPointOffset_ = -1 * bb.topLeft(); ppi.closeSubpath(); - screenOutline_ = ppi; - QTriangleSet ts = qTriangulate(ppi); - qreal *vx = ts.vertices.data(); - - screenIndices_.reserve(ts.indices.size()); - screenVertices_.reserve(ts.vertices.size()); + using Coord = double; + using N = uint32_t; + using Point = std::array<Coord, 2>; + + std::vector<std::vector<Point>> polygon; + polygon.push_back(std::vector<Point>()); + std::vector<Point> &poly = polygon.front(); + // ... fill polygon structure with actual data + + for (int i = 0; i < ppi.elementCount(); ++i) { + const QPainterPath::Element e = ppi.elementAt(i); + if (e.isMoveTo() || i == ppi.elementCount() - 1 + || (qAbs(e.x - poly.front()[0]) < 0.1 + && qAbs(e.y - poly.front()[1]) < 0.1)) { + Point p = { e.x, e.y }; + poly.push_back( p ); + } else if (e.isLineTo()) { + Point p = { e.x, e.y }; + poly.push_back( p ); + } else { + qWarning("Unhandled element type in polygon painterpath"); + } + } - if (ts.indices.type() == QVertexIndexVector::UnsignedInt) { - const quint32 *ix = reinterpret_cast<const quint32 *>(ts.indices.data()); - for (int i = 0; i < (ts.indices.size()/3*3); ++i) - screenIndices_ << ix[i]; - } else { - const quint16 *ix = reinterpret_cast<const quint16 *>(ts.indices.data()); - for (int i = 0; i < (ts.indices.size()/3*3); ++i) - screenIndices_ << ix[i]; + if (poly.size() > 2) { + // Run tessellation + // Returns array of indices that refer to the vertices of the input polygon. + // Three subsequent indices form a triangle. + screenVertices_.clear(); + screenIndices_.clear(); + for (const auto &p : poly) + screenVertices_ << QPointF(p[0], p[1]); + std::vector<N> indices = mapbox::earcut<N>(polygon); + for (const auto &i: indices) + screenIndices_ << quint32(i); } - for (int i = 0; i < (ts.vertices.size()/2*2); i += 2) - screenVertices_ << QPointF(vx[i], vx[i + 1]); screenBounds_ = ppi.boundingRect(); } diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp index 72c43a49..a97271aa 100644 --- a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp +++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp @@ -226,7 +226,7 @@ QList<QList<QDoubleVector2D> > QGeoMapPolylineGeometry::clipPath(const QGeoMap & // 2) QList<QList<QDoubleVector2D> > clippedPaths; - const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion(); + const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().projectableRegion(); if (visibleRegion.size()) { c2t::clip2tri clipper; clipper.addSubjectPath(QClipperUtils::qListToPath(wrappedPath), false); @@ -337,120 +337,7 @@ void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map, } //////////////////////////////////////////////////////////////////////////// -#if 0 // Old polyline to viewport clipping code. Retaining it for now. -/* Polyline clip */ - -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, lastY; - 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]; - } -} -#endif /*! \internal */ diff --git a/src/location/declarativemaps/qquickgeomapgesturearea.cpp b/src/location/declarativemaps/qquickgeomapgesturearea.cpp index 39fd2397..fc2debc3 100644 --- a/src/location/declarativemaps/qquickgeomapgesturearea.cpp +++ b/src/location/declarativemaps/qquickgeomapgesturearea.cpp @@ -498,7 +498,7 @@ QQuickGeoMapGestureArea::QQuickGeoMapGestureArea(QDeclarativeGeoMap *map) /*! \internal */ -void QQuickGeoMapGestureArea::setMap(QPointer<QGeoMap> map) +void QQuickGeoMapGestureArea::setMap(QGeoMap *map) { if (m_map || !map) return; diff --git a/src/location/declarativemaps/qquickgeomapgesturearea_p.h b/src/location/declarativemaps/qquickgeomapgesturearea_p.h index 5daa39cf..0bc774d3 100644 --- a/src/location/declarativemaps/qquickgeomapgesturearea_p.h +++ b/src/location/declarativemaps/qquickgeomapgesturearea_p.h @@ -178,7 +178,7 @@ public: void setMaximumZoomLevel(qreal max); qreal maximumZoomLevel() const; - void setMap(QPointer<QGeoMap> map); + void setMap(QGeoMap* map); bool preventStealing() const; void setPreventStealing(bool prevent); @@ -267,7 +267,7 @@ private: void updateFlickParameters(const QPointF &pos); private: - QPointer<QGeoMap> m_map; + QGeoMap* m_map; QDeclarativeGeoMap *m_declarativeMap; bool m_enabled; diff --git a/src/location/location.pro b/src/location/location.pro index 5dc89a63..a951ebd6 100644 --- a/src/location/location.pro +++ b/src/location/location.pro @@ -10,6 +10,7 @@ CONFIG += simd optimize_full # 3rdparty headers produce warnings with MSVC msvc: CONFIG -= warning_clean +INCLUDEPATH += ../3rdparty/earcut INCLUDEPATH += ../3rdparty/poly2tri INCLUDEPATH += ../3rdparty/clipper INCLUDEPATH += ../3rdparty/clip2tri diff --git a/src/location/maps/qgeomappingmanager.cpp b/src/location/maps/qgeomappingmanager.cpp index cf040beb..d73050f7 100644 --- a/src/location/maps/qgeomappingmanager.cpp +++ b/src/location/maps/qgeomappingmanager.cpp @@ -133,10 +133,8 @@ int QGeoMappingManager::managerVersion() const */ QGeoMap *QGeoMappingManager::createMap(QObject *parent) { - QGeoMap * map = d_ptr->engine->createMap(); - if (map) - connect(parent, &QObject::destroyed,map, &QGeoMap::deleteLater); - return map; + Q_UNUSED(parent) + return d_ptr->engine->createMap(); } QList<QGeoMapType> QGeoMappingManager::supportedMapTypes() const diff --git a/src/location/maps/qgeoprojection.cpp b/src/location/maps/qgeoprojection.cpp index 7fefba27..218d806b 100644 --- a/src/location/maps/qgeoprojection.cpp +++ b/src/location/maps/qgeoprojection.cpp @@ -212,14 +212,25 @@ QDoubleVector2D QGeoProjectionWebMercator::wrappedMapProjectionToItemPosition(co QDoubleVector2D QGeoProjectionWebMercator::itemPositionToWrappedMapProjection(const QDoubleVector2D &itemPosition) const { QDoubleVector2D pos = itemPosition; - // when the camera is tilted, picking a point above the horizon returns a coordinate behind the camera - if (pos.y() < m_minimumUnprojectableY) - pos.setY(m_minimumUnprojectableY); pos *= QDoubleVector2D(m_1_viewportWidth, m_1_viewportHeight); pos *= 2.0; pos -= QDoubleVector2D(1.0,1.0); - return viewportToWrappedMapProjection(pos); + double s; + QDoubleVector2D res = viewportToWrappedMapProjection(pos, s); + + // a positive s means a point behind the camera. So do it again, after clamping Y. See QTBUG-61813 + if (s > 0.0) { + pos = itemPosition; + // when the camera is tilted, picking a point above the horizon returns a coordinate behind the camera + pos.setY(m_minimumUnprojectableY); + pos *= QDoubleVector2D(m_1_viewportWidth, m_1_viewportHeight); + pos *= 2.0; + pos -= QDoubleVector2D(1.0,1.0); + res = viewportToWrappedMapProjection(pos, s); + } + + return res; } /* Default implementations */ @@ -317,10 +328,23 @@ QList<QDoubleVector2D> QGeoProjectionWebMercator::visibleRegion() const return m_visibleRegion; } +QList<QDoubleVector2D> QGeoProjectionWebMercator::projectableRegion() const +{ + if (m_visibleRegionDirty) + const_cast<QGeoProjectionWebMercator *>(this)->updateVisibleRegion(); + return m_projectableRegion; +} + +QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition) const +{ + double s; + return viewportToWrappedMapProjection(itemPosition, s); +} + /* actual implementation of itemPositionToWrappedMapProjection */ -QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition) const +QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition, double &s) const { QDoubleVector2D pos = itemPosition; pos *= QDoubleVector2D(m_halfWidth, m_halfHeight); @@ -332,7 +356,7 @@ QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(const QDoubleVector3D ray = p - m_eye; ray.normalize(); - return (xyPlane.lineIntersection(m_eye, ray) / m_sideLength).toVector2D(); + return (xyPlane.lineIntersection(m_eye, ray, s) / m_sideLength).toVector2D(); } void QGeoProjectionWebMercator::setupCamera() @@ -344,6 +368,8 @@ void QGeoProjectionWebMercator::setupCamera() int intZoomLevel = static_cast<int>(std::floor(m_cameraData.zoomLevel())); m_sideLength = (1 << intZoomLevel) * defaultTileSize; m_center = m_centerMercator * m_sideLength; + //aperture(90 / 2) = 1 + m_aperture = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5); double f = m_viewportHeight; double z = std::pow(2.0, m_cameraData.zoomLevel() - intZoomLevel) * defaultTileSize; @@ -352,15 +378,13 @@ void QGeoProjectionWebMercator::setupCamera() double z_mercator = std::pow(2.0, m_cameraData.zoomLevel()) * defaultTileSize; double altitude_mercator = f / (2.0 * z_mercator); - //aperture(90 / 2) = 1 - m_aperture = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5); // calculate eye m_eye = m_center; m_eye.setZ(altitude * defaultTileSize / m_aperture); // And in mercator space m_eyeMercator = m_centerMercator; - m_eyeMercator.setZ(altitude_mercator); + m_eyeMercator.setZ(altitude_mercator / m_aperture); m_view = m_eye - m_center; QDoubleVector3D side = QDoubleVector3D::normal(m_view, QDoubleVector3D(0.0, 1.0, 0.0)); @@ -396,7 +420,7 @@ void QGeoProjectionWebMercator::setupCamera() m_eyeMercator = mTiltMercator * m_viewMercator + m_centerMercator; } - m_view = m_eye - m_center; + m_view = m_eye - m_center; // ToDo: this should be inverted (center - eye), and the rest should follow m_viewNormalized = m_view.normalized(); m_up = QDoubleVector3D::normal(m_view, m_side); @@ -449,7 +473,7 @@ void QGeoProjectionWebMercator::setupCamera() m_transformation.scale(m_sideLength, m_sideLength, 1.0); m_centerNearPlane = m_eye + m_viewNormalized; - m_centerNearPlaneMercator = m_eyeMercator + m_viewNormalized * m_nearPlaneMercator; + m_centerNearPlaneMercator = m_eyeMercator - m_viewNormalized * m_nearPlaneMercator; // The method does not support tilting angles >= 90.0 or < 0. @@ -478,11 +502,17 @@ void QGeoProjectionWebMercator::updateVisibleRegion() QDoubleVector2D bl = viewportToWrappedMapProjection(QDoubleVector2D(-1, 1 )); QDoubleVector2D br = viewportToWrappedMapProjection(QDoubleVector2D( 1, 1 )); + // To make sure that what is returned can be safely converted back to lat/lon without risking overlaps + double mapLeftLongitude = QLocationUtils::mapLeftLongitude(m_cameraData.center().longitude()); + double mapRightLongitude = QLocationUtils::mapRightLongitude(m_cameraData.center().longitude()); + double leftX = geoToWrappedMapProjection(QGeoCoordinate(0, mapLeftLongitude)).x(); + double rightX = geoToWrappedMapProjection(QGeoCoordinate(0, mapRightLongitude)).x(); + QList<QDoubleVector2D> mapRect; - mapRect.push_back(QDoubleVector2D(-1.0, 1.0)); - mapRect.push_back(QDoubleVector2D( 2.0, 1.0)); - mapRect.push_back(QDoubleVector2D( 2.0, 0.0)); - mapRect.push_back(QDoubleVector2D(-1.0, 0.0)); + mapRect.push_back(QDoubleVector2D(leftX, 1.0)); + mapRect.push_back(QDoubleVector2D(rightX, 1.0)); + mapRect.push_back(QDoubleVector2D(rightX, 0.0)); + mapRect.push_back(QDoubleVector2D(leftX, 0.0)); QList<QDoubleVector2D> viewportRect; viewportRect.push_back(bl); @@ -499,6 +529,52 @@ void QGeoProjectionWebMercator::updateVisibleRegion() m_visibleRegion.clear(); if (res.size()) m_visibleRegion = QClipperUtils::pathToQList(res[0]); // Intersection between two convex quadrilaterals should always be a single polygon + + m_projectableRegion.clear(); + mapRect.clear(); + // The full map rectangle in extended mercator space + mapRect.push_back(QDoubleVector2D(-1.0, 1.0)); + mapRect.push_back(QDoubleVector2D( 2.0, 1.0)); + mapRect.push_back(QDoubleVector2D( 2.0, 0.0)); + mapRect.push_back(QDoubleVector2D(-1.0, 0.0)); + if (m_cameraData.tilt() == 0) { + m_projectableRegion = mapRect; + } else { + QGeoProjectionWebMercator::Plane nearPlane(m_centerNearPlaneMercator, m_viewNormalized); + Line2D nearPlaneXYIntersection = nearPlane.planeXYIntersection(); + double squareHalfSide = qMax(5.0, nearPlaneXYIntersection.m_point.length()); + QDoubleVector2D viewDirectionProjected = -m_viewNormalized.toVector2D().normalized(); + + + QDoubleVector2D tl = nearPlaneXYIntersection.m_point + - squareHalfSide * nearPlaneXYIntersection.m_direction + + 2 * squareHalfSide * viewDirectionProjected; + QDoubleVector2D tr = nearPlaneXYIntersection.m_point + + squareHalfSide * nearPlaneXYIntersection.m_direction + + 2 * squareHalfSide * viewDirectionProjected; + QDoubleVector2D bl = nearPlaneXYIntersection.m_point + - squareHalfSide * nearPlaneXYIntersection.m_direction; + QDoubleVector2D br = nearPlaneXYIntersection.m_point + + squareHalfSide * nearPlaneXYIntersection.m_direction; + + QList<QDoubleVector2D> projectableRect; + projectableRect.push_back(bl); + projectableRect.push_back(br); + projectableRect.push_back(tr); + projectableRect.push_back(tl); + + + c2t::clip2tri clipperProjectable; + clipperProjectable.clearClipper(); + clipperProjectable.addSubjectPath(QClipperUtils::qListToPath(mapRect), true); + clipperProjectable.addClipPolygon(QClipperUtils::qListToPath(projectableRect)); + + Paths resProjectable = clipperProjectable.execute(c2t::clip2tri::Intersection); + if (resProjectable.size()) + m_projectableRegion = QClipperUtils::pathToQList(resProjectable[0]); // Intersection between two convex quadrilaterals should always be a single polygon + else + m_projectableRegion = viewportRect; + } } QGeoCameraData QGeoProjectionWebMercator::cameraData() const @@ -544,9 +620,15 @@ QGeoProjectionWebMercator::Plane::Plane(const QDoubleVector3D &planePoint, const QDoubleVector3D QGeoProjectionWebMercator::Plane::lineIntersection(const QDoubleVector3D &linePoint, const QDoubleVector3D &lineDirection) const { + double s; + return lineIntersection(linePoint, lineDirection, s); +} + +QDoubleVector3D QGeoProjectionWebMercator::Plane::lineIntersection(const QDoubleVector3D &linePoint, const QDoubleVector3D &lineDirection, double &s) const +{ QDoubleVector3D w = linePoint - m_point; // s = -n.dot(w) / n.dot(u). p = p0 + su; u is lineDirection - double s = QDoubleVector3D::dotProduct(-m_normal, w) / QDoubleVector3D::dotProduct(m_normal, lineDirection); + s = QDoubleVector3D::dotProduct(-m_normal, w) / QDoubleVector3D::dotProduct(m_normal, lineDirection); return linePoint + lineDirection * s; } diff --git a/src/location/maps/qgeoprojection_p.h b/src/location/maps/qgeoprojection_p.h index d3be1177..ca81df3a 100644 --- a/src/location/maps/qgeoprojection_p.h +++ b/src/location/maps/qgeoprojection_p.h @@ -73,6 +73,7 @@ public: virtual bool isProjectable(const QDoubleVector2D &wrappedProjection) const = 0; virtual QList<QDoubleVector2D> visibleRegion() const = 0; + virtual QList<QDoubleVector2D> projectableRegion() const = 0; // Conversion methods for QGeoCoordinate <-> screen. // This currently assumes that the "MapProjection" space is [0, 1][0, 1] for every type of possibly supported map projection @@ -132,9 +133,9 @@ public: bool isProjectable(const QDoubleVector2D &wrappedProjection) const Q_DECL_OVERRIDE; QList<QDoubleVector2D> visibleRegion() const Q_DECL_OVERRIDE; - + QList<QDoubleVector2D> projectableRegion() const Q_DECL_OVERRIDE; inline QDoubleVector2D viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition) const; - + inline QDoubleVector2D viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition, double &s) const; private: void setupCamera(); void updateVisibleRegion(); @@ -158,6 +159,7 @@ public: Plane(const QDoubleVector3D &planePoint, const QDoubleVector3D &planeNormal); QDoubleVector3D lineIntersection(const QDoubleVector3D &linePoint, const QDoubleVector3D &lineDirection) const; + inline QDoubleVector3D lineIntersection(const QDoubleVector3D &linePoint, const QDoubleVector3D &lineDirection, double &s) const; Line2D planeXYIntersection() const; bool isValid() const; @@ -208,6 +210,7 @@ private: Line2D m_nearPlaneMapIntersection; QList<QDoubleVector2D> m_visibleRegion; + QList<QDoubleVector2D> m_projectableRegion; bool m_visibleRegionDirty; Q_DISABLE_COPY(QGeoProjectionWebMercator) diff --git a/src/location/maps/qgeoroute.cpp b/src/location/maps/qgeoroute.cpp index 52fa4a5e..facf1949 100644 --- a/src/location/maps/qgeoroute.cpp +++ b/src/location/maps/qgeoroute.cpp @@ -104,7 +104,7 @@ QGeoRoute &QGeoRoute::operator= (const QGeoRoute & other) */ bool QGeoRoute::operator ==(const QGeoRoute &other) const { - return (d_ptr.constData() == other.d_ptr.constData()); + return (*d_ptr.constData() == *other.d_ptr.constData()); } /*! @@ -112,7 +112,7 @@ bool QGeoRoute::operator ==(const QGeoRoute &other) const */ bool QGeoRoute::operator !=(const QGeoRoute &other) const { - return (d_ptr.constData() != other.d_ptr.constData()); + return !(*d_ptr.constData() == *other.d_ptr.constData()); } /*! |