diff options
Diffstat (limited to 'src/location/declarativemaps')
42 files changed, 0 insertions, 16531 deletions
diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem.cpp b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp deleted file mode 100644 index 2bec3455..00000000 --- a/src/location/declarativemaps/qdeclarativecirclemapitem.cpp +++ /dev/null @@ -1,714 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativecirclemapitem_p.h" -#include "qdeclarativepolygonmapitem_p.h" -#include "qdeclarativecirclemapitem_p_p.h" - -#include <QtCore/QScopedValueRollback> -#include <QPen> -#include <QPainter> -#include <qgeocircle.h> - -#include <QtGui/private/qtriangulator_p.h> -#include <QtLocation/private/qgeomap_p.h> -#include <QtPositioning/private/qlocationutils_p.h> -#include <QtPositioning/private/qclipperutils_p.h> - -#include <qmath.h> -#include <algorithm> - -QT_BEGIN_NAMESPACE - -/*! - \qmltype MapCircle - \instantiates QDeclarativeCircleMapItem - \inqmlmodule QtLocation - \ingroup qml-QtLocation5-maps - \since QtLocation 5.5 - - \brief The MapCircle type displays a geographic circle on a Map. - - The MapCircle type displays a geographic circle on a Map, which - consists of all points that are within a set distance from one - central point. Depending on map projection, a geographic circle - may not always be a perfect circle on the screen: for instance, in - the Mercator projection, circles become ovoid in shape as they near - the poles. To display a perfect screen circle around a point, use a - MapQuickItem containing a relevant Qt Quick type instead. - - By default, the circle is displayed as a 1 pixel black border with - no fill. To change its appearance, use the color, border.color - and border.width properties. - - Internally, a MapCircle is implemented as a many-sided polygon. To - calculate the radius points it uses a spherical model of the Earth, - similar to the atDistanceAndAzimuth method of the \l {coordinate} - type. These two things can occasionally have implications for the - accuracy of the circle's shape, depending on position and map - projection. - - \note Dragging a MapCircle (through the use of \l MouseArea) - causes new points to be generated at the same distance (in meters) - from the center. This is in contrast to other map items which store - their dimensions in terms of latitude and longitude differences between - vertices. - - \section2 Performance - - MapCircle performance is almost equivalent to that of a MapPolygon with - the same number of vertices. There is a small amount of additional - overhead with respect to calculating the vertices first. - - Like the other map objects, MapCircle is normally drawn without a smooth - appearance. Setting the opacity property will force the object to be - blended, which decreases performance considerably depending on the graphics - hardware in use. - - \section2 Example Usage - - The following snippet shows a map containing a MapCircle, centered at - the coordinate (-27, 153) with a radius of 5km. The circle is - filled in green, with a 3 pixel black border. - - \code - Map { - MapCircle { - center { - latitude: -27.5 - longitude: 153.0 - } - radius: 5000.0 - color: 'green' - border.width: 3 - } - } - \endcode - - \image api-mapcircle.png -*/ - -/*! - \qmlproperty bool QtLocation::MapCircle::autoFadeIn - - This property holds whether the item automatically fades in when zooming into the map - starting from very low zoom levels. By default this is \c true. - Setting this property to \c false causes the map item to always have the opacity specified - with the \l QtQuick::Item::opacity property, which is 1.0 by default. - - \since 5.14 -*/ - -struct Vertex -{ - QVector2D position; -}; - -QGeoMapCircleGeometry::QGeoMapCircleGeometry() -{ -} - -/*! - \internal -*/ -void QGeoMapCircleGeometry::updateScreenPointsInvert(const QList<QDoubleVector2D> &circlePath, const QGeoMap &map) -{ - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - // Not checking for !screenDirty anymore, as everything is now recalculated. - clear(); - if (map.viewportWidth() == 0 || map.viewportHeight() == 0 || circlePath.size() < 3) // a circle requires at least 3 points; - return; - - /* - * No special case for no tilting as these items are very rare, and usually at most one per map. - * - * Approach: - * 1) subtract the circle from a rectangle filling the whole map, *in wrapped mercator space* - * 2) clip the resulting geometries against the visible region, *in wrapped mercator space* - * 3) create a QPainterPath with each of the resulting polygons projected to screen - * 4) use qTriangulate() to triangulate the painter path - */ - - // 1) - const double topLati = QLocationUtils::mercatorMaxLatitude(); - const double bottomLati = -(QLocationUtils::mercatorMaxLatitude()); - const double leftLongi = QLocationUtils::mapLeftLongitude(map.cameraData().center().longitude()); - const double rightLongi = QLocationUtils::mapRightLongitude(map.cameraData().center().longitude()); - - srcOrigin_ = QGeoCoordinate(topLati,leftLongi); - const QDoubleVector2D tl = p.geoToWrappedMapProjection(QGeoCoordinate(topLati,leftLongi)); - const QDoubleVector2D tr = p.geoToWrappedMapProjection(QGeoCoordinate(topLati,rightLongi)); - const QDoubleVector2D br = p.geoToWrappedMapProjection(QGeoCoordinate(bottomLati,rightLongi)); - const QDoubleVector2D bl = p.geoToWrappedMapProjection(QGeoCoordinate(bottomLati,leftLongi)); - - QList<QDoubleVector2D> fill; - fill << tl << tr << br << bl; - - QList<QDoubleVector2D> hole; - for (const QDoubleVector2D &c: circlePath) - hole << p.wrapMapProjection(c); - - QClipperUtils clipper; - clipper.addSubjectPath(fill, true); - clipper.addClipPolygon(hole); - auto difference = clipper.execute(QClipperUtils::Difference, QClipperUtils::pftEvenOdd, - QClipperUtils::pftEvenOdd); - - // 2) - QDoubleVector2D lb = p.geoToWrappedMapProjection(srcOrigin_); - QList<QList<QDoubleVector2D> > clippedPaths; - const QList<QDoubleVector2D> &visibleRegion = p.visibleGeometry(); - if (visibleRegion.size()) { - clipper.clearClipper(); - for (const auto &p: difference) - clipper.addSubjectPath(p, true); - clipper.addClipPolygon(visibleRegion); - clippedPaths = clipper.execute(QClipperUtils::Intersection, QClipperUtils::pftEvenOdd, - QClipperUtils::pftEvenOdd); - - // 2.1) update srcOrigin_ with the point with minimum X/Y - lb = QDoubleVector2D(qInf(), qInf()); - for (const QList<QDoubleVector2D> &path: clippedPaths) { - for (const QDoubleVector2D &p: path) { - if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) { - lb = p; - } - } - } - if (qIsInf(lb.x())) - return; - - // Prevent the conversion to and from clipper from introducing negative offsets which - // in turn will make the geometry wrap around. - lb.setX(qMax(tl.x(), lb.x())); - srcOrigin_ = p.mapProjectionToGeo(p.unwrapMapProjection(lb)); - } else { - clippedPaths = difference; - } - - //3) - const QDoubleVector2D origin = p.wrappedMapProjectionToItemPosition(lb); - - QPainterPath ppi; - for (const QList<QDoubleVector2D> &path: clippedPaths) { - QDoubleVector2D lastAddedPoint; - for (qsizetype i = 0; i < path.size(); ++i) { - QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(path.at(i)); - //point = point - origin; // Do this using ppi.translate() - - if (i == 0) { - ppi.moveTo(point.toPointF()); - lastAddedPoint = point; - } else if ((point - lastAddedPoint).manhattanLength() > 3 || i == path.size() - 1) { - ppi.lineTo(point.toPointF()); - lastAddedPoint = point; - } - } - ppi.closeSubpath(); - } - ppi.translate(-1 * origin.toPointF()); - - QTriangleSet ts = qTriangulate(ppi); - qreal *vx = ts.vertices.data(); - - screenIndices_.reserve(ts.indices.size()); - screenVertices_.reserve(ts.vertices.size()); - - if (ts.indices.type() == QVertexIndexVector::UnsignedInt) { - const quint32 *ix = reinterpret_cast<const quint32 *>(ts.indices.data()); - for (qsizetype i = 0; i < (ts.indices.size()/3*3); ++i) - screenIndices_ << ix[i]; - } else { - const quint16 *ix = reinterpret_cast<const quint16 *>(ts.indices.data()); - for (qsizetype i = 0; i < (ts.indices.size()/3*3); ++i) - screenIndices_ << ix[i]; - } - for (qsizetype i = 0; i < (ts.vertices.size()/2*2); i += 2) - screenVertices_ << QPointF(vx[i], vx[i + 1]); - - screenBounds_ = ppi.boundingRect(); - sourceBounds_ = screenBounds_; -} - -struct CircleBackendSelector -{ - CircleBackendSelector() - { - backend = (qgetenv("QTLOCATION_OPENGL_ITEMS").toInt()) ? QDeclarativeCircleMapItem::OpenGL : QDeclarativeCircleMapItem::Software; - } - QDeclarativeCircleMapItem::Backend backend = QDeclarativeCircleMapItem::Software; -}; - -Q_GLOBAL_STATIC(CircleBackendSelector, mapCircleBackendSelector) - -QDeclarativeCircleMapItem::QDeclarativeCircleMapItem(QQuickItem *parent) -: QDeclarativeGeoMapItemBase(parent), m_border(this), m_color(Qt::transparent), m_dirtyMaterial(true), - m_updatingGeometry(false) - , m_d(new QDeclarativeCircleMapItemPrivateCPU(*this)) -{ - // ToDo: handle envvar, and switch implementation. - m_itemType = QGeoMap::MapCircle; - setFlag(ItemHasContents, true); - QObject::connect(&m_border, &QDeclarativeMapLineProperties::colorChanged, - this, &QDeclarativeCircleMapItem::onLinePropertiesChanged); - QObject::connect(&m_border, &QDeclarativeMapLineProperties::widthChanged, - this, &QDeclarativeCircleMapItem::onLinePropertiesChanged); - - // assume that circles are not self-intersecting - // to speed up processing - // FIXME: unfortunately they self-intersect at the poles due to current drawing method - // so the line is commented out until fixed - //geometry_.setAssumeSimple(true); - setBackend(mapCircleBackendSelector->backend); -} - -QDeclarativeCircleMapItem::~QDeclarativeCircleMapItem() -{ -} - -/*! - \qmlpropertygroup Location::MapCircle::border - \qmlproperty int MapCircle::border.width - \qmlproperty color MapCircle::border.color - - This property is part of the border group property. - The border property holds the width and color used to draw the border of the circle. - The width is in pixels and is independent of the zoom level of the map. - - The default values correspond to a black border with a width of 1 pixel. - For no line, use a width of 0 or a transparent color. -*/ -QDeclarativeMapLineProperties *QDeclarativeCircleMapItem::border() -{ - return &m_border; -} - -void QDeclarativeCircleMapItem::markSourceDirtyAndUpdate() -{ - m_d->markSourceDirtyAndUpdate(); -} - -void QDeclarativeCircleMapItem::onLinePropertiesChanged() -{ - m_d->onLinePropertiesChanged(); -} - -void QDeclarativeCircleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) -{ - QDeclarativeGeoMapItemBase::setMap(quickMap,map); - if (map) - m_d->onMapSet(); -} - -/*! - \qmlproperty coordinate MapCircle::center - - This property holds the central point about which the circle is defined. - - \sa radius -*/ -void QDeclarativeCircleMapItem::setCenter(const QGeoCoordinate ¢er) -{ - if (m_circle.center() == center) - return; - - possiblySwitchBackend(m_circle.center(), m_circle.radius(), center, m_circle.radius()); - m_circle.setCenter(center); - m_d->onGeoGeometryChanged(); - emit centerChanged(center); -} - -QGeoCoordinate QDeclarativeCircleMapItem::center() -{ - return m_circle.center(); -} - -/*! - \qmlproperty color MapCircle::color - - This property holds the fill color of the circle when drawn. For no fill, - use a transparent color. -*/ -void QDeclarativeCircleMapItem::setColor(const QColor &color) -{ - if (m_color == color) - return; - m_color = color; - m_dirtyMaterial = true; - update(); - emit colorChanged(m_color); -} - -QColor QDeclarativeCircleMapItem::color() const -{ - return m_color; -} - -/*! - \qmlproperty real MapCircle::radius - - This property holds the radius of the circle, in meters on the ground. - - \sa center -*/ -void QDeclarativeCircleMapItem::setRadius(qreal radius) -{ - if (m_circle.radius() == radius) - return; - - possiblySwitchBackend(m_circle.center(), m_circle.radius(), m_circle.center(), radius); - m_circle.setRadius(radius); - m_d->onGeoGeometryChanged(); - emit radiusChanged(radius); -} - -qreal QDeclarativeCircleMapItem::radius() const -{ - return m_circle.radius(); -} - -/*! - \qmlproperty real MapCircle::opacity - - This property holds the opacity of the item. Opacity is specified as a - number between 0 (fully transparent) and 1 (fully opaque). The default is 1. - - An item with 0 opacity will still receive mouse events. To stop mouse events, set the - visible property of the item to false. -*/ - -/*! - \internal -*/ -QSGNode *QDeclarativeCircleMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) -{ - return m_d->updateMapItemPaintNode(oldNode, data); -} - -/*! - \internal -*/ -void QDeclarativeCircleMapItem::updatePolish() -{ - if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) - return; - m_d->updatePolish(); -} - -/*! - \internal - - The OpenGL backend doesn't do circles crossing poles yet. - So if that backend is selected and the circle crosses the poles, use the CPU backend instead. -*/ -void QDeclarativeCircleMapItem::possiblySwitchBackend(const QGeoCoordinate &oldCenter, qreal oldRadius, const QGeoCoordinate &newCenter, qreal newRadius) -{ - if (m_backend != QDeclarativeCircleMapItem::OpenGL) - return; - - // if old does not cross and new crosses, move to CPU. - if (!QDeclarativeCircleMapItemPrivate::crossEarthPole(oldCenter, oldRadius) - && !QDeclarativeCircleMapItemPrivate::crossEarthPole(newCenter, newRadius)) { - std::unique_ptr<QDeclarativeCircleMapItemPrivate> d(static_cast<QDeclarativeCircleMapItemPrivate *>(new QDeclarativeCircleMapItemPrivateCPU(*this))); - std::swap(m_d, d); - } else if (QDeclarativeCircleMapItemPrivate::crossEarthPole(oldCenter, oldRadius) - && !QDeclarativeCircleMapItemPrivate::crossEarthPole(newCenter, newRadius)) { // else if old crosses and new does not cross, move back to OpenGL - std::unique_ptr<QDeclarativeCircleMapItemPrivate> d(static_cast<QDeclarativeCircleMapItemPrivate *>(new QDeclarativeCircleMapItemPrivateOpenGL(*this))); - std::swap(m_d, d); - } -} - -/*! - \internal -*/ -void QDeclarativeCircleMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event) -{ - if (event.mapSize.isEmpty()) - return; - - m_d->afterViewportChanged(); -} - -/*! - \internal -*/ -bool QDeclarativeCircleMapItem::contains(const QPointF &point) const -{ - return m_d->contains(point); - // -} - -const QGeoShape &QDeclarativeCircleMapItem::geoShape() const -{ - return m_circle; -} - -void QDeclarativeCircleMapItem::setGeoShape(const QGeoShape &shape) -{ - if (shape == m_circle) - return; - - const QGeoCircle circle(shape); // if shape isn't a circle, circle will be created as a default-constructed circle - const bool centerHasChanged = circle.center() != m_circle.center(); - const bool radiusHasChanged = circle.radius() != m_circle.radius(); - possiblySwitchBackend(m_circle.center(), m_circle.radius(), circle.center(), circle.radius()); - m_circle = circle; - - m_d->onGeoGeometryChanged(); - if (centerHasChanged) - emit centerChanged(m_circle.center()); - if (radiusHasChanged) - emit radiusChanged(m_circle.radius()); -} - -/*! - \qmlproperty MapCircle.Backend QtLocation::MapCircle::backend - - This property holds which backend is in use to render the map item. - Valid values are \b MapCircle.Software and \b{MapCircle.OpenGL}. - The default value is \b{MapCircle.Software}. - - \note \b{The release of this API with Qt 5.15 is a Technology Preview}. - Ideally, as the OpenGL backends for map items mature, there will be - no more need to also offer the legacy software-projection backend. - So this property will likely disappear at some later point. - To select OpenGL-accelerated item backends without using this property, - it is also possible to set the environment variable \b QTLOCATION_OPENGL_ITEMS - to \b{1}. - Also note that all current OpenGL backends won't work as expected when enabling - layers on the individual item, or when running on OpenGL core profiles greater than 2.x. - - \since 5.15 -*/ - -QDeclarativeCircleMapItem::Backend QDeclarativeCircleMapItem::backend() const -{ - return m_backend; -} - -void QDeclarativeCircleMapItem::setBackend(QDeclarativeCircleMapItem::Backend b) -{ - if (b == m_backend) - return; - m_backend = b; - std::unique_ptr<QDeclarativeCircleMapItemPrivate> d( - (m_backend == Software) ? static_cast<QDeclarativeCircleMapItemPrivate *>( - new QDeclarativeCircleMapItemPrivateCPU(*this)) - : static_cast<QDeclarativeCircleMapItemPrivate *>( - new QDeclarativeCircleMapItemPrivateOpenGL(*this))); - std::swap(m_d, d); - m_d->onGeoGeometryChanged(); - emit backendChanged(); -} - -/*! - \internal -*/ -void QDeclarativeCircleMapItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - if (!map() || !m_circle.isValid() || m_updatingGeometry || newGeometry == oldGeometry) { - QDeclarativeGeoMapItemBase::geometryChange(newGeometry, oldGeometry); - return; - } - - QDoubleVector2D newPoint = QDoubleVector2D(x(),y()) + QDoubleVector2D(width(), height()) * 0.5; - QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(newPoint, false); - if (newCoordinate.isValid()) - setCenter(newCoordinate); // ToDo: this is incorrect. setting such center might yield to another geometry changed. - - // Not calling QDeclarativeGeoMapItemBase::geometryChange() as it will be called from a nested - // call to this function. -} - -QDeclarativeCircleMapItemPrivate::~QDeclarativeCircleMapItemPrivate() {} - -QDeclarativeCircleMapItemPrivateCPU::~QDeclarativeCircleMapItemPrivateCPU() {} - -QDeclarativeCircleMapItemPrivateOpenGL::~QDeclarativeCircleMapItemPrivateOpenGL() {} - -bool QDeclarativeCircleMapItemPrivate::preserveCircleGeometry (QList<QDoubleVector2D> &path, - const QGeoCoordinate ¢er, qreal distance, const QGeoProjectionWebMercator &p) -{ - // if circle crosses north/south pole, then don't preserve circular shape, - if ( crossEarthPole(center, distance)) { - updateCirclePathForRendering(path, center, distance, p); - return false; - } - return true; -} - -/* - * A workaround for circle path to be drawn correctly using a polygon geometry - * This method generates a polygon like - * _____________ - * | | - * \ / - * | | - * / \ - * | | - * ------------- - * - * or a polygon like - * - * ______________ - * | ____ | - * \__/ \__/ - */ -void QDeclarativeCircleMapItemPrivate::updateCirclePathForRendering(QList<QDoubleVector2D> &path, - const QGeoCoordinate ¢er, - qreal distance, const QGeoProjectionWebMercator &p) -{ - const qreal poleLat = 90; - const qreal distanceToNorthPole = center.distanceTo(QGeoCoordinate(poleLat, 0)); - const qreal distanceToSouthPole = center.distanceTo(QGeoCoordinate(-poleLat, 0)); - bool crossNorthPole = distanceToNorthPole < distance; - bool crossSouthPole = distanceToSouthPole < distance; - - QList<qsizetype> wrapPathIndex; - QDoubleVector2D prev = p.wrapMapProjection(path.at(0)); - - for (qsizetype i = 1; i <= path.count(); ++i) { - const auto index = i % path.count(); - const QDoubleVector2D point = p.wrapMapProjection(path.at(index)); - double diff = qAbs(point.x() - prev.x()); - if (diff > 0.5) { - continue; - } - } - - // find the points in path where wrapping occurs - for (qsizetype i = 1; i <= path.count(); ++i) { - const auto index = i % path.count(); - const QDoubleVector2D point = p.wrapMapProjection(path.at(index)); - if ((qAbs(point.x() - prev.x())) >= 0.5) { - wrapPathIndex << index; - if (wrapPathIndex.size() == 2 || !(crossNorthPole && crossSouthPole)) - break; - } - prev = point; - } - // insert two additional coords at top/bottom map corners of the map for shape - // to be drawn correctly - if (wrapPathIndex.size() > 0) { - qreal newPoleLat = 0; // 90 latitude - QDoubleVector2D wrapCoord = path.at(wrapPathIndex[0]); - if (wrapPathIndex.size() == 2) { - QDoubleVector2D wrapCoord2 = path.at(wrapPathIndex[1]); - if (wrapCoord2.y() < wrapCoord.y()) - newPoleLat = 1; // -90 latitude - } else if (center.latitude() < 0) { - newPoleLat = 1; // -90 latitude - } - for (qsizetype i = 0; i < wrapPathIndex.size(); ++i) { - const qsizetype index = wrapPathIndex[i] == 0 ? 0 : wrapPathIndex[i] + i*2; - const qsizetype prevIndex = (index - 1) < 0 ? (path.count() - 1) : index - 1; - QDoubleVector2D coord0 = path.at(prevIndex); - QDoubleVector2D coord1 = path.at(index); - coord0.setY(newPoleLat); - coord1.setY(newPoleLat); - path.insert(index ,coord1); - path.insert(index, coord0); - newPoleLat = 1.0 - newPoleLat; - } - } -} - -bool QDeclarativeCircleMapItemPrivate::crossEarthPole(const QGeoCoordinate ¢er, qreal distance) -{ - qreal poleLat = 90; - QGeoCoordinate northPole = QGeoCoordinate(poleLat, center.longitude()); - QGeoCoordinate southPole = QGeoCoordinate(-poleLat, center.longitude()); - // approximate using great circle distance - qreal distanceToNorthPole = center.distanceTo(northPole); - qreal distanceToSouthPole = center.distanceTo(southPole); - if (distanceToNorthPole < distance || distanceToSouthPole < distance) - return true; - return false; -} - -void QDeclarativeCircleMapItemPrivate::calculatePeripheralPoints(QList<QGeoCoordinate> &path, - const QGeoCoordinate ¢er, - qreal distance, - int steps, - QGeoCoordinate &leftBound) -{ - // Calculate points based on great-circle distance - // Calculation is the same as GeoCoordinate's atDistanceAndAzimuth function - // but tweaked here for computing multiple points - - // 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 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) { - const qreal azimuthRad = 2 * M_PI * i / steps; - const qreal resultLatRad = std::asin(sinLatRad_x_cosRatio - + cosLatRad_x_sinRatio * std::cos(azimuthRad)); - const qreal resultLonRad = lonRad + std::atan2(std::sin(azimuthRad) * cosLatRad_x_sinRatio, - cosRatio - sinLatRad * std::sin(resultLatRad)); - const qreal lat2 = QLocationUtils::degrees(resultLatRad); - 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); -} - -////////////////////////////////////////////////////////////////////// - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem_p.h b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h deleted file mode 100644 index fbbe39a7..00000000 --- a/src/location/declarativemaps/qdeclarativecirclemapitem_p.h +++ /dev/null @@ -1,145 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVECIRCLEMAPITEM_H -#define QDECLARATIVECIRCLEMAPITEM_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 <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qdeclarativegeomapitembase_p.h> -#include <QtLocation/private/qdeclarativepolylinemapitem_p_p.h> -#include <QSGGeometryNode> -#include <QSGFlatColorMaterial> -#include <QtPositioning/QGeoCircle> - -QT_BEGIN_NAMESPACE - -class QDeclarativeCircleMapItemPrivate; -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeCircleMapItem : public QDeclarativeGeoMapItemBase -{ - Q_OBJECT - Q_ENUMS(Backend) - - Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged) - Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged) - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) - Q_PROPERTY(QDeclarativeMapLineProperties *border READ border CONSTANT) - Q_PROPERTY(Backend backend READ backend WRITE setBackend NOTIFY backendChanged REVISION 15) - -public: - enum Backend { - Software = 0, - OpenGL = 1 - }; - - explicit QDeclarativeCircleMapItem(QQuickItem *parent = nullptr); - ~QDeclarativeCircleMapItem() override; - - void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) override; - QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) override; - - QGeoCoordinate center(); - void setCenter(const QGeoCoordinate ¢er); - - qreal radius() const; - void setRadius(qreal radius); - - QColor color() const; - void setColor(const QColor &color); - - QDeclarativeMapLineProperties *border(); - - bool contains(const QPointF &point) const override; - const QGeoShape &geoShape() const override; - void setGeoShape(const QGeoShape &shape) override; - - Backend backend() const; - void setBackend(Backend b); - -Q_SIGNALS: - void centerChanged(const QGeoCoordinate ¢er); - void radiusChanged(qreal radius); - void colorChanged(const QColor &color); - void backendChanged(); - -protected: - void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; - void updatePolish() override; - void possiblySwitchBackend(const QGeoCoordinate &oldCenter, qreal oldRadius, const QGeoCoordinate &newCenter, qreal newRadius); - -protected Q_SLOTS: - void markSourceDirtyAndUpdate(); - void onLinePropertiesChanged(); - void afterViewportChanged(const QGeoMapViewportChangeEvent &event) override; - -private: - void updateCirclePath(); - -private: - QGeoCircle m_circle; - QDeclarativeMapLineProperties m_border; - QColor m_color; - bool m_dirtyMaterial; - bool m_updatingGeometry; - Backend m_backend = Software; - - std::unique_ptr<QDeclarativeCircleMapItemPrivate> m_d; - - friend class QDeclarativeCircleMapItemPrivate; - friend class QDeclarativeCircleMapItemPrivateCPU; - friend class QDeclarativeCircleMapItemPrivateOpenGL; -}; - -////////////////////////////////////////////////////////////////////// - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativeCircleMapItem) - -#endif /* QDECLARATIVECIRCLEMAPITEM_H */ diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem_p_p.h b/src/location/declarativemaps/qdeclarativecirclemapitem_p_p.h deleted file mode 100644 index 2810eb5d..00000000 --- a/src/location/declarativemaps/qdeclarativecirclemapitem_p_p.h +++ /dev/null @@ -1,452 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com> -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVECIRCLEMAPITEM_P_P_H -#define QDECLARATIVECIRCLEMAPITEM_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 <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qdeclarativepolygonmapitem_p_p.h> -#include <QtLocation/private/qdeclarativecirclemapitem_p.h> - -QT_BEGIN_NAMESPACE - -class Q_LOCATION_PRIVATE_EXPORT QGeoMapCircleGeometry : public QGeoMapPolygonGeometry -{ -public: - QGeoMapCircleGeometry(); - - void updateScreenPointsInvert(const QList<QDoubleVector2D> &circlePath, const QGeoMap &map); -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeCircleMapItemPrivate -{ -public: - static const int CircleSamples = 128; // ToDo: make this radius && ZL dependent? - - QDeclarativeCircleMapItemPrivate(QDeclarativeCircleMapItem &circle) : m_circle(circle) - { - - } - QDeclarativeCircleMapItemPrivate(QDeclarativeCircleMapItemPrivate &other) : m_circle(other.m_circle) - { - } - - virtual ~QDeclarativeCircleMapItemPrivate(); - virtual void onLinePropertiesChanged() = 0; - virtual void markSourceDirtyAndUpdate() = 0; - virtual void onMapSet() = 0; - virtual void onGeoGeometryChanged() = 0; - virtual void onItemGeometryChanged() = 0; - virtual void updatePolish() = 0; - virtual void afterViewportChanged() = 0; - virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0; - virtual bool contains(const QPointF &point) const = 0; - - void updateCirclePath() - { - if (!m_circle.map() || m_circle.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) - return; - - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_circle.map()->geoProjection()); - QList<QGeoCoordinate> path; - calculatePeripheralPoints(path, m_circle.center(), m_circle.radius(), CircleSamples, m_leftBound); - m_circlePath.clear(); - for (const QGeoCoordinate &c : path) - m_circlePath << p.geoToMapProjection(c); - } - - static bool crossEarthPole(const QGeoCoordinate ¢er, qreal distance); - - static bool preserveCircleGeometry(QList<QDoubleVector2D> &path, const QGeoCoordinate ¢er, - qreal distance, const QGeoProjectionWebMercator &p); - static void updateCirclePathForRendering(QList<QDoubleVector2D> &path, const QGeoCoordinate ¢er, - qreal distance, const QGeoProjectionWebMercator &p); - - static void calculatePeripheralPoints(QList<QGeoCoordinate> &path, const QGeoCoordinate ¢er, - qreal distance, int steps, QGeoCoordinate &leftBound); - - QDeclarativeCircleMapItem &m_circle; - QList<QDoubleVector2D> m_circlePath; - QGeoCoordinate m_leftBound; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeCircleMapItemPrivateCPU: public QDeclarativeCircleMapItemPrivate -{ -public: - - QDeclarativeCircleMapItemPrivateCPU(QDeclarativeCircleMapItem &circle) : QDeclarativeCircleMapItemPrivate(circle) - { - } - - QDeclarativeCircleMapItemPrivateCPU(QDeclarativeCircleMapItemPrivate &other) - : QDeclarativeCircleMapItemPrivate(other) - { - } - - ~QDeclarativeCircleMapItemPrivateCPU() override; - - void onLinePropertiesChanged() override - { - // mark dirty just in case we're a width change - markSourceDirtyAndUpdate(); - } - void markSourceDirtyAndUpdate() override - { - // preserveGeometry is cleared in updateMapItemPaintNode - m_geometry.markSourceDirty(); - m_borderGeometry.markSourceDirty(); - m_circle.polishAndUpdate(); - } - void onMapSet() override - { - updateCirclePath(); - markSourceDirtyAndUpdate(); - } - void onGeoGeometryChanged() override - { - updateCirclePath(); - markSourceDirtyAndUpdate(); - } - void onItemGeometryChanged() override - { - onGeoGeometryChanged(); - } - void afterViewportChanged() override - { - markSourceDirtyAndUpdate(); - } - void updatePolish() override - { - if (!m_circle.m_circle.isValid()) { - m_geometry.clear(); - m_borderGeometry.clear(); - m_circle.setWidth(0); - m_circle.setHeight(0); - return; - } - - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_circle.map()->geoProjection()); - QScopedValueRollback<bool> rollback(m_circle.m_updatingGeometry); - m_circle.m_updatingGeometry = true; - - QList<QDoubleVector2D> circlePath = m_circlePath; - - int pathCount = circlePath.size(); - bool preserve = preserveCircleGeometry(circlePath, m_circle.m_circle.center(), m_circle.m_circle.radius(), p); - // using leftBound_ instead of the analytically calculated circle_.boundingGeoRectangle().topLeft()); - // to fix QTBUG-62154 - m_geometry.setPreserveGeometry(true, m_leftBound); // to set the geoLeftBound_ - m_geometry.setPreserveGeometry(preserve, m_leftBound); - - bool invertedCircle = false; - if (crossEarthPole(m_circle.m_circle.center(), m_circle.m_circle.radius()) && circlePath.size() == pathCount) { - m_geometry.updateScreenPointsInvert(circlePath, *m_circle.map()); // invert fill area for really huge circles - invertedCircle = true; - } else { - m_geometry.updateSourcePoints(*m_circle.map(), circlePath); - m_geometry.updateScreenPoints(*m_circle.map(), m_circle.m_border.width()); - } - - m_borderGeometry.clear(); - QList<QGeoMapItemGeometry *> geoms; - geoms << &m_geometry; - - if (m_circle.m_border.color() != Qt::transparent && m_circle.m_border.width() > 0) { - QList<QDoubleVector2D> closedPath = circlePath; - closedPath << closedPath.first(); - - if (invertedCircle) { - closedPath = m_circlePath; - closedPath << closedPath.first(); - std::reverse(closedPath.begin(), closedPath.end()); - } - - m_borderGeometry.setPreserveGeometry(true, m_leftBound); - m_borderGeometry.setPreserveGeometry(preserve, m_leftBound); - - // Use srcOrigin_ from fill geometry after clipping to ensure that translateToCommonOrigin won't fail. - const QGeoCoordinate &geometryOrigin = m_geometry.origin(); - - m_borderGeometry.srcPoints_.clear(); - m_borderGeometry.srcPointTypes_.clear(); - - QDoubleVector2D borderLeftBoundWrapped; - QList<QList<QDoubleVector2D > > clippedPaths = m_borderGeometry.clipPath(*m_circle.map(), closedPath, borderLeftBoundWrapped); - if (clippedPaths.size()) { - borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin); - m_borderGeometry.pathToScreen(*m_circle.map(), clippedPaths, borderLeftBoundWrapped); - m_borderGeometry.updateScreenPoints(*m_circle.map(), m_circle.m_border.width()); - geoms << &m_borderGeometry; - } else { - m_borderGeometry.clear(); - } - } - - QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms); - - if (invertedCircle || !preserve) { - m_circle.setWidth(combined.width()); - m_circle.setHeight(combined.height()); - } else { - m_circle.setWidth(combined.width() + 2 * m_circle.m_border.width()); // ToDo: Fix this! - m_circle.setHeight(combined.height() + 2 * m_circle.m_border.width()); - } - - // No offsetting here, even in normal case, because first point offset is already translated - m_circle.setPositionOnMap(m_geometry.origin(), m_geometry.firstPointOffset()); - } - - QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override - { - Q_UNUSED(data); - if (!m_node || !oldNode) { // Apparently the QSG might delete the nodes if they become invisible - m_node = new MapPolygonNode(); - if (oldNode) { - delete oldNode; - oldNode = nullptr; - } - } else { - m_node = static_cast<MapPolygonNode *>(oldNode); - } - - //TODO: update only material - if (m_geometry.isScreenDirty() || m_borderGeometry.isScreenDirty() || m_circle.m_dirtyMaterial) { - m_node->update(m_circle.m_color, m_circle.m_border.color(), &m_geometry, &m_borderGeometry); - m_geometry.setPreserveGeometry(false); - m_borderGeometry.setPreserveGeometry(false); - m_geometry.markClean(); - m_borderGeometry.markClean(); - m_circle.m_dirtyMaterial = false; - } - return m_node; - } - bool contains(const QPointF &point) const override - { - return (m_geometry.contains(point) || m_borderGeometry.contains(point)); - } - - QGeoMapCircleGeometry m_geometry; - QGeoMapPolylineGeometry m_borderGeometry; - MapPolygonNode *m_node = nullptr; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeCircleMapItemPrivateOpenGL: public QDeclarativeCircleMapItemPrivate -{ -public: - QDeclarativeCircleMapItemPrivateOpenGL(QDeclarativeCircleMapItem &circle) : QDeclarativeCircleMapItemPrivate(circle) - { - } - - QDeclarativeCircleMapItemPrivateOpenGL(QDeclarativeCircleMapItemPrivate &other) - : QDeclarativeCircleMapItemPrivate(other) - { - } - - ~QDeclarativeCircleMapItemPrivateOpenGL() override; - - void onLinePropertiesChanged() override - { - m_circle.m_dirtyMaterial = true; - afterViewportChanged(); - } - void markScreenDirtyAndUpdate() - { - // preserveGeometry is cleared in updateMapItemPaintNode - m_geometry.markScreenDirty(); - m_borderGeometry.markScreenDirty(); - m_circle.polishAndUpdate(); - } - void markSourceDirtyAndUpdate() override - { - updateCirclePath(); - preserveGeometry(); - m_geometry.markSourceDirty(); - m_borderGeometry.markSourceDirty(); - m_circle.polishAndUpdate(); - } - void preserveGeometry() - { - m_geometry.setPreserveGeometry(true, m_leftBound); - m_borderGeometry.setPreserveGeometry(true, m_leftBound); - } - void onMapSet() override - { - markSourceDirtyAndUpdate(); - } - void onGeoGeometryChanged() override - { - - markSourceDirtyAndUpdate(); - } - void onItemGeometryChanged() override - { - onGeoGeometryChanged(); - } - void afterViewportChanged() override - { - preserveGeometry(); - markScreenDirtyAndUpdate(); - } - void updatePolish() override - { - if (m_circle.m_circle.isEmpty()) { - m_geometry.clear(); - m_borderGeometry.clear(); - m_circle.setWidth(0); - m_circle.setHeight(0); - return; - } - - QScopedValueRollback<bool> rollback(m_circle.m_updatingGeometry); - m_circle.m_updatingGeometry = true; - const qreal lineWidth = m_circle.m_border.width(); - const QColor &lineColor = m_circle.m_border.color(); - const QColor &fillColor = m_circle.color(); - if (fillColor.alpha() != 0) { - m_geometry.updateSourcePoints(*m_circle.map(), m_circlePath); - m_geometry.markScreenDirty(); - m_geometry.updateScreenPoints(*m_circle.map(), lineWidth, lineColor); - } else { - m_geometry.clearBounds(); - } - - QGeoMapItemGeometry * geom = &m_geometry; - m_borderGeometry.clearScreen(); - if (lineColor.alpha() != 0 && lineWidth > 0) { - m_borderGeometry.updateSourcePoints(*m_circle.map(), m_circle.m_circle); - m_borderGeometry.markScreenDirty(); - m_borderGeometry.updateScreenPoints(*m_circle.map(), lineWidth); - geom = &m_borderGeometry; - } - m_circle.setWidth(geom->sourceBoundingBox().width()); - m_circle.setHeight(geom->sourceBoundingBox().height()); - m_circle.setPosition(1.0 * geom->firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5)); - } - - QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override - { - Q_UNUSED(data); - - if (!m_rootNode || !oldNode) { - m_rootNode = new QDeclarativePolygonMapItemPrivateOpenGL::RootNode(); - m_node = new MapPolygonNodeGL(); - m_rootNode->appendChildNode(m_node); - m_polylinenode = new MapPolylineNodeOpenGLExtruded(); - m_rootNode->appendChildNode(m_polylinenode); - m_rootNode->markDirty(QSGNode::DirtyNodeAdded); - if (oldNode) - delete oldNode; - } else { - m_rootNode = static_cast<QDeclarativePolygonMapItemPrivateOpenGL::RootNode *>(oldNode); - } - - const QGeoMap *map = m_circle.map(); - const QMatrix4x4 &combinedMatrix = map->geoProjection().qsgTransform(); - const QDoubleVector3D &cameraCenter = map->geoProjection().centerMercator(); - - if (m_borderGeometry.isScreenDirty()) { - /* Do the border update first */ - m_polylinenode->update(m_circle.m_border.color(), - float(m_circle.m_border.width()), - &m_borderGeometry, - combinedMatrix, - cameraCenter, - Qt::SquareCap, - true, - 30); // No LOD for circles - m_borderGeometry.setPreserveGeometry(false); - m_borderGeometry.markClean(); - } else { - m_polylinenode->setSubtreeBlocked(true); - } - if (m_geometry.isScreenDirty()) { - m_node->update(m_circle.m_color, - &m_geometry, - combinedMatrix, - cameraCenter); - m_geometry.setPreserveGeometry(false); - m_geometry.markClean(); - } else { - m_node->setSubtreeBlocked(true); - } - - m_rootNode->setSubtreeBlocked(false); - return m_rootNode; - } - bool contains(const QPointF &point) const override - { - const qreal lineWidth = m_circle.m_border.width(); - const QColor &lineColor = m_circle.m_border.color(); - const QRectF &bounds = (lineColor.alpha() != 0 && lineWidth > 0) ? m_borderGeometry.sourceBoundingBox() : m_geometry.sourceBoundingBox(); - if (bounds.contains(point)) { - QDeclarativeGeoMap *m = m_circle.quickMap(); - if (m) { - const QGeoCoordinate crd = m->toCoordinate(m->mapFromItem(&m_circle, point)); - return m_circle.m_circle.contains(crd) || m_borderGeometry.contains(m_circle.mapToItem(m_circle.quickMap(), point), - m_circle.border()->width(), - static_cast<const QGeoProjectionWebMercator&>(m_circle.map()->geoProjection())); - } else { - return true; - } - } - return false; - } - - QGeoMapPolygonGeometryOpenGL m_geometry; - QGeoMapPolylineGeometryOpenGL m_borderGeometry; - QDeclarativePolygonMapItemPrivateOpenGL::RootNode *m_rootNode = nullptr; - MapPolygonNodeGL *m_node = nullptr; - MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr; -}; - -QT_END_NAMESPACE - -#endif // QDECLARATIVECIRCLEMAPITEM_P_P_H diff --git a/src/location/declarativemaps/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp deleted file mode 100644 index 0823772c..00000000 --- a/src/location/declarativemaps/qdeclarativegeomap.cpp +++ /dev/null @@ -1,2619 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativegeomap_p.h" -#include "qdeclarativegeomapquickitem_p.h" -#include "qdeclarativegeomapcopyrightsnotice_p.h" -#include "qdeclarativegeoserviceprovider_p.h" -#include "qgeomappingmanager_p.h" -#include "qgeocameracapabilities_p.h" -#include "qgeomap_p.h" -#include "qdeclarativegeomapparameter_p.h" -#include "qgeomapobject_p.h" -#include "qgeoprojection_p.h" -#include <QtPositioning/QGeoCircle> -#include <QtPositioning/QGeoRectangle> -#include <QtPositioning/QGeoPath> -#include <QtPositioning/QGeoPolygon> -#include <QtQuick/QQuickWindow> -#include <QtQuick/QSGRectangleNode> -#include <QtQml/qqmlinfo.h> -#include <QtQuick/private/qquickitem_p.h> -#include <cmath> - -#ifndef M_PI -#define M_PI 3.141592653589793238463 -#endif - - -QT_BEGIN_NAMESPACE - -static qreal sanitizeBearing(qreal bearing) -{ - bearing = std::fmod(bearing, qreal(360.0)); - if (bearing < 0.0) - bearing += 360.0; - - return bearing; -} - -/*! - \qmltype Map - \instantiates QDeclarativeGeoMap - \inqmlmodule QtLocation - \ingroup qml-QtLocation5-maps - \since QtLocation 5.0 - - \brief The Map type displays a map. - - The Map type is used to display a map or image of the Earth, with - the capability to also display interactive objects tied to the map's - surface. - - There are a variety of different ways to visualize the Earth's surface - in a 2-dimensional manner, but all of them involve some kind of projection: - a mathematical relationship between the 3D coordinates (latitude, longitude - and altitude) and 2D coordinates (X and Y in pixels) on the screen. - - Different sources of map data can use different projections, and from the - point of view of the Map type, we treat these as one replaceable unit: - the Map plugin. A Map plugin consists of a data source, as well as all other - details needed to display its data on-screen. - - The current Map plugin in use is contained in the \l plugin property of - the Map item. In order to display any image in a Map item, you will need - to set this property. See the \l Plugin type for a description of how - to retrieve an appropriate plugin for use. - - The geographic region displayed in the Map item is referred to as its - viewport, and this is defined by the properties \l center, and - \l zoomLevel. The \l center property contains a \l {coordinate} - specifying the center of the viewport, while \l zoomLevel controls the scale of the - map. See each of these properties for further details about their values. - - When the map is displayed, each possible geographic coordinate that is - visible will map to some pixel X and Y coordinate on the screen. To perform - conversions between these two, Map provides the \l toCoordinate and - \l fromCoordinate functions, which are of general utility. - - \section2 Map Objects - - Map related objects can be declared within the body of a Map object in Qt Quick and will - automatically appear on the Map. To add an object programmatically, first be - sure it is created with the Map as its parent (for example in an argument to - Component::createObject). - Then call the \l addMapItem method on the Map, if the type of this object is one of - \l MapCircle, \l MapRectangle, \l MapPolyline, \l MapPolygon, \l MapRoute or \l MapQuickItem. - A corresponding \l removeMapItem method also exists to do the opposite and - remove any of the above types of map objects from the Map. - - Moving Map objects around, resizing them or changing their shape normally - does not involve any special interaction with Map itself -- changing these - properties in a map object will automatically update the display. - - \section2 Interaction - - The Map type includes support for pinch and flick gestures to control - zooming and panning. These are enabled by default, and available at any - time by using the \l gesture object. The actual GestureArea is constructed - specially at startup and cannot be replaced or destroyed. Its properties - can be altered, however, to control its behavior. - - \section2 Performance - - Maps are rendered using OpenGL (ES) and the Qt Scene Graph stack, and as - a result perform quite well where GL accelerated hardware is available. - - For "online" Map plugins, network bandwidth and latency can be major - contributors to the user's perception of performance. Extensive caching is - performed to mitigate this, but such mitigation is not always perfect. For - "offline" plugins, the time spent retrieving the stored geographic data - and rendering the basic map features can often play a dominant role. Some - offline plugins may use hardware acceleration themselves to (partially) - avert this. - - In general, large and complex Map items such as polygons and polylines with - large numbers of vertices can have an adverse effect on UI performance. - Further, more detailed notes on this are in the documentation for each - map item type. - - \section2 Example Usage - - The following snippet shows a simple Map and the necessary Plugin type - to use it. The map is centered over Oslo, Norway, with zoom level 14. - - \quotefromfile minimal_map/main.qml - \skipto import - \printuntil } - \printline } - \skipto Map - \printuntil } - \printline } - - \image minimal_map.png -*/ - -/*! - \qmlsignal QtLocation::Map::copyrightLinkActivated(string link) - - This signal is emitted when the user clicks on a \a link in the copyright notice. The - application should open the link in a browser or display its contents to the user. -*/ - -QDeclarativeGeoMap::QDeclarativeGeoMap(QQuickItem *parent) - : QQuickItem(parent) -{ - m_gestureArea = new QQuickGeoMapGestureArea(this); - - setAcceptHoverEvents(false); - setAcceptTouchEvents(true); - setAcceptedMouseButtons(Qt::LeftButton); - setFlags(QQuickItem::ItemHasContents | QQuickItem::ItemClipsChildrenToShape); - setFiltersChildMouseEvents(true); // needed for childMouseEventFilter to work. - - m_activeMapType = QGeoMapType(QGeoMapType::NoMap, - tr("No Map"), - tr("No Map"), - false, false, - 0, - QByteArrayLiteral(""), - QGeoCameraCapabilities()); - m_cameraData.setCenter(QGeoCoordinate(51.5073,-0.1277)); //London city center - m_cameraData.setZoomLevel(8.0); - - m_cameraCapabilities.setTileSize(256); - m_cameraCapabilities.setSupportsBearing(true); - m_cameraCapabilities.setSupportsTilting(true); - m_cameraCapabilities.setMinimumZoomLevel(0); - m_cameraCapabilities.setMaximumZoomLevel(30); - m_cameraCapabilities.setMinimumTilt(0); - m_cameraCapabilities.setMaximumTilt(89.5); - m_cameraCapabilities.setMinimumFieldOfView(1); - m_cameraCapabilities.setMaximumFieldOfView(179); - - m_minimumTilt = m_cameraCapabilities.minimumTilt(); - m_maximumTilt = m_cameraCapabilities.maximumTilt(); - m_minimumFieldOfView = m_cameraCapabilities.minimumFieldOfView(); - m_maximumFieldOfView = m_cameraCapabilities.maximumFieldOfView(); -} - -QDeclarativeGeoMap::~QDeclarativeGeoMap() -{ - // Removing map parameters and map items from m_map - if (m_map) { - m_map->clearParameters(); - m_map->clearMapItems(); - } - - // Remove the items from the map, making them deletable. - // Go in the same order as in removeMapChild: views, groups, then items - if (!m_mapViews.isEmpty()) { - const auto mapViews = m_mapViews; - for (QDeclarativeGeoMapItemView *v : mapViews) { // so that removeMapItemView_real can safely modify m_mapViews; - if (!v) - continue; - - QQuickItem *parent = v->parentItem(); - QDeclarativeGeoMapItemGroup *group = qobject_cast<QDeclarativeGeoMapItemGroup *>(parent); - if (group) - continue; // Ignore non-top-level MIVs. They will be recursively processed. - // Identify them as being parented by a MapItemGroup. - - removeMapItemView_real(v); - } - } - - if (!m_mapItemGroups.isEmpty()) { - const auto mapGroups = m_mapItemGroups; - for (QDeclarativeGeoMapItemGroup *g : mapGroups) { - if (!g) - continue; - - QQuickItem *parent =g->parentItem(); - QDeclarativeGeoMapItemGroup *group = qobject_cast<QDeclarativeGeoMapItemGroup *>(parent); - if (group) - continue; // Ignore non-top-level Groups. They will be recursively processed. - // Identify them as being parented by a MapItemGroup. - - removeMapItemGroup_real(g); - } - } - - // remove any remaining map items associations - const auto mapItems = m_mapItems; - for (auto mi: mapItems) - removeMapItem_real(mi.data()); - - if (m_copyrights.data()) - delete m_copyrights.data(); - m_copyrights.clear(); - - for (auto obj: qAsConst(m_pendingMapObjects)) - obj->setMap(nullptr); // worst case: going to be setMap(nullptr)'d twice - - delete m_map; // map objects get reset here -} - -void QDeclarativeGeoMap::onSupportedMapTypesChanged() -{ - m_supportedMapTypes = m_mappingManager->supportedMapTypes(); - if (m_supportedMapTypes.isEmpty()) { - m_map->setActiveMapType(QGeoMapType()); // no supported map types: setting an invalid one - } else if (!m_supportedMapTypes.contains(m_map->activeMapType())) { - QGeoMapType type = m_supportedMapTypes.at(0); - m_activeMapType = type; - m_map->setActiveMapType(type); - } - - emit supportedMapTypesChanged(); -} - -void QDeclarativeGeoMap::setError(QGeoServiceProvider::Error error, const QString &errorString) -{ - if (m_error == error && m_errorString == errorString) - return; - m_error = error; - m_errorString = errorString; - emit errorChanged(); -} - -/*! - \internal - Called when the mapping manager is initialized AND the declarative element has a valid size > 0 -*/ -void QDeclarativeGeoMap::initialize() -{ - // try to keep change signals in the end - bool visibleAreaHasChanged = false; - - QGeoCoordinate center = m_cameraData.center(); - - if (!qIsFinite(m_userMinimumZoomLevel)) - setMinimumZoomLevel(m_map->minimumZoom(), false); - else - setMinimumZoomLevel(qMax<qreal>(m_map->minimumZoom(), m_userMinimumZoomLevel), false); - - double bearing = m_cameraData.bearing(); - double tilt = m_cameraData.tilt(); - double fov = m_cameraData.fieldOfView(); // Must be 45.0 - QGeoCameraData cameraData = m_cameraData; - - if (!m_cameraCapabilities.supportsBearing() && bearing != 0.0) - cameraData.setBearing(0); - - if (!m_cameraCapabilities.supportsTilting() && tilt != 0.0) - cameraData.setTilt(0); - - m_map->setVisibleArea(m_visibleArea); - if (m_map->visibleArea() != m_visibleArea) - visibleAreaHasChanged = true; - - cameraData.setFieldOfView(qBound(m_cameraCapabilities.minimumFieldOfView(), - fov, - m_cameraCapabilities.maximumFieldOfView())); - - // set latitude boundary check - m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(cameraData); - m_minimumViewportLatitude = m_map->minimumCenterLatitudeAtZoom(cameraData); - - center.setLatitude(qBound(m_minimumViewportLatitude, center.latitude(), m_maximumViewportLatitude)); - cameraData.setCenter(center); - - connect(m_map.data(), &QGeoMap::cameraDataChanged, - this, &QDeclarativeGeoMap::onCameraDataChanged); - m_map->setCameraData(cameraData); // This normally triggers property changed signals. - // BUT not in this case, since m_cameraData is already == cameraData. - // So, emit visibleRegionChanged() separately, as - // the effective visible region becomes available only now. - - for (const auto &obj : qAsConst(m_pendingMapObjects)) - obj->setMap(m_map); - - m_initialized = true; - - if (visibleAreaHasChanged) - emit visibleAreaChanged(); - connect(m_map.data(), &QGeoMap::visibleAreaChanged, this, &QDeclarativeGeoMap::visibleAreaChanged); - - emit mapReadyChanged(true); - emit visibleRegionChanged(); - - if (m_copyrights) // To not update during initialize() - update(); -} - -/*! - \internal -*/ -void QDeclarativeGeoMap::pluginReady() -{ - QGeoServiceProvider *provider = m_plugin->sharedGeoServiceProvider(); - m_mappingManager = provider->mappingManager(); - - if (provider->mappingError() != QGeoServiceProvider::NoError) { - setError(provider->mappingError(), provider->mappingErrorString()); - return; - } - - if (!m_mappingManager) { - //TODO Should really be EngineNotSetError (see QML GeoCodeModel) - setError(QGeoServiceProvider::NotSupportedError, tr("Plugin does not support mapping.")); - return; - } - - if (!m_mappingManager->isInitialized()) { - connect(m_mappingManager, &QGeoMappingManager::initialized, - this, &QDeclarativeGeoMap::mappingManagerInitialized); - } else { - mappingManagerInitialized(); - } - - // make sure this is only called once - disconnect(m_plugin, &QDeclarativeGeoServiceProvider::attached, - this, &QDeclarativeGeoMap::pluginReady); -} - -/*! - \internal -*/ -void QDeclarativeGeoMap::componentComplete() -{ - m_componentCompleted = true; - populateParameters(); - populateMap(); - QQuickItem::componentComplete(); -} - -/*! - \qmlproperty MapGestureArea QtLocation::Map::gesture - - Contains the MapGestureArea created with the Map. This covers pan, flick and pinch gestures. - Use \c{gesture.enabled: true} to enable basic gestures, or see \l{MapGestureArea} for - further details. -*/ - -QQuickGeoMapGestureArea *QDeclarativeGeoMap::gesture() -{ - return m_gestureArea; -} - -/*! - \internal - - This may happen before mappingManagerInitialized() -*/ -void QDeclarativeGeoMap::populateMap() -{ - QSet<QObject *> kids(children().cbegin(), children().cend()); - const QList<QQuickItem *> quickKids = childItems(); - for (QQuickItem *ite: quickKids) - kids.insert(ite); - - for (QObject *k : qAsConst(kids)) { - addMapChild(k); - } -} - -void QDeclarativeGeoMap::populateParameters() -{ - QObjectList kids = children(); - const QList<QQuickItem *> quickKids = childItems(); - for (const auto &quickKid : quickKids) - kids.append(quickKid); - for (auto *kid : qAsConst(kids)) { - if (auto *mapParameter = qobject_cast<QDeclarativeGeoMapParameter *>(kid)) - addMapParameter(mapParameter); - } -} - -/*! - \internal -*/ -void QDeclarativeGeoMap::setupMapView(QDeclarativeGeoMapItemView *view) -{ - view->setMap(this); -} - -/*! - * \internal - */ -QSGNode *QDeclarativeGeoMap::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) -{ - if (!m_map) { - delete oldNode; - return nullptr; - } - - QSGRectangleNode *root = static_cast<QSGRectangleNode *>(oldNode); - if (!root) - root = window()->createRectangleNode(); - - root->setRect(boundingRect()); - root->setColor(m_color); - - QSGNode *content = root->childCount() ? root->firstChild() : 0; - content = m_map->updateSceneGraph(content, window()); - if (content && root->childCount() == 0) - root->appendChildNode(content); - - return root; -} - -/*! - \qmlproperty Plugin QtLocation::Map::plugin - - This property holds the plugin which provides the mapping functionality. - - This is a write-once property. Once the map has a plugin associated with - it, any attempted modifications of the plugin will be ignored. -*/ - -void QDeclarativeGeoMap::setPlugin(QDeclarativeGeoServiceProvider *plugin) -{ - if (m_plugin) { - qmlWarning(this) << QStringLiteral("Plugin is a write-once property, and cannot be set again."); - return; - } - m_plugin = plugin; - emit pluginChanged(m_plugin); - - if (m_plugin->isAttached()) { - pluginReady(); - } else { - connect(m_plugin, &QDeclarativeGeoServiceProvider::attached, - this, &QDeclarativeGeoMap::pluginReady); - } -} - -/*! - \internal -*/ -void QDeclarativeGeoMap::onCameraCapabilitiesChanged(const QGeoCameraCapabilities &oldCameraCapabilities) -{ - if (m_map->cameraCapabilities() == oldCameraCapabilities) - return; - m_cameraCapabilities = m_map->cameraCapabilities(); - - //The zoom level limits are only restricted by the plugins values, if the user has set a more - //strict zoom level limit before initialization nothing is done here. - //minimum zoom level might be changed to limit gray bundaries - //This code assumes that plugins' maximum zoom level will never exceed 30.0 - if (m_cameraCapabilities.maximumZoomLevelAt256() < m_gestureArea->maximumZoomLevel()) { - setMaximumZoomLevel(m_cameraCapabilities.maximumZoomLevelAt256(), false); - } else if (m_cameraCapabilities.maximumZoomLevelAt256() > m_gestureArea->maximumZoomLevel()) { - if (!qIsFinite(m_userMaximumZoomLevel)) { - // If the user didn't set anything - setMaximumZoomLevel(m_cameraCapabilities.maximumZoomLevelAt256(), false); - } else { // Try to set what the user requested - // Else if the user set something larger, but that got clamped by the previous camera caps - setMaximumZoomLevel(qMin<qreal>(m_cameraCapabilities.maximumZoomLevelAt256(), - m_userMaximumZoomLevel), false); - } - } - - if (m_cameraCapabilities.minimumZoomLevelAt256() > m_gestureArea->minimumZoomLevel()) { - setMinimumZoomLevel(m_cameraCapabilities.minimumZoomLevelAt256(), false); - } else if (m_cameraCapabilities.minimumZoomLevelAt256() < m_gestureArea->minimumZoomLevel()) { - if (!qIsFinite(m_userMinimumZoomLevel)) { - // If the user didn't set anything, trying to set the new caps. - setMinimumZoomLevel(m_cameraCapabilities.minimumZoomLevelAt256(), false); - } else { // Try to set what the user requested - // Else if the user set a minimum, m_gestureArea->minimumZoomLevel() might be larger - // because of different reasons. Resetting it, as if it ends to be the same, - // no signal will be emitted. - setMinimumZoomLevel(qMax<qreal>(m_cameraCapabilities.minimumZoomLevelAt256(), - m_userMinimumZoomLevel), false); - } - } - - // Tilt - if (m_cameraCapabilities.minimumTilt() > m_minimumTilt) { - setMinimumTilt(m_cameraCapabilities.minimumTilt(), false); - } else if (m_cameraCapabilities.minimumTilt() < m_minimumTilt) { - if (!qIsFinite(m_userMinimumTilt)) - setMinimumTilt(m_cameraCapabilities.minimumTilt(), false); - else // Try to set what the user requested - setMinimumTilt(qMax<qreal>(m_cameraCapabilities.minimumTilt(), m_userMinimumTilt), false); - } - - if (m_cameraCapabilities.maximumTilt() < m_maximumTilt) { - setMaximumTilt(m_cameraCapabilities.maximumTilt(), false); - } else if (m_cameraCapabilities.maximumTilt() > m_maximumTilt) { - if (!qIsFinite(m_userMaximumTilt)) - setMaximumTilt(m_cameraCapabilities.maximumTilt(), false); - else // Try to set what the user requested - setMaximumTilt(qMin<qreal>(m_cameraCapabilities.maximumTilt(), m_userMaximumTilt), false); - } - - // FoV - if (m_cameraCapabilities.minimumFieldOfView() > m_minimumFieldOfView) { - setMinimumFieldOfView(m_cameraCapabilities.minimumFieldOfView(), false); - } else if (m_cameraCapabilities.minimumFieldOfView() < m_minimumFieldOfView) { - if (!qIsFinite(m_userMinimumFieldOfView)) - setMinimumFieldOfView(m_cameraCapabilities.minimumFieldOfView(), false); - else // Try to set what the user requested - setMinimumFieldOfView(qMax<qreal>(m_cameraCapabilities.minimumFieldOfView(), m_userMinimumFieldOfView), false); - } - - if (m_cameraCapabilities.maximumFieldOfView() < m_maximumFieldOfView) { - setMaximumFieldOfView(m_cameraCapabilities.maximumFieldOfView(), false); - } else if (m_cameraCapabilities.maximumFieldOfView() > m_maximumFieldOfView) { - if (!qIsFinite(m_userMaximumFieldOfView)) - setMaximumFieldOfView(m_cameraCapabilities.maximumFieldOfView(), false); - else // Try to set what the user requested - setMaximumFieldOfView(qMin<qreal>(m_cameraCapabilities.maximumFieldOfView(), m_userMaximumFieldOfView), false); - } -} - -/*! - \internal - this function will only be ever called once -*/ -void QDeclarativeGeoMap::mappingManagerInitialized() -{ - m_map = m_mappingManager->createMap(this); - - if (!m_map) - return; - - // Any map items that were added before the plugin was ready - // need to have setMap called again - for (const QPointer<QDeclarativeGeoMapItemBase> &item : qAsConst(m_mapItems)) { - if (item) { - item->setMap(this, m_map); - m_map->addMapItem(item.data()); // m_map filters out what is not supported. - } - } - - /* COPY NOTICE SETUP */ - m_copyrights = new QDeclarativeGeoMapCopyrightNotice(this); - m_copyrights->setCopyrightsZ(m_maxChildZ + 1); - m_copyrights->setCopyrightsVisible(m_copyrightsVisible); - m_copyrights->setMapSource(this); - - m_gestureArea->setMap(m_map); - - m_supportedMapTypes = m_mappingManager->supportedMapTypes(); - - if (m_activeMapType != QGeoMapType() && m_plugin->name().toLatin1() == m_activeMapType.pluginName()) { - m_map->setActiveMapType(m_activeMapType); - } else { - if (!m_supportedMapTypes.isEmpty()) { - m_activeMapType = m_supportedMapTypes.at(0); - m_map->setActiveMapType(m_activeMapType); - } else { - m_activeMapType = QGeoMapType(QGeoMapType::NoMap, - tr("No Map"), - tr("No Map"), - false, - false, - 0, - QByteArrayLiteral(""), - QGeoCameraCapabilities()); - } - } - - // Update camera capabilities - onCameraCapabilitiesChanged(m_cameraCapabilities); - - // Map tiles are built in this call. m_map->minimumZoom() becomes operational - // after this has been called at least once, after creation. - // However, getting into the following block may fire a copyrightsChanged that would get lost, - // as the connections are set up after. - QString copyrightString; - QImage copyrightImage; - if (!m_initialized && width() > 0 && height() > 0) { - QMetaObject::Connection copyrightStringCatcherConnection = - connect(m_map.data(), &QGeoMap::copyrightsChanged, - [©rightString](const QString ©){ copyrightString = copy; }); - QMetaObject::Connection copyrightImageCatcherConnection = - connect(m_map.data(), &QGeoMap::copyrightsImageChanged, - [©rightImage](const QImage ©){ copyrightImage = copy; }); - m_map->setViewportSize(QSize(width(), height())); - initialize(); // This emits the caught signals above - QObject::disconnect(copyrightStringCatcherConnection); - QObject::disconnect(copyrightImageCatcherConnection); - } - - - /* COPYRIGHT SIGNALS REWIRING */ - connect(m_map.data(), &QGeoMap::copyrightsImageChanged, - this, &QDeclarativeGeoMap::copyrightsImageChanged); - connect(m_map.data(), &QGeoMap::copyrightsChanged, - this, &QDeclarativeGeoMap::copyrightsChanged); - if (!copyrightString.isEmpty()) - emit m_map->copyrightsChanged(copyrightString); - else if (!copyrightImage.isNull()) - emit m_map->copyrightsImageChanged(copyrightImage); - - m_window = window(); - if (m_window) { - connect(m_window, &QQuickWindow::beforeSynchronizing, - this, &QDeclarativeGeoMap::updateItemToWindowTransform, Qt::DirectConnection); - } - connect(m_map.data(), &QGeoMap::sgNodeChanged, this, &QDeclarativeGeoMap::onSGNodeChanged); - connect(m_map.data(), &QGeoMap::cameraCapabilitiesChanged, - this, &QDeclarativeGeoMap::onCameraCapabilitiesChanged); - - // This prefetches a buffer around the map - m_map->prefetchData(); - - connect(m_mappingManager, &QGeoMappingManager::supportedMapTypesChanged, - this, &QDeclarativeGeoMap::onSupportedMapTypesChanged); - emit minimumZoomLevelChanged(); - emit maximumZoomLevelChanged(); - emit supportedMapTypesChanged(); - emit activeMapTypeChanged(); - - // Any map item groups that were added before the plugin was ready - // DO NOT need to have setMap called again on their children map items - // because they have been added to m_mapItems, which is processed right above. - - - // All map parameters that were added before the plugin was ready - // need to be added to m_map - for (QDeclarativeGeoMapParameter *p : qAsConst(m_mapParameters)) - m_map->addParameter(p); - - if (m_initialized) - update(); -} - -/*! - \internal -*/ -QDeclarativeGeoServiceProvider *QDeclarativeGeoMap::plugin() const -{ - return m_plugin; -} - -/*! - \internal - Sets the gesture areas minimum zoom level. If the camera capabilities - has been set this method honors the boundaries set by it. - The minimum zoom level will also have a lower bound dependent on the size - of the canvas, effectively preventing to display out of bounds areas. -*/ -void QDeclarativeGeoMap::setMinimumZoomLevel(qreal minimumZoomLevel, bool userSet) -{ - if (minimumZoomLevel >= 0) { - qreal oldUserMinimumZoomLevel = m_userMinimumZoomLevel; - if (userSet) - m_userMinimumZoomLevel = minimumZoomLevel; - qreal oldMinimumZoomLevel = this->minimumZoomLevel(); - - minimumZoomLevel = qBound(qreal(m_cameraCapabilities.minimumZoomLevelAt256()), minimumZoomLevel, maximumZoomLevel()); - if (m_map) - minimumZoomLevel = qMax<qreal>(minimumZoomLevel, m_map->minimumZoom()); - - // minimumZoomLevel is, at this point, the implicit minimum zoom level - m_gestureArea->setMinimumZoomLevel(minimumZoomLevel); - - if (zoomLevel() < minimumZoomLevel && (m_gestureArea->enabled() || !m_cameraCapabilities.overzoomEnabled())) - setZoomLevel(minimumZoomLevel); - - if (qIsNaN(m_userMinimumZoomLevel) && oldMinimumZoomLevel != minimumZoomLevel) - emit minimumZoomLevelChanged(); - else if (userSet && oldUserMinimumZoomLevel != m_userMinimumZoomLevel) - emit minimumZoomLevelChanged(); - } -} - -/*! - \qmlproperty real QtLocation::Map::minimumZoomLevel - - This property holds the minimum valid zoom level for the map. - - The minimum zoom level defined by the \l plugin used is a lower bound for - this property. However, the returned value is also canvas-size-dependent, and - can be higher than the user-specified value, or than the minimum zoom level - defined by the plugin used, to prevent the map from being smaller than the - viewport in either dimension. - - If the \l plugin property is not set or the plugin does not support mapping, this property is \c 0. -*/ - -qreal QDeclarativeGeoMap::minimumZoomLevel() const -{ - if (!qIsNaN(m_userMinimumZoomLevel)) - return m_userMinimumZoomLevel; - else - return m_gestureArea->minimumZoomLevel(); -} - -/*! - \internal -*/ -qreal QDeclarativeGeoMap::implicitMinimumZoomLevel() const -{ - return m_gestureArea->minimumZoomLevel(); -} - -/*! - \internal -*/ -qreal QDeclarativeGeoMap::effectiveMinimumZoomLevel() const -{ - return qMax<qreal>(minimumZoomLevel(), implicitMinimumZoomLevel()); -} - -/*! - \internal - Sets the gesture areas maximum zoom level. If the camera capabilities - has been set this method honors the boundaries set by it. -*/ -void QDeclarativeGeoMap::setMaximumZoomLevel(qreal maximumZoomLevel, bool userSet) -{ - if (maximumZoomLevel >= 0) { - if (userSet) - m_userMaximumZoomLevel = maximumZoomLevel; - qreal oldMaximumZoomLevel = this->maximumZoomLevel(); - - maximumZoomLevel = qBound(minimumZoomLevel(), maximumZoomLevel, qreal(m_cameraCapabilities.maximumZoomLevelAt256())); - - m_gestureArea->setMaximumZoomLevel(maximumZoomLevel); - - if (zoomLevel() > maximumZoomLevel && (m_gestureArea->enabled() || !m_cameraCapabilities.overzoomEnabled())) - setZoomLevel(maximumZoomLevel); - - if (oldMaximumZoomLevel != maximumZoomLevel) - emit maximumZoomLevelChanged(); - } -} - -/*! - \qmlproperty real QtLocation::Map::maximumZoomLevel - - This property holds the maximum valid zoom level for the map. - - The maximum zoom level is defined by the \l plugin used. - If the \l plugin property is not set or the plugin does not support mapping, this property is \c 30. -*/ - -qreal QDeclarativeGeoMap::maximumZoomLevel() const -{ - return m_gestureArea->maximumZoomLevel(); -} - -/*! - \qmlproperty real QtLocation::Map::zoomLevel - - This property holds the zoom level for the map. - - Larger values for the zoom level provide more detail. Zoom levels - are always non-negative. The default value is 8.0. Depending on the plugin in use, - values outside the [minimumZoomLevel, maximumZoomLevel] range, which represent the range for which - tiles are available, may be accepted, or clamped. -*/ -void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel) -{ - return setZoomLevel(zoomLevel, m_cameraCapabilities.overzoomEnabled()); -} - -/*! - \internal - - Sets the zoom level. - Larger values for the zoom level provide more detail. Zoom levels - are always non-negative. The default value is 8.0. Values outside the - [minimumZoomLevel, maximumZoomLevel] range, which represent the range for which - tiles are available, can be accepted or clamped by setting the overzoom argument - to true or false respectively. -*/ -void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel, bool overzoom) -{ - if (zoomLevel < 0) - return; - - if (m_initialized) { - QGeoCameraData cameraData = m_map->cameraData(); - if (cameraData.zoomLevel() == zoomLevel) - return; - - cameraData.setZoomLevel(qBound<qreal>(overzoom ? m_map->minimumZoom() : effectiveMinimumZoomLevel(), - zoomLevel, - overzoom ? 30 : maximumZoomLevel())); - m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(cameraData); - m_minimumViewportLatitude = m_map->minimumCenterLatitudeAtZoom(cameraData); - QGeoCoordinate coord = cameraData.center(); - coord.setLatitude(qBound(m_minimumViewportLatitude, coord.latitude(), m_maximumViewportLatitude)); - cameraData.setCenter(coord); - m_map->setCameraData(cameraData); - } else { - const bool zlHasChanged = zoomLevel != m_cameraData.zoomLevel(); - m_cameraData.setZoomLevel(zoomLevel); - if (zlHasChanged) { - emit zoomLevelChanged(zoomLevel); - // do not emit visibleRegionChanged() here, because, if the map isn't initialized, - // the getter won't return anything updated - } - } -} - -bool QDeclarativeGeoMap::addMapChild(QObject *child) -{ - // dispatch items appropriately - QDeclarativeGeoMapItemView *mapView = qobject_cast<QDeclarativeGeoMapItemView *>(child); - if (mapView) - return addMapItemView_real(mapView); - - QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast<QDeclarativeGeoMapItemGroup *>(child); - if (itemGroup) // addMapItemView calls addMapItemGroup - return addMapItemGroup_real(itemGroup); - - QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(child); - if (mapItem) - return addMapItem_real(mapItem); - - QGeoMapObject *mapObject = qobject_cast<QGeoMapObject *>(child); - if (mapObject) - addMapObject(mapObject); // this emits mapObjectsChanged, != mapItemsChanged - return false; -} - -bool QDeclarativeGeoMap::removeMapChild(QObject *child) -{ - // dispatch items appropriately - QDeclarativeGeoMapItemView *mapView = qobject_cast<QDeclarativeGeoMapItemView *>(child); - if (mapView) - return removeMapItemView_real(mapView); - - QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast<QDeclarativeGeoMapItemGroup *>(child); - if (itemGroup) // removeMapItemView calls removeMapItemGroup for itself. - return removeMapItemGroup_real(itemGroup); - - QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(child); - if (mapItem) - return removeMapItem_real(mapItem); - - QGeoMapObject *mapObject = qobject_cast<QGeoMapObject *>(child); - if (mapObject) - removeMapObject(mapObject); // this emits mapObjectsChanged, != mapItemsChanged - return false; -} - -bool QDeclarativeGeoMap::isGroupNested(QDeclarativeGeoMapItemGroup *group) const -{ - QObject *parent = group->parent(); - // Nested groups have parent set in parent's componentComplete() - // Those instantiated by MapItemView's delegateModel, however, do not, - // but have setParentItem set. - return qobject_cast<QDeclarativeGeoMapItemGroup *>(parent) - || qobject_cast<QDeclarativeGeoMapItemGroup *>(group->parentItem()); -} - -qreal QDeclarativeGeoMap::zoomLevel() const -{ - if (m_initialized) - return m_map->cameraData().zoomLevel(); - return m_cameraData.zoomLevel(); -} - -/*! - \qmlproperty real QtLocation::Map::bearing - - This property holds the bearing for the map. - The default value is 0. - If the Plugin used for the Map supports bearing, the valid range for this value is between 0 and 360. - If the Plugin used for the Map does not support bearing, changing this property will have no effect. - - \since QtLocation 5.9 -*/ -void QDeclarativeGeoMap::setBearing(qreal bearing) -{ - bearing = sanitizeBearing(bearing); - if (m_initialized) { - QGeoCameraData cameraData = m_map->cameraData(); - cameraData.setBearing(bearing); - m_map->setCameraData(cameraData); - } else { - const bool bearingHasChanged = bearing != m_cameraData.bearing(); - m_cameraData.setBearing(bearing); - if (bearingHasChanged) { - emit bearingChanged(bearing); - // do not emit visibleRegionChanged() here, because, if the map isn't initialized, - // the getter won't return anything updated - } - } -} - -/*! - \qmlmethod void QtLocation::Map::setBearing(real bearing, coordinate coordinate) - - Sets the bearing for the map to \a bearing, rotating it around \a coordinate. - If the Plugin used for the Map supports bearing, the valid range for \a bearing is between 0 and 360. - If the Plugin used for the Map does not support bearing, or if the map is tilted and \a coordinate happens - to be behind the camera, or if the map is not ready (see \l mapReady), calling this method will have no effect. - - The release of this API with Qt 5.10 is a Technology Preview. - - \since 5.10 -*/ -void QDeclarativeGeoMap::setBearing(qreal bearing, const QGeoCoordinate &coordinate) -{ - if (!m_initialized) - return; - - const QGeoCoordinate currentCenter = center(); - const qreal currentBearing = QDeclarativeGeoMap::bearing(); - bearing = sanitizeBearing(bearing); - - if (!coordinate.isValid() - || !qIsFinite(bearing) - || (coordinate == currentCenter && bearing == currentBearing)) - return; - - if (m_map->capabilities() & QGeoMap::SupportsSetBearing) - m_map->setBearing(bearing, coordinate); -} - -qreal QDeclarativeGeoMap::bearing() const -{ - if (m_initialized) - return m_map->cameraData().bearing(); - return m_cameraData.bearing(); -} - -/*! - \qmlproperty real QtLocation::Map::tilt - - This property holds the tilt for the map, in degrees. - The default value is 0. - The valid range for this value is [ minimumTilt, maximumTilt ]. - If the Plugin used for the Map does not support tilting, changing this property will have no effect. - - \sa minimumTilt, maximumTilt - - \since QtLocation 5.9 -*/ -void QDeclarativeGeoMap::setTilt(qreal tilt) -{ - tilt = qBound(minimumTilt(), tilt, maximumTilt()); - - if (m_initialized) { - QGeoCameraData cameraData = m_map->cameraData(); - cameraData.setTilt(tilt); - m_map->setCameraData(cameraData); - } else { - const bool tiltHasChanged = tilt != m_cameraData.tilt(); - m_cameraData.setTilt(tilt); - if (tiltHasChanged) { - emit tiltChanged(tilt); - // do not emit visibleRegionChanged() here, because, if the map isn't initialized, - // the getter won't return anything updated - } - } -} - -qreal QDeclarativeGeoMap::tilt() const -{ - if (m_initialized) - return m_map->cameraData().tilt(); - return m_cameraData.tilt(); -} - -void QDeclarativeGeoMap::setMinimumTilt(qreal minimumTilt, bool userSet) -{ - if (minimumTilt >= 0) { - if (userSet) - m_userMinimumTilt = minimumTilt; - qreal oldMinimumTilt = this->minimumTilt(); - - m_minimumTilt = qBound<double>(m_cameraCapabilities.minimumTilt(), - minimumTilt, - m_cameraCapabilities.maximumTilt()); - - if (tilt() < m_minimumTilt) - setTilt(m_minimumTilt); - - if (oldMinimumTilt != m_minimumTilt) - emit minimumTiltChanged(m_minimumTilt); - } -} - -/*! - \qmlproperty real QtLocation::Map::fieldOfView - - This property holds the field of view of the camera used to look at the map, in degrees. - If the plugin property of the map is not set, or the plugin does not support mapping, the value is 45 degrees. - - Note that changing this value implicitly changes also the distance between the camera and the map, - so that, at a tilting angle of 0 degrees, the resulting image is identical for any value used for this property. - - For more information about this parameter, consult the Wikipedia articles about \l {https://en.wikipedia.org/wiki/Field_of_view} {Field of view} and - \l {https://en.wikipedia.org/wiki/Angle_of_view} {Angle of view}. - - \sa minimumFieldOfView, maximumFieldOfView - - \since QtLocation 5.9 -*/ -void QDeclarativeGeoMap::setFieldOfView(qreal fieldOfView) -{ - fieldOfView = qBound(minimumFieldOfView(), fieldOfView, maximumFieldOfView()); - - if (m_initialized) { - QGeoCameraData cameraData = m_map->cameraData(); - cameraData.setFieldOfView(fieldOfView); - m_map->setCameraData(cameraData); - } else { - const bool fovChanged = fieldOfView != m_cameraData.fieldOfView(); - m_cameraData.setFieldOfView(fieldOfView); - if (fovChanged) { - emit fieldOfViewChanged(fieldOfView); - // do not emit visibleRegionChanged() here, because, if the map isn't initialized, - // the getter won't return anything updated - } - } -} - -qreal QDeclarativeGeoMap::fieldOfView() const -{ - if (m_initialized) - return m_map->cameraData().fieldOfView(); - return m_cameraData.fieldOfView(); -} - -void QDeclarativeGeoMap::setMinimumFieldOfView(qreal minimumFieldOfView, bool userSet) -{ - if (minimumFieldOfView > 0 && minimumFieldOfView < 180.0) { - if (userSet) - m_userMinimumFieldOfView = minimumFieldOfView; - qreal oldMinimumFoV = this->minimumFieldOfView(); - - m_minimumFieldOfView = qBound<double>(m_cameraCapabilities.minimumFieldOfView(), - minimumFieldOfView, - m_cameraCapabilities.maximumFieldOfView()); - - if (fieldOfView() < m_minimumFieldOfView) - setFieldOfView(m_minimumFieldOfView); - - if (oldMinimumFoV != m_minimumFieldOfView) - emit minimumFieldOfViewChanged(m_minimumFieldOfView); - } -} - -/*! - \qmlproperty real QtLocation::Map::minimumFieldOfView - - This property holds the minimum valid field of view for the map, in degrees. - - The minimum tilt field of view by the \l plugin used is a lower bound for - this property. - If the \l plugin property is not set or the plugin does not support mapping, this property is \c 1. - - \sa fieldOfView, maximumFieldOfView - - \since QtLocation 5.9 -*/ -qreal QDeclarativeGeoMap::minimumFieldOfView() const -{ - return m_minimumFieldOfView; -} - -void QDeclarativeGeoMap::setMaximumFieldOfView(qreal maximumFieldOfView, bool userSet) -{ - if (maximumFieldOfView > 0 && maximumFieldOfView < 180.0) { - if (userSet) - m_userMaximumFieldOfView = maximumFieldOfView; - qreal oldMaximumFoV = this->maximumFieldOfView(); - - m_maximumFieldOfView = qBound<double>(m_cameraCapabilities.minimumFieldOfView(), - maximumFieldOfView, - m_cameraCapabilities.maximumFieldOfView()); - - if (fieldOfView() > m_maximumFieldOfView) - setFieldOfView(m_maximumFieldOfView); - - if (oldMaximumFoV != m_maximumFieldOfView) - emit maximumFieldOfViewChanged(m_maximumFieldOfView); - } -} - -/*! - \qmlproperty real QtLocation::Map::maximumFieldOfView - - This property holds the maximum valid field of view for the map, in degrees. - - The minimum tilt field of view by the \l plugin used is an upper bound for - this property. - If the \l plugin property is not set or the plugin does not support mapping, this property is \c 179. - - \sa fieldOfView, minimumFieldOfView - - \since QtLocation 5.9 -*/ -qreal QDeclarativeGeoMap::maximumFieldOfView() const -{ - return m_maximumFieldOfView; -} - -/*! - \qmlproperty real QtLocation::Map::minimumTilt - - This property holds the minimum valid tilt for the map, in degrees. - - The minimum tilt defined by the \l plugin used is a lower bound for - this property. - If the \l plugin property is not set or the plugin does not support mapping, this property is \c 0. - - Since QtLocation 5.12, plugins can additionally restrict this value depending on the current zoom level. - - \sa tilt, maximumTilt - - \since QtLocation 5.9 -*/ -qreal QDeclarativeGeoMap::minimumTilt() const -{ - return m_minimumTilt; -} - -void QDeclarativeGeoMap::setMaximumTilt(qreal maximumTilt, bool userSet) -{ - if (maximumTilt >= 0) { - if (userSet) - m_userMaximumTilt = maximumTilt; - qreal oldMaximumTilt = this->maximumTilt(); - - m_maximumTilt = qBound<double>(m_cameraCapabilities.minimumTilt(), - maximumTilt, - m_cameraCapabilities.maximumTilt()); - - if (tilt() > m_maximumTilt) - setTilt(m_maximumTilt); - - if (oldMaximumTilt != m_maximumTilt) - emit maximumTiltChanged(m_maximumTilt); - } -} - -/*! - \qmlproperty real QtLocation::Map::maximumTilt - - This property holds the maximum valid tilt for the map, in degrees. - - The maximum tilt defined by the \l plugin used is an upper bound for - this property. - If the \l plugin property is not set or the plugin does not support mapping, this property is \c 89.5. - - Since QtLocation 5.12, plugins can additionally restrict this value depending on the current zoom level. - - \sa tilt, minimumTilt - - \since QtLocation 5.9 -*/ -qreal QDeclarativeGeoMap::maximumTilt() const -{ - return m_maximumTilt; -} - -/*! - \qmlproperty coordinate QtLocation::Map::center - - This property holds the coordinate which occupies the center of the - mapping viewport. Invalid center coordinates are ignored. - - The default value is an arbitrary valid coordinate. -*/ -void QDeclarativeGeoMap::setCenter(const QGeoCoordinate ¢er) -{ - if (!center.isValid()) - return; - - if (m_initialized) { - QGeoCoordinate coord(center); - coord.setLatitude(qBound(m_minimumViewportLatitude, center.latitude(), m_maximumViewportLatitude)); - QGeoCameraData cameraData = m_map->cameraData(); - cameraData.setCenter(coord); - m_map->setCameraData(cameraData); - } else { - const bool centerHasChanged = center != m_cameraData.center(); - m_cameraData.setCenter(center); - if (centerHasChanged) { - emit centerChanged(center); - // do not emit visibleRegionChanged() here, because, if the map isn't initialized, - // the getter won't return anything updated - } - } -} - -QGeoCoordinate QDeclarativeGeoMap::center() const -{ - if (m_initialized) - return m_map->cameraData().center(); - return m_cameraData.center(); -} - - -/*! - \qmlproperty geoshape QtLocation::Map::visibleRegion - - This property holds the region which occupies the viewport of - the map. The camera is positioned in the center of the shape, and - at the largest integral zoom level possible which allows the - whole shape to be visible on the screen. This implies that - reading this property back shortly after having been set the - returned area is equal or larger than the set area. - - Setting this property implicitly changes the \l center and - \l zoomLevel of the map. Any previously set value to those - properties will be overridden. - - \note Since Qt 5.14 This property provides change notifications. - - \since 5.6 -*/ -void QDeclarativeGeoMap::setVisibleRegion(const QGeoShape &shape) -{ - if (shape.boundingGeoRectangle() == visibleRegion()) - return; - - m_visibleRegion = shape.boundingGeoRectangle(); - if (!m_visibleRegion.isValid() - || (m_visibleRegion.bottomRight().latitude() >= 85.0) // rect entirely outside web mercator - || (m_visibleRegion.topLeft().latitude() <= -85.0)) { - // shape invalidated -> nothing to fit anymore - m_visibleRegion = QGeoRectangle(); - m_pendingFitViewport = false; - emit visibleRegionChanged(); - return; - } - - if (!m_map || !width() || !height()) { - m_pendingFitViewport = true; - emit visibleRegionChanged(); - return; - } - - fitViewportToGeoShape(m_visibleRegion); - emit visibleRegionChanged(); -} - -QGeoShape QDeclarativeGeoMap::visibleRegion() const -{ - if (!m_map || !width() || !height()) - return m_visibleRegion; - - if (m_map->capabilities() & QGeoMap::SupportsVisibleRegion) { - return m_map->visibleRegion(); - } else { - // ToDo: handle projections not supporting visible region in a better way. - // This approach will fail when horizon is in the view or the map is greatly zoomed out. - QList<QGeoCoordinate> visiblePoly; - visiblePoly << m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(0,0), false); - visiblePoly << m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_map->viewportWidth() - 1, - 0), false); - visiblePoly << m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_map->viewportWidth() - 1, - m_map->viewportHeight() - 1), false); - visiblePoly << m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(0, - m_map->viewportHeight() - 1), false); - QGeoPath path; - path.setPath(visiblePoly); - return path.boundingGeoRectangle(); - } -} - -/*! - \qmlproperty bool QtLocation::Map::copyrightsVisible - - This property holds the visibility of the copyrights notice. The notice is usually - displayed in the bottom left corner. By default, this property is set to \c true. - - \note Many map providers require the notice to be visible as part of the terms and conditions. - Please consult the relevant provider documentation before turning this notice off. - - \since 5.7 -*/ -void QDeclarativeGeoMap::setCopyrightsVisible(bool visible) -{ - if (m_copyrightsVisible == visible) - return; - - if (!m_copyrights.isNull()) - m_copyrights->setCopyrightsVisible(visible); - - m_copyrightsVisible = visible; - emit copyrightsVisibleChanged(visible); -} - -bool QDeclarativeGeoMap::copyrightsVisible() const -{ - return m_copyrightsVisible; -} - - - -/*! - \qmlproperty color QtLocation::Map::color - - This property holds the background color of the map element. - - \since 5.6 -*/ -void QDeclarativeGeoMap::setColor(const QColor &color) -{ - if (color != m_color) { - m_color = color; - update(); - emit colorChanged(m_color); - } -} - -QColor QDeclarativeGeoMap::color() const -{ - return m_color; -} - -/*! - \qmlproperty rect QtLocation::Map::visibleArea - - This property holds the visible area inside the Map QML element. - It is a rect whose coordinates are relative to the Map element. - Its size will be clamped to the size of the Map element. - A null visibleArea means that the whole Map is visible. - - \since 5.12 -*/ -QRectF QDeclarativeGeoMap::visibleArea() const -{ - if (m_initialized) - return m_map->visibleArea(); - return m_visibleArea; -} - -void QDeclarativeGeoMap::setVisibleArea(const QRectF &visibleArea) -{ - const QRectF oldVisibleArea = QDeclarativeGeoMap::visibleArea(); - if (visibleArea == oldVisibleArea) - return; - - if (!visibleArea.isValid() && !visibleArea.isEmpty()) // values < 0 - return; - - if (m_initialized) { - m_map->setVisibleArea(visibleArea); - const QRectF newVisibleArea = QDeclarativeGeoMap::visibleArea(); - if (newVisibleArea != oldVisibleArea) { - // polish map items - for (const QPointer<QDeclarativeGeoMapItemBase> &i: qAsConst(m_mapItems)) { - if (i) - i->visibleAreaChanged(); - } - } - } else { - m_visibleArea = visibleArea; - const QRectF newVisibleArea = QDeclarativeGeoMap::visibleArea(); - if (newVisibleArea != oldVisibleArea) - emit visibleAreaChanged(); - } -} - -/*! - \qmlproperty bool QtLocation::Map::mapReady - - This property holds whether the map has been successfully initialized and is ready to be used. - Some methods, such as \l fromCoordinate and \l toCoordinate, will not work before the map is ready. - Due to the architecture of the \l Map, it's advised to use the signal emitted for this property - in place of \l {QtQml::Component::completed()}{Component.onCompleted}, to make sure that everything behaves as expected. - - \since 5.9 -*/ -bool QDeclarativeGeoMap::mapReady() const -{ - return m_initialized; -} - -QMargins QDeclarativeGeoMap::mapMargins() const -{ - const QRectF va = m_map->visibleArea(); - if (va.isEmpty()) - return QMargins(); - return QMargins( va.x() - , va.y() - , width() - va.width() - va.x() - , height() - va.height() - va.y()); -} - -/*! - \qmlproperty list<mapType> QtLocation::Map::supportedMapTypes - - This read-only property holds the set of \l{mapType}{map types} supported by this map. - - \sa activeMapType -*/ -QList<QGeoMapType> QDeclarativeGeoMap::supportedMapTypes() -{ - return m_supportedMapTypes; -} - -/*! - \qmlmethod void QtLocation::Map::alignCoordinateToPoint(coordinate coordinate, QPointF point) - - Aligns \a coordinate to \a point. - This method effectively extends the functionality offered by the \l center qml property, allowing - to align a coordinate to point of the Map element other than its center. - This is useful in those applications where the center of the scene (e.g., a cursor) is not to be - placed exactly in the center of the map. - - If the map is tilted, and \a coordinate happens to be behind the camera, or if the map is not ready - (see \l mapReady), calling this method will have no effect. - - The release of this API with Qt 5.10 is a Technology Preview. - - \sa center - - \since 5.10 -*/ -void QDeclarativeGeoMap::alignCoordinateToPoint(const QGeoCoordinate &coordinate, const QPointF &point) -{ - if (!m_map || !(m_map->capabilities() & QGeoMap::SupportsAnchoringCoordinate)) - return; - - if (!coordinate.isValid() - || !qIsFinite(point.x()) - || !qIsFinite(point.y())) - return; - - m_map->anchorCoordinateToPoint(coordinate, point); -} - -/*! - \qmlmethod coordinate QtLocation::Map::toCoordinate(QPointF position, bool clipToViewPort) - - Returns the coordinate which corresponds to the \a position relative to the map item. - - If \a clipToViewPort is \c true, or not supplied then returns an invalid coordinate if - \a position is not within the current viewport. -*/ -QGeoCoordinate QDeclarativeGeoMap::toCoordinate(const QPointF &position, bool clipToViewPort) const -{ - if (m_map) - return m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(position), clipToViewPort); - else - return QGeoCoordinate(); -} - -/*! - \qmlmethod point QtLocation::Map::fromCoordinate(coordinate coordinate, bool clipToViewPort) - - Returns the position relative to the map item which corresponds to the \a coordinate. - - If \a clipToViewPort is \c true, or not supplied then returns an invalid QPointF if - \a coordinate is not within the current viewport. -*/ -QPointF QDeclarativeGeoMap::fromCoordinate(const QGeoCoordinate &coordinate, bool clipToViewPort) const -{ - if (m_map) - return m_map->geoProjection().coordinateToItemPosition(coordinate, clipToViewPort).toPointF(); - else - return QPointF(qQNaN(), qQNaN()); -} - -/*! - \qmlmethod void QtLocation::Map::pan(int dx, int dy) - - Starts panning the map by \a dx pixels along the x-axis and - by \a dy pixels along the y-axis. - - Positive values for \a dx move the map right, negative values left. - Positive values for \a dy move the map down, negative values up. - - During panning the \l center, and \l zoomLevel may change. -*/ -void QDeclarativeGeoMap::pan(int dx, int dy) -{ - if (!m_map) - return; - if (dx == 0 && dy == 0) - return; - - QGeoCoordinate coord = m_map->geoProjection().itemPositionToCoordinate( - QDoubleVector2D(m_map->viewportWidth() / 2 + dx, - m_map->viewportHeight() / 2 + dy)); - setCenter(coord); -} - - -/*! - \qmlmethod void QtLocation::Map::prefetchData() - - Optional hint that allows the map to prefetch during this idle period -*/ -void QDeclarativeGeoMap::prefetchData() -{ - if (!m_map) - return; - m_map->prefetchData(); -} - -/*! - \qmlmethod void QtLocation::Map::clearData() - - Clears map data collected by the currently selected plugin. - \note This method will delete cached files. - \sa plugin -*/ -void QDeclarativeGeoMap::clearData() -{ - if (m_map) - m_map->clearData(); -} - -/*! - \qmlmethod void QtLocation::Map::fitViewportToGeoShape(geoShape, margins) - - Fits the viewport to a specific geo shape \a geoShape. - The \a margins are in screen pixels. - - \note If the projection used by the plugin is not WebMercator, and the plugin does not have fitting to - shape capability, this method will do nothing. - - \sa visibleRegion - \since 5.13 -*/ -void QDeclarativeGeoMap::fitViewportToGeoShape(const QGeoShape &shape, QVariant margins) -{ - QMargins m(10, 10, 10, 10); // lets defaults to 10 if margins is invalid - switch (margins.typeId()) { - case QMetaType::Int: - case QMetaType::Double: { - const int value = int(margins.toDouble()); - m = QMargins(value, value, value, value); - } - break; - // ToDo: Support distinct margins in some QML form. Perhaps QRect? - default: - break; - } - fitViewportToGeoShape(shape, m); -} - -void QDeclarativeGeoMap::fitViewportToGeoShape(const QGeoShape &shape, const QMargins &borders) -{ - if (!m_map || !shape.isValid()) - return; - - if (m_map->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) { - // This case remains handled here, and not inside QGeoMap*::fitViewportToGeoRectangle, - // in order to honor animations on center and zoomLevel - const QMargins margins = borders + mapMargins(); - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); - const QPair<QGeoCoordinate, qreal> fitData = p.fitViewportToGeoRectangle(shape.boundingGeoRectangle(), - margins); - if (!fitData.first.isValid()) - return; - - // position camera to the center of bounding box - setProperty("center", QVariant::fromValue(fitData.first)); // not using setCenter(centerCoordinate) to honor a possible animation set on the center property - - if (!qIsFinite(fitData.second)) - return; - double newZoom = qMax<double>(minimumZoomLevel(), fitData.second); - setProperty("zoomLevel", QVariant::fromValue(newZoom)); // not using setZoomLevel(newZoom) to honor a possible animation set on the zoomLevel property - } else if (m_map->capabilities() & QGeoMap::SupportsFittingViewportToGeoRectangle) { - // Animations cannot be honored in this case, as m_map acts as a black box - m_map->fitViewportToGeoRectangle(m_visibleRegion, borders); - } - // else out of luck -} - -/*! - \qmlproperty string QtLocation::Map::errorString - - This read-only property holds the textual presentation of the latest mapping provider error. - If no error has occurred, an empty string is returned. - - An empty string may also be returned if an error occurred which has no associated - textual representation. - - \sa QGeoServiceProvider::errorString() -*/ - -QString QDeclarativeGeoMap::errorString() const -{ - return m_errorString; -} - -/*! - \qmlproperty enumeration QtLocation::Map::error - - This read-only property holds the last occurred mapping service provider error. - - \list - \li Map.NoError - No error has occurred. - \li Map.NotSupportedError -The maps plugin property was not set or there is no mapping manager associated with the plugin. - \li Map.UnknownParameterError -The plugin did not recognize one of the parameters it was given. - \li Map.MissingRequiredParameterError - The plugin did not find one of the parameters it was expecting. - \li Map.ConnectionError - The plugin could not connect to its backend service or database. - \endlist - - \sa QGeoServiceProvider::Error -*/ - -QGeoServiceProvider::Error QDeclarativeGeoMap::error() const -{ - return m_error; -} - -QGeoMap *QDeclarativeGeoMap::map() const -{ - return m_map; -} - -void QDeclarativeGeoMap::itemChange(ItemChange change, const ItemChangeData &value) -{ - if (change == ItemChildAddedChange) { - QQuickItem *child = value.item; - QQuickItem *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(child); - if (!mapItem) - mapItem = qobject_cast<QDeclarativeGeoMapItemGroup *>(child); - - if (mapItem) { - qreal z = mapItem->z(); - if (z > m_maxChildZ) { // Ignore children removal - m_maxChildZ = z; - // put the copyrights notice object at the highest z order - if (m_copyrights) - m_copyrights->setCopyrightsZ(m_maxChildZ + 1); - } - } - } else if (change == ItemSceneChange) { - if (m_window) { - disconnect(m_window, &QQuickWindow::beforeSynchronizing, - this, &QDeclarativeGeoMap::updateItemToWindowTransform); - } - m_window = value.window; - if (m_window) { - connect(m_window, &QQuickWindow::beforeSynchronizing, - this, &QDeclarativeGeoMap::updateItemToWindowTransform, Qt::DirectConnection); - } - } - QQuickItem::itemChange(change, value); -} - -bool QDeclarativeGeoMap::isInteractive() const -{ - return (m_gestureArea->enabled() && m_gestureArea->acceptedGestures()) || m_gestureArea->isActive(); -} - -void QDeclarativeGeoMap::attachCopyrightNotice(bool initialVisibility) -{ - if (initialVisibility) { - ++m_copyNoticesVisible; - if (m_map) - m_map->setCopyrightVisible(m_copyNoticesVisible > 0); - } -} - -void QDeclarativeGeoMap::detachCopyrightNotice(bool currentVisibility) -{ - if (currentVisibility) { - --m_copyNoticesVisible; - if (m_map) - m_map->setCopyrightVisible(m_copyNoticesVisible > 0); - } -} - -void QDeclarativeGeoMap::onAttachedCopyrightNoticeVisibilityChanged() -{ - QDeclarativeGeoMapCopyrightNotice *copy = static_cast<QDeclarativeGeoMapCopyrightNotice *>(sender()); - m_copyNoticesVisible += ( int(copy->copyrightsVisible()) * 2 - 1); - if (m_map) - m_map->setCopyrightVisible(m_copyNoticesVisible > 0); -} - -void QDeclarativeGeoMap::onCameraDataChanged(const QGeoCameraData &cameraData) -{ - bool centerHasChanged = cameraData.center() != m_cameraData.center(); - bool bearingHasChanged = cameraData.bearing() != m_cameraData.bearing(); - bool tiltHasChanged = cameraData.tilt() != m_cameraData.tilt(); - bool fovHasChanged = cameraData.fieldOfView() != m_cameraData.fieldOfView(); - bool zoomHasChanged = cameraData.zoomLevel() != m_cameraData.zoomLevel(); - - m_cameraData = cameraData; - // polish map items - for (const QPointer<QDeclarativeGeoMapItemBase> &i: qAsConst(m_mapItems)) { - if (i) - i->baseCameraDataChanged(m_cameraData); // Consider optimizing this further, removing the contained duplicate if conditions. - } - - if (centerHasChanged) - emit centerChanged(m_cameraData.center()); - if (zoomHasChanged) - emit zoomLevelChanged(m_cameraData.zoomLevel()); - if (bearingHasChanged) - emit bearingChanged(m_cameraData.bearing()); - if (tiltHasChanged) - emit tiltChanged(m_cameraData.tilt()); - if (fovHasChanged) - emit fieldOfViewChanged(m_cameraData.fieldOfView()); - if (centerHasChanged || zoomHasChanged || bearingHasChanged - || tiltHasChanged || fovHasChanged) - emit visibleRegionChanged(); -} - -/*! - \qmlmethod void QtLocation::Map::addMapParameter(MapParameter parameter) - - Adds the \a parameter object to the map. The effect of this call is dependent - on the combination of the content of the MapParameter and the type of - underlying QGeoMap. If a MapParameter that is not supported by the underlying - QGeoMap gets added, the call has no effect. - - The release of this API with Qt 5.9 is a Technology Preview. - - \sa MapParameter, removeMapParameter, mapParameters, clearMapParameters - - \since 5.9 -*/ -void QDeclarativeGeoMap::addMapParameter(QDeclarativeGeoMapParameter *parameter) -{ - if (!parameter->isComponentComplete()) { - connect(parameter, &QDeclarativeGeoMapParameter::completed, this, &QDeclarativeGeoMap::addMapParameter); - return; - } - - disconnect(parameter); - if (m_mapParameters.contains(parameter)) - return; - parameter->setParent(this); - m_mapParameters.append(parameter); // parameter now owned by QDeclarativeGeoMap - if (m_map) - m_map->addParameter(parameter); -} - -/*! - \qmlmethod void QtLocation::Map::removeMapParameter(MapParameter parameter) - - Removes the given \a parameter object from the map. - - The release of this API with Qt 5.9 is a Technology Preview. - - \sa MapParameter, addMapParameter, mapParameters, clearMapParameters - - \since 5.9 -*/ -void QDeclarativeGeoMap::removeMapParameter(QDeclarativeGeoMapParameter *parameter) -{ - if (!m_mapParameters.contains(parameter)) - return; - if (m_map) - m_map->removeParameter(parameter); - m_mapParameters.removeOne(parameter); -} - -/*! - \qmlmethod void QtLocation::Map::clearMapParameters() - - Removes all map parameters from the map. - - The release of this API with Qt 5.9 is a Technology Preview. - - \sa MapParameter, mapParameters, addMapParameter, removeMapParameter, clearMapParameters - - \since 5.9 -*/ -void QDeclarativeGeoMap::clearMapParameters() -{ - if (m_map) - m_map->clearParameters(); - m_mapParameters.clear(); -} - -/*! - \qmlproperty list<MapParameters> QtLocation::Map::mapParameters - - Returns the list of all map parameters in no particular order. - These items include map parameters that were declared statically as part of - the type declaration, as well as dynamical map parameters (\l addMapParameter). - - The release of this API with Qt 5.9 is a Technology Preview. - - \sa MapParameter, addMapParameter, removeMapParameter, clearMapParameters - - \since 5.9 -*/ -QList<QObject *> QDeclarativeGeoMap::mapParameters() -{ - QList<QObject *> ret; - for (QDeclarativeGeoMapParameter *p : qAsConst(m_mapParameters)) - ret << p; - return ret; -} - -/* - \internal -*/ -void QDeclarativeGeoMap::addMapObject(QGeoMapObject *object) -{ - if (!object || object->map()) - return; - - if (!m_initialized) { - m_pendingMapObjects.append(object); - return; - } - - int curObjects = m_map->mapObjects().size(); - // object adds itself to the map - object->setMap(m_map); - - if (curObjects != m_map->mapObjects().size()) - emit mapObjectsChanged(); -} - -/* - \internal -*/ -void QDeclarativeGeoMap::removeMapObject(QGeoMapObject *object) -{ - if (!object || object->map() != m_map) // if !initialized this is fine, since both object and m_map are supposed to be NULL - return; - - if (!m_initialized) { - m_pendingMapObjects.removeOne(object); - return; - } - - int curObjects = m_map->mapObjects().size(); - // object adds itself to the map - object->setMap(nullptr); - - if (curObjects != m_map->mapObjects().size()) - emit mapObjectsChanged(); -} - -/* - \internal -*/ -void QDeclarativeGeoMap::clearMapObjects() -{ - if (!m_initialized) { - m_pendingMapObjects.clear(); - } else { - const QList<QGeoMapObject *> objs = m_map->mapObjects(); - for (QGeoMapObject *o: objs) - o->setMap(nullptr); - if (objs.size()) - emit mapObjectsChanged(); - } -} - -/* - \internal -*/ -QList<QGeoMapObject *> QDeclarativeGeoMap::mapObjects() -{ - if (!m_initialized) - return m_pendingMapObjects; - else - return m_map->mapObjects(); -} - -/*! - \qmlproperty list<MapItem> QtLocation::Map::mapItems - - Returns the list of all map items in no particular order. - These items include items that were declared statically as part of - the type declaration, as well as dynamical items (\l addMapItem, - \l MapItemView). - - \sa addMapItem, removeMapItem, clearMapItems -*/ - -QList<QObject *> QDeclarativeGeoMap::mapItems() -{ - QList<QObject *> ret; - for (const auto &ptr : m_mapItems) { - if (ptr) - ret << ptr.data(); - } - return ret; -} - -/*! - \qmlmethod void QtLocation::Map::addMapItem(MapItem item) - - Adds the given \a item to the Map (for example MapQuickItem, MapCircle). If the object - already is on the Map, it will not be added again. - - As an example, consider the case where you have a MapCircle representing your current position: - - \snippet declarative/maps.qml QtQuick import - \snippet declarative/maps.qml QtLocation import - \codeline - \snippet declarative/maps.qml Map addMapItem MapCircle at current position - - \note MapItemViews cannot be added with this method. - - \sa mapItems, removeMapItem, clearMapItems -*/ - -void QDeclarativeGeoMap::addMapItem(QDeclarativeGeoMapItemBase *item) -{ - if (addMapItem_real(item)) - emit mapItemsChanged(); -} - -bool QDeclarativeGeoMap::addMapItem_real(QDeclarativeGeoMapItemBase *item) -{ - if (!item || item->quickMap()) - return false; - // If the item comes from a MapItemGroup, do not reparent it. - if (!qobject_cast<QDeclarativeGeoMapItemGroup *>(item->parentItem())) - item->setParentItem(this); - m_mapItems.append(item); - if (m_map) { - item->setMap(this, m_map); - m_map->addMapItem(item); - } - return true; -} - -/*! - \qmlmethod void QtLocation::Map::removeMapItem(MapItem item) - - Removes the given \a item from the Map (for example MapQuickItem, MapCircle). If - the MapItem does not exist or was not previously added to the map, the - method does nothing. - - \sa mapItems, addMapItem, clearMapItems -*/ -void QDeclarativeGeoMap::removeMapItem(QDeclarativeGeoMapItemBase *ptr) -{ - if (removeMapItem_real(ptr)) - emit mapItemsChanged(); -} - -bool QDeclarativeGeoMap::removeMapItem_real(QDeclarativeGeoMapItemBase *ptr) -{ - if (!ptr) - return false; - QPointer<QDeclarativeGeoMapItemBase> item(ptr); - if (!m_mapItems.contains(item)) - return false; - if (m_map) - m_map->removeMapItem(ptr); - if (item->parentItem() == this) - item->setParentItem(0); - item->setMap(0, 0); - // these can be optimized for perf, as we already check the 'contains' above - m_mapItems.removeOne(item); - return true; -} - -/*! - \qmlmethod void QtLocation::Map::clearMapItems() - - Removes all items and item groups from the map. - - \sa mapItems, addMapItem, removeMapItem, addMapItemGroup, removeMapItemGroup -*/ -void QDeclarativeGeoMap::clearMapItems() -{ - if (m_mapItems.isEmpty()) - return; - - qsizetype removed = 0; - for (qsizetype i = 0; i < m_mapItemGroups.count(); ++i) { - auto item = m_mapItemGroups.at(i); - // Processing only top-level groups (!views) - if (qobject_cast<QDeclarativeGeoMapItemView *>(item)) - continue; - - - if (item->parentItem() != this) - continue; - - if (removeMapItemGroup_real(item)) { - removed++; - --i; - } - } - - while (!m_mapItems.isEmpty()) - removed += removeMapItem_real(m_mapItems.first()); - - if (removed) - emit mapItemsChanged(); -} - -/*! - \qmlmethod void QtLocation::Map::addMapItemGroup(MapItemGroup itemGroup) - - Adds the map items contained in the given \a itemGroup to the Map - (for example MapQuickItem, MapCircle). - - \sa MapItemGroup, removeMapItemGroup - - \since 5.9 -*/ -void QDeclarativeGeoMap::addMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup) -{ - if (addMapItemGroup_real(itemGroup)) - emit mapItemsChanged(); -} - -bool QDeclarativeGeoMap::addMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup) -{ - if (!itemGroup || itemGroup->quickMap()) // Already added to some map - return false; - - itemGroup->setQuickMap(this); - - if (!isGroupNested(itemGroup)) - itemGroup->setParentItem(this); - - QPointer<QDeclarativeGeoMapItemGroup> g(itemGroup); - m_mapItemGroups.append(g); - - const QList<QQuickItem *> quickKids = itemGroup->childItems(); - int count = 0; - for (auto c: quickKids) { - count += addMapChild(c); // this calls addMapItemGroup recursively, if needed - } - return count; -} - -/*! - \qmlmethod void QtLocation::Map::removeMapItemGroup(MapItemGroup itemGroup) - - Removes \a itemGroup and the items contained therein from the Map. - - \sa MapItemGroup, addMapItemGroup - - \since 5.9 -*/ -void QDeclarativeGeoMap::removeMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup) -{ - if (removeMapItemGroup_real(itemGroup)) - emit mapItemsChanged(); -} - -bool QDeclarativeGeoMap::removeMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup) -{ - if (!itemGroup || itemGroup->quickMap() != this) // cant remove an itemGroup added to another map - return false; - - QPointer<QDeclarativeGeoMapItemGroup> g(itemGroup); - if (!m_mapItemGroups.removeOne(g)) - return false; - - const QList<QQuickItem *> quickKids = itemGroup->childItems(); - int count = 0; - for (auto c: quickKids) { - count += removeMapChild(c); - } - itemGroup->setQuickMap(nullptr); - if (itemGroup->parentItem() == this) - itemGroup->setParentItem(0); - return count; -} - -/*! - \qmlmethod void QtLocation::Map::removeMapItemView(MapItemView itemView) - - Removes \a itemView and the items instantiated by it from the Map. - - \sa MapItemView, addMapItemView - - \since 5.10 -*/ -void QDeclarativeGeoMap::removeMapItemView(QDeclarativeGeoMapItemView *itemView) -{ - if (removeMapItemView_real(itemView)) - emit mapItemsChanged(); -} - -bool QDeclarativeGeoMap::removeMapItemView_real(QDeclarativeGeoMapItemView *itemView) -{ - if (!itemView || itemView->m_map != this) // can't remove a view that is already added to another map - return false; - - itemView->removeInstantiatedItems(false); // remove the items without using transitions AND abort ongoing ones - itemView->m_map = 0; - m_mapViews.removeOne(itemView); - return removeMapItemGroup_real(itemView); // at this point, all delegate instances have been removed. -} - -void QDeclarativeGeoMap::updateItemToWindowTransform() -{ - if (!m_initialized) - return; - - // Update itemToWindowTransform into QGeoProjection - const QTransform item2WindowOld = m_map->geoProjection().itemToWindowTransform(); - QTransform item2Window = QQuickItemPrivate::get(this)->itemToWindowTransform(); - if (!property("layer").isNull() && property("layer").value<QObject *>()->property("enabled").toBool()) - item2Window.reset(); // When layer is enabled, the item is rendered offscreen with no transformation, then the layer is applied - - m_map->setItemToWindowTransform(item2Window); - - // This method is called at every redraw, including those redraws not generated by - // sgNodeChanged. - // In these cases, *if* the item2windowTransform has changed (e.g., if transformation of - // the item or one of its ancestors changed), a forced update of the map items using accelerated - // GL implementation has to be performed in order to have them pulling the updated itemToWindowTransform. - if (!m_sgNodeHasChanged && item2WindowOld != item2Window) { - for (auto i: qAsConst(m_mapItems)) - i->setMaterialDirty(); - } - - m_sgNodeHasChanged = false; -} - -void QDeclarativeGeoMap::onSGNodeChanged() -{ - m_sgNodeHasChanged = true; - update(); -} - -/*! - \qmlmethod void QtLocation::Map::addMapItemView(MapItemView itemView) - - Adds \a itemView to the Map. - - \sa MapItemView, removeMapItemView - - \since 5.10 -*/ -void QDeclarativeGeoMap::addMapItemView(QDeclarativeGeoMapItemView *itemView) -{ - if (addMapItemView_real(itemView)) - emit mapItemsChanged(); -} - -bool QDeclarativeGeoMap::addMapItemView_real(QDeclarativeGeoMapItemView *itemView) -{ - if (!itemView || itemView->m_map) // can't add a view twice - return false; - - int count = addMapItemGroup_real(itemView); // at this point, delegates aren't yet incubated. - // Not appending it to m_mapViews because it seems unnecessary even if the - // itemView is a child of this (in which case it would be destroyed - m_mapViews.append(itemView); - setupMapView(itemView); - return count; -} - -/*! - \qmlproperty mapType QtLocation::Map::activeMapType - - \brief Access to the currently active \l{mapType}{map type}. - - This property can be set to change the active \l{mapType}{map type}. - See the \l{Map::supportedMapTypes}{supportedMapTypes} property for possible values. - - \sa mapType -*/ -void QDeclarativeGeoMap::setActiveMapType(const QGeoMapType &mapType) -{ - if (m_activeMapType != mapType) { - if (m_map) { - if (mapType.pluginName() == m_plugin->name().toLatin1()) { - m_map->setActiveMapType(mapType); - m_activeMapType = mapType; - emit activeMapTypeChanged(); - } - } else { - m_activeMapType = mapType; - emit activeMapTypeChanged(); - } - } -} - -QGeoMapType QDeclarativeGeoMap::activeMapType() const -{ - return m_activeMapType; -} - -/*! - \internal -*/ -void QDeclarativeGeoMap::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - m_gestureArea->setSize(newGeometry.size()); - QQuickItem::geometryChange(newGeometry, oldGeometry); - - if (!m_map || newGeometry.size().isEmpty()) - return; - - m_map->setViewportSize(newGeometry.size().toSize()); - - if (!m_initialized) { - initialize(); - } else { - setMinimumZoomLevel(m_map->minimumZoom(), false); - - // Update the center latitudinal threshold - QGeoCameraData cameraData = m_map->cameraData(); - const double maximumCenterLatitudeAtZoom = m_map->maximumCenterLatitudeAtZoom(cameraData); - const double minimumCenterLatitudeAtZoom = m_map->minimumCenterLatitudeAtZoom(cameraData); - if (maximumCenterLatitudeAtZoom != m_maximumViewportLatitude - || minimumCenterLatitudeAtZoom != m_minimumViewportLatitude) { - m_maximumViewportLatitude = maximumCenterLatitudeAtZoom; - m_minimumViewportLatitude = minimumCenterLatitudeAtZoom; - QGeoCoordinate coord = cameraData.center(); - coord.setLatitude(qBound(m_minimumViewportLatitude, coord.latitude(), m_maximumViewportLatitude)); - cameraData.setCenter(coord); - m_map->setCameraData(cameraData); // this polishes map items - } else if (oldGeometry.size() != newGeometry.size()) { - // polish map items - for (const QPointer<QDeclarativeGeoMapItemBase> &i: qAsConst(m_mapItems)) { - if (i) - i->polishAndUpdate(); - } - } - } - - /* - The fitViewportTo*() functions depend on a valid map geometry. - If they were called prior to the first resize they cause - the zoomlevel to jump to 0 (showing the world). Therefore the - calls were queued up until now. - - Multiple fitViewportTo*() calls replace each other. - */ - if (m_pendingFitViewport && width() && height()) { - fitViewportToGeoShape(m_visibleRegion); - m_pendingFitViewport = false; - } - -} - -/*! - \qmlmethod void QtLocation::Map::fitViewportToMapItems(list<MapItems> items = {}) - - If no argument is provided, fits the current viewport to the boundary of all map items. - The camera is positioned in the center of the map items, and at the largest integral zoom level - possible which allows all map items to be visible on screen. - If \a items is provided, fits the current viewport to the boundary of the specified map items only. - - \note This method gained the optional \a items argument since Qt 5.15. - In previous releases, this method fitted the map to all map items. - - \sa fitViewportToVisibleMapItems -*/ -void QDeclarativeGeoMap::fitViewportToMapItems(const QVariantList &items) -{ - if (items.size()) { - QList<QPointer<QDeclarativeGeoMapItemBase> > itms; - for (const QVariant &i: items) { - QDeclarativeGeoMapItemBase *itm = qobject_cast<QDeclarativeGeoMapItemBase *>(i.value<QObject *>()); - if (itm) - itms.append(itm); - } - fitViewportToMapItemsRefine(itms, true, false); - } else { - fitViewportToMapItemsRefine(m_mapItems, true, false); - } -} - -/*! - \qmlmethod void QtLocation::Map::fitViewportToVisibleMapItems() - - Fits the current viewport to the boundary of all \b visible map items. - The camera is positioned in the center of the map items, and at the largest integral - zoom level possible which allows all map items to be visible on screen. - - \sa fitViewportToMapItems -*/ -void QDeclarativeGeoMap::fitViewportToVisibleMapItems() -{ - fitViewportToMapItemsRefine(m_mapItems, true, true); -} - -/*! - \internal -*/ -void QDeclarativeGeoMap::fitViewportToMapItemsRefine(const QList<QPointer<QDeclarativeGeoMapItemBase> > &mapItems, - bool refine, - bool onlyVisible) -{ - if (!m_map) - return; - - if (mapItems.size() == 0) - return; - - double minX = qInf(); - double maxX = -qInf(); - double minY = qInf(); - double maxY = -qInf(); - double topLeftX = 0; - double topLeftY = 0; - double bottomRightX = 0; - double bottomRightY = 0; - bool haveQuickItem = false; - - // find bounds of all map items - qsizetype itemCount = 0; - for (qsizetype i = 0; i < mapItems.count(); ++i) { - if (!mapItems.at(i)) - continue; - QDeclarativeGeoMapItemBase *item = mapItems.at(i).data(); - if (!item || (onlyVisible && (!item->isVisible() || item->mapItemOpacity() <= 0.0))) - continue; - - // skip quick items in the first pass and refine the fit later - QDeclarativeGeoMapQuickItem *quickItem = - qobject_cast<QDeclarativeGeoMapQuickItem*>(item); - if (refine && quickItem) { - haveQuickItem = true; - continue; - } - // Force map items to update immediately. Needed to ensure correct item size and positions - // when recursively calling this function. - // TODO: See if we really need updatePolish on delegated items, in particular - // in relation to - // a) fitViewportToMapItems - // b) presence of MouseArea - // - // This is also legacy code. It must be updated to not operate on screen sizes. - if (item->isPolishScheduled()) - item->updatePolish(); - - if (quickItem && quickItem->matrix_ && !quickItem->matrix_->m_matrix.isIdentity()) { - // TODO: recalculate the center/zoom level so that the item becomes projectable again - if (quickItem->zoomLevel() == 0.0) // the item is unprojectable, should be skipped. - continue; - - QRectF brect = item->boundingRect(); - brect = quickItem->matrix_->m_matrix.mapRect(brect); - QPointF transformedPosition = quickItem->matrix_->m_matrix.map(item->position()); - topLeftX = transformedPosition.x(); - topLeftY = transformedPosition.y(); - bottomRightX = topLeftX + brect.width(); - bottomRightY = topLeftY + brect.height(); - } else { - topLeftX = item->position().x(); - topLeftY = item->position().y(); - bottomRightX = topLeftX + item->width(); - bottomRightY = topLeftY + item->height(); - } - - minX = qMin(minX, topLeftX); - maxX = qMax(maxX, bottomRightX); - minY = qMin(minY, topLeftY); - maxY = qMax(maxY, bottomRightY); - - ++itemCount; - } - - if (itemCount == 0) { - if (haveQuickItem) - fitViewportToMapItemsRefine(mapItems, false, onlyVisible); - return; - } - double bboxWidth = maxX - minX; - double bboxHeight = maxY - minY; - double bboxCenterX = minX + (bboxWidth / 2.0); - double bboxCenterY = minY + (bboxHeight / 2.0); - - // position camera to the center of bounding box - QGeoCoordinate coordinate; - coordinate = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(bboxCenterX, bboxCenterY), false); - setProperty("center", QVariant::fromValue(coordinate)); - - // adjust zoom - double bboxWidthRatio = bboxWidth / (bboxWidth + bboxHeight); - double mapWidthRatio = width() / (width() + height()); - double zoomRatio; - - if (bboxWidthRatio > mapWidthRatio) - zoomRatio = bboxWidth / width(); - else - zoomRatio = bboxHeight / height(); - - qreal newZoom = std::log10(zoomRatio) / std::log10(0.5); - newZoom = std::floor(qMax(minimumZoomLevel(), (zoomLevel() + newZoom))); - setProperty("zoomLevel", QVariant::fromValue(newZoom)); - - // as map quick items retain the same screen size after the camera zooms in/out - // we refine the viewport again to achieve better results - if (refine) - fitViewportToMapItemsRefine(mapItems, false, onlyVisible); -} - -/*! - \internal -*/ -void QDeclarativeGeoMap::mousePressEvent(QMouseEvent *event) -{ - if (isInteractive() && event->source() == Qt::MouseEventNotSynthesized) - m_gestureArea->handleMousePressEvent(event); - else - QQuickItem::mousePressEvent(event); -} - -/*! - \internal -*/ -void QDeclarativeGeoMap::mouseMoveEvent(QMouseEvent *event) -{ - if (isInteractive() && event->source() == Qt::MouseEventNotSynthesized) - m_gestureArea->handleMouseMoveEvent(event); - else - QQuickItem::mouseMoveEvent(event); -} - -/*! - \internal -*/ -void QDeclarativeGeoMap::mouseReleaseEvent(QMouseEvent *event) -{ - if (isInteractive() && event->source() == Qt::MouseEventNotSynthesized) - m_gestureArea->handleMouseReleaseEvent(event); - else - QQuickItem::mouseReleaseEvent(event); -} - -void QDeclarativeGeoMap::touchUngrabEvent() -{ - if (isInteractive()) - m_gestureArea->handleTouchUngrabEvent(); - else - QQuickItem::touchUngrabEvent(); -} - -/*! - \internal -*/ -void QDeclarativeGeoMap::touchEvent(QTouchEvent *event) -{ - if (isInteractive()) { - m_gestureArea->handleTouchEvent(event); - } else { - //ignore event so sythesized event is generated; - QQuickItem::touchEvent(event); - } -} - -#if QT_CONFIG(wheelevent) -/*! - \internal -*/ -void QDeclarativeGeoMap::wheelEvent(QWheelEvent *event) -{ - if (isInteractive()) - m_gestureArea->handleWheelEvent(event); - else - QQuickItem::wheelEvent(event); - -} -#endif - -/*! - \internal -*/ -bool QDeclarativeGeoMap::childMouseEventFilter(QQuickItem *item, QEvent *event) -{ - Q_UNUSED(item); - if (!isVisible() || !isEnabled() || !isInteractive()) - return QQuickItem::childMouseEventFilter(item, event); - - switch (event->type()) { - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - case QEvent::TouchCancel: - return sendTouchEvent(static_cast<QTouchEvent *>(event)); - case QEvent::MouseButtonPress: - case QEvent::MouseMove: - case QEvent::MouseButtonRelease: - { - auto mEvent = static_cast<QMouseEvent*>(event); - if (mEvent->source() == Qt::MouseEventNotSynthesized){ - return sendTouchEvent(mEvent); - } - } - break; - case QEvent::UngrabMouse: { - QQuickWindow *win = window(); - if (!win) break; - if (!win->mouseGrabberItem() || - (win->mouseGrabberItem() && - win->mouseGrabberItem() != this)) { - // child lost grab, we could even lost - // some events if grab already belongs for example - // in item in diffrent window , clear up states - mouseUngrabEvent(); - } - break; - } - default: - break; - } - return QQuickItem::childMouseEventFilter(item, event); -} - -bool QDeclarativeGeoMap::sendMouseEvent(QMouseEvent *event) -{ - bool stealEvent = m_gestureArea->isActive(); - - if ((stealEvent || contains(mapFromScene(event->scenePosition())))) { - switch (event->type()) { - case QEvent::MouseMove: - m_gestureArea->handleMouseMoveEvent(event); - break; - case QEvent::MouseButtonPress: - m_gestureArea->handleMousePressEvent(event); - break; - case QEvent::MouseButtonRelease: - m_gestureArea->handleMouseReleaseEvent(event); - break; - default: - break; - } - - stealEvent = m_gestureArea->isActive(); - - if (stealEvent) { - //do not deliver - event->setAccepted(true); - return true; - } else { - return false; - } - } - return false; -} - -bool QDeclarativeGeoMap::sendTouchEvent(QPointerEvent *event) -{ - const QTouchEvent::TouchPoint &point = event->points().first(); - - bool stealEvent = m_gestureArea->isActive(); - bool containsPoint = contains(mapFromScene(point.scenePosition())); - - if ((stealEvent || containsPoint)) { - - m_gestureArea->handleTouchEvent(event); - stealEvent = m_gestureArea->isActive(); - - if (stealEvent) { - //event->setAccepted(true); - //return true; - } else { - return false; - } - } - return false; -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h deleted file mode 100644 index 03ca7194..00000000 --- a/src/location/declarativemaps/qdeclarativegeomap_p.h +++ /dev/null @@ -1,352 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEGEOMAP_H -#define QDECLARATIVEGEOMAP_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 <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qdeclarativegeomapitemview_p.h> -#include <QtLocation/private/qquickgeomapgesturearea_p.h> -#include <QtLocation/private/qdeclarativegeomapitemgroup_p.h> -#include <QtLocation/qgeoserviceprovider.h> -#include <QtLocation/private/qgeocameradata_p.h> -#include <QtLocation/private/qgeocameracapabilities_p.h> -#include <QtQuick/QQuickItem> -#include <QtCore/QList> -#include <QtCore/QPointer> -#include <QtGui/QColor> -#include <QtPositioning/qgeorectangle.h> -#include <QtLocation/private/qgeomap_p.h> - -Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeoserviceprovider_p.h>) - -QT_BEGIN_NAMESPACE - -class QQuickWindow; -class QDeclarativeGeoServiceProvider; -class QGeoMapType; -class QDeclarativeGeoMapCopyrightNotice; -class QDeclarativeGeoMapParameter; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMap : public QQuickItem -{ - Q_OBJECT - Q_ENUMS(QGeoServiceProvider::Error) - Q_PROPERTY(QQuickGeoMapGestureArea *gesture READ gesture CONSTANT) - Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) - Q_PROPERTY(qreal minimumZoomLevel READ minimumZoomLevel WRITE setMinimumZoomLevel NOTIFY minimumZoomLevelChanged) - Q_PROPERTY(qreal maximumZoomLevel READ maximumZoomLevel WRITE setMaximumZoomLevel NOTIFY maximumZoomLevelChanged) - Q_PROPERTY(qreal zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged) - - Q_PROPERTY(qreal tilt READ tilt WRITE setTilt NOTIFY tiltChanged) - Q_PROPERTY(qreal minimumTilt READ minimumTilt WRITE setMinimumTilt NOTIFY minimumTiltChanged) - Q_PROPERTY(qreal maximumTilt READ maximumTilt WRITE setMaximumTilt NOTIFY maximumTiltChanged) - - Q_PROPERTY(qreal bearing READ bearing WRITE setBearing NOTIFY bearingChanged) - - Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged) - Q_PROPERTY(qreal minimumFieldOfView READ minimumFieldOfView WRITE setMinimumFieldOfView NOTIFY minimumFieldOfViewChanged) - Q_PROPERTY(qreal maximumFieldOfView READ maximumFieldOfView WRITE setMaximumFieldOfView NOTIFY minimumFieldOfViewChanged) - - Q_PROPERTY(QGeoMapType activeMapType READ activeMapType WRITE setActiveMapType NOTIFY activeMapTypeChanged) - Q_PROPERTY(QList<QGeoMapType> supportedMapTypes READ supportedMapTypes NOTIFY supportedMapTypesChanged) - Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged) - Q_PROPERTY(QList<QObject *> mapItems READ mapItems NOTIFY mapItemsChanged) - Q_PROPERTY(QList<QObject *> mapParameters READ mapParameters) - Q_PROPERTY(QGeoServiceProvider::Error error READ error NOTIFY errorChanged) - Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged) - Q_PROPERTY(QGeoShape visibleRegion READ visibleRegion WRITE setVisibleRegion NOTIFY visibleRegionChanged) - Q_PROPERTY(bool copyrightsVisible READ copyrightsVisible WRITE setCopyrightsVisible NOTIFY copyrightsVisibleChanged) - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) - Q_PROPERTY(bool mapReady READ mapReady NOTIFY mapReadyChanged) - Q_PROPERTY(QRectF visibleArea READ visibleArea WRITE setVisibleArea NOTIFY visibleAreaChanged REVISION 12) - Q_INTERFACES(QQmlParserStatus) - -public: - - explicit QDeclarativeGeoMap(QQuickItem *parent = nullptr); - ~QDeclarativeGeoMap(); - - void setPlugin(QDeclarativeGeoServiceProvider *plugin); - QDeclarativeGeoServiceProvider *plugin() const; - - void setActiveMapType(const QGeoMapType &mapType); - QGeoMapType activeMapType() const; - - void setMinimumZoomLevel(qreal minimumZoomLevel, bool userSet = true); - qreal minimumZoomLevel() const; - qreal implicitMinimumZoomLevel() const; - qreal effectiveMinimumZoomLevel() const; - - void setMaximumZoomLevel(qreal maximumZoomLevel, bool userSet = true); - qreal maximumZoomLevel() const; - - void setZoomLevel(qreal zoomLevel); - qreal zoomLevel() const; - - void setBearing(qreal bearing); - qreal bearing() const; - - void setTilt(qreal tilt); - qreal tilt() const; - void setMinimumTilt(qreal minimumTilt, bool userSet = true); - qreal minimumTilt() const; - void setMaximumTilt(qreal maximumTilt, bool userSet = true); - qreal maximumTilt() const; - - void setFieldOfView(qreal fieldOfView); - qreal fieldOfView() const; - void setMinimumFieldOfView(qreal minimumFieldOfView, bool userSet = true); - qreal minimumFieldOfView() const; - void setMaximumFieldOfView(qreal maximumFieldOfView, bool userSet = true); - qreal maximumFieldOfView() const; - - void setCenter(const QGeoCoordinate ¢er); - QGeoCoordinate center() const; - - void setVisibleRegion(const QGeoShape &shape); - QGeoShape visibleRegion() const; - - void setCopyrightsVisible(bool visible); - bool copyrightsVisible() const; - - void setColor(const QColor &color); - QColor color() const; - - QRectF visibleArea() const; - void setVisibleArea(const QRectF &visibleArea); - - bool mapReady() const; - - QList<QGeoMapType> supportedMapTypes(); - - Q_INVOKABLE void setBearing(qreal bearing, const QGeoCoordinate &coordinate); - Q_INVOKABLE void alignCoordinateToPoint(const QGeoCoordinate &coordinate, const QPointF &point); - - Q_INVOKABLE void removeMapItem(QDeclarativeGeoMapItemBase *item); - Q_INVOKABLE void addMapItem(QDeclarativeGeoMapItemBase *item); - - Q_INVOKABLE void addMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup); - Q_INVOKABLE void removeMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup); - - Q_INVOKABLE void removeMapItemView(QDeclarativeGeoMapItemView *itemView); - Q_INVOKABLE void addMapItemView(QDeclarativeGeoMapItemView *itemView); - - Q_INVOKABLE void clearMapItems(); - QList<QObject *> mapItems(); - - Q_INVOKABLE void addMapParameter(QDeclarativeGeoMapParameter *parameter); - Q_INVOKABLE void removeMapParameter(QDeclarativeGeoMapParameter *parameter); - Q_INVOKABLE void clearMapParameters(); - QList<QObject *> mapParameters(); - - void addMapObject(QGeoMapObject *object); // Not invokable as currently meant to be used through a main MapObjectView - void removeMapObject(QGeoMapObject *object); - void clearMapObjects(); - QList<QGeoMapObject *> mapObjects(); - - - Q_INVOKABLE QGeoCoordinate toCoordinate(const QPointF &position, bool clipToViewPort = true) const; - Q_INVOKABLE QPointF fromCoordinate(const QGeoCoordinate &coordinate, bool clipToViewPort = true) const; - - QQuickGeoMapGestureArea *gesture(); - - Q_INVOKABLE void fitViewportToMapItems(const QVariantList &items = {}); - Q_INVOKABLE void fitViewportToVisibleMapItems(); - Q_INVOKABLE void pan(int dx, int dy); - Q_INVOKABLE void prefetchData(); // optional hint for prefetch - Q_INVOKABLE void clearData(); - Q_REVISION(13) Q_INVOKABLE void fitViewportToGeoShape(const QGeoShape &shape, QVariant margins); - void fitViewportToGeoShape(const QGeoShape &shape, const QMargins &borders = QMargins(10, 10, 10, 10)); - - QString errorString() const; - QGeoServiceProvider::Error error() const; - QGeoMap* map() const; - - // From QQuickItem - void itemChange(ItemChange, const ItemChangeData &) override; - -Q_SIGNALS: - void pluginChanged(QDeclarativeGeoServiceProvider *plugin); - void zoomLevelChanged(qreal zoomLevel); - void centerChanged(const QGeoCoordinate &coordinate); - void activeMapTypeChanged(); - void supportedMapTypesChanged(); - void minimumZoomLevelChanged(); - void maximumZoomLevelChanged(); - void mapItemsChanged(); - void errorChanged(); - void copyrightLinkActivated(const QString &link); - void copyrightsVisibleChanged(bool visible); - void colorChanged(const QColor &color); - void bearingChanged(qreal bearing); - void tiltChanged(qreal tilt); - void fieldOfViewChanged(qreal fieldOfView); - void minimumTiltChanged(qreal minimumTilt); - void maximumTiltChanged(qreal maximumTilt); - void minimumFieldOfViewChanged(qreal minimumFieldOfView); - void maximumFieldOfViewChanged(qreal maximumFieldOfView); - void copyrightsImageChanged(const QImage ©rightsImage); - void copyrightsChanged(const QString ©rightsHtml); - void mapReadyChanged(bool ready); - Q_REVISION(11) void mapObjectsChanged(); - void visibleAreaChanged(); - Q_REVISION(14) void visibleRegionChanged(); - -protected: - void mousePressEvent(QMouseEvent *event) override ; - void mouseMoveEvent(QMouseEvent *event) override ; - void mouseReleaseEvent(QMouseEvent *event) override ; - void touchUngrabEvent() override; - void touchEvent(QTouchEvent *event) override ; -#if QT_CONFIG(wheelevent) - void wheelEvent(QWheelEvent *event) override ; -#endif - - bool childMouseEventFilter(QQuickItem *item, QEvent *event) override; - bool sendMouseEvent(QMouseEvent *event); - bool sendTouchEvent(QPointerEvent *event); - - void componentComplete() override; - QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override; - void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; - - void setError(QGeoServiceProvider::Error error, const QString &errorString); - void initialize(); - void setZoomLevel(qreal zoomLevel, bool overzoom); - bool addMapChild(QObject *child); - bool removeMapChild(QObject *child); - bool isGroupNested(QDeclarativeGeoMapItemGroup *group) const; - - bool addMapItem_real(QDeclarativeGeoMapItemBase *item); - bool removeMapItem_real(QDeclarativeGeoMapItemBase *item); - bool addMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup); - bool removeMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup); - bool addMapItemView_real(QDeclarativeGeoMapItemView *itemView); - bool removeMapItemView_real(QDeclarativeGeoMapItemView *itemView); - void updateItemToWindowTransform(); - void onSGNodeChanged(); - -private Q_SLOTS: - void mappingManagerInitialized(); - void pluginReady(); - void onSupportedMapTypesChanged(); - void onCameraCapabilitiesChanged(const QGeoCameraCapabilities &oldCameraCapabilities); - void onAttachedCopyrightNoticeVisibilityChanged(); - void onCameraDataChanged(const QGeoCameraData &cameraData); - -private: - void setupMapView(QDeclarativeGeoMapItemView *view); - void populateMap(); - void populateParameters(); - void fitViewportToMapItemsRefine(const QList<QPointer<QDeclarativeGeoMapItemBase> > &mapItems, bool refine, bool onlyVisible); - bool isInteractive() const; - void attachCopyrightNotice(bool initialVisibility); - void detachCopyrightNotice(bool currentVisibility); - QMargins mapMargins() const; - -private: - QQuickWindow *m_window = nullptr; - QDeclarativeGeoServiceProvider *m_plugin = nullptr; - QGeoMappingManager *m_mappingManager = nullptr; - QGeoMapType m_activeMapType; - QList<QGeoMapType> m_supportedMapTypes; - QList<QDeclarativeGeoMapItemView *> m_mapViews; - QQuickGeoMapGestureArea *m_gestureArea = nullptr; - QPointer<QGeoMap> m_map; - QPointer<QDeclarativeGeoMapCopyrightNotice> m_copyrights; - QList<QPointer<QDeclarativeGeoMapItemBase> > m_mapItems; - QList<QPointer<QDeclarativeGeoMapItemGroup> > m_mapItemGroups; - QString m_errorString; - QGeoServiceProvider::Error m_error = QGeoServiceProvider::NoError; - QGeoRectangle m_visibleRegion; - QColor m_color = QColor::fromRgbF(0.9f, 0.9f, 0.9f); - QGeoCameraData m_cameraData; - bool m_componentCompleted = false; - bool m_pendingFitViewport = false; - bool m_copyrightsVisible = true; - double m_maximumViewportLatitude = 0.0; - double m_minimumViewportLatitude = 0.0; - bool m_initialized = false; - bool m_sgNodeHasChanged = false; - QList<QDeclarativeGeoMapParameter *> m_mapParameters; - QList<QGeoMapObject*> m_pendingMapObjects; // Used only in the initialization phase - QGeoCameraCapabilities m_cameraCapabilities; - qreal m_userMinimumZoomLevel = Q_QNAN; - qreal m_userMaximumZoomLevel = Q_QNAN; - - qreal m_minimumTilt = Q_QNAN; - qreal m_maximumTilt = Q_QNAN; - qreal m_userMinimumTilt = Q_QNAN; - qreal m_userMaximumTilt = Q_QNAN; - - qreal m_minimumFieldOfView = Q_QNAN; - qreal m_maximumFieldOfView = Q_QNAN; - qreal m_userMinimumFieldOfView = Q_QNAN; - qreal m_userMaximumFieldOfView = Q_QNAN; - - int m_copyNoticesVisible = 0; - qreal m_maxChildZ = 0; - QRectF m_visibleArea; - - - friend class QDeclarativeGeoMapItem; - friend class QDeclarativeGeoMapItemView; - friend class QQuickGeoMapGestureArea; - friend class QDeclarativeGeoMapCopyrightNotice; - Q_DISABLE_COPY(QDeclarativeGeoMap) -}; - - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativeGeoMap) - -#endif diff --git a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp deleted file mode 100644 index 725ff20d..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com> -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativegeomapcopyrightsnotice_p.h" - -#include <QtGui/QTextDocument> -#include <QtGui/QAbstractTextDocumentLayout> -#include <QtGui/QPainter> -#include <QtGui/QImage> -#include <QtQuick/private/qquickanchors_p.h> -#include <QtLocation/private/qdeclarativegeomap_p.h> -#include <QtQuick/private/qquickpainteditem_p.h> - -QT_BEGIN_NAMESPACE - -class QDeclarativeGeoMapCopyrightNoticePrivate: public QQuickPaintedItemPrivate -{ - Q_DECLARE_PUBLIC(QDeclarativeGeoMapCopyrightNotice) -public: - void setVisible(bool visible) override; -}; - -/*! - \qmltype MapCopyrightNotice - \instantiates QDeclarativeGeoMapCopyrightNotice - \inqmlmodule QtLocation - \ingroup qml-QtLocation5-maps - \since QtLocation 5.9 - - \brief The MapCopyrightNotice item displays the current valid - copyright notice for a Map element. - - This object can be used to place an additional copyright notices - programmatically. - - Note that declaring a MapCopyrightNotice inside a QtLocation::Map element - is not possible, like for any other QQuickItem. - - The release of this API with Qt 5.9 is a Technology Preview. -*/ - -/*! - \qmlproperty Map QtLocation::MapCopyrightNotice::mapSource - - This property holds the current map source providing the copyright data shown - in this notice. - In order to let the MapCopyrightNotice display a copyright, this property must - be set, as it is the only data source for this element. -*/ - -/*! - \qmlproperty string QtLocation::MapCopyrightNotice::styleSheet - - This property holds the current css2.1 style sheet used to style the copyright notice, if in HTML form. - - Example: - \code - MapCopyrightNotice { - mapSource: myMap - styleSheet: "body { color : green; font-family: \"Lucida\"; font-size: 8px} a{ font-size: 8px; color:#A62900}" - } - \endcode -*/ - -QDeclarativeGeoMapCopyrightNotice::QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent) -: QQuickPaintedItem(parent) -{ - // If this item is constructed inside the map, automatically anchor it where it always used to be. - if (qobject_cast<QDeclarativeGeoMap *>(parent)) - anchorToBottomLeft(); -} - -QDeclarativeGeoMapCopyrightNotice::~QDeclarativeGeoMapCopyrightNotice() -{ - setMapSource(nullptr); -} - -void QDeclarativeGeoMapCopyrightNotice::anchorToBottomLeft() -{ - if (!parent()) - return; - QQuickAnchors *anchors = property("anchors").value<QQuickAnchors *>(); - if (anchors) { - anchors->setLeft(QQuickAnchorLine(qobject_cast<QQuickItem *>(parent()), QQuickAnchors::LeftAnchor)); - anchors->setBottom(QQuickAnchorLine(qobject_cast<QQuickItem *>(parent()), QQuickAnchors::BottomAnchor)); - } -} - -void QDeclarativeGeoMapCopyrightNotice::setMapSource(QDeclarativeGeoMap *map) -{ - if (m_mapSource == map) - return; - - if (m_mapSource) { - // disconnect this object from current map source - m_mapSource->detachCopyrightNotice(copyrightsVisible()); - m_mapSource->disconnect(this); - m_mapSource->m_map->disconnect(this); - if (m_copyrightsHtml) - m_copyrightsHtml->clear(); - m_copyrightsImage = QImage(); - m_mapSource = nullptr; - } - - if (map) { - m_mapSource = map; - m_mapSource->attachCopyrightNotice(copyrightsVisible()); - connect(this, &QDeclarativeGeoMapCopyrightNotice::copyrightsVisibleChanged, - mapSource(), &QDeclarativeGeoMap::onAttachedCopyrightNoticeVisibilityChanged); - - // First update the copyright. Only Image will do here, no need to store HTML right away. - if (m_mapSource->m_copyrights && !m_mapSource->m_copyrights->m_copyrightsImage.isNull()) - m_copyrightsImage = m_mapSource->m_copyrights->m_copyrightsImage; - - connect(mapSource(), &QDeclarativeGeoMap::copyrightsImageChanged, - this, &QDeclarativeGeoMapCopyrightNotice::copyrightsImageChanged); - connect(mapSource(), &QDeclarativeGeoMap::copyrightsChanged, - this, &QDeclarativeGeoMapCopyrightNotice::copyrightsChanged); - - if (m_mapSource->m_map) - connectMap(); - else - connect(mapSource(), &QDeclarativeGeoMap::mapReadyChanged, this, &QDeclarativeGeoMapCopyrightNotice::connectMap); - } -} - -void QDeclarativeGeoMapCopyrightNotice::connectMap() -{ - connect(m_mapSource->m_map.data(), &QGeoMap::copyrightsStyleSheetChanged, - this, &QDeclarativeGeoMapCopyrightNotice::onCopyrightsStyleSheetChanged); - connect(this, &QDeclarativeGeoMapCopyrightNotice::linkActivated, - mapSource(), &QDeclarativeGeoMap::copyrightLinkActivated); - - onCopyrightsStyleSheetChanged(m_mapSource->m_map->copyrightsStyleSheet()); - - update(); - emit mapSourceChanged(); -} - -QDeclarativeGeoMap *QDeclarativeGeoMapCopyrightNotice::mapSource() -{ - return m_mapSource.data(); -} - -QString QDeclarativeGeoMapCopyrightNotice::styleSheet() const -{ - return m_styleSheet; -} - -void QDeclarativeGeoMapCopyrightNotice::setStyleSheet(const QString &styleSheet) -{ - m_userDefinedStyleSheet = true; - - if (styleSheet == m_styleSheet) - return; - - m_styleSheet = styleSheet; - if (!m_html.isEmpty() && m_copyrightsHtml) { - delete m_copyrightsHtml; - createCopyright(); -#if QT_CONFIG(texthtmlparser) - m_copyrightsHtml->setHtml(m_html); -#else - m_copyrightsHtml->setPlainText(m_html); -#endif - } - rasterizeHtmlAndUpdate(); - emit styleSheetChanged(m_styleSheet); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapCopyrightNotice::paint(QPainter *painter) -{ - painter->drawImage(0, 0, m_copyrightsImage); -} - -void QDeclarativeGeoMapCopyrightNotice::mousePressEvent(QMouseEvent *event) -{ - if (m_copyrightsHtml) { - m_activeAnchor = m_copyrightsHtml->documentLayout()->anchorAt(event->pos()); - if (!m_activeAnchor.isEmpty()) - return; - } - - QQuickPaintedItem::mousePressEvent(event); -} - -void QDeclarativeGeoMapCopyrightNotice::mouseReleaseEvent(QMouseEvent *event) -{ - if (m_copyrightsHtml) { - QString anchor = m_copyrightsHtml->documentLayout()->anchorAt(event->pos()); - if (anchor == m_activeAnchor && !anchor.isEmpty()) { - emit linkActivated(anchor); - m_activeAnchor.clear(); - } - } -} - -void QDeclarativeGeoMapCopyrightNotice::rasterizeHtmlAndUpdate() -{ - if (!m_copyrightsHtml || m_copyrightsHtml->isEmpty()) - return; - - m_copyrightsImage = QImage(m_copyrightsHtml->size().toSize(), - QImage::Format_ARGB32_Premultiplied); - - m_copyrightsImage.fill(qPremultiply(QColor(Qt::transparent).rgba())); - QPainter painter(&m_copyrightsImage); - QAbstractTextDocumentLayout::PaintContext ctx; - ctx.palette.setColor(QPalette::Text, QColor::fromString("black")); - m_copyrightsHtml->documentLayout()->draw(&painter, ctx); - - setImplicitSize(m_copyrightsImage.width(), m_copyrightsImage.height()); - setContentsSize(m_copyrightsImage.size()); - - setKeepMouseGrab(true); - setAcceptedMouseButtons(Qt::LeftButton); - - update(); -} - -void QDeclarativeGeoMapCopyrightNotice::createCopyright() -{ - m_copyrightsHtml = new QTextDocument(this); -#if QT_CONFIG(cssparser) - if (!m_styleSheet.isEmpty()) - m_copyrightsHtml->setDefaultStyleSheet(m_styleSheet); -#endif - - // The default 4 makes the copyright too wide and tall. - m_copyrightsHtml->setDocumentMargin(0); -} - -void QDeclarativeGeoMapCopyrightNoticePrivate::setVisible(bool visible) -{ - Q_Q(QDeclarativeGeoMapCopyrightNotice); - q->m_copyrightsVisible = visible; - QQuickItemPrivate::setVisible(visible); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapCopyrightNotice::setCopyrightsVisible(bool visible) -{ - Q_D(QDeclarativeGeoMapCopyrightNotice); - if (visible == m_copyrightsVisible) - return; - - m_copyrightsVisible = visible; - d->QQuickItemPrivate::setVisible(!m_copyrightsImage.isNull() && visible); - emit copyrightsVisibleChanged(); -} - -bool QDeclarativeGeoMapCopyrightNotice::copyrightsVisible() const -{ - return m_copyrightsVisible; -} - -/*! - \internal -*/ -void QDeclarativeGeoMapCopyrightNotice::setCopyrightsZ(qreal copyrightsZ) -{ - setZ(copyrightsZ); - update(); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapCopyrightNotice::copyrightsImageChanged(const QImage ©rightsImage) -{ - Q_D(QDeclarativeGeoMapCopyrightNotice); - delete m_copyrightsHtml; - m_copyrightsHtml = nullptr; - - m_copyrightsImage = copyrightsImage; - - setImplicitSize(m_copyrightsImage.width(), m_copyrightsImage.height()); - - setKeepMouseGrab(false); - setAcceptedMouseButtons(Qt::NoButton); - d->QQuickItemPrivate::setVisible(m_copyrightsVisible && !m_copyrightsImage.isNull()); - - update(); -} - -void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QString ©rightsHtml) -{ - Q_D(QDeclarativeGeoMapCopyrightNotice); - if (copyrightsHtml.isEmpty()) { - d->QQuickItemPrivate::setVisible(false); - return; - } else { - d->QQuickItemPrivate::setVisible(m_copyrightsVisible); - } - - // Divfy, so we can style the background. The extra <span> is a - // workaround to QTBUG-58838 and should be removed when it gets fixed. -#if QT_CONFIG(texthtmlparser) - m_html = QStringLiteral("<div id='copyright-root'><span>") + copyrightsHtml + QStringLiteral("</span></div>"); -#else - m_html = copyrightsHtml; -#endif - - if (!m_copyrightsHtml) - createCopyright(); - -#if QT_CONFIG(texthtmlparser) - m_copyrightsHtml->setHtml(m_html); -#else - m_copyrightsHtml->setPlainText(m_html); -#endif - rasterizeHtmlAndUpdate(); -} - -void QDeclarativeGeoMapCopyrightNotice::onCopyrightsStyleSheetChanged(const QString &styleSheet) -{ - if (m_userDefinedStyleSheet || styleSheet == m_styleSheet) - return; - - m_styleSheet = styleSheet; - if (!m_html.isEmpty() && m_copyrightsHtml) { - delete m_copyrightsHtml; - createCopyright(); -#if QT_CONFIG(texthtmlparser) - m_copyrightsHtml->setHtml(m_html); -#else - m_copyrightsHtml->setPlainText(m_html); -#endif - } - rasterizeHtmlAndUpdate(); - emit styleSheetChanged(m_styleSheet); -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h deleted file mode 100644 index 7e4c9957..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h +++ /dev/null @@ -1,129 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com> -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEGEOMAPCOPYRIGHTSNOTICE_H -#define QDECLARATIVEGEOMAPCOPYRIGHTSNOTICE_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 <QtLocation/private/qlocationglobal_p.h> - -#include <QtGui/QImage> -#include <QPointer> -#include <QtQuick/QQuickPaintedItem> - -Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeomap_p.h>) - - -QT_BEGIN_NAMESPACE - -class QTextDocument; -class QDeclarativeGeoMap; -class QDeclarativeGeoMapCopyrightNoticePrivate; -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapCopyrightNotice : public QQuickPaintedItem -{ - Q_OBJECT - Q_PROPERTY(QDeclarativeGeoMap *mapSource READ mapSource WRITE setMapSource NOTIFY mapSourceChanged) - Q_PROPERTY(QString styleSheet READ styleSheet WRITE setStyleSheet NOTIFY styleSheetChanged) - -public: - QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent = nullptr); - ~QDeclarativeGeoMapCopyrightNotice(); - - void setCopyrightsZ(qreal copyrightsZ); - - void setCopyrightsVisible(bool visible); - bool copyrightsVisible() const; - void anchorToBottomLeft(); - - void setMapSource(QDeclarativeGeoMap *mapSource); - QDeclarativeGeoMap *mapSource(); - - QString styleSheet() const; - void setStyleSheet(const QString &styleSheet); - -public Q_SLOTS: - void copyrightsImageChanged(const QImage ©rightsImage); - void copyrightsChanged(const QString ©rightsHtml); - void onCopyrightsStyleSheetChanged(const QString &styleSheet); - -signals: - void linkActivated(const QString &link); - void mapSourceChanged(); - void backgroundColorChanged(const QColor &color); - void styleSheetChanged(const QString &styleSheet); - void copyrightsVisibleChanged(); - -protected: - void paint(QPainter *painter) override; - void mousePressEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void rasterizeHtmlAndUpdate(); - void connectMap(); - -private: - void createCopyright(); - - QTextDocument *m_copyrightsHtml = nullptr; - QString m_html; - QImage m_copyrightsImage; - QString m_activeAnchor; - bool m_copyrightsVisible = true; - QPointer<QDeclarativeGeoMap> m_mapSource; - QColor m_backgroundColor; - QString m_styleSheet; - bool m_userDefinedStyleSheet = false; - - Q_DISABLE_COPY(QDeclarativeGeoMapCopyrightNotice) - Q_DECLARE_PRIVATE(QDeclarativeGeoMapCopyrightNotice) -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp deleted file mode 100644 index 3767351c..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativegeomapitembase_p.h" -#include "qgeocameradata_p.h" - -#include <QtQml/QQmlInfo> -#include <QtQuick/QSGOpacityNode> - -#include <QtQuick/private/qquickmousearea_p.h> -#include <QtQuick/private/qquickitem_p.h> -#include <QtPositioning/private/qdoublevector2d_p.h> -#include <QtLocation/private/qgeomap_p.h> -#include <QtLocation/private/qgeoprojection_p.h> - -QT_BEGIN_NAMESPACE - -QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent) - : QQuickItem(parent) -{ - setFiltersChildMouseEvents(true); - connect(this, &QDeclarativeGeoMapItemBase::childrenChanged, - this, &QDeclarativeGeoMapItemBase::afterChildrenChanged); - // Changing opacity on a mapItemGroup should affect also the opacity on the children. - // This must be notified to plugins, if they are to render the item. - connect(this, &QQuickItem::opacityChanged, this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged); -} - -QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase() -{ - disconnect(this, &QDeclarativeGeoMapItemBase::childrenChanged, - this, &QDeclarativeGeoMapItemBase::afterChildrenChanged); - if (quickMap_) - quickMap_->removeMapItem(this); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapItemBase::afterChildrenChanged() -{ - const QList<QQuickItem *> kids = childItems(); - if (kids.size() > 0) { - bool printedWarning = false; - for (auto *i : kids) { - if (i->flags() & QQuickItem::ItemHasContents - && !qobject_cast<QQuickMouseArea *>(i)) { - if (!printedWarning) { - qmlWarning(this) << "Geographic map items do not support child items"; - printedWarning = true; - } - - qmlWarning(i) << "deleting this child"; - i->deleteLater(); - } - } - } -} - -/*! - \internal -*/ -void QDeclarativeGeoMapItemBase::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) -{ - if (quickMap == quickMap_) - return; - if (quickMap && quickMap_) - return; // don't allow association to more than one map - - quickMap_ = quickMap; - map_ = map; - - if (map_ && quickMap_) { - // For performance reasons we're not connecting map_'s and quickMap_'s signals to this. - // Rather, the handling of cameraDataChanged, visibleAreaChanged, heightChanged and widthChanged is done explicitly in QDeclarativeGeoMap by directly calling methods on the items. - // See QTBUG-76950 - lastSize_ = QSizeF(quickMap_->width(), quickMap_->height()); - lastCameraData_ = map_->cameraData(); - } -} - -/*! - \internal -*/ -void QDeclarativeGeoMapItemBase::baseCameraDataChanged(const QGeoCameraData &cameraData) -{ - QGeoMapViewportChangeEvent evt; - evt.cameraData = cameraData; - evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height()); - - if (evt.mapSize != lastSize_) - evt.mapSizeChanged = true; - - if (cameraData.bearing() != lastCameraData_.bearing()) - evt.bearingChanged = true; - if (cameraData.center() != lastCameraData_.center()) - evt.centerChanged = true; - if (cameraData.roll() != lastCameraData_.roll()) - evt.rollChanged = true; - if (cameraData.tilt() != lastCameraData_.tilt()) - evt.tiltChanged = true; - if (cameraData.zoomLevel() != lastCameraData_.zoomLevel()) - evt.zoomLevelChanged = true; - - lastSize_ = evt.mapSize; - lastCameraData_ = cameraData; - - afterViewportChanged(evt); -} - -void QDeclarativeGeoMapItemBase::visibleAreaChanged() -{ - QGeoMapViewportChangeEvent evt; - evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height()); - afterViewportChanged(evt); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset) -{ - if (!map_ || !quickMap_) - return; - - QDoubleVector2D pos; - if (map()->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) { - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection()); - QDoubleVector2D wrappedProjection = p.geoToWrappedMapProjection(coordinate); - if (!p.isProjectable(wrappedProjection)) - return; - pos = p.wrappedMapProjectionToItemPosition(wrappedProjection); - } else { - pos = map()->geoProjection().coordinateToItemPosition(coordinate, false); - if (qIsNaN(pos.x())) - return; - } - - QPointF topLeft = pos.toPointF() - offset; - - setPosition(topLeft); -} - -bool QDeclarativeGeoMapItemBase::autoFadeIn() const -{ - return m_autoFadeIn; -} - -static const double opacityRampMin = 1.5; -static const double opacityRampMax = 2.5; - -void QDeclarativeGeoMapItemBase::setAutoFadeIn(bool fadeIn) -{ - if (fadeIn == m_autoFadeIn) - return; - m_autoFadeIn = fadeIn; - if (quickMap_ && quickMap_->zoomLevel() < opacityRampMax) - polishAndUpdate(); -} - -int QDeclarativeGeoMapItemBase::lodThreshold() const -{ - return m_lodThreshold; -} - -void QDeclarativeGeoMapItemBase::setLodThreshold(int lt) -{ - if (lt == m_lodThreshold) - return; - m_lodThreshold = lt; - update(); -} - -/*! - \internal - - This returns the zoom level to be used when requesting the LOD. - Essentially it clamps to m_lodThreshold, and if above, it selects - a ZL higher than the maximum LODable level. -*/ -unsigned int QDeclarativeGeoMapItemBase::zoomForLOD(int zoom) const -{ - if (zoom >= m_lodThreshold) - return 30; // some arbitrarily large zoom - return uint(zoom); -} - -/*! - \internal -*/ -float QDeclarativeGeoMapItemBase::zoomLevelOpacity() const -{ - if (!m_autoFadeIn) // Consider skipping the opacity node instead. - return 1.0; - else if (quickMap_->zoomLevel() > opacityRampMax) - return 1.0; - else if (quickMap_->zoomLevel() > opacityRampMin) - return quickMap_->zoomLevel() - opacityRampMin; - else - return 0.0; -} - -bool QDeclarativeGeoMapItemBase::childMouseEventFilter(QQuickItem *item, QEvent *event) -{ - Q_UNUSED(item); - if (event->type() == QEvent::MouseButtonPress && !contains(static_cast<QMouseEvent*>(event)->pos())) { - // In case of items that are not rectangles, this filter is used to test if the event has landed - // inside the actual item shape. - // If so, the method returns true, meaning that it prevents the event delivery to child "*item" (for example, - // a mouse area that is on top of this map item). - // However, this method sets "accepted" to false, so that the event can still be passed further up, - // specifically to the parent Map, that is a sort of flickable. - // Otherwise, if the event is not contained within the map item, the method returns false, meaning the event - // is delivered to the child *item (like the mouse area associated). - event->setAccepted(false); - return true; - } - return false; -} - -/*! - \internal -*/ -QSGNode *QDeclarativeGeoMapItemBase::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *pd) -{ - if (!map_ || !quickMap_ || map_->supportedMapItemTypes() & itemType()) { - if (oldNode) - delete oldNode; - oldNode = nullptr; - return nullptr; - } - - QSGOpacityNode *opn = static_cast<QSGOpacityNode *>(oldNode); - if (!opn) - opn = new QSGOpacityNode(); - - opn->setOpacity(zoomLevelOpacity()); - - QSGNode *oldN = opn->childCount() ? opn->firstChild() : 0; - opn->removeAllChildNodes(); - if (opn->opacity() > 0.0) { - QSGNode *n = this->updateMapItemPaintNode(oldN, pd); - if (n) - opn->appendChildNode(n); - } else { - delete oldN; - } - - return opn; -} - -/*! - \internal -*/ -QSGNode *QDeclarativeGeoMapItemBase::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *) -{ - delete oldNode; - return nullptr; -} - -QGeoMap::ItemType QDeclarativeGeoMapItemBase::itemType() const -{ - return m_itemType; -} - -/*! - \internal - - The actual combined opacity of the item. Needed by custom renderer to look like - the scene-graph one. -*/ -qreal QDeclarativeGeoMapItemBase::mapItemOpacity() const -{ - if (parentGroup_) - return parentGroup_->mapItemOpacity() * opacity(); - return opacity(); -} - -void QDeclarativeGeoMapItemBase::setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup) -{ - parentGroup_ = &parentGroup; - if (parentGroup_) { - connect(parentGroup_, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged, - this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged); - } -} - -bool QDeclarativeGeoMapItemBase::isPolishScheduled() const -{ - return QQuickItemPrivate::get(this)->polishScheduled; -} - -void QDeclarativeGeoMapItemBase::setMaterialDirty() {} - -void QDeclarativeGeoMapItemBase::polishAndUpdate() -{ - polish(); - update(); -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h deleted file mode 100644 index 8031a204..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h +++ /dev/null @@ -1,174 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEGEOMAPITEMBASE_H -#define QDECLARATIVEGEOMAPITEMBASE_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 <QtLocation/private/qlocationglobal_p.h> - -#include <QtQuick/QQuickItem> -#include <QtPositioning/QGeoShape> - -#include <QtLocation/private/qdeclarativegeomap_p.h> -#include <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qgeomap_p.h> -#include <QtLocation/private/qdeclarativegeomapitemtransitionmanager_p.h> -#include <QScopedPointer> - -QT_BEGIN_NAMESPACE - -struct Q_LOCATION_PRIVATE_EXPORT QGeoMapViewportChangeEvent -{ - QGeoCameraData cameraData; - QSizeF mapSize; - - bool zoomLevelChanged = false; - bool centerChanged = false; - bool mapSizeChanged = false; - bool tiltChanged = false; - bool bearingChanged = false; - bool rollChanged = false; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemBase : public QQuickItem -{ - Q_OBJECT - - Q_PROPERTY(QGeoShape geoShape READ geoShape WRITE setGeoShape STORED false ) - Q_PROPERTY(bool autoFadeIn READ autoFadeIn WRITE setAutoFadeIn REVISION 14) - Q_PROPERTY(int lodThreshold READ lodThreshold WRITE setLodThreshold NOTIFY lodThresholdChanged REVISION 15) - -public: - explicit QDeclarativeGeoMapItemBase(QQuickItem *parent = nullptr); - virtual ~QDeclarativeGeoMapItemBase(); - - virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map); - virtual void setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset); - - QDeclarativeGeoMap *quickMap() const { return quickMap_; } - QGeoMap *map() const { return map_; } - virtual const QGeoShape &geoShape() const = 0; - virtual void setGeoShape(const QGeoShape &shape) = 0; - - bool autoFadeIn() const; - void setAutoFadeIn(bool fadeIn); - - int lodThreshold() const; - void setLodThreshold(int lt); - unsigned int zoomForLOD(int zoom) const; - - QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override; - virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *); - - QGeoMap::ItemType itemType() const; - qreal mapItemOpacity() const; - - void setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup); - - template <typename T = QObject> - - QList<T*> quickChildren() const - { - QList<T*> res; - QObjectList kids = children(); - const QList<QQuickItem *> quickKids = childItems(); - for (const auto &quickKid : quickKids) - kids.append(quickKid); - for (auto *kid : qAsConst(kids)) { - if (auto *val = qobject_cast<T*>(kid)) - res.push_back(val); - } - return res; - } - -Q_SIGNALS: - void mapItemOpacityChanged(); - Q_REVISION(12) void addTransitionFinished(); - Q_REVISION(12) void removeTransitionFinished(); - void lodThresholdChanged(); - -protected Q_SLOTS: - virtual void afterChildrenChanged(); - virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) = 0; - void polishAndUpdate(); - -protected: - float zoomLevelOpacity() const; - bool childMouseEventFilter(QQuickItem *item, QEvent *event) override; - bool isPolishScheduled() const; - virtual void setMaterialDirty(); - - QGeoMap::ItemType m_itemType = QGeoMap::NoItem; - -private Q_SLOTS: - void baseCameraDataChanged(const QGeoCameraData &camera); - void visibleAreaChanged(); - -private: - QPointer<QGeoMap> map_; - QDeclarativeGeoMap *quickMap_ = nullptr; - - QSizeF lastSize_; - QGeoCameraData lastCameraData_; - - QDeclarativeGeoMapItemGroup *parentGroup_ = nullptr; - - std::unique_ptr<QDeclarativeGeoMapItemTransitionManager> m_transitionManager; - bool m_autoFadeIn = true; - int m_lodThreshold = 0; - - friend class QDeclarativeGeoMap; - friend class QDeclarativeGeoMapItemView; - friend class QDeclarativeGeoMapItemTransitionManager; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp b/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp deleted file mode 100644 index fde79f85..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativegeomapitemgroup_p.h" -#include "qdeclarativegeomapitembase_p.h" -#include "qdeclarativegeomap_p.h" - -QT_BEGIN_NAMESPACE - -/*! - \qmltype MapItemGroup - \instantiates QDeclarativeGeoMapItemGroup - \inqmlmodule QtLocation - \ingroup qml-QtLocation5-maps - \since QtLocation 5.9 - - \brief The MapItemGroup type is a container for map items. - - Its purpose is to enable code modularization by allowing the usage - of qml files containing map elements related to each other, and - the associated bindings. - - \note The release of this API with Qt 5.9 is a Technology Preview. - - \section2 Example Usage - - The following snippet shows how to use a MapItemGroup to create a MapCircle, centered at - the coordinate (63, -18) with a radius of 100km, filled in red, surrounded by an ondulated green border, - both contained in a semitransparent blue circle with a MouseArea that moves the whole group. - This group is defined in a separate file named PolygonGroup.qml: - - \code - import QtQuick 2.4 - import QtPositioning 5.6 - import QtLocation 5.9 - - MapItemGroup { - id: itemGroup - property alias position: mainCircle.center - property var radius: 100 * 1000 - property var borderHeightPct : 0.3 - - MapCircle { - id: mainCircle - center : QtPositioning.coordinate(40, 0) - radius: itemGroup.radius * (1.0 + borderHeightPct) - opacity: 0.05 - visible: true - color: 'blue' - - MouseArea{ - anchors.fill: parent - drag.target: parent - id: maItemGroup - } - } - - MapCircle { - id: groupCircle - center: itemGroup.position - radius: itemGroup.radius - color: 'crimson' - - onCenterChanged: { - groupPolyline.populateBorder(); - } - } - - MapPolyline { - id: groupPolyline - line.color: 'green' - line.width: 3 - - function populateBorder() { - groupPolyline.path = [] // clearing the path - var waveLength = 8.0; - var waveAmplitude = groupCircle.radius * borderHeightPct; - for (var i=0; i <= 360; i++) { - var wavePhase = (i/360.0 * 2.0 * Math.PI )* waveLength - var waveHeight = (Math.cos(wavePhase) + 1.0) / 2.0 - groupPolyline.addCoordinate(groupCircle.center.atDistanceAndAzimuth(groupCircle.radius + waveAmplitude * waveHeight , i)) - } - } - - Component.onCompleted: { - populateBorder() - } - } - } - \endcode - - PolygonGroup.qml is now a reusable component that can then be used in a Map as: - - \code - Map { - id: map - PolygonGroup { - id: polygonGroup - position: QtPositioning.coordinate(63,-18) - } - } - \endcode - - \image api-mapitemgroup.png -*/ - -QDeclarativeGeoMapItemGroup::QDeclarativeGeoMapItemGroup(QQuickItem *parent) - : QQuickItem(parent) -{ - connect(this, &QQuickItem::opacityChanged, - this, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged); -} - -QDeclarativeGeoMapItemGroup::~QDeclarativeGeoMapItemGroup() -{ - -} - -void QDeclarativeGeoMapItemGroup::setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup) -{ - m_parentGroup = &parentGroup; - connect(m_parentGroup, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged, - this, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged); -} - -void QDeclarativeGeoMapItemGroup::setQuickMap(QDeclarativeGeoMap *quickMap) -{ - if (!quickMap && m_quickMap) - m_quickMap->disconnect(this); - m_quickMap = quickMap; - if (m_quickMap) { - onMapSizeChanged(); - connect(m_quickMap, &QQuickItem::widthChanged, this, &QDeclarativeGeoMapItemGroup::onMapSizeChanged); - connect(m_quickMap, &QQuickItem::heightChanged, this, &QDeclarativeGeoMapItemGroup::onMapSizeChanged); - } -} - -QDeclarativeGeoMap *QDeclarativeGeoMapItemGroup::quickMap() const -{ - return m_quickMap; -} - -qreal QDeclarativeGeoMapItemGroup::mapItemOpacity() const -{ - return ((m_parentGroup) ? m_parentGroup->mapItemOpacity() : 1.0) * opacity(); -} - -void QDeclarativeGeoMapItemGroup::classBegin() -{ - QQuickItem::classBegin(); -} - -void QDeclarativeGeoMapItemGroup::componentComplete() -{ - QQuickItem::componentComplete(); - - // In certain cases the parent won't be set via the constructor, but rather later on - // during the instantiation/incubation process. - // Therefore calling setParentGroup here, when the parent is known. - // The childrenChanged use case to handle dynamically-added items is currently unsupported. - const QList<QQuickItem *> &quickKids = childItems(); - for (QQuickItem *k : quickKids) { - QDeclarativeGeoMapItemGroup *childGroup - = qobject_cast<QDeclarativeGeoMapItemGroup *>(k); - if (childGroup) { - childGroup->setParentGroup(*this); - continue; - } - QDeclarativeGeoMapItemBase *childItem - = qobject_cast<QDeclarativeGeoMapItemBase *>(k); - if (childItem) { - childItem->setParentGroup(*this); - continue; - } - } -} - -void QDeclarativeGeoMapItemGroup::onMapSizeChanged() -{ - setWidth(m_quickMap->width()); - setHeight(m_quickMap->height()); -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h b/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h deleted file mode 100644 index c3e997ad..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEGEOMAPITEMGROUP_P_H -#define QDECLARATIVEGEOMAPITEMGROUP_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 <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qdeclarativegeomapitemtransitionmanager_p.h> -#include <QtQuick/QQuickItem> - -QT_BEGIN_NAMESPACE - -class QDeclarativeGeoMap; -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemGroup : public QQuickItem -{ - Q_OBJECT -public: - explicit QDeclarativeGeoMapItemGroup(QQuickItem *parent = nullptr); - virtual ~QDeclarativeGeoMapItemGroup(); - - void setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup); - void setQuickMap(QDeclarativeGeoMap *quickMap); - QDeclarativeGeoMap *quickMap() const; - - qreal mapItemOpacity() const; - -Q_SIGNALS: - void mapItemOpacityChanged(); - void addTransitionFinished(); - void removeTransitionFinished(); - -protected: - // QQmlParserStatus interface - void classBegin() override; - void componentComplete() override; - -protected slots: - void onMapSizeChanged(); - -private: - QDeclarativeGeoMap *m_quickMap = nullptr; - QDeclarativeGeoMapItemGroup *m_parentGroup = nullptr; - std::unique_ptr<QDeclarativeGeoMapItemTransitionManager> m_transitionManager; - - friend class QDeclarativeGeoMapItemView; - friend class QDeclarativeGeoMapItemTransitionManager; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativeGeoMapItemGroup) - -#endif // QDECLARATIVEGEOMAPITEMGROUP_P_H diff --git a/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager.cpp b/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager.cpp deleted file mode 100644 index 5b307e87..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativegeomapitemtransitionmanager_p.h" -#include "qdeclarativegeomapitemview_p.h" - -QT_BEGIN_NAMESPACE - -QDeclarativeGeoMapItemTransitionManager::QDeclarativeGeoMapItemTransitionManager(QObject *mapItem) - : QQuickTransitionManager(), m_mapItem(mapItem) -{ -} - -void QDeclarativeGeoMapItemTransitionManager::transitionEnter() -{ - if (m_transitionState == ExitTransition) - cancel(); - - if (!prepareEnterTransition()) - return; - - if (m_view && m_view->m_enter) - transition(enterActions, m_view->m_enter, m_mapItem); - else - finished(); -} - -void QDeclarativeGeoMapItemTransitionManager::transitionExit() -{ - if (!prepareExitTransition()) - return; - - if (m_view && m_view->m_exit) - transition(exitActions, m_view->m_exit, m_mapItem); - else - finished(); -} - -void QDeclarativeGeoMapItemTransitionManager::finished() -{ - if (m_transitionState == EnterTransition) - finalizeEnterTransition(); - else if (m_transitionState == ExitTransition) - finalizeExitTransition(); -} - - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager_p.h b/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager_p.h deleted file mode 100644 index 53eec2b2..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager_p.h +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEGEOMAPITEMTRANSITIONMANAGER_H -#define QDECLARATIVEGEOMAPITEMTRANSITIONMANAGER_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 <QtLocation/private/qlocationglobal_p.h> -#include <QtQuick/QQuickItem> -#include <QtQuick/private/qquicktransitionmanager_p_p.h> - -QT_BEGIN_NAMESPACE - -class QDeclarativeGeoMapItemView; - -class QDeclarativeGeoMapItemTransitionManager : public QQuickTransitionManager -{ -public: - enum TransitionState { - NoTransition, EnterTransition, ExitTransition - }; - - QDeclarativeGeoMapItemTransitionManager(QObject *mapItem); - - void transitionEnter(); - void transitionExit(); - - bool prepareEnterTransition() - { - if (m_transitionState == QDeclarativeGeoMapItemTransitionManager::EnterTransition - && isRunning()) - return false; - - if (m_transitionState != QDeclarativeGeoMapItemTransitionManager::EnterTransition) { - // setVisible(true); - m_transitionState = QDeclarativeGeoMapItemTransitionManager::EnterTransition; - } - return true; - } - bool prepareExitTransition() - { - if (m_transitionState == QDeclarativeGeoMapItemTransitionManager::ExitTransition - && isRunning()) - return false; - - if (m_transitionState != QDeclarativeGeoMapItemTransitionManager::ExitTransition) { - m_transitionState = QDeclarativeGeoMapItemTransitionManager::ExitTransition; - } - return true; - } - void finalizeEnterTransition() - { - m_transitionState = QDeclarativeGeoMapItemTransitionManager::NoTransition; - // use invokeMethod since this is used on both QDeclarativeGeoMapItemBase and QDeclarativeGeoMapItemGroup - QMetaObject::invokeMethod(m_mapItem, QByteArrayLiteral("addTransitionFinished").constData(), Qt::DirectConnection); - } - void finalizeExitTransition() - { -// setVisible(false); - m_transitionState = QDeclarativeGeoMapItemTransitionManager::NoTransition; - QMetaObject::invokeMethod(m_mapItem, QByteArrayLiteral("removeTransitionFinished").constData(), Qt::DirectConnection); - } - -protected: - void finished() override; - -public: - QObject *m_mapItem; - QDeclarativeGeoMapItemView *m_view = nullptr; - QList<QQuickStateAction> enterActions; - QList<QQuickStateAction> exitActions; - TransitionState m_transitionState = NoTransition; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/location/declarativemaps/qdeclarativegeomapitemutils.cpp b/src/location/declarativemaps/qdeclarativegeomapitemutils.cpp deleted file mode 100644 index db5189ee..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitemutils.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com> -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativegeomapitemutils_p.h" - -#include <QPointF> -#include <QMatrix4x4> -#include <QPainterPath> -#include <QPainterPathStroker> -#include <QtPositioning/QGeoCoordinate> - -#include <QtPositioning/private/qclipperutils_p.h> - -QT_BEGIN_NAMESPACE - -namespace QDeclarativeGeoMapItemUtils { - -void wrapPath(const QList<QGeoCoordinate> &perimeter, - const QGeoCoordinate &geoLeftBound, - const QGeoProjectionWebMercator &p, - QList<QDoubleVector2D> &wrappedPath, - QList<QDoubleVector2D> &wrappedPathMinus1, - QList<QDoubleVector2D> &wrappedPathPlus1, - QDoubleVector2D *leftBoundWrapped) -{ - QList<QDoubleVector2D> path; - for (const QGeoCoordinate &c : perimeter) - path << p.geoToMapProjection(c); - const QDoubleVector2D leftBound = p.geoToMapProjection(geoLeftBound); - wrappedPath.clear(); - wrappedPathPlus1.clear(); - wrappedPathMinus1.clear(); - // compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0 - for (QDoubleVector2D coord : path) { - // We can get NaN if the map isn't set up correctly, or the projection - // is faulty -- probably best thing to do is abort - if (!qIsFinite(coord.x()) || !qIsFinite(coord.y())) - return; - - const bool isPointLessThanUnwrapBelowX = (coord.x() < leftBound.x()); - // unwrap x to preserve geometry if moved to border of map - if (isPointLessThanUnwrapBelowX) - coord.setX(coord.x() + 1.0); - - QDoubleVector2D coordP1(coord.x() + 1.0, coord.y()); - QDoubleVector2D coordM1(coord.x() - 1.0, coord.y()); - - wrappedPath.append(coord); - wrappedPathPlus1.append(coordP1); - wrappedPathMinus1.append(coordM1); - } - if (leftBoundWrapped) - *leftBoundWrapped = leftBound; -} - -void wrapPath(const QList<QGeoCoordinate> &perimeter, - const QGeoCoordinate &geoLeftBound, - const QGeoProjectionWebMercator &p, - QList<QDoubleVector2D> &wrappedPath, - QDoubleVector2D *leftBoundWrapped) -{ - QList<QDoubleVector2D> path; - for (const QGeoCoordinate &c : perimeter) - path << p.geoToMapProjection(c); - const QDoubleVector2D leftBound = p.geoToMapProjection(geoLeftBound); - wrapPath(path, leftBound,wrappedPath); - if (leftBoundWrapped) - *leftBoundWrapped = leftBound; -} - -void wrapPath(const QList<QDoubleVector2D> &path, - const QDoubleVector2D &geoLeftBound, - QList<QDoubleVector2D> &wrappedPath) -{ - wrappedPath.clear(); - // compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0 - for (QDoubleVector2D coord : path) { - // We can get NaN if the map isn't set up correctly, or the projection - // is faulty -- probably best thing to do is abort - if (!qIsFinite(coord.x()) || !qIsFinite(coord.y())) - return; - - const bool isPointLessThanUnwrapBelowX = (coord.x() < geoLeftBound.x()); - // unwrap x to preserve geometry if moved to border of map - if (isPointLessThanUnwrapBelowX) - coord.setX(coord.x() + 1.0); - - wrappedPath.append(coord); - } -} - -void clipPolygon(const QList<QDoubleVector2D> &wrappedPath, - const QGeoProjectionWebMercator &p, - QList<QList<QDoubleVector2D>> &clippedPaths, - QDoubleVector2D *leftBoundWrapped, - bool closed) -{ - // 2) Clip bounding box - clippedPaths.clear(); - const QList<QDoubleVector2D> &visibleRegion = p.projectableGeometry(); - if (visibleRegion.size()) { - QClipperUtils clipper; - clipper.addSubjectPath(wrappedPath, closed); - clipper.addClipPolygon(visibleRegion); - clippedPaths = clipper.execute(QClipperUtils::Intersection, QClipperUtils::pftEvenOdd, - QClipperUtils::pftEvenOdd); - - if (leftBoundWrapped) { - // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X - QDoubleVector2D lb(qInf(), qInf()); - for (const QList<QDoubleVector2D> &path : clippedPaths) { - for (const QDoubleVector2D &p : path) { - if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) - // y-minimization needed to find the same point on polygon and border - lb = p; - } - } - - if (qIsInf(lb.x())) // e.g., when the polygon is clipped entirely - return; - - // 2.2) Prevent the conversion to and from clipper from introducing tiny negative offsets which, - // in turn will make the geometry wrap around. - lb.setX(qMax(leftBoundWrapped->x(), lb.x())); - - *leftBoundWrapped = lb; - // srcOrigin_ = p.mapProjectionToGeo(p.unwrapMapProjection(lb)); - } - } else { - clippedPaths.append(wrappedPath); - } -} - -void projectBbox(const QList<QDoubleVector2D> &clippedBbox, - const QGeoProjectionWebMercator &p, - QPainterPath &projectedBbox) -{ - projectedBbox.clear(); - bool first = true; - for (const auto &coord : clippedBbox) { - QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(coord); - if (first) { - first = false; - projectedBbox.moveTo(point.toPointF()); - } else { - projectedBbox.lineTo(point.toPointF()); - } - } - projectedBbox.closeSubpath(); -} - -} // namespace QDeclarativeGeoMapItemUtils - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitemutils_p.h b/src/location/declarativemaps/qdeclarativegeomapitemutils_p.h deleted file mode 100644 index 8b636ff7..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitemutils_p.h +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com> -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEGEOMAPITEMUTILS_P_H -#define QDECLARATIVEGEOMAPITEMUTILS_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 <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qgeoprojection_p.h> -#include <QtPositioning/private/qdoublevector2d_p.h> - - -QT_BEGIN_NAMESPACE - -namespace QDeclarativeGeoMapItemUtils -{ - struct vec2 { - float x; - float y; - vec2(const QDoubleVector2D &p) - { - x = float(p.x()); - y = float(p.y()); - } - vec2() = default; - vec2 &operator=(const QPointF &p) - { - x = float(p.x()); - y = float(p.y()); - return *this; - } - vec2 &operator=(const QDoubleVector2D &p) - { - x = float(p.x()); - y = float(p.y()); - return *this; - } - QDoubleVector2D toDoubleVector2D() const - { - return QDoubleVector2D(double(x), double(y)); - } - }; - - void wrapPath(const QList<QGeoCoordinate> &perimeter - , const QGeoCoordinate &geoLeftBound - , const QGeoProjectionWebMercator &p - , QList<QDoubleVector2D> &wrappedPath - , QList<QDoubleVector2D> &wrappedPathMinus1 - , QList<QDoubleVector2D> &wrappedPathPlus1 - , QDoubleVector2D *leftBoundWrapped = nullptr); - - void wrapPath(const QList<QGeoCoordinate> &perimeter - , const QGeoCoordinate &geoLeftBound - , const QGeoProjectionWebMercator &p - , QList<QDoubleVector2D> &wrappedPath - , QDoubleVector2D *leftBoundWrapped = nullptr); - - void wrapPath(const QList<QDoubleVector2D> &path - , const QDoubleVector2D &geoLeftBound - , QList<QDoubleVector2D> &wrappedPath); - - void clipPolygon(const QList<QDoubleVector2D> &wrappedPath - , const QGeoProjectionWebMercator &p - , QList<QList<QDoubleVector2D> > &clippedPaths - , QDoubleVector2D *leftBoundWrapped = nullptr - , bool closed = true); - - void projectBbox(const QList<QDoubleVector2D> &clippedBbox - , const QGeoProjectionWebMercator &p - , QPainterPath &projectedBbox); - -}; - -QT_END_NAMESPACE - -#endif // QDECLARATIVEGEOMAPITEMUTILS_P_H diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp deleted file mode 100644 index 27527d35..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp +++ /dev/null @@ -1,578 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Jolla Ltd. -** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com> -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativegeomapitemview_p.h" -#include "qdeclarativegeomap_p.h" -#include "qdeclarativegeomapitembase_p.h" - -#include <QtCore/QAbstractItemModel> -#include <QtQml/QQmlContext> -#include <QtQuick/private/qquickanimation_p.h> -#include <QtQml/QQmlListProperty> - -QT_BEGIN_NAMESPACE - -/*! - \qmltype MapItemView - \instantiates QDeclarativeGeoMapItemView - \inqmlmodule QtLocation - \ingroup qml-QtLocation5-maps - \since QtLocation 5.5 - \inherits QObject - - \brief The MapItemView is used to populate Map from a model. - - The MapItemView is used to populate Map with MapItems from a model. - The MapItemView type only makes sense when contained in a Map, - meaning that it has no standalone presentation. - - \section2 Example Usage - - This example demonstrates how to use the MapViewItem object to display - a \l{Route}{route} on a \l{Map}{map}: - - \snippet declarative/maps.qml QtQuick import - \snippet declarative/maps.qml QtLocation import - \codeline - \snippet declarative/maps.qml MapRoute -*/ - -/*! - \qmlproperty Transition QtLocation::MapItemView::add - - This property holds the transition that is applied to the map items created by the view - when they are instantiated and added to the map. - - \since QtLocation 5.12 -*/ - -/*! - \qmlproperty Transition QtLocation::MapItemView::remove - - This property holds the transition that is applied to the map items created by the view - when they are removed. - - \since QtLocation 5.12 -*/ - -QDeclarativeGeoMapItemView::QDeclarativeGeoMapItemView(QQuickItem *parent) - : QDeclarativeGeoMapItemGroup(parent) -{ - m_exit = new QQuickTransition(this); - QQmlListProperty<QQuickAbstractAnimation> anims = m_exit->animations(); - QQuickNumberAnimation *ani = new QQuickNumberAnimation(m_exit); - ani->setProperty(QStringLiteral("opacity")); - ani->setTo(0.0); - ani->setDuration(300.0); - anims.append(&anims, ani); -} - -QDeclarativeGeoMapItemView::~QDeclarativeGeoMapItemView() -{ - // No need to remove instantiated items: if the MIV has instantiated items because it has been added - // to a Map (or is child of a Map), the Map destructor takes care of removing it and the instantiated items. -} - -/*! - \internal -*/ -void QDeclarativeGeoMapItemView::componentComplete() -{ - QDeclarativeGeoMapItemGroup::componentComplete(); - m_componentCompleted = true; - if (!m_itemModel.isNull()) - m_delegateModel->setModel(m_itemModel); - - if (m_delegate) - m_delegateModel->setDelegate(m_delegate); - - m_delegateModel->componentComplete(); -} - -void QDeclarativeGeoMapItemView::classBegin() -{ - QDeclarativeGeoMapItemGroup::classBegin(); - QQmlContext *ctx = qmlContext(this); - m_delegateModel = new QQmlDelegateModel(ctx, this); - m_delegateModel->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); -} - -void QDeclarativeGeoMapItemView::destroyingItem(QObject * /*object*/) -{ - -} - -void QDeclarativeGeoMapItemView::initItem(int /*index*/, QObject * /*object*/) -{ - -} - -void QDeclarativeGeoMapItemView::createdItem(int index, QObject * /*object*/) -{ - if (!m_map) - return; - // createdItem is emitted on asynchronous creation. In which case, object has to be invoked again. - // See QQmlDelegateModel::object for further info. - - // 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, true); - else - qWarning() << "QQmlDelegateModel:: object called in createdItem for " << index << " produced a null item"; -} - -void QDeclarativeGeoMapItemView::modelUpdated(const QQmlChangeSet &changeSet, bool reset) -{ - if (!m_map) // everything will be done in instantiateAllItems. Removal is done by declarativegeomap. - return; - - // move changes are expressed as one remove + one insert, with the same moveId. - // For simplicity, they will be treated as remove + insert. - // Changes will be also ignored, as they represent only data changes, not layout changes - if (reset) { // Assuming this means "remove everything already instantiated" - removeInstantiatedItems(); - } else { - // Remove items from the back to the front to retain the mapping to what is received from the changesets - const QList<QQmlChangeSet::Change> &removes = changeSet.removes(); - std::map<int, int> mapRemoves; - for (qsizetype i = 0; i < removes.size(); i++) - mapRemoves.insert(std::pair<int, int>(removes.at(i).start(), i)); - - for (auto rit = mapRemoves.rbegin(); rit != mapRemoves.rend(); ++rit) { - const QQmlChangeSet::Change &c = removes.at(rit->second); - for (auto idx = c.end() - 1; idx >= c.start(); --idx) - removeDelegateFromMap(idx); - } - } - - QBoolBlocker createBlocker(m_creatingObject, true); - for (const QQmlChangeSet::Change &c: changeSet.inserts()) { - for (auto idx = c.start(); idx < c.end(); idx++) { - QObject *delegateInstance = m_delegateModel->object(idx, m_incubationMode); - addDelegateToMap(qobject_cast<QQuickItem *>(delegateInstance), idx); - } - } - - fitViewport(); -} - -/*! - \qmlproperty model QtLocation::MapItemView::model - - This property holds the model that provides data used for creating the map items defined by the - delegate. Only QAbstractItemModel based models are supported. -*/ -QVariant QDeclarativeGeoMapItemView::model() const -{ - return m_itemModel; -} - -void QDeclarativeGeoMapItemView::setModel(const QVariant &model) -{ - if (model == m_itemModel) - return; - - m_itemModel = model; - if (m_componentCompleted) - m_delegateModel->setModel(m_itemModel); - - emit modelChanged(); -} - -/*! - \qmlproperty Component QtLocation::MapItemView::delegate - - This property holds the delegate which defines how each item in the - model should be displayed. The Component must contain exactly one - MapItem -derived object as the root object. -*/ -QQmlComponent *QDeclarativeGeoMapItemView::delegate() const -{ - return m_delegate; -} - -void QDeclarativeGeoMapItemView::setDelegate(QQmlComponent *delegate) -{ - if (m_delegate == delegate) - return; - - m_delegate = delegate; - if (m_componentCompleted) - m_delegateModel->setDelegate(m_delegate); - - emit delegateChanged(); -} - -/*! - \qmlproperty bool QtLocation::MapItemView::autoFitViewport - - This property controls whether to automatically pan and zoom the viewport - to display all map items when items are added or removed. - - Defaults to false. -*/ -bool QDeclarativeGeoMapItemView::autoFitViewport() const -{ - return m_fitViewport; -} - -void QDeclarativeGeoMapItemView::setAutoFitViewport(const bool &fit) -{ - if (fit == m_fitViewport) - return; - m_fitViewport = fit; - fitViewport(); - emit autoFitViewportChanged(); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapItemView::fitViewport() -{ - - if (!m_map || !m_map->mapReady() || !m_fitViewport) - return; - - if (m_map->mapItems().size() > 0) - m_map->fitViewportToMapItems(); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapItemView::setMap(QDeclarativeGeoMap *map) -{ - if (!map || m_map) // changing map on the fly not supported - return; - m_map = map; - instantiateAllItems(); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapItemView::removeInstantiatedItems(bool transition) -{ - if (!m_map) - return; - - // with transition = false removeInstantiatedItems aborts ongoing exit transitions //QTBUG-69195 - // Backward as removeItemFromMap modifies m_instantiatedItems - for (qsizetype i = m_instantiatedItems.size() -1; i >= 0 ; i--) - removeDelegateFromMap(i, transition); -} - -/*! - \internal - - Instantiates all items. -*/ -void QDeclarativeGeoMapItemView::instantiateAllItems() -{ - // The assumption is that if m_instantiatedItems isn't empty, instantiated items have been already added - if (!m_componentCompleted || !m_map || !m_delegate || m_itemModel.isNull() || !m_instantiatedItems.isEmpty()) - return; - - // If here, m_delegateModel may contain data, but QQmlInstanceModel::object for each row hasn't been called yet. - QBoolBlocker createBlocker(m_creatingObject, true); - for (qsizetype i = 0; i < m_delegateModel->count(); i++) { - QObject *delegateInstance = m_delegateModel->object(i, m_incubationMode); - addDelegateToMap(qobject_cast<QQuickItem *>(delegateInstance), i); - } - - fitViewport(); -} - -void QDeclarativeGeoMapItemView::setIncubateDelegates(bool useIncubators) -{ - const QQmlIncubator::IncubationMode incubationMode = - (useIncubators) ? QQmlIncubator::Asynchronous : QQmlIncubator::Synchronous; - if (m_incubationMode == incubationMode) - return; - m_incubationMode = incubationMode; - emit incubateDelegatesChanged(); -} - -bool QDeclarativeGeoMapItemView::incubateDelegates() const -{ - return m_incubationMode == QQmlIncubator::Asynchronous; -} - -QList<QQuickItem *> QDeclarativeGeoMapItemView::mapItems() -{ - return m_instantiatedItems; -} - -QQmlInstanceModel::ReleaseFlags QDeclarativeGeoMapItemView::disposeDelegate(QQuickItem *item) -{ - disconnect(item, 0, this, 0); - removeDelegateFromMap(item); - item->setParentItem(nullptr); // Needed because - item->setParent(nullptr); // m_delegateModel->release(item) does not destroy the item most of the times!! - QQmlInstanceModel::ReleaseFlags releaseStatus = m_delegateModel->release(item); - return releaseStatus; -} - -void QDeclarativeGeoMapItemView::removeDelegateFromMap(int index, bool transition) -{ - if (index >= 0 && index < m_instantiatedItems.size()) { - QQuickItem *item = m_instantiatedItems.takeAt(index); - if (!item) { // not yet incubated - // Don't cancel incubation explicitly when model rows are removed, as DelegateModel - // apparently takes care of incubating elements when the model remove those indices. - // Cancel them explicitly only when a MIV is removed from a map. - if (!transition) - m_delegateModel->cancel(index); - return; - } - // item can be either a QDeclarativeGeoMapItemBase or a QDeclarativeGeoMapItemGroup (subclass) - if (m_exit && m_map && transition) { - transitionItemOut(item); - } else { - if (m_exit && m_map && !transition) { - // check if the exit transition is still running, if so stop it. - // This can happen when explicitly calling Map.removeMapItemView, soon after adding it. - terminateExitTransition(item); - } - QQmlInstanceModel::ReleaseFlags releaseStatus = disposeDelegate(item); -#ifdef QT_DEBUG - if (releaseStatus == QQmlInstanceModel::Referenced) - qWarning() << "item "<< index << "(" << item << ") still referenced"; -#else - Q_UNUSED(releaseStatus); -#endif - } - } -} - -void QDeclarativeGeoMapItemView::removeDelegateFromMap(QQuickItem *o) -{ - if (!m_map) - return; - - QDeclarativeGeoMapItemBase *item = qobject_cast<QDeclarativeGeoMapItemBase *>(o); - if (item) { - m_map->removeMapItem(item); - return; - } - QDeclarativeGeoMapItemView *view = qobject_cast<QDeclarativeGeoMapItemView *>(o); - if (view) { - m_map->removeMapItemView(view); - return; - } - QDeclarativeGeoMapItemGroup *group = qobject_cast<QDeclarativeGeoMapItemGroup *>(o); - if (group) { - m_map->removeMapItemGroup(group); - return; - } -} - -void QDeclarativeGeoMapItemView::transitionItemOut(QQuickItem *o) -{ - QDeclarativeGeoMapItemGroup *group = qobject_cast<QDeclarativeGeoMapItemGroup *>(o); - if (group) { - if (!group->m_transitionManager) { - std::unique_ptr<QDeclarativeGeoMapItemTransitionManager>manager(new QDeclarativeGeoMapItemTransitionManager(group)); - group->m_transitionManager.swap(manager); - group->m_transitionManager->m_view = this; - } - connect(group, &QDeclarativeGeoMapItemGroup::removeTransitionFinished, - this, &QDeclarativeGeoMapItemView::exitTransitionFinished); - - group->m_transitionManager->transitionExit(); - return; - } - QDeclarativeGeoMapItemBase *item = qobject_cast<QDeclarativeGeoMapItemBase *>(o); - if (item) { - if (!item->m_transitionManager) { - std::unique_ptr<QDeclarativeGeoMapItemTransitionManager> manager(new QDeclarativeGeoMapItemTransitionManager(item)); - item->m_transitionManager.swap(manager); - item->m_transitionManager->m_view = this; - } - connect(item, &QDeclarativeGeoMapItemBase::removeTransitionFinished, - this, &QDeclarativeGeoMapItemView::exitTransitionFinished); - - item->m_transitionManager->transitionExit(); - return; - } -} - -void QDeclarativeGeoMapItemView::terminateExitTransition(QQuickItem *o) -{ - QDeclarativeGeoMapItemGroup *group = qobject_cast<QDeclarativeGeoMapItemGroup *>(o); - if (group && group->m_transitionManager) { - group->m_transitionManager->cancel(); - return; - } - QDeclarativeGeoMapItemBase *item = qobject_cast<QDeclarativeGeoMapItemBase *>(o); - if (item && item->m_transitionManager) { - item->m_transitionManager->cancel(); - return; - } -} - -void QDeclarativeGeoMapItemView::exitTransitionFinished() -{ - QQuickItem *item = qobject_cast<QQuickItem *>(sender()); - if (!item) - return; - QQmlInstanceModel::ReleaseFlags releaseStatus = disposeDelegate(item); -#ifdef QT_DEBUG - if (releaseStatus == QQmlInstanceModel::Referenced) - qWarning() << "item "<<item<<" still referenced"; -#else - Q_UNUSED(releaseStatus); -#endif -} - -void QDeclarativeGeoMapItemView::addItemToMap(QDeclarativeGeoMapItemBase *item, int index, bool createdItem) -{ - - if (m_map && item->quickMap() == m_map) // test for *item done in the caller - return; - - if (m_map) { - insertInstantiatedItem(index, item, createdItem); - item->setParentItem(this); - m_map->addMapItem(item); - if (m_enter) { - if (!item->m_transitionManager) { - std::unique_ptr<QDeclarativeGeoMapItemTransitionManager>manager(new QDeclarativeGeoMapItemTransitionManager(item)); - item->m_transitionManager.swap(manager); - } - item->m_transitionManager->m_view = this; - item->m_transitionManager->transitionEnter(); - } - } -} - -void QDeclarativeGeoMapItemView::insertInstantiatedItem(int index, QQuickItem *o, bool createdItem) -{ - if (createdItem) - m_instantiatedItems.replace(index, o); - else - m_instantiatedItems.insert(index, o); -} - -void QDeclarativeGeoMapItemView::addItemViewToMap(QDeclarativeGeoMapItemView *item, int index, bool createdItem) -{ - if (m_map && item->quickMap() == m_map) // test for *item done in the caller - return; - - if (m_map) { - insertInstantiatedItem(index, item, createdItem); - item->setParentItem(this); - m_map->addMapItemView(item); - if (m_enter) { - if (!item->m_transitionManager) { - std::unique_ptr<QDeclarativeGeoMapItemTransitionManager> manager(new QDeclarativeGeoMapItemTransitionManager(item)); - item->m_transitionManager.swap(manager); - } - item->m_transitionManager->m_view = this; - item->m_transitionManager->transitionEnter(); - } - } -} - -void QDeclarativeGeoMapItemView::addItemGroupToMap(QDeclarativeGeoMapItemGroup *item, int index, bool createdItem) -{ - if (m_map && item->quickMap() == m_map) // test for *item done in the caller - return; - - if (m_map) { - insertInstantiatedItem(index, item, createdItem); - item->setParentItem(this); - m_map->addMapItemGroup(item); - if (m_enter) { - if (!item->m_transitionManager) { - std::unique_ptr<QDeclarativeGeoMapItemTransitionManager>manager(new QDeclarativeGeoMapItemTransitionManager(item)); - item->m_transitionManager.swap(manager); - } - item->m_transitionManager->m_view = this; - item->m_transitionManager->transitionEnter(); - } - } -} - -void QDeclarativeGeoMapItemView::addDelegateToMap(QQuickItem *object, int index, bool createdItem) -{ - if (!object) { - 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, createdItem); - return; - } - QDeclarativeGeoMapItemView *view = qobject_cast<QDeclarativeGeoMapItemView *>(object); - if (view) { - addItemViewToMap(view, index, createdItem); - return; - } - QDeclarativeGeoMapItemGroup *group = qobject_cast<QDeclarativeGeoMapItemGroup *>(object); - if (group) { - 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 deleted file mode 100644 index 25c54d48..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h +++ /dev/null @@ -1,166 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Jolla Ltd. -** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com> -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEGEOMAPITEMVIEW_H -#define QDECLARATIVEGEOMAPITEMVIEW_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 <QtLocation/private/qlocationglobal_p.h> -#include <map> -#include <QtCore/QModelIndex> -#include <QtQml/QQmlParserStatus> -#include <QtQml/QQmlIncubator> -#include <QtQml/qqml.h> -#include <private/qqmldelegatemodel_p.h> -#include <QtQuick/private/qquicktransition_p.h> -#include <QtLocation/private/qdeclarativegeomapitemgroup_p.h> - -QT_BEGIN_NAMESPACE - -class QAbstractItemModel; -class QQmlComponent; -class QQuickItem; -class QDeclarativeGeoMap; -class QDeclarativeGeoMapItemBase; -class QQmlOpenMetaObject; -class QQmlOpenMetaObjectType; -class MapItemViewDelegateIncubator; -class QDeclarativeGeoMapItemViewItemData; -class QDeclarativeGeoMapItemView; -class QDeclarativeGeoMapItemGroup; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemView : public QDeclarativeGeoMapItemGroup -{ - Q_OBJECT - - Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged) - Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) - Q_PROPERTY(bool autoFitViewport READ autoFitViewport WRITE setAutoFitViewport NOTIFY autoFitViewportChanged) - Q_PROPERTY(QQuickTransition *add MEMBER m_enter REVISION 12) - Q_PROPERTY(QQuickTransition *remove MEMBER m_exit REVISION 12) - Q_PROPERTY(QList<QQuickItem *> mapItems READ mapItems REVISION 12) - Q_PROPERTY(bool incubateDelegates READ incubateDelegates WRITE setIncubateDelegates NOTIFY incubateDelegatesChanged REVISION 12) - -public: - explicit QDeclarativeGeoMapItemView(QQuickItem *parent = nullptr); - ~QDeclarativeGeoMapItemView(); - - QVariant model() const; - void setModel(const QVariant &); - - QQmlComponent *delegate() const; - void setDelegate(QQmlComponent *); - - bool autoFitViewport() const; - void setAutoFitViewport(const bool &fit); - - void setMap(QDeclarativeGeoMap *); - void removeInstantiatedItems(bool transition = true); - void instantiateAllItems(); - - void setIncubateDelegates(bool useIncubators); - bool incubateDelegates() const; - - QList<QQuickItem *> mapItems(); - - // From QQmlParserStatus - void componentComplete() override; - void classBegin() override; - -Q_SIGNALS: - void modelChanged(); - void delegateChanged(); - void autoFitViewportChanged(); - void incubateDelegatesChanged(); - -private Q_SLOTS: - void destroyingItem(QObject *object); - void initItem(int index, QObject *object); - void createdItem(int index, QObject *object); - void modelUpdated(const QQmlChangeSet &changeSet, bool reset); - void exitTransitionFinished(); - -private: - void fitViewport(); - void removeDelegateFromMap(int index, bool transition = true); - void removeDelegateFromMap(QQuickItem *o); - void transitionItemOut(QQuickItem *o); - void terminateExitTransition(QQuickItem *o); - QQmlInstanceModel::ReleaseFlags disposeDelegate(QQuickItem *item); - - 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 = false; - QQmlIncubator::IncubationMode m_incubationMode = QQmlIncubator::Asynchronous; - QQmlComponent *m_delegate = nullptr; - QVariant m_itemModel; - QDeclarativeGeoMap *m_map = nullptr; - QList<QQuickItem *> m_instantiatedItems; - bool m_fitViewport = false; - bool m_creatingObject = false; - QQmlDelegateModel *m_delegateModel = nullptr; - QQuickTransition *m_enter = nullptr; - QQuickTransition *m_exit = nullptr; - - friend class QDeclarativeGeoMap; - friend class QDeclarativeGeoMapItemBase; - friend class QDeclarativeGeoMapItemTransitionManager; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativeGeoMapItemView) - -#endif diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp deleted file mode 100644 index 59c770d5..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp +++ /dev/null @@ -1,487 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativegeomapquickitem_p.h" - -#include <QtCore/QScopedValueRollback> -#include <QtQml/qqmlinfo.h> -#include <QtQuick/QSGOpacityNode> -#include <QtPositioning/private/qdoublevector2d_p.h> -#include <QtQuick/private/qquickmousearea_p.h> -#include <QtLocation/private/qgeomap_p.h> -#include <QtLocation/private/qgeoprojection_p.h> -#include <QDebug> -#include <cmath> - -QT_BEGIN_NAMESPACE - -/*! - \qmltype MapQuickItem - \instantiates QDeclarativeGeoMapQuickItem - \inqmlmodule QtLocation - \ingroup qml-QtLocation5-maps - \since QtLocation 5.5 - - \brief The MapQuickItem type displays an arbitrary Qt Quick object - on a Map. - - The MapQuickItem type is used to place an arbitrary Qt Quick object - on a Map at a specified location and size. Compared to floating an item - above the Map, a MapQuickItem will follow the panning (and optionally, the - zooming) of the Map as if it is on the Map surface. - - The \l{sourceItem} property contains the Qt Quick item to be drawn, which - can be any kind of visible type. - - \section2 Positioning and Sizing - - The positioning of the MapQuickItem on the Map is controlled by two - properties: \l coordinate and \l anchorPoint. If only \l coordinate is set, - it specifies a longitude/latitude coordinate for the item to be placed at. - The set coordinate will line up with the top-left corner of the contained - item when shown on the screen. - - The \l anchorPoint property provides a way to line up the coordinate with - other parts of the item than just the top-left corner, by setting a number - of pixels the item will be offset by. A simple way to think about it is - to note that the point given by \l anchorPoint on the item itself is the - point that will line up with the given \l coordinate when displayed. - - In addition to being anchored to the map, the MapQuickItem can optionally - follow the scale of the map, and change size when the Map is zoomed in or - zoomed out. This behaviour is controlled by the \l zoomLevel property. The - default behaviour if \l zoomLevel is not set is for the item to be drawn - "on the screen" rather than "on the map", so that its size remains the same - regardless of the zoom level of the Map. - - \section2 Performance - - Performance of a MapQuickItem is normally in the same ballpark as the - contained Qt Quick item alone. Overheads added amount to a translation - and (possibly) scaling of the original item, as well as a transformation - from longitude and latitude to screen position. - - \section2 Limitations - - \note Due to an implementation detail, items placed inside a - MapQuickItem will have a \c{parent} item which is not the MapQuickItem. - Refer to the MapQuickItem by its \c{id}, and avoid the use of \c{anchor} - in the \c{sourceItem}. - - \section2 Example Usage - - The following snippet shows a MapQuickItem containing an Image object, - to display a Marker on the Map. This strategy is used to show the map - markers in the MapViewer example. - - \snippet mapviewer/map/Marker.qml mqi-top - \snippet mapviewer/map/Marker.qml mqi-anchor - \snippet mapviewer/map/Marker.qml mqi-closeimage - \snippet mapviewer/map/Marker.qml mqi-close - - \image api-mapquickitem.png -*/ - -/*! - \qmlproperty bool QtLocation::MapQuickItem::autoFadeIn - - This property holds whether the item automatically fades in when zooming into the map - starting from very low zoom levels. By default this is \c true. - Setting this property to \c false causes the map item to always have the opacity specified - with the \l QtQuick::Item::opacity property, which is 1.0 by default. - - \since 5.14 -*/ - -QMapQuickItemMatrix4x4::QMapQuickItemMatrix4x4(QObject *parent) : QQuickTransform(parent) { } - -void QMapQuickItemMatrix4x4::setMatrix(const QMatrix4x4 &matrix) -{ - if (m_matrix == matrix) - return; - m_matrix = matrix; - update(); -} - -void QMapQuickItemMatrix4x4::applyTo(QMatrix4x4 *matrix) const -{ - *matrix *= m_matrix; -} - - -QDeclarativeGeoMapQuickItem::QDeclarativeGeoMapQuickItem(QQuickItem *parent) - : QDeclarativeGeoMapItemBase(parent) -{ - m_itemType = QGeoMap::MapQuickItem; - setFlag(ItemHasContents, true); - opacityContainer_ = new QQuickItem(this); - opacityContainer_->setParentItem(this); - opacityContainer_->setFlag(ItemHasContents, true); - setFiltersChildMouseEvents(true); -} - -QDeclarativeGeoMapQuickItem::~QDeclarativeGeoMapQuickItem() {} - -/*! - \qmlproperty coordinate MapQuickItem::coordinate - - This property holds the anchor coordinate of the MapQuickItem. The point - on the sourceItem that is specified by anchorPoint is kept aligned with - this coordinate when drawn on the map. - - In the image below, there are 3 MapQuickItems that are identical except - for the value of their anchorPoint properties. The values of anchorPoint - for each are written on top of the item. - - \image api-mapquickitem-anchor.png -*/ -void QDeclarativeGeoMapQuickItem::setCoordinate(const QGeoCoordinate &coordinate) -{ - if (coordinate_ == coordinate) - return; - - coordinate_ = coordinate; - geoshape_.setTopLeft(coordinate_); - geoshape_.setBottomRight(coordinate_); - // TODO: Handle zoomLevel != 0.0 - polishAndUpdate(); - emit coordinateChanged(); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapQuickItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) -{ - QDeclarativeGeoMapItemBase::setMap(quickMap,map); - if (map && quickMap) { - connect(map, &QGeoMap::cameraDataChanged, - this, &QDeclarativeGeoMapQuickItem::polishAndUpdate); - polishAndUpdate(); - } -} -// See QQuickMultiPointTouchArea::childMouseEventFilter for reference -bool QDeclarativeGeoMapQuickItem::childMouseEventFilter(QQuickItem *receiver, QEvent *event) -{ - if (isEnabled() && isVisible()) { - switch (event->type()) { - case QEvent::MouseButtonPress: - case QEvent::TouchBegin: - dragStartCoordinate_ = coordinate_; - default: - break; - } - } - return QQuickItem::childMouseEventFilter(receiver, event); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapQuickItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - if (!mapAndSourceItemSet_ || updatingGeometry_ || - newGeometry.topLeft() == oldGeometry.topLeft()) { - QDeclarativeGeoMapItemBase::geometryChange(newGeometry, oldGeometry); - return; - } - - QGeoCoordinate newCoordinate; - // with zoomLevel set the anchorPoint has to be factored into the transformation to properly transform around it. - if (zoomLevel_ != 0.0 - && map()->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) { - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection()); - - // When dragStartCoordinate_ can't be projected to screen, dragging must be disabled. - if (!p.isProjectable(p.geoToWrappedMapProjection(dragStartCoordinate_))) - return; - - QDoubleVector2D pos = map()->geoProjection().coordinateToItemPosition(dragStartCoordinate_, false); - // oldGeometry.topLeft() is always intended to be (0,0), even when for some reason it's not. - pos.setX(pos.x() + newGeometry.topLeft().x()); - pos.setY(pos.y() + newGeometry.topLeft().y()); - newCoordinate = map()->geoProjection().itemPositionToCoordinate(pos, false); - } else { - newCoordinate = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(x(), y()) + QDoubleVector2D(anchorPoint_), false); - } - - if (newCoordinate.isValid()) - setCoordinate(newCoordinate); - - // Not calling QDeclarativeGeoMapItemBase::geometryChange() as it will be called from a nested - // call to this function. -} - -/*! - \internal -*/ -QGeoCoordinate QDeclarativeGeoMapQuickItem::coordinate() -{ - return coordinate_; -} - -/*! - \qmlproperty object MapQuickItem::sourceItem - - This property holds the source item that will be drawn on the map. -*/ -void QDeclarativeGeoMapQuickItem::setSourceItem(QQuickItem *sourceItem) -{ - QQuickItem *item = qobject_cast<QQuickItem *>(sourceItem); // Workaround for QTBUG-72930 - if (sourceItem_.data() == item) - return; - sourceItem_ = item; - polishAndUpdate(); - emit sourceItemChanged(); -} - -QQuickItem *QDeclarativeGeoMapQuickItem::sourceItem() -{ - return sourceItem_.data(); -} - -/*! - \internal -*/ -void QDeclarativeGeoMapQuickItem::afterChildrenChanged() -{ - const QList<QQuickItem *> kids = childItems(); - if (kids.size() > 0) { - bool printedWarning = false; - for (auto *i : kids) { - if (i->flags() & QQuickItem::ItemHasContents - && !qobject_cast<QQuickMouseArea *>(i) - && sourceItem_.data() != i - && opacityContainer_ != i) { - if (!printedWarning) { - qmlWarning(this) << "Use the sourceItem property for the contained item, direct children are not supported"; - printedWarning = true; - } - - qmlWarning(i) << "deleting this child"; - i->deleteLater(); - } - } - } -} - -/*! - \qmlproperty QPointF MapQuickItem::anchorPoint - - This property determines which point on the sourceItem that will be lined - up with the coordinate on the map. -*/ -void QDeclarativeGeoMapQuickItem::setAnchorPoint(const QPointF &anchorPoint) -{ - if (anchorPoint == anchorPoint_) - return; - anchorPoint_ = anchorPoint; - polishAndUpdate(); - emit anchorPointChanged(); -} - -QPointF QDeclarativeGeoMapQuickItem::anchorPoint() const -{ - return anchorPoint_; -} - -/*! - \qmlproperty real MapQuickItem::zoomLevel - - This property controls the scaling behaviour of the contents of the - MapQuickItem. In particular, by setting this property it is possible - to choose between objects that are drawn on the screen (and sized in - screen pixels), and those drawn on the map surface (which change size - with the zoom level of the map). - - The default value for this property is 0.0, which corresponds to drawing - the object on the screen surface. If set to another value, the object will - be drawn on the map surface instead. The value (if not zero) specifies the - zoomLevel at which the object will be visible at a scale of 1:1 (ie, where - object pixels and screen pixels are the same). At zoom levels lower than - this, the object will appear smaller, and at higher zoom levels, appear - larger. This is in contrast to when this property is set to zero, where - the object remains the same size on the screen at all zoom levels. -*/ -void QDeclarativeGeoMapQuickItem::setZoomLevel(qreal zoomLevel) -{ - if (zoomLevel == zoomLevel_) - return; - zoomLevel_ = zoomLevel; - // TODO: update geoshape_! - polishAndUpdate(); - emit zoomLevelChanged(); -} - -qreal QDeclarativeGeoMapQuickItem::zoomLevel() const -{ - return zoomLevel_; -} - -const QGeoShape &QDeclarativeGeoMapQuickItem::geoShape() const -{ - // TODO: return a QGeoRectangle representing the bounding geo rectangle of the quick item - // when zoomLevel_ is != 0.0 - return geoshape_; -} - -void QDeclarativeGeoMapQuickItem::setGeoShape(const QGeoShape &shape) -{ - if (shape == geoshape_) - return; - - const QGeoRectangle rect = shape.boundingGeoRectangle(); - geoshape_ = rect; - coordinate_ = rect.center(); - - // TODO: Handle zoomLevel != 0.0 - polishAndUpdate(); - emit coordinateChanged(); - -} - -/*! - \internal -*/ -void QDeclarativeGeoMapQuickItem::updatePolish() -{ - if (!quickMap() && sourceItem_) { - mapAndSourceItemSet_ = false; - sourceItem_.data()->setParentItem(0); - return; - } - - if (!quickMap() || !map() || !sourceItem_) { - mapAndSourceItemSet_ = false; - return; - } - - if (!mapAndSourceItemSet_ && quickMap() && map() && sourceItem_) { - mapAndSourceItemSet_ = true; - sourceItem_.data()->setParentItem(opacityContainer_); - sourceItem_.data()->setTransformOrigin(QQuickItem::TopLeft); - connect(sourceItem_.data(), &QQuickItem::xChanged, - this, &QDeclarativeGeoMapQuickItem::polishAndUpdate); - connect(sourceItem_.data(), &QQuickItem::yChanged, - this, &QDeclarativeGeoMapQuickItem::polishAndUpdate); - connect(sourceItem_.data(), &QQuickItem::widthChanged, - this, &QDeclarativeGeoMapQuickItem::polishAndUpdate); - connect(sourceItem_.data(), &QQuickItem::heightChanged, - this, &QDeclarativeGeoMapQuickItem::polishAndUpdate); - } - - if (!coordinate_.isValid()) { - opacityContainer_->setVisible(false); - return; - } else { - opacityContainer_->setVisible(true); - } - - QScopedValueRollback<bool> rollback(updatingGeometry_); - updatingGeometry_ = true; - - opacityContainer_->setOpacity(zoomLevelOpacity()); - - setWidth(sourceItem_.data()->width()); - setHeight(sourceItem_.data()->height()); - if (zoomLevel_ != 0.0 // zoom level initialized to 0.0. If it's different, it has been set explicitly. - && map()->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) { // Currently unsupported on any other projection - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection()); - - if (!matrix_) { - matrix_ = new QMapQuickItemMatrix4x4(this); - matrix_->appendToItem(opacityContainer_); - } - matrix_->setMatrix(p.quickItemTransformation(coordinate(), anchorPoint_, zoomLevel_)); - setPosition(QPointF(0,0)); - } else { - if (map()->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) { - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection()); - if (map()->cameraData().tilt() > 0.0 - && !p.isProjectable(p.geoToWrappedMapProjection(coordinate()))) { - // if the coordinate is behind the camera, we use the transformation to get the item out of the way - if (!matrix_) { - matrix_ = new QMapQuickItemMatrix4x4(this); - matrix_->appendToItem(opacityContainer_); - } - matrix_->setMatrix(p.quickItemTransformation(coordinate(), anchorPoint_, map()->cameraData().zoomLevel())); - setPosition(QPointF(0,0)); - } else { // All good, rendering screen-aligned - if (matrix_) - matrix_->setMatrix(QMatrix4x4()); - setPositionOnMap(coordinate(), anchorPoint_); - } - } else { // On other projections we can only currently test if coordinateToItemPosition returns a valid position - if (map()->cameraData().tilt() > 0.0 - && qIsNaN(map()->geoProjection().coordinateToItemPosition(coordinate(), false).x())) { - opacityContainer_->setVisible(false); - } else { - if (matrix_) - matrix_->setMatrix(QMatrix4x4()); - setPositionOnMap(coordinate(), anchorPoint_); - } - } - } -} - -/*! - \internal -*/ -void QDeclarativeGeoMapQuickItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event) -{ - Q_UNUSED(event); - if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0) - return; - - polishAndUpdate(); -} - -/*! - \internal -*/ -qreal QDeclarativeGeoMapQuickItem::scaleFactor() -{ - qreal scale = 1.0; - // use 1+x to avoid fuzzy compare against zero - if (!qFuzzyCompare(1.0 + zoomLevel_, 1.0)) - scale = std::pow(0.5, zoomLevel_ - map()->cameraData().zoomLevel()); - return scale; -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h b/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h deleted file mode 100644 index b8e093af..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEGEOMAPQUICKITEM_H -#define QDECLARATIVEGEOMAPQUICKITEM_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 <QtLocation/private/qlocationglobal_p.h> - -#include <QtQuick/QQuickItem> -#include <QtQuick/QSGNode> - -#include <QtLocation/private/qdeclarativegeomap_p.h> -#include <QtLocation/private/qdeclarativegeomapitembase_p.h> -#include <QtPositioning/qgeoshape.h> - -QT_BEGIN_NAMESPACE - -class QMapQuickItemMatrix4x4 : public QQuickTransform -{ -public: - QMapQuickItemMatrix4x4(QObject *parent = nullptr); - - void setMatrix(const QMatrix4x4& matrix); - void applyTo(QMatrix4x4 *matrix) const override; - - QMatrix4x4 m_matrix; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapQuickItem : public QDeclarativeGeoMapItemBase -{ - Q_OBJECT - Q_PROPERTY(QGeoCoordinate coordinate READ coordinate WRITE setCoordinate NOTIFY coordinateChanged) - Q_PROPERTY(QPointF anchorPoint READ anchorPoint WRITE setAnchorPoint NOTIFY anchorPointChanged) - Q_PROPERTY(qreal zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged) - Q_PROPERTY(QQuickItem *sourceItem READ sourceItem WRITE setSourceItem NOTIFY sourceItemChanged) - -public: - explicit QDeclarativeGeoMapQuickItem(QQuickItem *parent = nullptr); - ~QDeclarativeGeoMapQuickItem(); - - void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) override; - - void setCoordinate(const QGeoCoordinate &coordinate); - QGeoCoordinate coordinate(); - - void setSourceItem(QQuickItem *sourceItem); - QQuickItem *sourceItem(); - - void setAnchorPoint(const QPointF &anchorPoint); - QPointF anchorPoint() const; - - void setZoomLevel(qreal zoomLevel); - qreal zoomLevel() const; - - const QGeoShape &geoShape() const override; - void setGeoShape(const QGeoShape &shape) override; - -Q_SIGNALS: - void coordinateChanged(); - void sourceItemChanged(); - void anchorPointChanged(); - void zoomLevelChanged(); - -protected: - void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; - void updatePolish() override; - bool childMouseEventFilter(QQuickItem *item, QEvent *event) override; - -protected Q_SLOTS: - void afterChildrenChanged() override; - void afterViewportChanged(const QGeoMapViewportChangeEvent &event) override; - -private: - qreal scaleFactor(); - QGeoCoordinate dragStartCoordinate_; - QGeoCoordinate coordinate_; - QGeoRectangle geoshape_; - QPointer<QQuickItem> sourceItem_; - QQuickItem *opacityContainer_ = nullptr; - QPointF anchorPoint_; - qreal zoomLevel_ = 0.0; - bool mapAndSourceItemSet_ = false; - bool updatingGeometry_ = false; - QMapQuickItemMatrix4x4 *matrix_ = nullptr; - - friend class QDeclarativeGeoMap; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativeGeoMapQuickItem) - -#endif diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp deleted file mode 100644 index dabd9714..00000000 --- a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp +++ /dev/null @@ -1,1061 +0,0 @@ -/**************************************************************************** - ** - ** Copyright (C) 2022 The Qt Company Ltd. - ** Contact: https://www.qt.io/licensing/ - ** - ** This file is part of the QtLocation module of the Qt Toolkit. - ** - ** $QT_BEGIN_LICENSE:LGPL$ - ** Commercial License Usage - ** Licensees holding valid commercial Qt licenses may use this file in - ** accordance with the commercial license agreement provided with the - ** Software or, alternatively, in accordance with the terms contained in - ** a written agreement between you and The Qt Company. For licensing terms - ** and conditions see https://www.qt.io/terms-conditions. For further - ** information use the contact form at https://www.qt.io/contact-us. - ** - ** GNU Lesser General Public License Usage - ** Alternatively, this file may be used under the terms of the GNU Lesser - ** General Public License version 3 as published by the Free Software - ** Foundation and appearing in the file LICENSE.LGPL3 included in the - ** packaging of this file. Please review the following information to - ** ensure the GNU Lesser General Public License version 3 requirements - ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. - ** - ** GNU General Public License Usage - ** Alternatively, this file may be used under the terms of the GNU - ** General Public License version 2.0 or (at your option) the GNU General - ** Public license version 3 or any later version approved by the KDE Free - ** Qt Foundation. The licenses are as published by the Free Software - ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 - ** included in the packaging of this file. Please review the following - ** information to ensure the GNU General Public License requirements will - ** be met: https://www.gnu.org/licenses/gpl-2.0.html and - ** https://www.gnu.org/licenses/gpl-3.0.html. - ** - ** $QT_END_LICENSE$ - ** - ****************************************************************************/ - -#include "qdeclarativegeomapitemutils_p.h" -#include "qdeclarativepolygonmapitem_p.h" -#include "qdeclarativepolylinemapitem_p_p.h" -#include "qdeclarativepolygonmapitem_p_p.h" -#include "qdeclarativerectanglemapitem_p_p.h" -#include "error_messages_p.h" - -#include <QtCore/QScopedValueRollback> -#include <qnumeric.h> -#include <QPainter> -#include <QPainterPath> -#include <QtQml/QQmlInfo> -#include <QtQuick/qsgnode.h> - -#include <QtQuick/private/qsgmaterialshader_p.h> -#include <QtLocation/private/qgeomap_p.h> -#include <QtPositioning/private/qlocationutils_p.h> -#include <QtPositioning/private/qdoublevector2d_p.h> -#include <QtPositioning/private/qclipperutils_p.h> -#include <QtPositioning/private/qgeopolygon_p.h> -#include <QtPositioning/private/qwebmercator_p.h> - -/* poly2tri triangulator includes */ -#include <earcut.hpp> -#include <array> - -QT_BEGIN_NAMESPACE - -/*! - \qmltype MapPolygon - \instantiates QDeclarativePolygonMapItem - \inqmlmodule QtLocation - \ingroup qml-QtLocation5-maps - \since QtLocation 5.5 - - \brief The MapPolygon type displays a polygon on a Map. - - The MapPolygon type displays a polygon on a Map, specified in terms of an ordered list of - \l {QtPositioning::coordinate}{coordinates}. For best appearance and results, polygons should be - simple (not self-intersecting). - - The \l {QtPositioning::coordinate}{coordinates} on the path cannot be directly changed after - being added to the Polygon. Instead, copy the \l path into a var, modify the copy and reassign - the copy back to the \l path. - - \code - var path = mapPolygon.path; - path[0].latitude = 5; - mapPolygon.path = path; - \endcode - - Coordinates can also be added and removed at any time using the \l addCoordinate and - \l removeCoordinate methods. - - For drawing rectangles with "straight" edges (same latitude across one - edge, same latitude across the other), the \l MapRectangle type provides - a simpler, two-point API. - - By default, the polygon is displayed as a 1 pixel black border with no - fill. To change its appearance, use the \l color, \l border.color and - \l border.width properties. - - \note Since MapPolygons are geographic items, dragging a MapPolygon - (through the use of \l MouseArea) causes its vertices to be - recalculated in the geographic coordinate space. The edges retain the - same geographic lengths (latitude and longitude differences between the - vertices), but they remain straight. Apparent stretching of the item occurs - when dragged to a different latitude. - - \section2 Performance - - MapPolygons have a rendering cost that is O(n) with respect to the number - of vertices. This means that the per frame cost of having a Polygon on the - Map grows in direct proportion to the number of points on the Polygon. There - is an additional triangulation cost (approximately O(n log n)) which is - currently paid with each frame, but in future may be paid only upon adding - or removing points. - - Like the other map objects, MapPolygon is normally drawn without a smooth - appearance. Setting the \l {Item::opacity}{opacity} property will force the object to - be blended, which decreases performance considerably depending on the hardware in use. - - \section2 Example Usage - - The following snippet shows a MapPolygon being used to display a triangle, - with three vertices near Brisbane, Australia. The triangle is filled in - green, with a 1 pixel black border. - - \code - Map { - MapPolygon { - color: 'green' - path: [ - { latitude: -27, longitude: 153.0 }, - { latitude: -27, longitude: 154.1 }, - { latitude: -28, longitude: 153.5 } - ] - } - } - \endcode - - \image api-mappolygon.png -*/ - -/*! - \qmlproperty bool QtLocation::MapPolygon::autoFadeIn - - This property holds whether the item automatically fades in when zooming into the map - starting from very low zoom levels. By default this is \c true. - Setting this property to \c false causes the map item to always have the opacity specified - with the \l QtQuick::Item::opacity property, which is 1.0 by default. - - \since 5.14 -*/ - -QGeoMapPolygonGeometry::QGeoMapPolygonGeometry() = default; - -/*! - \internal -*/ -void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map, - const QList<QDoubleVector2D> &path) -{ - if (!sourceDirty_) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - srcPath_ = QPainterPath(); - - // build the actual path - // The approach is the same as described in QGeoMapPolylineGeometry::updateSourcePoints - srcOrigin_ = geoLeftBound_; - double unwrapBelowX = 0; - QDoubleVector2D leftBoundWrapped = p.wrapMapProjection(p.geoToMapProjection(geoLeftBound_)); - if (preserveGeometry_) - unwrapBelowX = leftBoundWrapped.x(); - - QList<QDoubleVector2D> wrappedPath; - wrappedPath.reserve(path.size()); - QDoubleVector2D wrappedLeftBound(qInf(), qInf()); - // 1) - for (const auto &coord : path) { - QDoubleVector2D wrappedProjection = p.wrapMapProjection(coord); - - // We can get NaN if the map isn't set up correctly, or the projection - // is faulty -- probably best thing to do is abort - if (!qIsFinite(wrappedProjection.x()) || !qIsFinite(wrappedProjection.y())) - return; - - const bool isPointLessThanUnwrapBelowX = (wrappedProjection.x() < leftBoundWrapped.x()); - // unwrap x to preserve geometry if moved to border of map - if (preserveGeometry_ && isPointLessThanUnwrapBelowX) { - double distance = wrappedProjection.x() - unwrapBelowX; - if (distance < 0.0) - distance += 1.0; - wrappedProjection.setX(unwrapBelowX + distance); - } - if (wrappedProjection.x() < wrappedLeftBound.x() || (wrappedProjection.x() == wrappedLeftBound.x() && wrappedProjection.y() < wrappedLeftBound.y())) { - wrappedLeftBound = wrappedProjection; - } - wrappedPath.append(wrappedProjection); - } - - // 2) - QList<QList<QDoubleVector2D> > clippedPaths; - const QList<QDoubleVector2D> &visibleRegion = p.projectableGeometry(); - if (visibleRegion.size()) { - QClipperUtils clipper; - clipper.addSubjectPath(wrappedPath, true); - clipper.addClipPolygon(visibleRegion); - clippedPaths = clipper.execute(QClipperUtils::Intersection, QClipperUtils::pftEvenOdd, - QClipperUtils::pftEvenOdd); - - // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X - QDoubleVector2D lb(qInf(), qInf()); - for (const QList<QDoubleVector2D> &path: clippedPaths) - for (const QDoubleVector2D &p: path) - if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) - // y-minimization needed to find the same point on polygon and border - lb = p; - - if (qIsInf(lb.x())) // e.g., when the polygon is clipped entirely - return; - - // 2.2) Prevent the conversion to and from clipper from introducing negative offsets which - // in turn will make the geometry wrap around. - lb.setX(qMax(wrappedLeftBound.x(), lb.x())); - leftBoundWrapped = lb; - srcOrigin_ = p.mapProjectionToGeo(p.unwrapMapProjection(lb)); - } else { - clippedPaths.append(wrappedPath); - } - - // 3) - QDoubleVector2D origin = p.wrappedMapProjectionToItemPosition(leftBoundWrapped); - for (const QList<QDoubleVector2D> &path: clippedPaths) { - QDoubleVector2D lastAddedPoint; - for (qsizetype i = 0; i < path.size(); ++i) { - QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(path.at(i)); - point = point - origin; // (0,0) if point == geoLeftBound_ - - if (i == 0) { - srcPath_.moveTo(point.toPointF()); - lastAddedPoint = point; - } else { - if ((point - lastAddedPoint).manhattanLength() > 3 || - i == path.size() - 1) { - srcPath_.lineTo(point.toPointF()); - lastAddedPoint = point; - } - } - } - srcPath_.closeSubpath(); - } - - if (!assumeSimple_) - srcPath_ = srcPath_.simplified(); - - sourceBounds_ = srcPath_.boundingRect(); -} - -/*! - \internal -*/ -void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map, qreal strokeWidth) -{ - if (!screenDirty_) - return; - - if (map.viewportWidth() == 0 || map.viewportHeight() == 0) { - clear(); - return; - } - - // The geometry has already been clipped against the visible region projection in wrapped mercator space. - QPainterPath ppi = srcPath_; - clear(); - - // a polygon requires at least 3 points; - if (ppi.elementCount() < 3) - return; - - // 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; - - 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 (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 = qt_mapbox::earcut<N>(polygon); - for (const auto &i: indices) - screenIndices_ << quint32(i); - } - - screenBounds_ = ppi.boundingRect(); - if (strokeWidth != 0.0) - this->translate(QPointF(strokeWidth, strokeWidth)); -} - -QGeoMapPolygonGeometryOpenGL::QGeoMapPolygonGeometryOpenGL() -{ -} - -void QGeoMapPolygonGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QList<QDoubleVector2D> &path) -{ - QList<QGeoCoordinate> geopath; - for (const auto &c: path) - geopath.append(QWebMercator::mercatorToCoord(c)); - updateSourcePoints(map, geopath); -} - -// wrapPath always preserves the geometry -// This one handles holes -static void wrapPath(const QGeoPolygon &poly - ,const QGeoCoordinate &geoLeftBound - ,const QGeoProjectionWebMercator &p - ,QList<QList<QDoubleVector2D> > &wrappedPaths - ,QDoubleVector2D *leftBoundWrapped = nullptr) -{ - QList<QList<QDoubleVector2D> > paths; - for (qsizetype i = 0; i < 1 + poly.holesCount(); ++i) { - QList<QDoubleVector2D> path; - if (!i) { - for (const QGeoCoordinate &c : poly.perimeter()) - path << p.geoToMapProjection(c); - } else { - for (const QGeoCoordinate &c : poly.holePath(i-1)) - path << p.geoToMapProjection(c); - } - paths.append(path); - } - - const QDoubleVector2D leftBound = p.geoToMapProjection(geoLeftBound); - wrappedPaths.clear(); - - QList<QDoubleVector2D> wrappedPath; - // compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0 - for (const auto &path : paths) { - wrappedPath.clear(); - for (QDoubleVector2D coord : path) { - // We can get NaN if the map isn't set up correctly, or the projection - // is faulty -- probably best thing to do is abort - if (!qIsFinite(coord.x()) || !qIsFinite(coord.y())) { - wrappedPaths.clear(); - return; - } - - const bool isPointLessThanUnwrapBelowX = (coord.x() < leftBound.x()); - // unwrap x to preserve geometry if moved to border of map - if (isPointLessThanUnwrapBelowX) - coord.setX(coord.x() + 1.0); - wrappedPath.append(coord); - } - wrappedPaths.append(wrappedPath); - } - - if (leftBoundWrapped) - *leftBoundWrapped = leftBound; -} - -static void cutPathEars(const QList<QList<QDoubleVector2D>> &wrappedPaths, - QList<QDeclarativeGeoMapItemUtils::vec2> &screenVertices, - QList<quint32> &screenIndices) -{ - using Coord = double; - using N = uint32_t; - using Point = std::array<Coord, 2>; - screenVertices.clear(); - screenIndices.clear(); - - std::vector<std::vector<Point>> polygon; - std::vector<Point> poly; - - for (const QList<QDoubleVector2D> &wrappedPath: wrappedPaths) { - poly.clear(); - for (const QDoubleVector2D &v: wrappedPath) { - screenVertices << v; - Point pt = {{ v.x(), v.y() }}; - poly.push_back( pt ); - } - polygon.push_back(poly); - } - - std::vector<N> indices = qt_mapbox::earcut<N>(polygon); - - for (const auto &i: indices) - screenIndices << quint32(i); -} - -static void cutPathEars(const QList<QDoubleVector2D> &wrappedPath, - QList<QDeclarativeGeoMapItemUtils::vec2> &screenVertices, - QList<quint32> &screenIndices) -{ - using Coord = double; - using N = uint32_t; - using Point = std::array<Coord, 2>; - screenVertices.clear(); - screenIndices.clear(); - - std::vector<std::vector<Point>> polygon; - std::vector<Point> poly; - - for (const QDoubleVector2D &v: wrappedPath) { - screenVertices << v; - Point pt = {{ v.x(), v.y() }}; - poly.push_back( pt ); - } - polygon.push_back(poly); - - std::vector<N> indices = qt_mapbox::earcut<N>(polygon); - - for (const auto &i: indices) - screenIndices << quint32(i); -} - -/*! - \internal -*/ -// This one does only a perimeter -void QGeoMapPolygonGeometryOpenGL::updateSourcePoints(const QGeoMap &map, - const QList<QGeoCoordinate> &perimeter) -{ - if (!sourceDirty_) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - - // build the actual path - // The approach is the same as described in QGeoMapPolylineGeometry::updateSourcePoints - srcOrigin_ = geoLeftBound_; - - QDoubleVector2D leftBoundWrapped; - // 1) pre-compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0 - QList<QDoubleVector2D> wrappedPath; - QDeclarativeGeoMapItemUtils::wrapPath(perimeter, geoLeftBound_, p, - wrappedPath, &leftBoundWrapped); - - // 1.1) do the same for the bbox - QList<QDoubleVector2D> wrappedBbox, wrappedBboxPlus1, wrappedBboxMinus1; - QGeoPolygon bbox(QGeoPath(perimeter).boundingGeoRectangle()); - QDeclarativeGeoMapItemUtils::wrapPath(bbox.perimeter(), bbox.boundingGeoRectangle().topLeft(), p, - wrappedBbox, wrappedBboxMinus1, wrappedBboxPlus1, &m_bboxLeftBoundWrapped); - - // 2) Store the triangulated polygon, and the wrapped bbox paths. - // the triangulations can be used as they are, as they "bypass" the QtQuick display chain - // the bbox wraps have to be however clipped, and then projected, in order to figure out the geometry. - // Note that this might still cause the geometryChange method to fail under some extreme conditions. - cutPathEars(wrappedPath, m_screenVertices, m_screenIndices); - - m_wrappedPolygons.resize(3); - m_wrappedPolygons[0].wrappedBboxes = wrappedBboxMinus1; - m_wrappedPolygons[1].wrappedBboxes = wrappedBbox; - m_wrappedPolygons[2].wrappedBboxes = wrappedBboxPlus1; -} - -// This one handles whole QGeoPolygon w. holes -void QGeoMapPolygonGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QGeoPolygon &poly) -{ - if (!sourceDirty_) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - - // build the actual path - // The approach is the same as described in QGeoMapPolylineGeometry::updateSourcePoints - srcOrigin_ = geoLeftBound_; - - QDoubleVector2D leftBoundWrapped; - QList<QList<QDoubleVector2D>> wrappedPath; - // 1) pre-compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0 - wrapPath(poly, geoLeftBound_, p, - wrappedPath, &leftBoundWrapped); - - // 1.1) do the same for the bbox - QList<QDoubleVector2D> wrappedBbox, wrappedBboxPlus1, wrappedBboxMinus1; - QGeoPolygon bbox(poly.boundingGeoRectangle()); - QDeclarativeGeoMapItemUtils::wrapPath(bbox.perimeter(), bbox.boundingGeoRectangle().topLeft(), p, - wrappedBbox, wrappedBboxMinus1, wrappedBboxPlus1, &m_bboxLeftBoundWrapped); - - // 2) Store the triangulated polygon, and the wrapped bbox paths. - // the triangulations can be used as they are, as they "bypass" the QtQuick display chain - // the bbox wraps have to be however clipped, and then projected, in order to figure out the geometry. - // Note that this might still cause the geometryChange method to fail under some extreme conditions. - cutPathEars(wrappedPath, m_screenVertices, m_screenIndices); - m_wrappedPolygons.resize(3); - m_wrappedPolygons[0].wrappedBboxes = wrappedBboxMinus1; - m_wrappedPolygons[1].wrappedBboxes = wrappedBbox; - m_wrappedPolygons[2].wrappedBboxes = wrappedBboxPlus1; -} - -void QGeoMapPolygonGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QGeoRectangle &rect) -{ - if (!sourceDirty_) - return; - const QList<QGeoCoordinate> perimeter = QDeclarativeRectangleMapItemPrivateCPU::path(rect); - updateSourcePoints(map, perimeter); -} - -/*! - \internal -*/ -void QGeoMapPolygonGeometryOpenGL::updateScreenPoints(const QGeoMap &map, qreal strokeWidth , const QColor &strokeColor) -{ - if (map.viewportWidth() == 0 || map.viewportHeight() == 0) { - clear(); - return; - } - - // 1) identify which set to use: std, +1 or -1 - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - const QDoubleVector2D leftBoundMercator = p.geoToMapProjection(srcOrigin_); - m_wrapOffset = p.projectionWrapFactor(leftBoundMercator) + 1; // +1 to get the offset into QLists - - // 1.1) select geometry set - // This could theoretically be skipped for those polygons whose bbox is not even projectable. - // However, such optimization could only be introduced if not calculating bboxes lazily. - // Hence not doing it. - if (sourceDirty_) { - m_dataChanged = true; - } - - if (strokeWidth == 0.0 || strokeColor.alpha() == 0) // or else the geometry of the border is used, so no point in calculating 2 of them - updateQuickGeometry(p, strokeWidth); -} - -void QGeoMapPolygonGeometryOpenGL::updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal /*strokeWidth*/) -{ - // 2) clip bbox - // BBox handling -- this is related to the bounding box geometry - // that has to inevitably follow the old projection codepath - // As it needs to provide projected coordinates for QtQuick interaction. - // This could be futher optimized to be updated in a lazy fashion. - const QList<QDoubleVector2D> &wrappedBbox = m_wrappedPolygons.at(m_wrapOffset).wrappedBboxes; - QList<QList<QDoubleVector2D> > clippedBbox; - QDoubleVector2D bboxLeftBoundWrapped = m_bboxLeftBoundWrapped; - bboxLeftBoundWrapped.setX(bboxLeftBoundWrapped.x() + double(m_wrapOffset - 1)); - QDeclarativeGeoMapItemUtils::clipPolygon(wrappedBbox, p, clippedBbox, &bboxLeftBoundWrapped); - - // 3) project bbox - QPainterPath ppi; - if (!clippedBbox.size() || clippedBbox.first().size() < 3) { - sourceBounds_ = screenBounds_ = QRectF(); - firstPointOffset_ = QPointF(); - screenOutline_ = ppi; - return; - } - - QDeclarativeGeoMapItemUtils::projectBbox(clippedBbox.first(), p, ppi); // Using first because a clipped box should always result in one polygon - const QRectF brect = ppi.boundingRect(); - firstPointOffset_ = QPointF(brect.topLeft()); - screenOutline_ = ppi; - - // 4) Set Screen bbox - screenBounds_ = brect; - sourceBounds_.setX(0); - sourceBounds_.setY(0); - sourceBounds_.setWidth(brect.width()); - sourceBounds_.setHeight(brect.height()); -} -/* - * QDeclarativePolygonMapItem Private Implementations - */ - -QDeclarativePolygonMapItemPrivate::~QDeclarativePolygonMapItemPrivate() {} - -QDeclarativePolygonMapItemPrivateCPU::~QDeclarativePolygonMapItemPrivateCPU() {} - -QDeclarativePolygonMapItemPrivateOpenGL::~QDeclarativePolygonMapItemPrivateOpenGL() {} -/* - * QDeclarativePolygonMapItem Implementation - */ - -struct PolygonBackendSelector -{ - PolygonBackendSelector() - { - backend = (qgetenv("QTLOCATION_OPENGL_ITEMS").toInt()) ? QDeclarativePolygonMapItem::OpenGL : QDeclarativePolygonMapItem::Software; - } - QDeclarativePolygonMapItem::Backend backend = QDeclarativePolygonMapItem::Software; -}; - -Q_GLOBAL_STATIC(PolygonBackendSelector, mapPolygonBackendSelector) - -QDeclarativePolygonMapItem::QDeclarativePolygonMapItem(QQuickItem *parent) -: QDeclarativeGeoMapItemBase(parent), m_border(this), m_color(Qt::transparent), m_dirtyMaterial(true), - m_updatingGeometry(false) - , m_d(new QDeclarativePolygonMapItemPrivateCPU(*this)) - -{ - // ToDo: handle envvar, and switch implementation. - m_itemType = QGeoMap::MapPolygon; - m_geopoly = QGeoPolygonEager(); - setFlag(ItemHasContents, true); - // ToDo: fix this, only flag material? - QObject::connect(&m_border, &QDeclarativeMapLineProperties::colorChanged, - this, &QDeclarativePolygonMapItem::onLinePropertiesChanged); - QObject::connect(&m_border, &QDeclarativeMapLineProperties::widthChanged, - this, &QDeclarativePolygonMapItem::onLinePropertiesChanged); - setBackend(mapPolygonBackendSelector->backend); -} - -QDeclarativePolygonMapItem::~QDeclarativePolygonMapItem() -{ -} - -/*! - \qmlpropertygroup Location::MapPolygon::border - \qmlproperty int MapPolygon::border.width - \qmlproperty color MapPolygon::border.color - - This property is part of the border property group. The border property - group holds the width and color used to draw the border of the polygon. - - The width is in pixels and is independent of the zoom level of the map. - - The default values correspond to a black border with a width of 1 pixel. - For no line, use a width of 0 or a transparent color. -*/ - -QDeclarativeMapLineProperties *QDeclarativePolygonMapItem::border() -{ - return &m_border; -} - -/*! - \qmlproperty MapPolygon.Backend QtLocation::MapPolygon::backend - - This property holds which backend is in use to render the map item. - Valid values are \b MapPolygon.Software and \b{MapPolygon.OpenGL}. - The default value is \b{MapPolygon.Software}. - - \note \b{The release of this API with Qt 5.15 is a Technology Preview}. - Ideally, as the OpenGL backends for map items mature, there will be - no more need to also offer the legacy software-projection backend. - So this property will likely disappear at some later point. - To select OpenGL-accelerated item backends without using this property, - it is also possible to set the environment variable \b QTLOCATION_OPENGL_ITEMS - to \b{1}. - Also note that all current OpenGL backends won't work as expected when enabling - layers on the individual item, or when running on OpenGL core profiles greater than 2.x. - - \since 5.15 -*/ -QDeclarativePolygonMapItem::Backend QDeclarativePolygonMapItem::backend() const -{ - return m_backend; -} - -void QDeclarativePolygonMapItem::setBackend(QDeclarativePolygonMapItem::Backend b) -{ - if (b == m_backend) - return; - m_backend = b; - std::unique_ptr<QDeclarativePolygonMapItemPrivate> d( - (m_backend == Software) ? static_cast<QDeclarativePolygonMapItemPrivate *>( - new QDeclarativePolygonMapItemPrivateCPU(*this)) - : static_cast<QDeclarativePolygonMapItemPrivate *>( - new QDeclarativePolygonMapItemPrivateOpenGL(*this))); - std::swap(m_d, d); - m_d->onGeoGeometryChanged(); - emit backendChanged(); -} - -/*! - \internal -*/ -void QDeclarativePolygonMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) -{ - QDeclarativeGeoMapItemBase::setMap(quickMap,map); - if (map) - m_d->onMapSet(); -} - -/*! - \qmlproperty list<coordinate> MapPolygon::path - - This property holds the ordered list of coordinates which - define the polygon. - Having less than 3 different coordinates in the path results in undefined behavior. - - \sa addCoordinate, removeCoordinate -*/ -QList<QGeoCoordinate> QDeclarativePolygonMapItem::path() const -{ - return m_geopoly.perimeter(); -} - -void QDeclarativePolygonMapItem::setPath(const QList<QGeoCoordinate> &path) -{ - // Equivalent to QDeclarativePolylineMapItem::setPathFromGeoList - if (m_geopoly.perimeter() == path) - return; - - m_geopoly.setPerimeter(path); - - m_d->onGeoGeometryChanged(); - emit pathChanged(); -} - -/*! - \qmlmethod void MapPolygon::addCoordinate(coordinate) - - Adds the specified \a coordinate to the path. - - \sa removeCoordinate, path -*/ - -void QDeclarativePolygonMapItem::addCoordinate(const QGeoCoordinate &coordinate) -{ - if (!coordinate.isValid()) - return; - - m_geopoly.addCoordinate(coordinate); - m_d->onGeoGeometryUpdated(); - emit pathChanged(); -} - -/*! - \qmlmethod void MapPolygon::removeCoordinate(coordinate) - - Removes \a coordinate from the path. If there are multiple instances of the - same coordinate, the one added last is removed. - - If \a coordinate is not in the path this method does nothing. - - \sa addCoordinate, path -*/ -void QDeclarativePolygonMapItem::removeCoordinate(const QGeoCoordinate &coordinate) -{ - int length = m_geopoly.perimeter().length(); - m_geopoly.removeCoordinate(coordinate); - if (m_geopoly.perimeter().length() == length) - return; - - m_d->onGeoGeometryChanged(); - emit pathChanged(); -} - -/*! - \qmlproperty color MapPolygon::color - - This property holds the color used to fill the polygon. - - The default value is transparent. -*/ - -QColor QDeclarativePolygonMapItem::color() const -{ - return m_color; -} - -void QDeclarativePolygonMapItem::setColor(const QColor &color) -{ - if (m_color == color) - return; - - m_color = color; - m_dirtyMaterial = true; - polishAndUpdate(); // in case color was transparent and now is not or vice versa - emit colorChanged(m_color); -} - -/*! - \internal -*/ -QSGNode *QDeclarativePolygonMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) -{ - return m_d->updateMapItemPaintNode(oldNode, data); -} - -/*! - \internal -*/ -void QDeclarativePolygonMapItem::updatePolish() -{ - if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) - return; - m_d->updatePolish(); -} - -void QDeclarativePolygonMapItem::setMaterialDirty() -{ - m_dirtyMaterial = true; - update(); -} - -void QDeclarativePolygonMapItem::markSourceDirtyAndUpdate() -{ - m_d->markSourceDirtyAndUpdate(); -} - -void QDeclarativePolygonMapItem::onLinePropertiesChanged() -{ - m_d->onLinePropertiesChanged(); -} - -/*! - \internal -*/ -void QDeclarativePolygonMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event) -{ - if (event.mapSize.isEmpty()) - return; - - m_d->afterViewportChanged(); -} - -/*! - \internal -*/ -bool QDeclarativePolygonMapItem::contains(const QPointF &point) const -{ - return m_d->contains(point); -} - -const QGeoShape &QDeclarativePolygonMapItem::geoShape() const -{ - return m_geopoly; -} - -void QDeclarativePolygonMapItem::setGeoShape(const QGeoShape &shape) -{ - if (shape == m_geopoly) - return; - - m_geopoly = QGeoPolygonEager(shape); - m_d->onGeoGeometryChanged(); - emit pathChanged(); -} - -/*! - \internal -*/ -void QDeclarativePolygonMapItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - if (newGeometry.topLeft() == oldGeometry.topLeft() || !map() || !m_geopoly.isValid() || m_updatingGeometry) { - QDeclarativeGeoMapItemBase::geometryChange(newGeometry, oldGeometry); - return; - } - // TODO: change the algorithm to preserve the distances and size! - QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false); - QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false); - if (!newCenter.isValid() || !oldCenter.isValid()) - return; - double offsetLongi = newCenter.longitude() - oldCenter.longitude(); - double offsetLati = newCenter.latitude() - oldCenter.latitude(); - if (offsetLati == 0.0 && offsetLongi == 0.0) - return; - - m_geopoly.translate(offsetLati, offsetLongi); - m_d->onGeoGeometryChanged(); - emit pathChanged(); - - // Not calling QDeclarativeGeoMapItemBase::geometryChange() as it will be called from a nested - // call to this function. -} - -////////////////////////////////////////////////////////////////////// - -QSGMaterialShader *MapPolygonMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const -{ - Q_UNUSED(renderMode); - return new MapPolygonShader(); -} - -int MapPolygonMaterial::compare(const QSGMaterial *other) const -{ - const MapPolygonMaterial &o = *static_cast<const MapPolygonMaterial *>(other); - if (o.m_center == m_center && o.m_geoProjection == m_geoProjection && o.m_wrapOffset == m_wrapOffset) - return QSGFlatColorMaterial::compare(other); - return -1; -} - -QSGMaterialType *MapPolygonMaterial::type() const -{ - static QSGMaterialType type; - return &type; -} - -MapPolygonNode::MapPolygonNode() - : border_(new MapPolylineNode()), - geometry_(QSGGeometry::defaultAttributes_Point2D(), 0) -{ - geometry_.setDrawingMode(QSGGeometry::DrawTriangles); - QSGGeometryNode::setMaterial(&fill_material_); - QSGGeometryNode::setGeometry(&geometry_); - - appendChildNode(border_); -} - -MapPolygonNode::~MapPolygonNode() -{ -} - -/*! - \internal -*/ -void MapPolygonNode::update(const QColor &fillColor, const QColor &borderColor, - const QGeoMapItemGeometry *fillShape, - const QGeoMapItemGeometry *borderShape) -{ - /* Do the border update first */ - border_->update(borderColor, borderShape); - - /* If we have neither fill nor border with valid points, block the whole - * tree. We can't just block the fill without blocking the border too, so - * we're a little conservative here (maybe at the expense of rendering - * accuracy) */ - if (fillShape->size() == 0 && borderShape->size() == 0) { - setSubtreeBlocked(true); - return; - } - setSubtreeBlocked(false); - - - // TODO: do this only if the geometry has changed!! - // No need to do this every frame. - // Then benchmark the difference! - QSGGeometry *fill = QSGGeometryNode::geometry(); - fillShape->allocateAndFill(fill); - markDirty(DirtyGeometry); - - if (fillColor != fill_material_.color()) { - fill_material_.setColor(fillColor); - setMaterial(&fill_material_); - markDirty(DirtyMaterial); - } -} - -MapPolygonNodeGL::MapPolygonNodeGL() : - //fill_material_(this), - fill_material_(), - geometry_(QSGGeometry::defaultAttributes_Point2D(), 0) -{ - geometry_.setDrawingMode(QSGGeometry::DrawTriangles); - QSGGeometryNode::setMaterial(&fill_material_); - QSGGeometryNode::setGeometry(&geometry_); -} - -MapPolygonNodeGL::~MapPolygonNodeGL() -{ -} - -/*! - \internal -*/ -void MapPolygonNodeGL::update(const QColor &fillColor, - const QGeoMapPolygonGeometryOpenGL *fillShape, - const QMatrix4x4 &geoProjection, - const QDoubleVector3D ¢er) -{ - if (fillShape->m_screenIndices.size() < 3 || fillColor.alpha() == 0) { - setSubtreeBlocked(true); - return; - } - setSubtreeBlocked(false); - - QSGGeometry *fill = QSGGeometryNode::geometry(); - if (fillShape->m_dataChanged || !fill->vertexCount()) { - fillShape->allocateAndFillPolygon(fill); - markDirty(DirtyGeometry); - fillShape->m_dataChanged = false; - } - - //if (fillColor != fill_material_.color()) // Any point in optimizing this? - { - fill_material_.setColor(fillColor); - fill_material_.setGeoProjection(geoProjection); - fill_material_.setCenter(center); - fill_material_.setWrapOffset(fillShape->m_wrapOffset - 1); - setMaterial(&fill_material_); - markDirty(DirtyMaterial); - } -} - -MapPolygonShader::MapPolygonShader() : QSGMaterialShader(*new QSGMaterialShaderPrivate(this)) -{ - setShaderFileName(VertexStage, QLatin1String(":/location/declarativemaps/declarativemaps/shaders/polygon.vert.qsb")); - setShaderFileName(FragmentStage, QLatin1String(":/location/declarativemaps/declarativemaps/shaders/polygon.frag.qsb")); -} - -bool MapPolygonShader::updateUniformData(RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) -{ - Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); - MapPolygonMaterial *oldMaterial = static_cast<MapPolygonMaterial *>(oldEffect); - MapPolygonMaterial *newMaterial = static_cast<MapPolygonMaterial *>(newEffect); - - const QColor &c = newMaterial->color(); - const QMatrix4x4 &geoProjection = newMaterial->geoProjection(); - const QDoubleVector3D ¢er = newMaterial->center(); - - // It is safer to use vec4 instead on vec3, as described in: - // https://www.khronos.org/opengl/wiki/Interface_Block_(GLSL)#Memory_layout - QVector4D vecCenter, vecCenter_lowpart; - for (int i = 0; i < 3; i++) - QLocationUtils::split_double(center.get(i), &vecCenter[i], &vecCenter_lowpart[i]); - vecCenter[3] = 0; - vecCenter_lowpart[3] = 0; - - int offset = 0; - char *buf_p = state.uniformData()->data(); - - if (state.isMatrixDirty()) { - const QMatrix4x4 m = state.projectionMatrix(); - memcpy(buf_p + offset, m.constData(), 4*4*4); - } - offset += 4*4*4; - - memcpy(buf_p + offset, geoProjection.constData(), 4*4*4); offset+=4*4*4; - - memcpy(buf_p + offset, &vecCenter, 4*4); offset += 4*4; - - memcpy(buf_p + offset, &vecCenter_lowpart, 4*4); offset+=4*4; - - const float wrapOffset = newMaterial->wrapOffset(); - memcpy(buf_p + offset, &wrapOffset, 4); offset+=4; - - offset += 4+4+4; // Padding - - if (oldMaterial == nullptr || c != oldMaterial->color() || state.isOpacityDirty()) { - float opacity = state.opacity() * c.alphaF(); - QVector4D v(c.redF() * opacity, - c.greenF() * opacity, - c.blueF() * opacity, - opacity); - memcpy(buf_p + offset, &v, 4*4); - } - offset+=4*4; - - return true; -} -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h b/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h deleted file mode 100644 index d388c007..00000000 --- a/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEPOLYGONMAPITEM -#define QDECLARATIVEPOLYGONMAPITEM - -// -// 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 <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qdeclarativegeomapitembase_p.h> -#include <QtLocation/private/qdeclarativepolylinemapitem_p.h> -#include <QtPositioning/qgeopolygon.h> - -QT_BEGIN_NAMESPACE - -class QDeclarativePolygonMapItemPrivate; -class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItem : public QDeclarativeGeoMapItemBase -{ - Q_OBJECT - Q_ENUMS(Backend) - - Q_PROPERTY(QList<QGeoCoordinate> path READ path WRITE setPath NOTIFY pathChanged) - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) - Q_PROPERTY(QDeclarativeMapLineProperties *border READ border CONSTANT) - Q_PROPERTY(Backend backend READ backend WRITE setBackend NOTIFY backendChanged REVISION 15) - -public: - enum Backend { - Software = 0, - OpenGL = 1 - }; - - explicit QDeclarativePolygonMapItem(QQuickItem *parent = nullptr); - ~QDeclarativePolygonMapItem() override; - - void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) override; - //from QuickItem - QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) override; - - Q_INVOKABLE void addCoordinate(const QGeoCoordinate &coordinate); - Q_INVOKABLE void removeCoordinate(const QGeoCoordinate &coordinate); - - QList<QGeoCoordinate> path() const; - void setPath(const QList<QGeoCoordinate> &value); - - QColor color() const; - void setColor(const QColor &color); - - QDeclarativeMapLineProperties *border(); - - Backend backend() const; - void setBackend(Backend b); - - bool contains(const QPointF &point) const override; - const QGeoShape &geoShape() const override; - void setGeoShape(const QGeoShape &shape) override; - -Q_SIGNALS: - void pathChanged(); - void colorChanged(const QColor &color); - void backendChanged(); - -protected Q_SLOTS: - void markSourceDirtyAndUpdate(); - void onLinePropertiesChanged(); - void afterViewportChanged(const QGeoMapViewportChangeEvent &event) override; - -protected: - void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; - void updatePolish() override; - void setMaterialDirty() override; - -#ifdef QT_LOCATION_DEBUG -public: -#endif - QGeoPolygon m_geopoly; - QDeclarativeMapLineProperties m_border; - QColor m_color; - Backend m_backend = Software; - bool m_dirtyMaterial; -// bool m_dirtyGeometry = false; - bool m_updatingGeometry; - - std::unique_ptr<QDeclarativePolygonMapItemPrivate> m_d; - - friend class QDeclarativePolygonMapItemPrivate; - friend class QDeclarativePolygonMapItemPrivateCPU; - friend class QDeclarativePolygonMapItemPrivateOpenGL; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativePolygonMapItem) - -#endif /* QDECLARATIVEPOLYGONMAPITEM_H_ */ diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem_p_p.h b/src/location/declarativemaps/qdeclarativepolygonmapitem_p_p.h deleted file mode 100644 index cbea7971..00000000 --- a/src/location/declarativemaps/qdeclarativepolygonmapitem_p_p.h +++ /dev/null @@ -1,625 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com> -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEPOLYGONMAPITEM_P_P_H -#define QDECLARATIVEPOLYGONMAPITEM_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 <QList> -#include <QtCore/QScopedValueRollback> -#include <QtGui/QMatrix4x4> -#include <QColor> - -#include <QSGGeometryNode> -#include <QSGFlatColorMaterial> - -#include <QtPositioning/QGeoPath> -#include <QtPositioning/QGeoRectangle> -#include <QtPositioning/QGeoPolygon> - -#include <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qgeomapitemgeometry_p.h> -#include <QtLocation/private/qdeclarativegeomapitembase_p.h> -#include <QtLocation/private/qdeclarativepolylinemapitem_p.h> -#include <QtLocation/private/qdeclarativegeomapitemutils_p.h> -#include <QtLocation/private/qdeclarativepolygonmapitem_p.h> -#include <QtLocation/private/qdeclarativepolylinemapitem_p_p.h> -#include <QtPositioning/private/qdoublevector2d_p.h> - -QT_BEGIN_NAMESPACE - -class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolygonGeometry : public QGeoMapItemGeometry -{ -public: - QGeoMapPolygonGeometry(); - - inline void setAssumeSimple(bool value) { assumeSimple_ = value; } - - void updateSourcePoints(const QGeoMap &map, - const QList<QDoubleVector2D> &path); - - void updateScreenPoints(const QGeoMap &map, qreal strokeWidth = 0.0); - -protected: - QPainterPath srcPath_; - bool assumeSimple_ = false; -}; - -class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolygonGeometryOpenGL : public QGeoMapItemGeometry -{ -public: - typedef struct { - QList<QDoubleVector2D> wrappedBboxes; - } WrappedPolygon; - QGeoMapPolygonGeometryOpenGL(); - ~QGeoMapPolygonGeometryOpenGL() override {} - - // Temporary method for compatibility in MapCircleObject. Remove when MapObjects are ported. - void updateSourcePoints(const QGeoMap &map, - const QList<QDoubleVector2D> &path); - - void updateSourcePoints(const QGeoMap &map, - const QList<QGeoCoordinate> &perimeter); - - void updateSourcePoints(const QGeoMap &map, - const QGeoPolygon &poly); - - void updateSourcePoints(const QGeoMap &map, - const QGeoRectangle &rect); - - void updateScreenPoints(const QGeoMap &map, qreal strokeWidth = 0.0, const QColor &strokeColor = Qt::transparent); - void updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal strokeWidth = 0.0); - - void allocateAndFillPolygon(QSGGeometry *geom) const - { - - const QList<QDeclarativeGeoMapItemUtils::vec2> &vx = m_screenVertices; - const QList<quint32> &ix = m_screenIndices; - - geom->allocate(vx.size(), ix.size()); - if (geom->indexType() == QSGGeometry::UnsignedShortType) { - quint16 *its = geom->indexDataAsUShort(); - for (qsizetype i = 0; i < ix.size(); ++i) - its[i] = ix[i]; - } else if (geom->indexType() == QSGGeometry::UnsignedIntType) { - quint32 *its = geom->indexDataAsUInt(); - for (qsizetype i = 0; i < ix.size(); ++i) - its[i] = ix[i]; - } - - QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D(); - for (qsizetype i = 0; i < vx.size(); ++i) - pts[i].set(vx[i].x, vx[i].y); - } - - QList<QDeclarativeGeoMapItemUtils::vec2> m_screenVertices; - QList<quint32> m_screenIndices; - QDoubleVector2D m_bboxLeftBoundWrapped; - QList<WrappedPolygon> m_wrappedPolygons; - int m_wrapOffset = 0; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolygonShader : public QSGMaterialShader -{ -public: - MapPolygonShader(); - - bool updateUniformData(RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolygonMaterial : public QSGFlatColorMaterial -{ -public: - MapPolygonMaterial() - : QSGFlatColorMaterial() - { - // Passing RequiresFullMatrix is essential in order to prevent the - // batch renderer from baking in simple, translate-only transforms into - // the vertex data. The shader will rely on the fact that - // vertexCoord.xy is the Shape-space coordinate and so no modifications - // are welcome. - setFlag(Blending | RequiresFullMatrix); - } - - QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override; - - void setGeoProjection(const QMatrix4x4 &p) - { - m_geoProjection = p; - } - - QMatrix4x4 geoProjection() const - { - return m_geoProjection; - } - - void setCenter(const QDoubleVector3D &c) - { - m_center = c; - } - - QDoubleVector3D center() const - { - return m_center; - } - - int wrapOffset() const - { - return m_wrapOffset; - } - - void setWrapOffset(int wrapOffset) - { - m_wrapOffset = wrapOffset; - } - - int compare(const QSGMaterial *other) const override; - QSGMaterialType *type() const override; - -protected: - QMatrix4x4 m_geoProjection; - QDoubleVector3D m_center; - int m_wrapOffset = 0; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolygonNode : public MapItemGeometryNode -{ - -public: - MapPolygonNode(); - ~MapPolygonNode() override; - - void update(const QColor &fillColor, const QColor &borderColor, - const QGeoMapItemGeometry *fillShape, - const QGeoMapItemGeometry *borderShape); -private: - QSGFlatColorMaterial fill_material_; - MapPolylineNode *border_; - QSGGeometry geometry_; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolygonNodeGL : public MapItemGeometryNode -{ - -public: - MapPolygonNodeGL(); - ~MapPolygonNodeGL() override; - - void update(const QColor &fillColor, - const QGeoMapPolygonGeometryOpenGL *fillShape, - const QMatrix4x4 &geoProjection, - const QDoubleVector3D ¢er); - - MapPolygonMaterial fill_material_; - QSGGeometry geometry_; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivate -{ -public: - QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItem &polygon) : m_poly(polygon) - { - - } - QDeclarativePolygonMapItemPrivate(QDeclarativePolygonMapItemPrivate &other) : m_poly(other.m_poly) - { - } - - virtual ~QDeclarativePolygonMapItemPrivate(); - virtual void onLinePropertiesChanged() = 0; - virtual void markSourceDirtyAndUpdate() = 0; - virtual void onMapSet() = 0; - virtual void onGeoGeometryChanged() = 0; - virtual void onGeoGeometryUpdated() = 0; - virtual void onItemGeometryChanged() = 0; - virtual void updatePolish() = 0; - virtual void afterViewportChanged() = 0; - virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0; - virtual bool contains(const QPointF &point) const = 0; - - QDeclarativePolygonMapItem &m_poly; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivateCPU: public QDeclarativePolygonMapItemPrivate -{ -public: - QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItem &polygon) - : QDeclarativePolygonMapItemPrivate(polygon) - { - } - - QDeclarativePolygonMapItemPrivateCPU(QDeclarativePolygonMapItemPrivate &other) - : QDeclarativePolygonMapItemPrivate(other) - { - } - - ~QDeclarativePolygonMapItemPrivateCPU() override; - void onLinePropertiesChanged() override - { - // mark dirty just in case we're a width change - markSourceDirtyAndUpdate(); - } - void markSourceDirtyAndUpdate() override - { - // preserveGeometry is cleared in updateMapItemPaintNode - m_geometry.markSourceDirty(); - m_borderGeometry.markSourceDirty(); - m_poly.polishAndUpdate(); - } - void regenerateCache() - { - if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()); - m_geopathProjected.clear(); - m_geopathProjected.reserve(m_poly.m_geopoly.size()); - for (const QGeoCoordinate &c : m_poly.m_geopoly.perimeter()) - m_geopathProjected << p.geoToMapProjection(c); - } - void updateCache() - { - if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()); - m_geopathProjected << p.geoToMapProjection(m_poly.m_geopoly.perimeter().last()); - } - void preserveGeometry() - { - m_geometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); - m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); - } - void afterViewportChanged() override - { - // preserveGeometry is cleared in updateMapItemPaintNode - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onMapSet() override - { - regenerateCache(); - markSourceDirtyAndUpdate(); - } - void onGeoGeometryChanged() override - { - regenerateCache(); - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onGeoGeometryUpdated() override - { - updateCache(); - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onItemGeometryChanged() override - { - onGeoGeometryChanged(); - } - void updatePolish() override - { - if (m_poly.m_geopoly.perimeter().length() == 0) { // Possibly cleared - m_geometry.clear(); - m_borderGeometry.clear(); - m_poly.setWidth(0); - m_poly.setHeight(0); - return; - } - const QGeoMap *map = m_poly.map(); - const qreal borderWidth = m_poly.m_border.width(); - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map->geoProjection()); - QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry); - m_poly.m_updatingGeometry = true; - - m_geometry.updateSourcePoints(*map, m_geopathProjected); - m_geometry.updateScreenPoints(*map, borderWidth); - - QList<QGeoMapItemGeometry *> geoms; - geoms << &m_geometry; - m_borderGeometry.clear(); - - if (m_poly.m_border.color().alpha() != 0 && borderWidth > 0) { - QList<QDoubleVector2D> closedPath = m_geopathProjected; - closedPath << closedPath.first(); - - m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); - - const QGeoCoordinate &geometryOrigin = m_geometry.origin(); - - m_borderGeometry.srcPoints_.clear(); - m_borderGeometry.srcPointTypes_.clear(); - - QDoubleVector2D borderLeftBoundWrapped; - QList<QList<QDoubleVector2D > > clippedPaths = m_borderGeometry.clipPath(*map, closedPath, borderLeftBoundWrapped); - if (clippedPaths.size()) { - borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin); - m_borderGeometry.pathToScreen(*map, clippedPaths, borderLeftBoundWrapped); - m_borderGeometry.updateScreenPoints(*map, borderWidth); - - geoms << &m_borderGeometry; - } else { - m_borderGeometry.clear(); - } - } - - QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms); - m_poly.setWidth(combined.width() + 2 * borderWidth); - m_poly.setHeight(combined.height() + 2 * borderWidth); - - m_poly.setPositionOnMap(m_geometry.origin(), -1 * m_geometry.sourceBoundingBox().topLeft() - + QPointF(borderWidth, borderWidth)); - } - QSGNode *updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override - { - Q_UNUSED(data); - if (!m_node || !oldNode) { - m_node = new MapPolygonNode(); - if (oldNode) { - delete oldNode; - oldNode = nullptr; - } - } else { - m_node = static_cast<MapPolygonNode *>(oldNode); - } - - //TODO: update only material - if (m_geometry.isScreenDirty() - || m_borderGeometry.isScreenDirty() - || m_poly.m_dirtyMaterial - || !oldNode) { - m_node->update(m_poly.m_color, - m_poly.m_border.color(), - &m_geometry, - &m_borderGeometry); - m_geometry.setPreserveGeometry(false); - m_borderGeometry.setPreserveGeometry(false); - m_geometry.markClean(); - m_borderGeometry.markClean(); - m_poly.m_dirtyMaterial = false; - } - return m_node; - } - bool contains(const QPointF &point) const override - { - return (m_geometry.contains(point) || m_borderGeometry.contains(point)); - } - - QList<QDoubleVector2D> m_geopathProjected; - QGeoMapPolygonGeometry m_geometry; - QGeoMapPolylineGeometry m_borderGeometry; - MapPolygonNode *m_node = nullptr; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItemPrivateOpenGL: public QDeclarativePolygonMapItemPrivate -{ -public: - struct RootNode : public QSGNode /*QSGTransformNode*/, public VisibleNode - { - RootNode() { } - - bool isSubtreeBlocked() const override - { - return subtreeBlocked(); - } - }; - - QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItem &polygon) : QDeclarativePolygonMapItemPrivate(polygon) - { - } - - QDeclarativePolygonMapItemPrivateOpenGL(QDeclarativePolygonMapItemPrivate &other) - : QDeclarativePolygonMapItemPrivate(other) - { - } - - ~QDeclarativePolygonMapItemPrivateOpenGL() override; - - void markScreenDirtyAndUpdate() - { - // preserveGeometry is cleared in updateMapItemPaintNode - m_geometry.markScreenDirty(); - m_borderGeometry.markScreenDirty(); - m_poly.polishAndUpdate(); - } - void onLinePropertiesChanged() override - { - m_poly.m_dirtyMaterial = true; - afterViewportChanged(); - } - void markSourceDirtyAndUpdate() override - { - // preserveGeometry is cleared in updateMapItemPaintNode - m_geometry.markSourceDirty(); - m_borderGeometry.markSourceDirty(); - m_poly.polishAndUpdate(); - } - void preserveGeometry() - { - m_geometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); - m_borderGeometry.setPreserveGeometry(true, m_poly.m_geopoly.boundingGeoRectangle().topLeft()); - } - void afterViewportChanged() override // This is called when the camera changes, or visibleArea changes. - { - // preserveGeometry is cleared in updateMapItemPaintNode - preserveGeometry(); - markScreenDirtyAndUpdate(); - } - void onMapSet() override - { - markSourceDirtyAndUpdate(); - } - void onGeoGeometryChanged() override - { - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onGeoGeometryUpdated() override - { - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onItemGeometryChanged() override - { - onGeoGeometryChanged(); - } - void updatePolish() override - { - if (m_poly.m_geopoly.perimeter().length() == 0) { // Possibly cleared - m_geometry.clear(); - m_borderGeometry.clear(); - m_poly.setWidth(0); - m_poly.setHeight(0); - return; - } - - QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry); - m_poly.m_updatingGeometry = true; - const qreal lineWidth = m_poly.m_border.width(); - const QColor &lineColor = m_poly.m_border.color(); - const QColor &fillColor = m_poly.color(); - if (fillColor.alpha() != 0) { - m_geometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopoly); - m_geometry.markScreenDirty(); - m_geometry.updateScreenPoints(*m_poly.map(), lineWidth, lineColor); - } else { - m_geometry.clearBounds(); - } - - QGeoMapItemGeometry * geom = &m_geometry; - m_borderGeometry.clearScreen(); - if (lineColor.alpha() != 0 && lineWidth > 0) { - m_borderGeometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopoly); - m_borderGeometry.markScreenDirty(); - m_borderGeometry.updateScreenPoints(*m_poly.map(), lineWidth); - geom = &m_borderGeometry; - } - m_poly.setWidth(geom->sourceBoundingBox().width()); - m_poly.setHeight(geom->sourceBoundingBox().height()); - m_poly.setPosition(1.0 * geom->firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5)); - } - QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override - { - Q_UNUSED(data); - - if (!m_rootNode || !oldNode) { - m_rootNode = new RootNode(); - m_node = new MapPolygonNodeGL(); - m_rootNode->appendChildNode(m_node); - m_polylinenode = new MapPolylineNodeOpenGLExtruded(); - m_rootNode->appendChildNode(m_polylinenode); - m_rootNode->markDirty(QSGNode::DirtyNodeAdded); - if (oldNode) - delete oldNode; - } else { - m_rootNode = static_cast<RootNode *>(oldNode); - } - - const QGeoMap *map = m_poly.map(); - const QMatrix4x4 &combinedMatrix = map->geoProjection().qsgTransform(); - const QDoubleVector3D &cameraCenter = map->geoProjection().centerMercator(); - - if (m_borderGeometry.isScreenDirty()) { - /* Do the border update first */ - m_polylinenode->update(m_poly.m_border.color(), - float(m_poly.m_border.width()), - &m_borderGeometry, - combinedMatrix, - cameraCenter, - Qt::SquareCap, - true, - 30); // No LOD for polygons just yet. - // First figure out what to do with holes. - m_borderGeometry.setPreserveGeometry(false); - m_borderGeometry.markClean(); - } else { - m_polylinenode->setSubtreeBlocked(true); - } - if (m_geometry.isScreenDirty()) { - m_node->update(m_poly.m_color, - &m_geometry, - combinedMatrix, - cameraCenter); - m_geometry.setPreserveGeometry(false); - m_geometry.markClean(); - } else { - m_node->setSubtreeBlocked(true); - } - - m_rootNode->setSubtreeBlocked(false); - return m_rootNode; - } - bool contains(const QPointF &point) const override - { - const qreal lineWidth = m_poly.m_border.width(); - const QColor &lineColor = m_poly.m_border.color(); - const QRectF &bounds = (lineColor.alpha() != 0 && lineWidth > 0) ? m_borderGeometry.sourceBoundingBox() : m_geometry.sourceBoundingBox(); - if (bounds.contains(point)) { - QDeclarativeGeoMap *m = m_poly.quickMap(); - if (m) { - const QGeoCoordinate crd = m->toCoordinate(m->mapFromItem(&m_poly, point)); - return m_poly.m_geopoly.contains(crd) || m_borderGeometry.contains(m_poly.mapToItem(m_poly.quickMap(), point), - m_poly.border()->width(), - static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection())); - } else { - return true; - } - } - return false; - } - - QGeoMapPolygonGeometryOpenGL m_geometry; - QGeoMapPolylineGeometryOpenGL m_borderGeometry; - RootNode *m_rootNode = nullptr; - MapPolygonNodeGL *m_node = nullptr; - MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr; -}; - -QT_END_NAMESPACE - -#endif // QDECLARATIVEPOLYGONMAPITEM_P_P_H diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp deleted file mode 100644 index 784e0146..00000000 --- a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp +++ /dev/null @@ -1,1975 +0,0 @@ -/**************************************************************************** - ** - ** Copyright (C) 2022 The Qt Company Ltd. - ** Contact: https://www.qt.io/licensing/ - ** - ** This file is part of the QtLocation module of the Qt Toolkit. - ** - ** $QT_BEGIN_LICENSE:LGPL$ - ** Commercial License Usage - ** Licensees holding valid commercial Qt licenses may use this file in - ** accordance with the commercial license agreement provided with the - ** Software or, alternatively, in accordance with the terms contained in - ** a written agreement between you and The Qt Company. For licensing terms - ** and conditions see https://www.qt.io/terms-conditions. For further - ** information use the contact form at https://www.qt.io/contact-us. - ** - ** GNU Lesser General Public License Usage - ** Alternatively, this file may be used under the terms of the GNU Lesser - ** General Public License version 3 as published by the Free Software - ** Foundation and appearing in the file LICENSE.LGPL3 included in the - ** packaging of this file. Please review the following information to - ** ensure the GNU Lesser General Public License version 3 requirements - ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. - ** - ** GNU General Public License Usage - ** Alternatively, this file may be used under the terms of the GNU - ** General Public License version 2.0 or (at your option) the GNU General - ** Public license version 3 or any later version approved by the KDE Free - ** Qt Foundation. The licenses are as published by the Free Software - ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 - ** included in the packaging of this file. Please review the following - ** information to ensure the GNU General Public License requirements will - ** be met: https://www.gnu.org/licenses/gpl-2.0.html and - ** https://www.gnu.org/licenses/gpl-3.0.html. - ** - ** $QT_END_LICENSE$ - ** - ****************************************************************************/ - -#include "qdeclarativepolylinemapitem_p.h" -#include "qdeclarativepolylinemapitem_p_p.h" -#include "qdeclarativerectanglemapitem_p_p.h" -#include "qdeclarativecirclemapitem_p_p.h" -#include "qdeclarativegeomapitemutils_p.h" -#include "error_messages_p.h" -#include "qgeosimplify_p.h" - -#include <QtCore/QScopedValueRollback> -#include <qnumeric.h> -#include <QThreadPool> -#include <QRunnable> -#include <QPainter> -#include <QPainterPath> -#include <QtQml/QQmlInfo> - -#include <QtGui/private/qtriangulatingstroker_p.h> -#include <QtGui/private/qtriangulator_p.h> -#include <QtQuick/private/qsgmaterialshader_p.h> -#include <QtPositioning/private/qlocationutils_p.h> -#include <QtPositioning/private/qdoublevector2d_p.h> -#include <QtPositioning/private/qwebmercator_p.h> -#include <QtPositioning/private/qclipperutils_p.h> -#include <QtPositioning/private/qgeopath_p.h> -#include <QtLocation/private/qgeomapparameter_p.h> -#include <QtLocation/private/qgeomap_p.h> - -#include <array> - -QT_BEGIN_NAMESPACE - -struct ThreadPool // to have a thread pool with max 1 thread for geometry processing -{ - ThreadPool () - { - m_threadPool.setMaxThreadCount(1); - } - - void start(QRunnable *runnable, int priority = 0) - { - m_threadPool.start(runnable, priority); - } - - QThreadPool m_threadPool; -}; - -Q_GLOBAL_STATIC(ThreadPool, threadPool) - - -static bool get_line_intersection(const double p0_x, - const double p0_y, - const double p1_x, - const double p1_y, - const double p2_x, - const double p2_y, - const double p3_x, - const double p3_y, - double *i_x, - double *i_y, - double *i_t) -{ - const double s10_x = p1_x - p0_x; - const double s10_y = p1_y - p0_y; - const double s32_x = p3_x - p2_x; - const double s32_y = p3_y - p2_y; - - const double denom = s10_x * s32_y - s32_x * s10_y; - if (denom == 0.0) - return false; // Collinear - const bool denomPositive = denom > 0; - - const double s02_x = p0_x - p2_x; - const double s02_y = p0_y - p2_y; - const double s_numer = s10_x * s02_y - s10_y * s02_x; - if ((s_numer < 0.0) == denomPositive) - return false; // No collision - - const double t_numer = s32_x * s02_y - s32_y * s02_x; - if ((t_numer < 0.0) == denomPositive) - return false; // No collision - - if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive)) - return false; // No collision - // Collision detected - *i_t = t_numer / denom; - *i_x = p0_x + (*i_t * s10_x); - *i_y = p0_y + (*i_t * s10_y); - - return true; -} - -enum SegmentType { - NoIntersection, - OneIntersection, - TwoIntersections -}; - -static QList<QList<QDoubleVector2D> > clipLine( - const QList<QDoubleVector2D> &l, - const QList<QDoubleVector2D> &poly) -{ - QList<QList<QDoubleVector2D> > res; - if (poly.size() < 2 || l.size() < 2) - return res; - - // Step 1: build edges - std::vector<std::array<double, 4> > edges; - for (qsizetype i = 1; i < poly.size(); i++) - edges.push_back({ { poly.at(i-1).x(), poly.at(i-1).y(), poly.at(i).x(), poly.at(i).y() } }); - edges.push_back({ { poly.at(poly.size()-1).x(), poly.at(poly.size()-1).y(), poly.at(0).x(), poly.at(0).y() } }); - - // Step 2: check each segment against each edge - QList<QDoubleVector2D> subLine; - std::array<double, 4> intersections = { { 0.0, 0.0, 0.0, 0.0 } }; - - for (qsizetype i = 0; i < l.size() - 1; ++i) { - SegmentType type = NoIntersection; - double t = -1; // valid values are in [0, 1]. Only written if intersects - double previousT = t; - double i_x, i_y; - - const int firstContained = QClipperUtils::pointInPolygon(l.at(i), poly); - const int secondContained = QClipperUtils::pointInPolygon(l.at(i+1), poly); - - if (firstContained && secondContained) { // Second most common condition, test early and skip inner loop if possible - if (!subLine.size()) - subLine.push_back(l.at(i)); // the initial element has to be pushed now. - subLine.push_back(l.at(i+1)); - continue; - } - - for (unsigned int j = 0; j < edges.size(); ++j) { - const bool intersects = get_line_intersection(l.at(i).x(), - l.at(i).y(), - l.at(i+1).x(), - l.at(i+1).y(), - edges.at(j).at(0), - edges.at(j).at(1), - edges.at(j).at(2), - edges.at(j).at(3), - &i_x, - &i_y, - &t); - if (intersects) { - if (previousT >= 0.0) { //One intersection already hit - if (t < previousT) { // Reorder - intersections[2] = intersections[0]; - intersections[3] = intersections[1]; - intersections[0] = i_x; - intersections[1] = i_y; - } else { - intersections[2] = i_x; - intersections[3] = i_y; - } - - type = TwoIntersections; - break; // no need to check anything else - } else { // First intersection - intersections[0] = i_x; - intersections[1] = i_y; - type = OneIntersection; - } - previousT = t; - } - } - - if (type == NoIntersection) { - if (!firstContained && !secondContained) { // Both outside - subLine.clear(); - } else if (firstContained && secondContained) { - // Handled above already. - } else { // Mismatch between PointInPolygon and get_line_intersection. Treat it as no intersection - if (subLine.size()) - res.push_back(subLine); - subLine.clear(); - } - } else if (type == OneIntersection) { // Need to check the following cases to avoid mismatch with PointInPolygon result. - if (firstContained <= 0 && secondContained > 0) { // subLine MUST be empty - if (!subLine.size()) - subLine.push_back(QDoubleVector2D(intersections[0], intersections[1])); - subLine.push_back(l.at(i+1)); - } else if (firstContained > 0 && secondContained <= 0) { // subLine MUST NOT be empty - if (!subLine.size()) - subLine.push_back(l.at(i)); - subLine.push_back(QDoubleVector2D(intersections[0], intersections[1])); - res.push_back(subLine); - subLine.clear(); - } else { - if (subLine.size()) - res.push_back(subLine); - subLine.clear(); - } - } else { // Two - // restart strip - subLine.clear(); - subLine.push_back(QDoubleVector2D(intersections[0], intersections[1])); - subLine.push_back(QDoubleVector2D(intersections[2], intersections[3])); - res.push_back(subLine); - subLine.clear(); - } - } - - if (subLine.size()) - res.push_back(subLine); - return res; -} - -/*! - \qmltype MapPolyline - \instantiates QDeclarativePolylineMapItem - \inqmlmodule QtLocation - \ingroup qml-QtLocation5-maps - \since QtLocation 5.0 - - \brief The MapPolyline type displays a polyline on a map. - - The MapPolyline type displays a polyline on a map, specified in terms of an ordered list of - \l {coordinate}{coordinates}. The \l {coordinate}{coordinates} on - the path cannot be directly changed after being added to the Polyline. Instead, copy the - \l path into a var, modify the copy and reassign the copy back to the \l path. - - \code - var path = mapPolyline.path; - path[0].latitude = 5; - mapPolyline.path = path; - \endcode - - Coordinates can also be added and removed at any time using the \l addCoordinate and - \l removeCoordinate methods. - - By default, the polyline is displayed as a 1-pixel thick black line. This - can be changed using the \l line.width and \l line.color properties. - - \section2 Performance - - MapPolylines have a rendering cost that is O(n) with respect to the number - of vertices. This means that the per frame cost of having a polyline on - the Map grows in direct proportion to the number of points in the polyline. - - Like the other map objects, MapPolyline is normally drawn without a smooth - appearance. Setting the \l {Item::opacity}{opacity} property will force the object to - be blended, which decreases performance considerably depending on the hardware in use. - - \section2 Example Usage - - The following snippet shows a MapPolyline with 4 points, making a shape - like the top part of a "question mark" (?), near Brisbane, Australia. - The line drawn is 3 pixels in width and green in color. - - \code - Map { - MapPolyline { - line.width: 3 - line.color: 'green' - path: [ - { latitude: -27, longitude: 153.0 }, - { latitude: -27, longitude: 154.1 }, - { latitude: -28, longitude: 153.5 }, - { latitude: -29, longitude: 153.5 } - ] - } - } - \endcode - - \image api-mappolyline.png -*/ - -/*! - \qmlproperty bool QtLocation::MapPolyline::autoFadeIn - - This property holds whether the item automatically fades in when zooming into the map - starting from very low zoom levels. By default this is \c true. - Setting this property to \c false causes the map item to always have the opacity specified - with the \l QtQuick::Item::opacity property, which is 1.0 by default. - - \since 5.14 -*/ - -QDeclarativeMapLineProperties::QDeclarativeMapLineProperties(QObject *parent) - : QObject(parent) -{ -} - -/*! - \internal -*/ -QColor QDeclarativeMapLineProperties::color() const -{ - return color_; -} - -/*! - \internal -*/ -void QDeclarativeMapLineProperties::setColor(const QColor &color) -{ - if (color_ == color) - return; - - color_ = color; - emit colorChanged(color_); -} - -/*! - \internal -*/ -qreal QDeclarativeMapLineProperties::width() const -{ - return width_; -} - -/*! - \internal -*/ -void QDeclarativeMapLineProperties::setWidth(qreal width) -{ - if (width_ == width) - return; - - width_ = width; - emit widthChanged(width_); -} - -QGeoMapPolylineGeometry::QGeoMapPolylineGeometry() -{ -} - -QList<QList<QDoubleVector2D> > QGeoMapPolylineGeometry::clipPath(const QGeoMap &map, - const QList<QDoubleVector2D> &path, - QDoubleVector2D &leftBoundWrapped) -{ - /* - * Approach: - * 1) project coordinates to wrapped web mercator, and do unwrapBelowX - * 2) if the scene is tilted, clip the geometry against the visible region (this may generate multiple polygons) - * 2.1) recalculate the origin and geoLeftBound to prevent these parameters from ending in unprojectable areas - * 2.2) ensure the left bound does not wrap around due to QGeoCoordinate <-> clipper conversions - */ - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - srcOrigin_ = geoLeftBound_; - - double unwrapBelowX = 0; - leftBoundWrapped = p.wrapMapProjection(p.geoToMapProjection(geoLeftBound_)); - if (preserveGeometry_) - unwrapBelowX = leftBoundWrapped.x(); - - QList<QDoubleVector2D> wrappedPath; - wrappedPath.reserve(path.size()); - QDoubleVector2D wrappedLeftBound(qInf(), qInf()); - // 1) - for (const auto &coord : path) { - QDoubleVector2D wrappedProjection = p.wrapMapProjection(coord); - - // We can get NaN if the map isn't set up correctly, or the projection - // is faulty -- probably best thing to do is abort - if (!qIsFinite(wrappedProjection.x()) || !qIsFinite(wrappedProjection.y())) - return QList<QList<QDoubleVector2D> >(); - - const bool isPointLessThanUnwrapBelowX = (wrappedProjection.x() < leftBoundWrapped.x()); - // unwrap x to preserve geometry if moved to border of map - if (preserveGeometry_ && isPointLessThanUnwrapBelowX) { - double distance = wrappedProjection.x() - unwrapBelowX; - if (distance < 0.0) - distance += 1.0; - wrappedProjection.setX(unwrapBelowX + distance); - } - if (wrappedProjection.x() < wrappedLeftBound.x() || (wrappedProjection.x() == wrappedLeftBound.x() && wrappedProjection.y() < wrappedLeftBound.y())) { - wrappedLeftBound = wrappedProjection; - } - wrappedPath.append(wrappedProjection); - } - -#ifdef QT_LOCATION_DEBUG - m_wrappedPath = wrappedPath; -#endif - - // 2) - QList<QList<QDoubleVector2D> > clippedPaths; - const QList<QDoubleVector2D> &visibleRegion = p.projectableGeometry(); - if (visibleRegion.size()) { - clippedPaths = clipLine(wrappedPath, visibleRegion); - - // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X - QDoubleVector2D lb(qInf(), qInf()); - for (const QList<QDoubleVector2D> &path: clippedPaths) { - for (const QDoubleVector2D &p: path) { - if (p == leftBoundWrapped) { - lb = p; - break; - } else if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) { - // y-minimization needed to find the same point on polygon and border - lb = p; - } - } - } - if (qIsInf(lb.x())) - return QList<QList<QDoubleVector2D> >(); - - // 2.2) Prevent the conversion to and from clipper from introducing negative offsets which - // in turn will make the geometry wrap around. - lb.setX(qMax(wrappedLeftBound.x(), lb.x())); - leftBoundWrapped = lb; - } else { - clippedPaths.append(wrappedPath); - } - -#ifdef QT_LOCATION_DEBUG - m_clippedPaths = clippedPaths; -#endif - - return clippedPaths; -} - -void QGeoMapPolylineGeometry::pathToScreen(const QGeoMap &map, - const QList<QList<QDoubleVector2D> > &clippedPaths, - const QDoubleVector2D &leftBoundWrapped) -{ - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - // 3) project the resulting geometry to screen position and calculate screen bounds - double minX = qInf(); - 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 (qsizetype 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); - minY = qMin(point.y(), minY); - maxX = qMax(point.x(), maxX); - maxY = qMax(point.y(), maxY); - - if (i == 0) { - srcPoints_ << point.x() << point.y(); - srcPointTypes_ << QPainterPath::MoveToElement; - lastAddedPoint = point; - } else { - if ((point - lastAddedPoint).manhattanLength() > 3 || - i == path.size() - 1) { - srcPoints_ << point.x() << point.y(); - srcPointTypes_ << QPainterPath::LineToElement; - lastAddedPoint = point; - } - } - } - } - - sourceBounds_ = QRectF(QPointF(minX, minY), QPointF(maxX, maxY)); -} - -/*! - \internal -*/ -void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map, - const QList<QDoubleVector2D> &path, - const QGeoCoordinate geoLeftBound) -{ - if (!sourceDirty_) - return; - - geoLeftBound_ = geoLeftBound; - - // clear the old data and reserve enough memory - srcPoints_.clear(); - srcPoints_.reserve(path.size() * 2); - srcPointTypes_.clear(); - srcPointTypes_.reserve(path.size()); - - /* - * Approach: - * 1) project coordinates to wrapped web mercator, and do unwrapBelowX - * 2) if the scene is tilted, clip the geometry against the visible region (this may generate multiple polygons) - * 3) project the resulting geometry to screen position and calculate screen bounds - */ - - QDoubleVector2D leftBoundWrapped; - // 1, 2) - const QList<QList<QDoubleVector2D> > &clippedPaths = clipPath(map, path, leftBoundWrapped); - - // 3) - 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, - QList<qreal> &outPoints, QList<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 QList<qreal> &points, - const QList<QPainterPath::ElementType> &types, const QRectF &clipRect, - QList<qreal> &outPoints, QList<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 (qsizetype 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]; - } -} - -//////////////////////////////////////////////////////////////////////////// - -/*! - \internal -*/ -void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map, - qreal strokeWidth, - bool adjustTranslation) -{ - if (!screenDirty_) - return; - - QPointF origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false).toPointF(); - - if (!qIsFinite(origin.x()) || !qIsFinite(origin.y()) || srcPointTypes_.size() < 2) { // the line might have been clipped away. - clear(); - return; - } - - // 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 * 2, strokeWidth * 2); - viewport.translate(-1 * origin); - - QList<qreal> points; - QList<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; - // As of Qt5.11, the clip argument is not actually used, in the call below. - ts.process(vp, QPen(QBrush(Qt::black), strokeWidth), QRectF(), QPainter::Antialiasing); - - clear(); - - // Nothing is on the screen - if (ts.vertexCount() == 0) - return; - - // QTriangulatingStroker#vertexCount is actually the length of the array, - // not the number of vertices - screenVertices_.reserve(ts.vertexCount()); - - QRectF bb; - - QPointF pt; - const float *vs = ts.vertices(); - for (int i = 0; i < (ts.vertexCount()/2*2); i += 2) { - pt = QPointF(vs[i], vs[i + 1]); - screenVertices_ << pt; - - if (!qIsFinite(pt.x()) || !qIsFinite(pt.y())) - break; - - if (!bb.contains(pt)) { - if (pt.x() < bb.left()) - bb.setLeft(pt.x()); - - if (pt.x() > bb.right()) - bb.setRight(pt.x()); - - if (pt.y() < bb.top()) - bb.setTop(pt.y()); - - if (pt.y() > bb.bottom()) - bb.setBottom(pt.y()); - } - } - - screenBounds_ = bb; - const QPointF strokeOffset = (adjustTranslation) ? QPointF(strokeWidth, strokeWidth) * 0.5: QPointF(); - this->translate( -1 * sourceBounds_.topLeft() + strokeOffset); -} - -void QGeoMapPolylineGeometry::clearSource() -{ - srcPoints_.clear(); - srcPointTypes_.clear(); -} - -bool QGeoMapPolylineGeometry::contains(const QPointF &point) const -{ - // screenOutline_.contains(screenPoint) doesn't work, as, it appears, that - // screenOutline_ for QGeoMapPolylineGeometry is empty (QRectF(0,0 0x0)) - const QList<QPointF> &verts = vertices(); - QPolygonF tri; - for (const auto &v : verts) { - tri << v; - if (tri.size() == 3) { - if (tri.containsPoint(point, Qt::OddEvenFill)) - return true; - tri.remove(0); - } - } - - return false; -} - -void QGeoMapPolylineGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QGeoPolygon &poly) -{ - if (!sourceDirty_) - return; - QGeoPath p(poly.perimeter()); - if (poly.perimeter().size() && poly.perimeter().last() != poly.perimeter().first()) - p.addCoordinate(poly.perimeter().first()); - updateSourcePoints(map, p); -} - -void QGeoMapPolylineGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QGeoPath &poly) -{ - if (!sourceDirty_) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - - // build the actual path - // The approach is the same as described in QGeoMapPolylineGeometry::updateSourcePoints - - - QDoubleVector2D leftBoundWrapped; - // 1) pre-compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0 - QList<QDoubleVector2D> wrappedPath; - QDeclarativeGeoMapItemUtils::wrapPath(poly.path(), geoLeftBound_, p, - wrappedPath, &leftBoundWrapped); - - const QGeoRectangle &boundingRectangle = poly.boundingGeoRectangle(); - updateSourcePoints(p, wrappedPath, boundingRectangle); -} - -void QGeoMapPolylineGeometryOpenGL::updateSourcePoints(const QGeoProjectionWebMercator &p, - const QList<QDoubleVector2D> &wrappedPath, - const QGeoRectangle &boundingRectangle) { - if (!sourceDirty_) - return; - // 1.1) do the same for the bbox - // Beware: vertical lines (or horizontal lines) might have an "empty" bbox. Check for that - - QGeoCoordinate topLeft = boundingRectangle.topLeft(); - QGeoCoordinate bottomRight = boundingRectangle.bottomRight(); - const qreal epsilon = 0.000001; - if (qFuzzyCompare(topLeft.latitude(), bottomRight.latitude())) { - topLeft.setLatitude(qBound(-90.0, topLeft.latitude() + epsilon ,90.0)); - bottomRight.setLatitude(qBound(-90.0, bottomRight.latitude() - epsilon ,90.0)); - } - if (qFuzzyCompare(topLeft.longitude(), bottomRight.longitude())) { - topLeft.setLongitude(QLocationUtils::wrapLong(topLeft.longitude() - epsilon)); - bottomRight.setLongitude(QLocationUtils::wrapLong(bottomRight.longitude() + epsilon)); - } - QGeoPolygon bbox(QGeoRectangle(topLeft, bottomRight)); - QList<QDoubleVector2D> wrappedBbox, wrappedBboxPlus1, wrappedBboxMinus1; - QDeclarativeGeoMapItemUtils::wrapPath(bbox.perimeter(), bbox.boundingGeoRectangle().topLeft(), p, - wrappedBbox, wrappedBboxMinus1, wrappedBboxPlus1, &m_bboxLeftBoundWrapped); - - // New pointers, some old LOD task might still be running and operating on the old pointers. - resetLOD(); - - for (const auto &v: qAsConst(wrappedPath)) m_screenVertices->append(v); - - m_wrappedPolygons.resize(3); - m_wrappedPolygons[0].wrappedBboxes = wrappedBboxMinus1; - m_wrappedPolygons[1].wrappedBboxes = wrappedBbox; - m_wrappedPolygons[2].wrappedBboxes = wrappedBboxPlus1; - srcOrigin_ = geoLeftBound_; -} - -void QGeoMapPolylineGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QGeoRectangle &rect) -{ - const QGeoPath path(QDeclarativeRectangleMapItemPrivateCPU::perimeter(rect)); - updateSourcePoints(map, path); -} - -void QGeoMapPolylineGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QGeoCircle &circle) -{ - if (!sourceDirty_) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - - QDoubleVector2D leftBoundWrapped; - // 1) pre-compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0 - QList<QGeoCoordinate> path; - QGeoCoordinate leftBound; - QList<QDoubleVector2D> wrappedPath; - QDeclarativeCircleMapItemPrivateCPU::calculatePeripheralPoints(path, circle.center(), circle.radius(), QDeclarativeCircleMapItemPrivateCPU::CircleSamples, leftBound); - path << path.first(); - geoLeftBound_ = leftBound; - QDeclarativeGeoMapItemUtils::wrapPath(path, leftBound, p, wrappedPath, &leftBoundWrapped); - const QGeoRectangle &boundingRectangle = circle.boundingGeoRectangle(); - updateSourcePoints(p, wrappedPath, boundingRectangle); -} - -void QGeoMapPolylineGeometryOpenGL::updateScreenPoints(const QGeoMap &map, qreal strokeWidth, bool /*adjustTranslation*/) -{ - if (map.viewportWidth() == 0 || map.viewportHeight() == 0) { - clear(); - return; - } - - // 1) identify which set to use: std, +1 or -1 - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - const QDoubleVector2D leftBoundMercator = p.geoToMapProjection(srcOrigin_); - m_wrapOffset = p.projectionWrapFactor(leftBoundMercator) + 1; // +1 to get the offset into QLists - - if (sourceDirty_) { - // 1.1) select geometry set - // This could theoretically be skipped for those polylines whose bbox is not even projectable. - // However, such optimization could only be introduced if not calculating bboxes lazily. - // Hence not doing it. -// if (m_screenVertices.size() > 1) - m_dataChanged = true; - } - - updateQuickGeometry(p, strokeWidth); -} - -void QGeoMapPolylineGeometryOpenGL::updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal strokeWidth) -{ - // 2) clip bbox - // BBox handling -- this is related to the bounding box geometry - // that has to inevitably follow the old projection codepath - // As it needs to provide projected coordinates for QtQuick interaction. - // This could be futher optimized to be updated in a lazy fashion. - const QList<QDoubleVector2D> &wrappedBbox = m_wrappedPolygons.at(m_wrapOffset).wrappedBboxes; - QList<QList<QDoubleVector2D> > clippedBbox; - QDoubleVector2D bboxLeftBoundWrapped = m_bboxLeftBoundWrapped; - bboxLeftBoundWrapped.setX(bboxLeftBoundWrapped.x() + double(m_wrapOffset - 1)); - QDeclarativeGeoMapItemUtils::clipPolygon(wrappedBbox, p, clippedBbox, &bboxLeftBoundWrapped, false); - - // 3) project bbox - QPainterPath ppi; - - if ( !clippedBbox.size() || - clippedBbox.first().size() < 3) { - sourceBounds_ = screenBounds_ = QRectF(); - firstPointOffset_ = QPointF(); - screenOutline_ = ppi; - return; - } - - QDeclarativeGeoMapItemUtils::projectBbox(clippedBbox.first(), p, ppi); // Using first because a clipped box should always result in one polygon - const QRectF brect = ppi.boundingRect(); - firstPointOffset_ = QPointF(brect.topLeft()); - sourceBounds_ = brect; - screenOutline_ = ppi; - - // 4) Set Screen bbox - screenBounds_ = brect; - sourceBounds_.setX(0); - sourceBounds_.setY(0); - sourceBounds_.setWidth(brect.width() + strokeWidth); - sourceBounds_.setHeight(brect.height() + strokeWidth); -} - -/* - * QDeclarativePolygonMapItem Private Implementations - */ - -QDeclarativePolylineMapItemPrivate::~QDeclarativePolylineMapItemPrivate() {} - -QDeclarativePolylineMapItemPrivateCPU::~QDeclarativePolylineMapItemPrivateCPU() {} - -QDeclarativePolylineMapItemPrivateOpenGLLineStrip::~QDeclarativePolylineMapItemPrivateOpenGLLineStrip() {} - -QDeclarativePolylineMapItemPrivateOpenGLExtruded::~QDeclarativePolylineMapItemPrivateOpenGLExtruded() {} - -/* - * QDeclarativePolygonMapItem Implementation - */ - -struct PolylineBackendSelector -{ - PolylineBackendSelector() - { - backend = (qgetenv("QTLOCATION_OPENGL_ITEMS").toInt()) ? QDeclarativePolylineMapItem::OpenGLExtruded : QDeclarativePolylineMapItem::Software; - } - QDeclarativePolylineMapItem::Backend backend = QDeclarativePolylineMapItem::Software; -}; - -Q_GLOBAL_STATIC(PolylineBackendSelector, mapPolylineBackendSelector) - -QDeclarativePolylineMapItem::QDeclarativePolylineMapItem(QQuickItem *parent) - : QDeclarativeGeoMapItemBase(parent), m_line(this), - m_d(new QDeclarativePolylineMapItemPrivateCPU(*this)) -{ - m_itemType = QGeoMap::MapPolyline; - m_geopath = QGeoPathEager(); - setFlag(ItemHasContents, true); - QObject::connect(&m_line, &QDeclarativeMapLineProperties::colorChanged, - this, &QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged); - QObject::connect(&m_line, &QDeclarativeMapLineProperties::widthChanged, - this, &QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged); - setBackend(mapPolylineBackendSelector->backend); -} - -QDeclarativePolylineMapItem::~QDeclarativePolylineMapItem() -{ -} - -/*! - \internal -*/ -void QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged() -{ - m_d->onLinePropertiesChanged(); -} - -/*! - \internal -*/ -void QDeclarativePolylineMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) -{ - QDeclarativeGeoMapItemBase::setMap(quickMap,map); - if (map) - m_d->onMapSet(); -} - -/*! - \qmlproperty list<coordinate> MapPolyline::path - - This property holds the ordered list of coordinates which - define the polyline. -*/ - -QList<QGeoCoordinate> QDeclarativePolylineMapItem::path() const -{ - return m_geopath.path(); -} - -void QDeclarativePolylineMapItem::setPath(const QList<QGeoCoordinate> &value) -{ - setPathFromGeoList(value); -} - -/*! - \qmlmethod void MapPolyline::setPath(geopath path) - - Sets the \a path using a geopath type. - - \since 5.10 - - \sa path -*/ -void QDeclarativePolylineMapItem::setPath(const QGeoPath &path) -{ - if (m_geopath.path() == path.path()) - return; - - m_geopath = QGeoPathEager(path); - m_d->onGeoGeometryChanged(); - emit pathChanged(); -} - -/*! - \internal -*/ -void QDeclarativePolylineMapItem::setPathFromGeoList(const QList<QGeoCoordinate> &path) -{ - if (m_geopath.path() == path) - return; - - m_geopath.setPath(path); - - m_d->onGeoGeometryChanged(); - emit pathChanged(); -} - -/*! - \qmlmethod int MapPolyline::pathLength() - - Returns the number of coordinates of the polyline. - - \since QtLocation 5.6 - - \sa path -*/ -int QDeclarativePolylineMapItem::pathLength() const -{ - return m_geopath.path().length(); -} - -/*! - \qmlmethod void MapPolyline::addCoordinate(coordinate) - - Adds the specified \a coordinate to the end of the path. - - \sa insertCoordinate, removeCoordinate, path -*/ -void QDeclarativePolylineMapItem::addCoordinate(const QGeoCoordinate &coordinate) -{ - if (!coordinate.isValid()) - return; - - m_geopath.addCoordinate(coordinate); - - m_d->onGeoGeometryUpdated(); - emit pathChanged(); -} - -/*! - \qmlmethod void MapPolyline::insertCoordinate(index, coordinate) - - Inserts a \a coordinate to the path at the given \a index. - - \since QtLocation 5.6 - - \sa addCoordinate, removeCoordinate, path -*/ -void QDeclarativePolylineMapItem::insertCoordinate(int index, const QGeoCoordinate &coordinate) -{ - if (index < 0 || index > m_geopath.path().length()) - return; - - m_geopath.insertCoordinate(index, coordinate); - - m_d->onGeoGeometryChanged(); - emit pathChanged(); -} - -/*! - \qmlmethod void MapPolyline::replaceCoordinate(index, coordinate) - - Replaces the coordinate in the current path at the given \a index - with the new \a coordinate. - - \since QtLocation 5.6 - - \sa addCoordinate, insertCoordinate, removeCoordinate, path -*/ -void QDeclarativePolylineMapItem::replaceCoordinate(int index, const QGeoCoordinate &coordinate) -{ - if (index < 0 || index >= m_geopath.path().length()) - return; - - m_geopath.replaceCoordinate(index, coordinate); - - m_d->onGeoGeometryChanged(); - emit pathChanged(); -} - -/*! - \qmlmethod coordinate MapPolyline::coordinateAt(index) - - Gets the coordinate of the polyline at the given \a index. - If the index is outside the path's bounds then an invalid - coordinate is returned. - - \since QtLocation 5.6 -*/ -QGeoCoordinate QDeclarativePolylineMapItem::coordinateAt(int index) const -{ - if (index < 0 || index >= m_geopath.path().length()) - return QGeoCoordinate(); - - return m_geopath.coordinateAt(index); -} - -/*! - \qmlmethod coordinate MapPolyline::containsCoordinate(coordinate) - - Returns true if the given \a coordinate is part of the path. - - \since QtLocation 5.6 -*/ -bool QDeclarativePolylineMapItem::containsCoordinate(const QGeoCoordinate &coordinate) -{ - return m_geopath.containsCoordinate(coordinate); -} - -/*! - \qmlmethod void MapPolyline::removeCoordinate(coordinate) - - Removes \a coordinate from the path. If there are multiple instances of the - same coordinate, the one added last is removed. - - If \a coordinate is not in the path this method does nothing. - - \sa addCoordinate, insertCoordinate, path -*/ -void QDeclarativePolylineMapItem::removeCoordinate(const QGeoCoordinate &coordinate) -{ - int length = m_geopath.path().length(); - m_geopath.removeCoordinate(coordinate); - if (m_geopath.path().length() == length) - return; - - m_d->onGeoGeometryChanged(); - emit pathChanged(); -} - -/*! - \qmlmethod void MapPolyline::removeCoordinate(index) - - Removes a coordinate from the path at the given \a index. - - If \a index is invalid then this method does nothing. - - \since QtLocation 5.6 - - \sa addCoordinate, insertCoordinate, path -*/ -void QDeclarativePolylineMapItem::removeCoordinate(int index) -{ - if (index < 0 || index >= m_geopath.path().length()) - return; - - m_geopath.removeCoordinate(index); - - m_d->onGeoGeometryChanged(); - emit pathChanged(); -} - -/*! - \qmlpropertygroup Location::MapPolyline::line - \qmlproperty int MapPolyline::line.width - \qmlproperty color MapPolyline::line.color - - This property is part of the line property group. The line - property group holds the width and color used to draw the line. - - The width is in pixels and is independent of the zoom level of the map. - The default values correspond to a black border with a width of 1 pixel. - - For no line, use a width of 0 or a transparent color. -*/ - -QDeclarativeMapLineProperties *QDeclarativePolylineMapItem::line() -{ - return &m_line; -} - -/*! - \qmlproperty MapPolyline.Backend QtLocation::MapPolyline::backend - - This property holds which backend is in use to render the map item. - Valid values are \b MapPolyline.Software and \b{MapPolyline.OpenGLLineStrip} - and \b{MapPolyline.OpenGLExtruded}. - The default value is \b{MapPolyline.Software}. - - \note \b{The release of this API with Qt 5.15 is a Technology Preview}. - Ideally, as the OpenGL backends for map items mature, there will be - no more need to also offer the legacy software-projection backend. - So this property will likely disappear at some later point. - To select OpenGL-accelerated item backends without using this property, - it is also possible to set the environment variable \b QTLOCATION_OPENGL_ITEMS - to \b{1}. - Also note that all current OpenGL backends won't work as expected when enabling - layers on the individual item, or when running on OpenGL core profiles greater than 2.x. - - \since 5.15 -*/ -QDeclarativePolylineMapItem::Backend QDeclarativePolylineMapItem::backend() const -{ - return m_backend; -} - -void QDeclarativePolylineMapItem::setBackend(QDeclarativePolylineMapItem::Backend b) -{ - if (b == m_backend) - return; - m_backend = b; - std::unique_ptr<QDeclarativePolylineMapItemPrivate> d( - (m_backend == Software) - ? static_cast<QDeclarativePolylineMapItemPrivate *>( - new QDeclarativePolylineMapItemPrivateCPU(*this)) - : ((m_backend == OpenGLExtruded) - ? static_cast<QDeclarativePolylineMapItemPrivate *>( - new QDeclarativePolylineMapItemPrivateOpenGLExtruded(*this)) - : static_cast<QDeclarativePolylineMapItemPrivate *>( - new QDeclarativePolylineMapItemPrivateOpenGLLineStrip( - *this)))); - m_d.swap(d); - m_d->onGeoGeometryChanged(); - emit backendChanged(); -} - -/*! - \internal -*/ -void QDeclarativePolylineMapItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - if (newGeometry.topLeft() == oldGeometry.topLeft() || !map() || !m_geopath.isValid() || m_updatingGeometry) { - QDeclarativeGeoMapItemBase::geometryChange(newGeometry, oldGeometry); - return; - } - // TODO: change the algorithm to preserve the distances and size! - QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false); - QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false); - if (!newCenter.isValid() || !oldCenter.isValid()) - return; - double offsetLongi = newCenter.longitude() - oldCenter.longitude(); - double offsetLati = newCenter.latitude() - oldCenter.latitude(); - if (offsetLati == 0.0 && offsetLongi == 0.0) - return; - - m_geopath.translate(offsetLati, offsetLongi); - m_d->onGeoGeometryChanged(); - emit pathChanged(); - - // Not calling QDeclarativeGeoMapItemBase::geometryChange() as it will be called from a nested - // call to this function. -} - -/*! - \internal -*/ -void QDeclarativePolylineMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event) -{ - if (event.mapSize.isEmpty()) - return; - - m_d->afterViewportChanged(); -} - -/*! - \internal -*/ -void QDeclarativePolylineMapItem::updatePolish() -{ - if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) - return; - m_d->updatePolish(); -} - -void QDeclarativePolylineMapItem::updateLineStyleParameter(QGeoMapParameter *p, - const char *propertyName, - bool update) -{ - static const QByteArrayList acceptedParameterTypes = QByteArrayList() - << QByteArrayLiteral("lineCap") - << QByteArrayLiteral("pen"); - switch (acceptedParameterTypes.indexOf(QByteArray(propertyName))) { - case -1: - qWarning() << "Invalid property " << QLatin1String(propertyName) << " for parameter lineStyle"; - break; - case 0: // lineCap - { - const QVariant lineCap = p->property("lineCap"); - m_d->m_penCapStyle = lineCap.value<Qt::PenCapStyle>(); // if invalid, will return 0 == FlatCap - if (update) - markSourceDirtyAndUpdate(); - break; - } - case 1: // penStyle - { - const QVariant penStyle = p->property("pen"); - m_d->m_penStyle = penStyle.value<Qt::PenStyle>(); - if (m_d->m_penStyle == Qt::NoPen) - m_d->m_penStyle = Qt::SolidLine; - if (update) - markSourceDirtyAndUpdate(); - break; - } - } -} - -void QDeclarativePolylineMapItem::updateLineStyleParameter(QGeoMapParameter *p, const char *propertyName) -{ - updateLineStyleParameter(p, propertyName, true); -} - -void QDeclarativePolylineMapItem::componentComplete() -{ - QQuickItem::componentComplete(); - // Set up Dynamic Parameters - QList<QGeoMapParameter *> dynamicParameters = quickChildren<QGeoMapParameter>(); - for (QGeoMapParameter *p : qAsConst(dynamicParameters)) { - if (p->type() == QLatin1String("lineStyle")) { - updateLineStyleParameter(p, "lineCap", false); - updateLineStyleParameter(p, "pen", false); - connect(p, &QGeoMapParameter::propertyUpdated, - this, static_cast<void (QDeclarativePolylineMapItem::*)(QGeoMapParameter *, const char *)>(&QDeclarativePolylineMapItem::updateLineStyleParameter)); - markSourceDirtyAndUpdate(); - } - } -} - -void QDeclarativePolylineMapItem::markSourceDirtyAndUpdate() -{ - m_d->markSourceDirtyAndUpdate(); -} - -/*! - \internal -*/ -QSGNode *QDeclarativePolylineMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) -{ - return m_d->updateMapItemPaintNode(oldNode, data); -} - -bool QDeclarativePolylineMapItem::contains(const QPointF &point) const -{ - return m_d->contains(point); -} - -const QGeoShape &QDeclarativePolylineMapItem::geoShape() const -{ - return m_geopath; -} - -void QDeclarativePolylineMapItem::setGeoShape(const QGeoShape &shape) -{ - const QGeoPath geopath(shape); // if shape isn't a path, path will be created as a default-constructed path - setPath(geopath); -} - -////////////////////////////////////////////////////////////////////// - -/*! - \internal -*/ -VisibleNode::VisibleNode() : m_blocked{true}, m_visible{true} -{ - -} - -VisibleNode::~VisibleNode() -{ - -} - -/*! - \internal -*/ -bool VisibleNode::subtreeBlocked() const -{ - return m_blocked || !m_visible; -} - -/*! - \internal -*/ -void VisibleNode::setSubtreeBlocked(bool blocked) -{ - m_blocked = blocked; -} - -bool VisibleNode::visible() const -{ - return m_visible; -} - -/*! - \internal -*/ -void VisibleNode::setVisible(bool visible) -{ - m_visible = visible; -} - -/*! - \internal -*/ -MapItemGeometryNode::~MapItemGeometryNode() -{ - -} - -bool MapItemGeometryNode::isSubtreeBlocked() const -{ - return subtreeBlocked(); -} - - -/*! - \internal -*/ -MapPolylineNode::MapPolylineNode() : - geometry_(QSGGeometry::defaultAttributes_Point2D(),0) -{ - geometry_.setDrawingMode(QSGGeometry::DrawTriangleStrip); - QSGGeometryNode::setMaterial(&fill_material_); - QSGGeometryNode::setGeometry(&geometry_); -} - - -/*! - \internal -*/ -MapPolylineNode::~MapPolylineNode() -{ -} - -/*! - \internal -*/ -void MapPolylineNode::update(const QColor &fillColor, - const QGeoMapItemGeometry *shape) -{ - if (shape->size() == 0) { - setSubtreeBlocked(true); - return; - } else { - setSubtreeBlocked(false); - } - - QSGGeometry *fill = QSGGeometryNode::geometry(); - shape->allocateAndFill(fill); - markDirty(DirtyGeometry); - - if (fillColor != fill_material_.color()) { - fill_material_.setColor(fillColor); - setMaterial(&fill_material_); - markDirty(DirtyMaterial); - } -} - -MapPolylineNodeOpenGLLineStrip::MapPolylineNodeOpenGLLineStrip() -: geometry_(QSGGeometry::defaultAttributes_Point2D(), 0) -{ - geometry_.setDrawingMode(QSGGeometry::DrawLineStrip); - QSGGeometryNode::setMaterial(&fill_material_); - QSGGeometryNode::setGeometry(&geometry_); -} - -MapPolylineNodeOpenGLLineStrip::~MapPolylineNodeOpenGLLineStrip() -{ - -} - -void MapPolylineNodeOpenGLLineStrip::update(const QColor &fillColor, - const qreal lineWidth, - const QGeoMapPolylineGeometryOpenGL *shape, - const QMatrix4x4 &geoProjection, - const QDoubleVector3D ¢er, - const Qt::PenCapStyle /*capStyle*/) -{ - if (shape->m_screenVertices->size() < 2) { - setSubtreeBlocked(true); - return; - } else { - setSubtreeBlocked(false); - } - - QSGGeometry *fill = QSGGeometryNode::geometry(); - if (shape->m_dataChanged) { - shape->allocateAndFillLineStrip(fill); - markDirty(DirtyGeometry); - shape->m_dataChanged = false; - } - fill->setLineWidth(lineWidth); - fill_material_.setLineWidth(lineWidth); // to make the material not compare equal if linewidth changes - -// if (fillColor != fill_material_.color()) - { - fill_material_.setWrapOffset(shape->m_wrapOffset - 1); - fill_material_.setColor(fillColor); - fill_material_.setGeoProjection(geoProjection); - fill_material_.setCenter(center); - setMaterial(&fill_material_); - markDirty(DirtyMaterial); - } -} - -MapPolylineShaderLineStrip::MapPolylineShaderLineStrip() : QSGMaterialShader(*new QSGMaterialShaderPrivate(this)) -{ - setShaderFileName(VertexStage, QLatin1String(":/location/declarativemaps/declarativemaps/shaders/polyline_linestrip.vert.qsb")); - setShaderFileName(FragmentStage, QLatin1String(":/location/declarativemaps/declarativemaps/shaders/polyline_linestrip.frag.qsb")); -} - -bool MapPolylineShaderLineStrip::updateUniformData(QSGMaterialShader::RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) -{ - Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); - MapPolylineMaterial *oldMaterial = static_cast<MapPolylineMaterial *>(oldEffect); - MapPolylineMaterial *newMaterial = static_cast<MapPolylineMaterial *>(newEffect); - - const QColor &c = newMaterial->color(); - const QMatrix4x4 &geoProjection = newMaterial->geoProjection(); - const QDoubleVector3D ¢er = newMaterial->center(); - - QVector4D vecCenter, vecCenter_lowpart; - for (int i = 0; i < 3; i++) - QLocationUtils::split_double(center.get(i), &vecCenter[i], &vecCenter_lowpart[i]); - vecCenter[3] = 0; - vecCenter_lowpart[3] = 0; - - int offset = 0; - char *buf_p = state.uniformData()->data(); - - if (state.isMatrixDirty()) { - const QMatrix4x4 m = state.projectionMatrix(); - memcpy(buf_p + offset, m.constData(), 4*4*4); - } - offset += 4*4*4; - - memcpy(buf_p + offset, geoProjection.constData(), 4*4*4); offset+=4*4*4; - - memcpy(buf_p + offset, &vecCenter, 4*4); offset += 4*4; - - memcpy(buf_p + offset, &vecCenter_lowpart, 4*4); offset+=4*4; - - if (state.isOpacityDirty()) { - const float opacity = state.opacity(); - memcpy(buf_p + offset, &opacity, 4); - } - offset += 4; - - float wrapOffset = newMaterial->wrapOffset(); - memcpy(buf_p + offset, &wrapOffset, 4); offset+=4; - - offset+=8; // float padding - - if (oldMaterial == nullptr || c != oldMaterial->color() || state.isOpacityDirty()) { - float opacity = state.opacity() * c.alphaF(); - QVector4D v(c.redF() * opacity, - c.greenF() * opacity, - c.blueF() * opacity, - opacity); - memcpy(buf_p + offset, &v, 4*4); - } - offset+=4*4; - - return true; -} - -QSGMaterialShader *MapPolylineMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const -{ - Q_UNUSED(renderMode); - return new MapPolylineShaderLineStrip(); -} - -QSGMaterialType *MapPolylineMaterial::type() const -{ - static QSGMaterialType type; - return &type; -} - -int MapPolylineMaterial::compare(const QSGMaterial *other) const -{ - const MapPolylineMaterial &o = *static_cast<const MapPolylineMaterial *>(other); - if (o.m_center == m_center && o.m_geoProjection == m_geoProjection && o.m_wrapOffset == m_wrapOffset && o.m_lineWidth == m_lineWidth) - return QSGFlatColorMaterial::compare(other); - return -1; -} - -const QSGGeometry::AttributeSet &MapPolylineNodeOpenGLExtruded::attributesMapPolylineTriangulated() -{ - return MapPolylineEntry::attributes(); -} - -MapPolylineNodeOpenGLExtruded::MapPolylineNodeOpenGLExtruded() -: m_geometryTriangulating(MapPolylineNodeOpenGLExtruded::attributesMapPolylineTriangulated(), - 0 /* vtx cnt */, 0 /* index cnt */, QSGGeometry::UnsignedIntType /* index type */) -{ - m_geometryTriangulating.setDrawingMode(QSGGeometry::DrawTriangles); - QSGGeometryNode::setMaterial(&fill_material_); - QSGGeometryNode::setGeometry(&m_geometryTriangulating); -} - -MapPolylineNodeOpenGLExtruded::~MapPolylineNodeOpenGLExtruded() -{ - -} - -bool QGeoMapPolylineGeometryOpenGL::allocateAndFillEntries(QSGGeometry *geom, - bool closed, - unsigned int zoom) const -{ - // Select LOD. Generate if not present. Assign it to m_screenVertices; - if (m_dataChanged) { - // it means that the data really changed. - // So synchronously produce LOD 1, and enqueue the requested one if != 0 or 1. - // Select 0 if 0 is requested, or 1 in all other cases. - selectLODOnDataChanged(zoom, m_bboxLeftBoundWrapped.x()); - } else { - // Data has not changed, but active LOD != requested LOD. - // So, if there are no active tasks, try to change to the correct one. - if (!selectLODOnLODMismatch(zoom, m_bboxLeftBoundWrapped.x(), closed)) - return false; - } - - const QList<QDeclarativeGeoMapItemUtils::vec2> &v = *m_screenVertices; - if (v.size() < 2) { - geom->allocate(0, 0); - return true; - } - const int numSegments = (v.size() - 1); - - const int numIndices = numSegments * 6; // six vertices per line segment - geom->allocate(numIndices); - MapPolylineNodeOpenGLExtruded::MapPolylineEntry *vertices = - static_cast<MapPolylineNodeOpenGLExtruded::MapPolylineEntry *>(geom->vertexData()); - - for (int i = 0; i < numSegments; ++i) { - MapPolylineNodeOpenGLExtruded::MapPolylineEntry e; - const QDeclarativeGeoMapItemUtils::vec2 &cur = v[i]; - const QDeclarativeGeoMapItemUtils::vec2 &next = v[i+1]; - e.triangletype = 1.0; - e.next = next; - e.prev = cur; - e.pos = cur; - e.direction = 1.0; - e.vertextype = -1.0; - vertices[i*6] = e; - e.direction = -1.0; - vertices[i*6+1] = e; - e.pos = next; - e.vertextype = 1.0; - vertices[i*6+2] = e; - - // Second tri - e.triangletype = -1.0; - e.direction = -1.0; - vertices[i*6+3] = e; - e.direction = 1.0; - vertices[i*6+4] = e; - e.pos = cur; - e.vertextype = -1.0; - vertices[i*6+5] = e; - - if (i != 0) { - vertices[i*6].prev = vertices[i*6+1].prev = vertices[i*6+5].prev = v[i-1]; - } else { - if (closed) { - vertices[i*6].prev = vertices[i*6+1].prev = vertices[i*6+5].prev = v[numSegments - 1]; - } else { - vertices[i*6].triangletype = vertices[i*6+1].triangletype = vertices[i*6+5].triangletype = 2.0; - } - } - if (i != numSegments - 1) { - vertices[i*6+2].next = vertices[i*6+3].next = vertices[i*6+4].next = v[i+2]; - } else { - if (closed) { - vertices[i*6+2].next = vertices[i*6+3].next = vertices[i*6+4].next = v[1]; - } else { - vertices[i*6+2].triangletype = vertices[i*6+3].triangletype = vertices[i*6+4].triangletype = 3.0; - } - } - } - return true; -} - -void QGeoMapPolylineGeometryOpenGL::allocateAndFillLineStrip(QSGGeometry *geom, - int lod) const -{ - // Select LOD. Generate if not present. Assign it to m_screenVertices; - Q_UNUSED(lod); - - const QList<QDeclarativeGeoMapItemUtils::vec2> &vx = *m_screenVertices; - geom->allocate(vx.size()); - - QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D(); - for (qsizetype i = 0; i < vx.size(); ++i) - pts[i].set(vx[i].x, vx[i].y); -} - -void MapPolylineNodeOpenGLExtruded::update(const QColor &fillColor, - float lineWidth, - const QGeoMapPolylineGeometryOpenGL *shape, - const QMatrix4x4 &geoProjection, - const QDoubleVector3D ¢er, - const Qt::PenCapStyle capStyle, - bool closed, - unsigned int zoom) -{ - // shape->size() == number of triangles - if (shape->m_screenVertices->size() < 2 - || lineWidth < 0.5 || fillColor.alpha() == 0) { // number of points - setSubtreeBlocked(true); - return; - } else { - setSubtreeBlocked(false); - } - - QSGGeometry *fill = QSGGeometryNode::geometry(); - if (shape->m_dataChanged || !shape->isLODActive(zoom) || !fill->vertexCount()) { // fill->vertexCount for when node gets destroyed by MapItemBase bcoz of opacity, then recreated. - if (shape->allocateAndFillEntries(fill, closed, zoom)) { - markDirty(DirtyGeometry); - shape->m_dataChanged = false; - } - } - - // Update this -// if (fillColor != fill_material_.color()) - { - fill_material_.setWrapOffset(shape->m_wrapOffset - 1); - fill_material_.setColor(fillColor); - fill_material_.setGeoProjection(geoProjection); - fill_material_.setCenter(center); - fill_material_.setLineWidth(lineWidth); - fill_material_.setMiter(capStyle != Qt::FlatCap); - setMaterial(&fill_material_); - markDirty(DirtyMaterial); - } -} - -MapPolylineShaderExtruded::MapPolylineShaderExtruded() : QSGMaterialShader(*new QSGMaterialShaderPrivate(this)) -{ - // Heavily adapted from https://github.com/mattdesl/webgl-lines/blob/master/projected/vert.glsl, - // that is (c) Matt DesLauriers, and released under the MIT license. - setShaderFileName(VertexStage, QLatin1String(":/location/declarativemaps/declarativemaps/shaders/polyline_extruded.vert.qsb")); - setShaderFileName(FragmentStage, QLatin1String(":/location/declarativemaps/declarativemaps/shaders/polyline_extruded.frag.qsb")); -} - -bool MapPolylineShaderExtruded::updateUniformData(QSGMaterialShader::RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) -{ - Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); - MapPolylineMaterialExtruded *oldMaterial = static_cast<MapPolylineMaterialExtruded *>(oldEffect); - MapPolylineMaterialExtruded *newMaterial = static_cast<MapPolylineMaterialExtruded *>(newEffect); - - const QColor &c = newMaterial->color(); - const QMatrix4x4 &geoProjection = newMaterial->geoProjection(); - const QDoubleVector3D ¢er = newMaterial->center(); - - // It is safer to use vec4 instead on vec3, as described in: - // https://www.khronos.org/opengl/wiki/Interface_Block_(GLSL)#Memory_layout - QVector4D vecCenter, vecCenter_lowpart; - for (int i = 0; i < 3; i++) - QLocationUtils::split_double(center.get(i), &vecCenter[i], &vecCenter_lowpart[i]); - vecCenter[3] = 0; - vecCenter_lowpart[3] = 0; - - int offset = 0; - char *buf_p = state.uniformData()->data(); - - if (state.isMatrixDirty()) { - const QMatrix4x4 m = state.projectionMatrix(); - memcpy(buf_p + offset, m.constData(), 4*4*4); - } - offset += 4*4*4; - - memcpy(buf_p + offset, geoProjection.constData(), 4*4*4); offset+=4*4*4; - - memcpy(buf_p + offset, &vecCenter, 4*4); offset += 4*4; - - memcpy(buf_p + offset, &vecCenter_lowpart, 4*4); offset+=4*4; - - const float lineWidth = newMaterial->lineWidth(); - memcpy(buf_p + offset, &lineWidth, 4); offset+=4; - - const QRectF viewportRect = state.viewportRect(); - const float aspect = float(viewportRect.width() / viewportRect.height()); - memcpy(buf_p + offset, &aspect, 4); offset+=4; - - offset += 4; // Padding - - int miter = newMaterial->miter(); - memcpy(buf_p + offset, &miter, 4); offset+=4; - - if (oldMaterial == nullptr || c != oldMaterial->color() || state.isOpacityDirty()) { - float opacity = state.opacity() * c.alphaF(); - QVector4D v(c.redF() * opacity, - c.greenF() * opacity, - c.blueF() * opacity, - opacity); - memcpy(buf_p + offset, &v, 4*4); - } - offset+=4*4; - - const float wrapOffset = newMaterial->wrapOffset(); - memcpy(buf_p + offset, &wrapOffset, 4); offset+=4; - - return true; -} - -QSGMaterialShader *MapPolylineMaterialExtruded::createShader(QSGRendererInterface::RenderMode renderMode) const -{ - Q_UNUSED(renderMode); - return new MapPolylineShaderExtruded(); -} - -QSGMaterialType *MapPolylineMaterialExtruded::type() const -{ - static QSGMaterialType type; - return &type; -} - -int MapPolylineMaterialExtruded::compare(const QSGMaterial *other) const -{ - const MapPolylineMaterialExtruded &o = *static_cast<const MapPolylineMaterialExtruded *>(other); - if (o.m_miter == m_miter) - return MapPolylineMaterial::compare(other); - return -1; -} - -QList<QDeclarativeGeoMapItemUtils::vec2> QGeoMapItemLODGeometry::getSimplified( - QList<QDeclarativeGeoMapItemUtils::vec2> - &wrappedPath, // reference as it gets copied in the nested call - double leftBoundWrapped, unsigned int zoom) -{ - // Try a simplify step - QList<QDoubleVector2D> data; - for (auto e: wrappedPath) - data << e.toDoubleVector2D(); - const QList<QDoubleVector2D> simplified = QGeoSimplify::geoSimplifyZL(data, - leftBoundWrapped, - zoom); - - data.clear(); - QList<QDeclarativeGeoMapItemUtils::vec2> simple; - for (auto e: simplified) - simple << e; - return simple; -} - - -bool QGeoMapItemLODGeometry::isLODActive(unsigned int lod) const -{ - return m_screenVertices == m_verticesLOD[zoomToLOD(lod)].data(); -} - -class PolylineSimplifyTask : public QRunnable -{ -public: - PolylineSimplifyTask(const QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>> - &input, // reference as it gets copied in the nested call - const QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>> &output, - double leftBound, unsigned int zoom, QSharedPointer<unsigned int> &working) - : m_zoom(zoom), m_leftBound(leftBound), m_input(input), m_output(output), m_working(working) - { - Q_ASSERT(!input.isNull()); - Q_ASSERT(!output.isNull()); - } - - ~PolylineSimplifyTask() override; - - void run() override - { - // Skip sending notifications for now. Updated data will be picked up eventually. - // ToDo: figure out how to connect a signal from here to a slot in the item. - *m_working = QGeoMapPolylineGeometryOpenGL::zoomToLOD(m_zoom); - const QList<QDeclarativeGeoMapItemUtils::vec2> res = - QGeoMapPolylineGeometryOpenGL::getSimplified( - *m_input, m_leftBound, QGeoMapPolylineGeometryOpenGL::zoomForLOD(m_zoom)); - *m_output = res; - *m_working = 0; - } - - unsigned int m_zoom; - double m_leftBound; - QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>> m_input, m_output; - QSharedPointer<unsigned int> m_working; -}; - -void QGeoMapItemLODGeometry::enqueueSimplificationTask( - const QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>> &input, - const QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>> &output, double leftBound, - unsigned int zoom, QSharedPointer<unsigned int> &working) -{ - Q_ASSERT(!input.isNull()); - Q_ASSERT(!output.isNull()); - PolylineSimplifyTask *task = new PolylineSimplifyTask(input, - output, - leftBound, - zoom, - working); - threadPool->start(task); -} - -PolylineSimplifyTask::~PolylineSimplifyTask() {} - -void QGeoMapItemLODGeometry::selectLOD(unsigned int zoom, double leftBound, bool /* closed */) // closed to tell if this is a polygon or a polyline. -{ - unsigned int requestedLod = zoomToLOD(zoom); - if (!m_verticesLOD[requestedLod].isNull()) { - m_screenVertices = m_verticesLOD[requestedLod].data(); - } else if (!m_verticesLOD.at(0)->isEmpty()) { - // if here, zoomToLOD != 0 and no current working task. - // So select the last filled LOD != m_working (lower-bounded by 1, - // guaranteed to exist), and enqueue the right one - m_verticesLOD[requestedLod] = QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>>( - new QList<QDeclarativeGeoMapItemUtils::vec2>); - - for (unsigned int i = requestedLod - 1; i >= 1; i--) { - if (*m_working != i && !m_verticesLOD[i].isNull()) { - m_screenVertices = m_verticesLOD[i].data(); - break; - } else if (i == 1) { - // get 1 synchronously if not computed already - m_verticesLOD[1] = QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>>( - new QList<QDeclarativeGeoMapItemUtils::vec2>); - *m_verticesLOD[1] = getSimplified( *m_verticesLOD[0], - leftBound, - zoomForLOD(0)); - if (requestedLod == 1) - return; - } - } - - enqueueSimplificationTask( m_verticesLOD.at(0), - m_verticesLOD[requestedLod], - leftBound, - zoom, - m_working); - - } -} - -void QGeoMapItemLODGeometry::selectLODOnDataChanged(unsigned int zoom, double leftBound) const -{ - unsigned int lod = zoomToLOD(zoom); - if (lod > 0) { - // Generate ZL 1 as fallback for all cases != 0. Do not do if 0 is requested - // (= old behavior, LOD disabled) - m_verticesLOD[1] = QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>>( - new QList<QDeclarativeGeoMapItemUtils::vec2>); - *m_verticesLOD[1] = getSimplified( *m_verticesLOD[0], - leftBound, - zoomForLOD(0)); - } - if (lod > 1) { - if (!m_verticesLOD[lod]) - m_verticesLOD[lod] = QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>>( - new QList<QDeclarativeGeoMapItemUtils::vec2>); - enqueueSimplificationTask( m_verticesLOD.at(0), - m_verticesLOD[lod], - leftBound, - zoom, - m_working); - } - m_screenVertices = m_verticesLOD[qMin<unsigned int>(lod, 1)].data(); // return only 0,1 synchronously -} - -unsigned int QGeoMapItemLODGeometry::zoomToLOD(unsigned int zoom) -{ - unsigned int res; - if (zoom > 20) - res = 0; - else - res = qBound<unsigned int>(3, zoom, 20) / 3; // bound LOD'ing between ZL 3 and 20. Every 3 ZoomLevels - return res; -} - -unsigned int QGeoMapItemLODGeometry::zoomForLOD(unsigned int zoom) -{ - unsigned int res = (qBound<unsigned int>(3, zoom, 20) / 3) * 3; - if (zoom < 6) - return res; - return res + 1; // give more resolution when closing in -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h deleted file mode 100644 index 0f52aaaa..00000000 --- a/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h +++ /dev/null @@ -1,177 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEPOLYLINEMAPITEM -#define QDECLARATIVEPOLYLINEMAPITEM - -// -// 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 <QSGGeometryNode> -#include <QSGFlatColorMaterial> -#include <QtPositioning/QGeoPath> - -#include <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qdeclarativegeomapitembase_p.h> -#include <QtLocation/private/qgeomapitemgeometry_p.h> - -#include <QtPositioning/private/qdoublevector2d_p.h> - -QT_BEGIN_NAMESPACE - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeMapLineProperties : public QObject -{ - Q_OBJECT - - Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged) - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) - -public: - explicit QDeclarativeMapLineProperties(QObject *parent = nullptr); - - QColor color() const; - void setColor(const QColor &color); - - qreal width() const; - void setWidth(qreal width); - -Q_SIGNALS: - void widthChanged(qreal width); - void colorChanged(const QColor &color); - -private: - qreal width_ = 1.0; - QColor color_ = Qt::black; -}; - -class QDeclarativePolylineMapItemPrivate; -class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItem : public QDeclarativeGeoMapItemBase -{ - Q_OBJECT - Q_ENUMS(Backend) - - Q_PROPERTY(QList<QGeoCoordinate> path READ path WRITE setPath NOTIFY pathChanged) - Q_PROPERTY(QDeclarativeMapLineProperties *line READ line CONSTANT) - Q_PROPERTY(Backend backend READ backend WRITE setBackend NOTIFY backendChanged REVISION 15) - -public: - enum Backend { - Software = 0, - OpenGLLineStrip = 1, - OpenGLExtruded = 2, - }; - - explicit QDeclarativePolylineMapItem(QQuickItem *parent = nullptr); - ~QDeclarativePolylineMapItem(); - - void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) override; - //from QuickItem - QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) override; - - Q_INVOKABLE int pathLength() const; - Q_INVOKABLE void addCoordinate(const QGeoCoordinate &coordinate); - Q_INVOKABLE void insertCoordinate(int index, const QGeoCoordinate &coordinate); - Q_INVOKABLE void replaceCoordinate(int index, const QGeoCoordinate &coordinate); - Q_INVOKABLE QGeoCoordinate coordinateAt(int index) const; - Q_INVOKABLE bool containsCoordinate(const QGeoCoordinate &coordinate); - Q_INVOKABLE void removeCoordinate(const QGeoCoordinate &coordinate); - Q_INVOKABLE void removeCoordinate(int index); - - QList<QGeoCoordinate> path() const; - virtual void setPath(const QList<QGeoCoordinate> &value); - Q_INVOKABLE void setPath(const QGeoPath &path); - - bool contains(const QPointF &point) const override; - const QGeoShape &geoShape() const override; - void setGeoShape(const QGeoShape &shape) override; - - QDeclarativeMapLineProperties *line(); - - Backend backend() const; - void setBackend(Backend b); - -Q_SIGNALS: - void pathChanged(); - void backendChanged(); - -protected Q_SLOTS: - void markSourceDirtyAndUpdate(); - void updateAfterLinePropertiesChanged(); - void afterViewportChanged(const QGeoMapViewportChangeEvent &event) override; - -protected: - void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; - void setPathFromGeoList(const QList<QGeoCoordinate> &path); - void updatePolish() override; - void componentComplete() override; - void updateLineStyleParameter(QGeoMapParameter *p, const char *propertyName); - void updateLineStyleParameter(QGeoMapParameter *p, const char *propertyName, bool update); - -#ifdef QT_LOCATION_DEBUG -public: -#endif - QGeoPath m_geopath; - QDeclarativeMapLineProperties m_line; - - Backend m_backend = Software; - bool m_dirtyMaterial = true; - bool m_updatingGeometry = false; - - std::unique_ptr<QDeclarativePolylineMapItemPrivate> m_d; - - friend class QDeclarativePolylineMapItemPrivate; - friend class QDeclarativePolylineMapItemPrivateCPU; - friend class QDeclarativePolylineMapItemPrivateOpenGLLineStrip; - friend class QDeclarativePolylineMapItemPrivateOpenGLExtruded; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativeMapLineProperties) -QML_DECLARE_TYPE(QDeclarativePolylineMapItem) - -#endif /* QDECLARATIVEPOLYLINEMAPITEM_H_ */ diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h b/src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h deleted file mode 100644 index 50a1561b..00000000 --- a/src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h +++ /dev/null @@ -1,802 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com> -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEPOLYLINEMAPITEM_P_P_H -#define QDECLARATIVEPOLYLINEMAPITEM_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 <QSharedPointer> -#include <QtCore/QScopedValueRollback> -#include <QSGGeometryNode> -#include <QSGFlatColorMaterial> -#include <QSGMaterialShader> -#include <QtPositioning/QGeoPath> -#include <QtPositioning/QGeoPolygon> -#include <QtPositioning/QGeoRectangle> -#include <QtPositioning/QGeoCircle> - -#include <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qdeclarativepolylinemapitem_p.h> -#include <QtLocation/private/qdeclarativegeomapitemutils_p.h> -#include <QtLocation/private/qdeclarativepolylinemapitem_p.h> -#include <QtLocation/private/qgeomapitemgeometry_p.h> - -#include <QtPositioning/private/qdoublevector2d_p.h> - -#include <array> - -QT_BEGIN_NAMESPACE - -class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolylineGeometry : public QGeoMapItemGeometry -{ -public: - QGeoMapPolylineGeometry(); - - void updateSourcePoints(const QGeoMap &map, - const QList<QDoubleVector2D> &path, - const QGeoCoordinate geoLeftBound); - - void updateScreenPoints(const QGeoMap &map, - qreal strokeWidth, - bool adjustTranslation = true); - - void clearSource(); - - bool contains(const QPointF &point) const override; - - QList<QList<QDoubleVector2D> > clipPath(const QGeoMap &map, - const QList<QDoubleVector2D> &path, - QDoubleVector2D &leftBoundWrapped); - - void pathToScreen(const QGeoMap &map, - const QList<QList<QDoubleVector2D> > &clippedPaths, - const QDoubleVector2D &leftBoundWrapped); - -public: - QList<qreal> srcPoints_; - QList<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; -}; - -class Q_LOCATION_PRIVATE_EXPORT VisibleNode -{ -public: - VisibleNode(); - virtual ~VisibleNode(); - - bool subtreeBlocked() const; - void setSubtreeBlocked(bool blocked); - bool visible() const; - void setVisible(bool visible); - - bool m_blocked : 1; - bool m_visible : 1; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapItemGeometryNode : public QSGGeometryNode, public VisibleNode -{ -public: - ~MapItemGeometryNode() override; - bool isSubtreeBlocked() const override; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolylineMaterial : public QSGFlatColorMaterial -{ -public: - MapPolylineMaterial() - : QSGFlatColorMaterial() - { - // Passing RequiresFullMatrix is essential in order to prevent the - // batch renderer from baking in simple, translate-only transforms into - // the vertex data. The shader will rely on the fact that - // vertexCoord.xy is the Shape-space coordinate and so no modifications - // are welcome. - setFlag(Blending | RequiresFullMatrix); - } - - QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override; - - void setGeoProjection(const QMatrix4x4 &p) - { - m_geoProjection = p; - } - - QMatrix4x4 geoProjection() const - { - return m_geoProjection; - } - - void setCenter(const QDoubleVector3D &c) - { - m_center = c; - } - - QDoubleVector3D center() const - { - return m_center; - } - - int wrapOffset() const - { - return m_wrapOffset; - } - - void setWrapOffset(int wrapOffset) - { - m_wrapOffset = wrapOffset; - } - - void setLineWidth(float lw) - { - m_lineWidth = lw; - } - - float lineWidth() const - { - return m_lineWidth; - } - - QSGMaterialType *type() const override; - int compare(const QSGMaterial *other) const override; - -protected: - QMatrix4x4 m_geoProjection; - QDoubleVector3D m_center; - int m_wrapOffset = 0; - float m_lineWidth = 1.0; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolylineNode : public MapItemGeometryNode -{ -public: - MapPolylineNode(); - ~MapPolylineNode() override; - - void update(const QColor &fillColor, const QGeoMapItemGeometry *shape); - -protected: - QSGFlatColorMaterial fill_material_; - QSGGeometry geometry_; -}; - -class Q_LOCATION_PRIVATE_EXPORT QGeoMapItemLODGeometry -{ -public: - mutable std::array<QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>>, 7> - m_verticesLOD; // fix it to 7, - // do not allow simplifications beyond ZL 20. This could actually be - // limited even further - mutable QList<QDeclarativeGeoMapItemUtils::vec2> *m_screenVertices; - mutable QSharedPointer<unsigned int> m_working; - - QGeoMapItemLODGeometry() - { - resetLOD(); - } - - void resetLOD() - { - // New pointer, some old LOD task might still be running and operating on the old pointers. - m_verticesLOD[0] = QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>>( - new QList<QDeclarativeGeoMapItemUtils::vec2>); - for (unsigned int i = 1; i < m_verticesLOD.size(); ++i) - m_verticesLOD[i] = nullptr; // allocate on first use - m_screenVertices = m_verticesLOD.front().data(); // resetting pointer to data to be LOD 0 - } - - static unsigned int zoomToLOD(unsigned int zoom); - - static unsigned int zoomForLOD(unsigned int zoom); - - bool isLODActive(unsigned int lod) const; - - void selectLOD(unsigned int zoom, double leftBound, bool /*closed*/); - - static QList<QDeclarativeGeoMapItemUtils::vec2> - getSimplified(QList<QDeclarativeGeoMapItemUtils::vec2> &wrappedPath, double leftBoundWrapped, - unsigned int zoom); - - static void enqueueSimplificationTask( - const QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>> - &input, // reference as it gets copied in the nested call - const QSharedPointer<QList<QDeclarativeGeoMapItemUtils::vec2>> &output, - double leftBound, unsigned int zoom, QSharedPointer<unsigned int> &working); - - void selectLODOnDataChanged(unsigned int zoom, double leftBound) const; - - bool selectLODOnLODMismatch(unsigned int zoom, double leftBound, bool closed) const - { - if (*m_working > 0) { - return false; - } - const_cast<QGeoMapItemLODGeometry *>(this)->selectLOD(zoom, - leftBound, - closed); - return true; - } -}; - -class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolylineGeometryOpenGL : public QGeoMapItemGeometry, public QGeoMapItemLODGeometry -{ -public: - typedef struct { - QList<QDoubleVector2D> wrappedBboxes; - } WrappedPolyline; - - QGeoMapPolylineGeometryOpenGL() - { - m_working = QSharedPointer<unsigned int>(new unsigned int(0)); - } - - void updateSourcePoints(const QGeoMap &map, - const QGeoPolygon &poly); - - void updateSourcePoints(const QGeoMap &map, - const QGeoPath &poly); - - void updateSourcePoints(const QGeoProjectionWebMercator &p, - const QList<QDoubleVector2D> &wrappedPath, - const QGeoRectangle &boundingRectangle); - - void updateSourcePoints(const QGeoMap &map, - const QGeoRectangle &rect); - - void updateSourcePoints(const QGeoMap &map, - const QGeoCircle &circle); - - void updateScreenPoints(const QGeoMap &map, - qreal strokeWidth, - bool adjustTranslation = true); - - void updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal strokeWidth = 0.0); - - bool allocateAndFillEntries(QSGGeometry *geom, - bool closed = false, - unsigned int zoom = 0) const; - void allocateAndFillLineStrip(QSGGeometry *geom, - int lod = 0) const; - - bool contains(const QPointF &point) const override - { - Q_UNUSED(point); - return false; - } - - static double distanceTo(const QDoubleVector2D &a, const QDoubleVector2D &b, const QDoubleVector2D &p) - { - double u = ((p.x() - a.x()) * (b.x() - a.x()) + (p.y() - a.y()) * (b.y() - a.y()) ) / (b - a).lengthSquared(); - QDoubleVector2D intersection(a.x() + u * (b.x() - a.x()) , a.y() + u * (b.y() - a.y()) ); - - QDoubleVector2D candidate = ( (p-a).length() < (p-b).length() ) ? a : b; - - if (u > 0 && u < 1 - && (p-intersection).length() < (p-candidate).length() ) // And it falls in the segment - candidate = intersection; - - return qAbs((candidate - p).length()); - } - // Note: this is also slightly incorrect on joins and in the beginning/end of the line - bool contains(const QPointF &point, qreal lineWidth, const QGeoProjectionWebMercator &p) const - { - const double lineHalfWidth = lineWidth * 0.5; - const QDoubleVector2D pt(point); - QDoubleVector2D a; - if (m_screenVertices->size()) - a = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(m_screenVertices->first().toDoubleVector2D())); - QDoubleVector2D b; - for (qsizetype i = 1; i < m_screenVertices->size(); ++i) { - const auto &screenVertice = m_screenVertices->at(i); - if (!a.isFinite()) { - a = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(screenVertice.toDoubleVector2D())); - continue; - } - - b = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(screenVertice.toDoubleVector2D())); - if (!b.isFinite()) { - a = b; - continue; - } - - if (b == a) - continue; - - // Heavily simplifying it here: if a point is not projectable, skip the segment. - // For a correct solution, the segment should be clipped instead. - if (distanceTo(a, b, pt) <= lineHalfWidth) - return true; - - a = b; - } - return false; - } - -public: - QDoubleVector2D m_bboxLeftBoundWrapped; - QList<WrappedPolyline> m_wrappedPolygons; - int m_wrapOffset; - - friend class QDeclarativeCircleMapItem; - friend class QDeclarativePolygonMapItem; - friend class QDeclarativeRectangleMapItem; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolylineShaderLineStrip : public QSGMaterialShader -{ -public: - MapPolylineShaderLineStrip(); - - bool updateUniformData(RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolylineShaderExtruded : public QSGMaterialShader -{ -public: - MapPolylineShaderExtruded(); - - bool updateUniformData(RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolylineNodeOpenGLLineStrip : public MapItemGeometryNode -{ -public: - MapPolylineNodeOpenGLLineStrip(); - ~MapPolylineNodeOpenGLLineStrip() override; - - void update(const QColor &fillColor, - const qreal lineWidth, - const QGeoMapPolylineGeometryOpenGL *shape, - const QMatrix4x4 &geoProjection, - const QDoubleVector3D ¢er, - const Qt::PenCapStyle capStyle = Qt::SquareCap); - -protected: - MapPolylineMaterial fill_material_; - QSGGeometry geometry_; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolylineMaterialExtruded : public MapPolylineMaterial -{ -public: - MapPolylineMaterialExtruded() : MapPolylineMaterial() - { - - } - QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override; - - void setMiter(int m) - { - m_miter = m; - } - - int miter() const - { - return m_miter; - } - - QSGMaterialType *type() const override; - int compare(const QSGMaterial *other) const override; - - int m_miter = 0; -}; - -class Q_LOCATION_PRIVATE_EXPORT MapPolylineNodeOpenGLExtruded : public MapItemGeometryNode -{ -public: - - typedef struct MapPolylineEntry { - QDeclarativeGeoMapItemUtils::vec2 pos; - QDeclarativeGeoMapItemUtils::vec2 prev; - QDeclarativeGeoMapItemUtils::vec2 next; - float direction; - float triangletype; // es2 does not support int attribs - float vertextype; - - static const QSGGeometry::AttributeSet &attributes() - { - static const QSGGeometry::Attribute dataTri[] = { - QSGGeometry::Attribute::createWithAttributeType(0, 2, QSGGeometry::FloatType, QSGGeometry::PositionAttribute) // pos - ,QSGGeometry::Attribute::createWithAttributeType(1, 2, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // next - ,QSGGeometry::Attribute::createWithAttributeType(2, 2, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // previous - ,QSGGeometry::Attribute::createWithAttributeType(3, 1, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // direction - ,QSGGeometry::Attribute::createWithAttributeType(4, 1, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // triangletype - ,QSGGeometry::Attribute::createWithAttributeType(5, 1, QSGGeometry::FloatType, QSGGeometry::UnknownAttribute) // vertextype - }; - static const QSGGeometry::AttributeSet attrsTri = { 6, sizeof(MapPolylineNodeOpenGLExtruded::MapPolylineEntry), dataTri }; - return attrsTri; - } - } MapPolylineEntry; - - MapPolylineNodeOpenGLExtruded(); - ~MapPolylineNodeOpenGLExtruded() override; - - void update(const QColor &fillColor, - float lineWidth, - const QGeoMapPolylineGeometryOpenGL *shape, - const QMatrix4x4 &geoProjection, - const QDoubleVector3D ¢er, - const Qt::PenCapStyle capStyle = Qt::FlatCap, - bool closed = false, - unsigned int zoom = 30); - - static const QSGGeometry::AttributeSet &attributesMapPolylineTriangulated(); - -protected: - MapPolylineMaterialExtruded fill_material_; - QSGGeometry m_geometryTriangulating; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivate -{ -public: - QDeclarativePolylineMapItemPrivate(QDeclarativePolylineMapItem &poly) : m_poly(poly) - { - - } - QDeclarativePolylineMapItemPrivate(QDeclarativePolylineMapItemPrivate &other) : m_poly(other.m_poly) - { - } - - virtual ~QDeclarativePolylineMapItemPrivate(); - virtual void markSourceDirtyAndUpdate() = 0; - virtual void onMapSet() = 0; - virtual void onLinePropertiesChanged() = 0; - virtual void onGeoGeometryChanged() = 0; - virtual void onGeoGeometryUpdated() = 0; - virtual void onItemGeometryChanged() = 0; - virtual void updatePolish() = 0; - virtual void afterViewportChanged() = 0; - virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0; - virtual bool contains(const QPointF &point) const = 0; - - QDeclarativePolylineMapItem &m_poly; - Qt::PenStyle m_penStyle = Qt::SolidLine; - Qt::PenCapStyle m_penCapStyle = Qt::SquareCap; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateCPU: public QDeclarativePolylineMapItemPrivate -{ -public: - QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItem &poly) : QDeclarativePolylineMapItemPrivate(poly) - { - } - - QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItemPrivate &other) - : QDeclarativePolylineMapItemPrivate(other) - { - } - - ~QDeclarativePolylineMapItemPrivateCPU() override; - void onLinePropertiesChanged() override - { - // mark dirty just in case we're a width change - markSourceDirtyAndUpdate(); - } - void markSourceDirtyAndUpdate() override - { - m_geometry.markSourceDirty(); - m_poly.polishAndUpdate(); - } - void regenerateCache() - { - if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()); - m_geopathProjected.clear(); - m_geopathProjected.reserve(m_poly.m_geopath.size()); - for (const QGeoCoordinate &c : m_poly.m_geopath.path()) - m_geopathProjected << p.geoToMapProjection(c); - } - void updateCache() - { - if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection()); - m_geopathProjected << p.geoToMapProjection(m_poly.m_geopath.path().last()); - } - void preserveGeometry() - { - m_geometry.setPreserveGeometry(true, m_poly.m_geopath.boundingGeoRectangle().topLeft()); - } - void afterViewportChanged() override - { - // preserveGeometry is cleared in updateMapItemPaintNode - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onMapSet() override - { - regenerateCache(); - markSourceDirtyAndUpdate(); - } - void onGeoGeometryChanged() override - { - regenerateCache(); - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onGeoGeometryUpdated() override - { - updateCache(); - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onItemGeometryChanged() override - { - onGeoGeometryChanged(); - } - void updatePolish() override - { - if (m_poly.m_geopath.path().length() < 2) { // Possibly cleared - m_geometry.clear(); - m_poly.setWidth(0); - m_poly.setHeight(0); - return; - } - QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry); - m_poly.m_updatingGeometry = true; - - const QGeoMap *map = m_poly.map(); - const qreal borderWidth = m_poly.m_line.width(); - - m_geometry.updateSourcePoints(*map, m_geopathProjected, m_poly.m_geopath.boundingGeoRectangle().topLeft()); - m_geometry.updateScreenPoints(*map, borderWidth); - - m_poly.setWidth(m_geometry.sourceBoundingBox().width() + borderWidth); - m_poly.setHeight(m_geometry.sourceBoundingBox().height() + borderWidth); - - m_poly.setPositionOnMap(m_geometry.origin(), -1 * m_geometry.sourceBoundingBox().topLeft() - + QPointF(borderWidth, borderWidth) * 0.5 ); // it has to be shifted so that the center of the line is on the correct geocoord - } - QSGNode *updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData * /*data*/) override - { - if (!m_node || !oldNode) { - m_node = new MapPolylineNode(); - if (oldNode) { - delete oldNode; - oldNode = nullptr; - } - } else { - m_node = static_cast<MapPolylineNode *>(oldNode); - } - - //TODO: update only material - if (m_geometry.isScreenDirty() || m_poly.m_dirtyMaterial || !oldNode) { - m_node->update(m_poly.m_line.color(), &m_geometry); - m_geometry.setPreserveGeometry(false); - m_geometry.markClean(); - m_poly.m_dirtyMaterial = false; - } - return m_node; - } - bool contains(const QPointF &point) const override - { - return m_geometry.contains(point); - } - - QList<QDoubleVector2D> m_geopathProjected; - QGeoMapPolylineGeometry m_geometry; - MapPolylineNode *m_node = nullptr; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateOpenGLLineStrip: public QDeclarativePolylineMapItemPrivate -{ -public: - - QDeclarativePolylineMapItemPrivateOpenGLLineStrip(QDeclarativePolylineMapItem &poly) : QDeclarativePolylineMapItemPrivate(poly) - { - } - - QDeclarativePolylineMapItemPrivateOpenGLLineStrip(QDeclarativePolylineMapItemPrivate &other) - : QDeclarativePolylineMapItemPrivate(other) - { - } - - ~QDeclarativePolylineMapItemPrivateOpenGLLineStrip() override; - void onLinePropertiesChanged() override - { - afterViewportChanged(); - } - void markSourceDirtyAndUpdate() override - { - m_geometry.markSourceDirty(); - m_poly.polishAndUpdate(); - } - void preserveGeometry() - { - m_geometry.setPreserveGeometry(true, m_poly.m_geopath.boundingGeoRectangle().topLeft()); - } - void onMapSet() override - { - markSourceDirtyAndUpdate(); - } - void onGeoGeometryChanged() override - { - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onGeoGeometryUpdated() override - { - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onItemGeometryChanged() override - { - onGeoGeometryChanged(); - } - void afterViewportChanged() override - { - preserveGeometry(); - m_poly.polishAndUpdate(); - } - bool contains(const QPointF &point) const override - { - return m_geometry.contains(m_poly.mapToItem(m_poly.quickMap(), point), - m_poly.line()->width(), - static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection())); - } - void updatePolish() override - { - if (m_poly.m_geopath.path().length() == 0) { // Possibly cleared - m_geometry.clear(); - m_geometry.clear(); - m_poly.setWidth(0); - m_poly.setHeight(0); - return; - } - - QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry); - m_poly.m_updatingGeometry = true; - const qreal lineWidth = m_poly.m_line.width(); - m_geometry.updateSourcePoints(*m_poly.map(), m_poly.m_geopath); - m_geometry.markScreenDirty(); - m_geometry.updateScreenPoints(*m_poly.map(), lineWidth); - - m_poly.setWidth(m_geometry.sourceBoundingBox().width()); - m_poly.setHeight(m_geometry.sourceBoundingBox().height()); - m_poly.setPosition(1.0 * m_geometry.firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5)); - } - QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override - { - Q_UNUSED(data); - - if (!m_node || !oldNode) { - m_node = new MapPolylineNodeOpenGLLineStrip(); - if (oldNode) - delete oldNode; - } else { - m_node = static_cast<MapPolylineNodeOpenGLLineStrip *>(oldNode); - } - - if (m_geometry.isScreenDirty() || m_poly.m_dirtyMaterial) { - const QGeoMap *map = m_poly.map(); - const QMatrix4x4 &combinedMatrix = map->geoProjection().qsgTransform(); - const QDoubleVector3D &cameraCenter = map->geoProjection().centerMercator(); - m_node->update(m_poly.m_line.color(), // This updates only the material if the geometry is unchanged - m_poly.m_line.width(), - &m_geometry, - combinedMatrix, - cameraCenter); - m_geometry.setPreserveGeometry(false); - m_geometry.markClean(); - m_poly.m_dirtyMaterial = false; - } - return m_node; - } - - QGeoMapPolylineGeometryOpenGL m_geometry; - MapPolylineNodeOpenGLLineStrip *m_node = nullptr; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItemPrivateOpenGLExtruded: public QDeclarativePolylineMapItemPrivateOpenGLLineStrip -{ -public: - - QDeclarativePolylineMapItemPrivateOpenGLExtruded(QDeclarativePolylineMapItem &poly) - : QDeclarativePolylineMapItemPrivateOpenGLLineStrip(poly) - { - } - - QDeclarativePolylineMapItemPrivateOpenGLExtruded(QDeclarativePolylineMapItemPrivate &other) - : QDeclarativePolylineMapItemPrivateOpenGLLineStrip(other) - { - } - - ~QDeclarativePolylineMapItemPrivateOpenGLExtruded() override; - - QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override - { - Q_UNUSED(data); - const QGeoMap *map = m_poly.map(); - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map->geoProjection()); - const QMatrix4x4 &combinedMatrix = p.qsgTransform(); - const QDoubleVector3D &cameraCenter = p.centerMercator(); - const QColor &color = m_poly.m_line.color(); - const float lineWidth = m_poly.m_line.width(); - - MapPolylineNodeOpenGLExtruded *nodeTri = nullptr; - if (!m_nodeTri || !oldNode) { - if (oldNode) - delete oldNode; - nodeTri = new MapPolylineNodeOpenGLExtruded(); - } else { - nodeTri = static_cast<MapPolylineNodeOpenGLExtruded *>(oldNode); - } - - //TODO: update only material - if (m_geometry.isScreenDirty() || m_poly.m_dirtyMaterial) { - nodeTri->update(color, - lineWidth , - &m_geometry, - combinedMatrix, - cameraCenter, - m_penCapStyle, - false, - m_poly.zoomForLOD(int(map->cameraData().zoomLevel()))); - m_geometry.setPreserveGeometry(false); - m_geometry.markClean(); - m_poly.m_dirtyMaterial = false; - } - m_nodeTri = nodeTri; - return nodeTri; - } - - MapPolylineNodeOpenGLExtruded *m_nodeTri = nullptr; -}; -QT_END_NAMESPACE - -#endif // QDECLARATIVEPOLYLINEMAPITEM_P_P_H diff --git a/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp deleted file mode 100644 index b7d01150..00000000 --- a/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp +++ /dev/null @@ -1,409 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativerectanglemapitem_p.h" -#include "qdeclarativerectanglemapitem_p_p.h" -#include "qdeclarativepolygonmapitem_p.h" - -#include <QtCore/QScopedValueRollback> -#include <QPainterPath> -#include <qnumeric.h> -#include <QRectF> -#include <QPointF> - -#include <QtLocation/private/qgeomap_p.h> -#include <QtPositioning/private/qlocationutils_p.h> -#include <QtPositioning/private/qwebmercator_p.h> -#include <QtPositioning/private/qdoublevector2d_p.h> - -QT_BEGIN_NAMESPACE - -/*! - \qmltype MapRectangle - \instantiates QDeclarativeRectangleMapItem - \inqmlmodule QtLocation - \ingroup qml-QtLocation5-maps - \since QtLocation 5.5 - - \brief The MapRectangle type displays a rectangle on a Map. - - The MapRectangle type displays a rectangle on a Map. Rectangles are a - special case of Polygon with exactly 4 vertices and 4 "straight" edges. In - this case, "straight" means that the top-left point has the same latitude - as the top-right point (the top edge), and the bottom-left point has the - same latitude as the bottom-right point (the bottom edge). Similarly, the - points on the left side have the same longitude, and the points on the - right side have the same longitude. - - To specify the rectangle, it requires a \l topLeft and \l bottomRight point, - both given by a \l {coordinate}. - - By default, the rectangle is displayed with transparent fill and a 1-pixel - thick black border. This can be changed using the \l color, \l border.color - and \l border.width properties. - - \note Similar to the \l MapPolygon type, MapRectangles are geographic - items, thus dragging a MapRectangle causes its vertices to be recalculated - in the geographic coordinate space. Apparent stretching of the item - occurs when dragged to the a different latitude, however, its edges - remain straight. - - \section2 Performance - - MapRectangles have a rendering cost identical to a MapPolygon with 4 - vertices. - - Like the other map objects, MapRectangle is normally drawn without a smooth - appearance. Setting the \l opacity property will force the object to be - blended, which decreases performance considerably depending on the hardware - in use. - - \section2 Example Usage - - The following snippet shows a map containing a MapRectangle, spanning - from (-27, 153) to (-28, 153.5), near Brisbane, Australia. The rectangle - is filled in green, with a 2 pixel black border. - - \code - Map { - MapRectangle { - color: 'green' - border.width: 2 - topLeft { - latitude: -27 - longitude: 153 - } - bottomRight { - latitude: -28 - longitude: 153.5 - } - } - } - \endcode - - \image api-maprectangle.png -*/ - -/*! - \qmlproperty bool QtLocation::MapRectangle::autoFadeIn - - This property holds whether the item automatically fades in when zooming into the map - starting from very low zoom levels. By default this is \c true. - Setting this property to \c false causes the map item to always have the opacity specified - with the \l QtQuick::Item::opacity property, which is 1.0 by default. - - \since 5.14 -*/ - -struct RectangleBackendSelector -{ - RectangleBackendSelector() - { - backend = (qgetenv("QTLOCATION_OPENGL_ITEMS").toInt()) ? QDeclarativeRectangleMapItem::OpenGL : QDeclarativeRectangleMapItem::Software; - } - QDeclarativeRectangleMapItem::Backend backend = QDeclarativeRectangleMapItem::Software; -}; - -Q_GLOBAL_STATIC(RectangleBackendSelector, mapRectangleBackendSelector) - -QDeclarativeRectangleMapItem::QDeclarativeRectangleMapItem(QQuickItem *parent) - : QDeclarativeGeoMapItemBase(parent), m_border(this), - m_d(new QDeclarativeRectangleMapItemPrivateCPU(*this)) -{ - // ToDo: handle envvar, and switch implementation. - m_itemType = QGeoMap::MapRectangle; - setFlag(ItemHasContents, true); - QObject::connect(&m_border, &QDeclarativeMapLineProperties::colorChanged, - this, &QDeclarativeRectangleMapItem::onLinePropertiesChanged); - QObject::connect(&m_border, &QDeclarativeMapLineProperties::widthChanged, - this, &QDeclarativeRectangleMapItem::onLinePropertiesChanged); - setBackend(mapRectangleBackendSelector->backend); -} - -QDeclarativeRectangleMapItem::~QDeclarativeRectangleMapItem() -{ -} - -/*! - \qmlproperty MapRectangle.Backend QtLocation::MapRectangle::backend - - This property holds which backend is in use to render the map item. - Valid values are \b MapRectangle.Software and \b{MapRectangle.OpenGL}. - The default value is \b{MapRectangle.Software}. - - \note \b{The release of this API with Qt 5.15 is a Technology Preview}. - Ideally, as the OpenGL backends for map items mature, there will be - no more need to also offer the legacy software-projection backend. - So this property will likely disappear at some later point. - To select OpenGL-accelerated item backends without using this property, - it is also possible to set the environment variable \b QTLOCATION_OPENGL_ITEMS - to \b{1}. - Also note that all current OpenGL backends won't work as expected when enabling - layers on the individual item, or when running on OpenGL core profiles greater than 2.x. - - \since 5.15 -*/ -QDeclarativeRectangleMapItem::Backend QDeclarativeRectangleMapItem::backend() const -{ - return m_backend; -} - -void QDeclarativeRectangleMapItem::setBackend(QDeclarativeRectangleMapItem::Backend b) -{ - if (b == m_backend) - return; - m_backend = b; - std::unique_ptr<QDeclarativeRectangleMapItemPrivate> d( - (m_backend == Software) ? static_cast<QDeclarativeRectangleMapItemPrivate *>( - new QDeclarativeRectangleMapItemPrivateCPU(*this)) - : static_cast<QDeclarativeRectangleMapItemPrivate *>( - new QDeclarativeRectangleMapItemPrivateOpenGL(*this))); - - std::swap(m_d, d); - m_d->onGeoGeometryChanged(); - emit backendChanged(); -} - -/*! - \internal -*/ -void QDeclarativeRectangleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) -{ - QDeclarativeGeoMapItemBase::setMap(quickMap,map); - if (!map) - return; - m_d->onMapSet(); -} - -/*! - \qmlpropertygroup Location::MapRectangle::border - \qmlproperty int MapRectangle::border.width - \qmlproperty color MapRectangle::border.color - - This property is part of the border property group. The border property group - holds the width and color used to draw the border of the rectangle. - The width is in pixels and is independent of the zoom level of the map. - - The default values correspond to a black border with a width of 1 pixel. - For no line, use a width of 0 or a transparent color. -*/ -QDeclarativeMapLineProperties *QDeclarativeRectangleMapItem::border() -{ - return &m_border; -} - -/*! - \qmlproperty coordinate MapRectangle::topLeft - - This property holds the top-left coordinate of the MapRectangle which - can be used to retrieve its longitude, latitude and altitude. -*/ -void QDeclarativeRectangleMapItem::setTopLeft(const QGeoCoordinate &topLeft) -{ - if (m_rectangle.topLeft() == topLeft) - return; - - m_rectangle.setTopLeft(topLeft); - m_d->onGeoGeometryChanged(); - emit topLeftChanged(topLeft); -} - -QGeoCoordinate QDeclarativeRectangleMapItem::topLeft() -{ - return m_rectangle.topLeft(); -} - -/*! - \internal -*/ -void QDeclarativeRectangleMapItem::markSourceDirtyAndUpdate() -{ - m_d->markSourceDirtyAndUpdate(); -} - -void QDeclarativeRectangleMapItem::onLinePropertiesChanged() -{ - m_d->onLinePropertiesChanged(); -} - -/*! - \qmlproperty coordinate MapRectangle::bottomRight - - This property holds the bottom-right coordinate of the MapRectangle which - can be used to retrieve its longitude, latitude and altitude. -*/ -void QDeclarativeRectangleMapItem::setBottomRight(const QGeoCoordinate &bottomRight) -{ - if (m_rectangle.bottomRight() == bottomRight) - return; - - m_rectangle.setBottomRight(bottomRight); - m_d->onGeoGeometryChanged(); - emit bottomRightChanged(bottomRight); -} - -QGeoCoordinate QDeclarativeRectangleMapItem::bottomRight() -{ - return m_rectangle.bottomRight(); -} - -/*! - \qmlproperty color MapRectangle::color - - This property holds the fill color of the rectangle. For no fill, use - a transparent color. -*/ -QColor QDeclarativeRectangleMapItem::color() const -{ - return m_color; -} - -void QDeclarativeRectangleMapItem::setColor(const QColor &color) -{ - if (m_color == color) - return; - m_color = color; - m_dirtyMaterial = true; - polishAndUpdate(); - emit colorChanged(m_color); -} - -/*! - \qmlproperty real MapRectangle::opacity - - This property holds the opacity of the item. Opacity is specified as a - number between 0 (fully transparent) and 1 (fully opaque). The default is 1. - - An item with 0 opacity will still receive mouse events. To stop mouse events, set the - visible property of the item to false. -*/ - -/*! - \internal -*/ -QSGNode *QDeclarativeRectangleMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) -{ - return m_d->updateMapItemPaintNode(oldNode, data); -} - -/*! - \internal -*/ -void QDeclarativeRectangleMapItem::updatePolish() -{ - if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator) - return; - m_d->updatePolish(); -} - -/*! - \internal -*/ -void QDeclarativeRectangleMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event) -{ - if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0) - return; - m_d->afterViewportChanged(); -} - -/*! - \internal -*/ -bool QDeclarativeRectangleMapItem::contains(const QPointF &point) const -{ - return m_d->contains(point); -} - -const QGeoShape &QDeclarativeRectangleMapItem::geoShape() const -{ - return m_rectangle; -} - -void QDeclarativeRectangleMapItem::setGeoShape(const QGeoShape &shape) -{ - if (shape == m_rectangle) - return; - - const QGeoRectangle rectangle = m_rectangle.boundingGeoRectangle(); - const bool tlHasChanged = rectangle.topLeft() != m_rectangle.topLeft(); - const bool brHasChanged = rectangle.bottomRight() != m_rectangle.bottomRight(); - m_rectangle = rectangle; - - m_d->onGeoGeometryChanged(); - if (tlHasChanged) - emit topLeftChanged(m_rectangle.topLeft()); - if (brHasChanged) - emit bottomRightChanged(m_rectangle.bottomRight()); -} - -/*! - \internal -*/ -void QDeclarativeRectangleMapItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - if (!map() || !m_rectangle.isValid() || m_updatingGeometry || newGeometry.topLeft() == oldGeometry.topLeft()) { - QDeclarativeGeoMapItemBase::geometryChange(newGeometry, oldGeometry); - return; - } - // TODO: change the algorithm to preserve the distances and size - QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false); - QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false); - if (!newCenter.isValid() || !oldCenter.isValid()) - return; - double offsetLongi = newCenter.longitude() - oldCenter.longitude(); - double offsetLati = newCenter.latitude() - oldCenter.latitude(); - if (offsetLati == 0.0 && offsetLongi == 0.0) - return; - - m_rectangle.translate(offsetLati, offsetLongi); - m_d->onItemGeometryChanged(); - emit topLeftChanged(m_rectangle.topLeft()); - emit bottomRightChanged(m_rectangle.bottomRight()); - - // Not calling QDeclarativeGeoMapItemBase::geometryChange() as it will be called from a nested - // call to this function. -} - -QDeclarativeRectangleMapItemPrivate::~QDeclarativeRectangleMapItemPrivate() {} - -QDeclarativeRectangleMapItemPrivateCPU::~QDeclarativeRectangleMapItemPrivateCPU() {} - -QDeclarativeRectangleMapItemPrivateOpenGL::~QDeclarativeRectangleMapItemPrivateOpenGL() {} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h b/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h deleted file mode 100644 index 968b9f21..00000000 --- a/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h +++ /dev/null @@ -1,146 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVERECTANGLEMAPITEM_H_ -#define QDECLARATIVERECTANGLEMAPITEM_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 <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qdeclarativegeomapitembase_p.h> -#include <QtLocation/private/qgeomapitemgeometry_p.h> -#include <QtLocation/private/qdeclarativepolylinemapitem_p.h> -#include <QtLocation/private/qdeclarativepolygonmapitem_p_p.h> -#include <QtPositioning/private/qdoublevector2d_p.h> - -#include <QSGGeometryNode> -#include <QSGFlatColorMaterial> - -QT_BEGIN_NAMESPACE - -class QDeclarativeRectangleMapItemPrivate; -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRectangleMapItem: public QDeclarativeGeoMapItemBase -{ - Q_OBJECT - Q_ENUMS(Backend) - - Q_PROPERTY(QGeoCoordinate topLeft READ topLeft WRITE setTopLeft NOTIFY topLeftChanged) - Q_PROPERTY(QGeoCoordinate bottomRight READ bottomRight WRITE setBottomRight NOTIFY bottomRightChanged) - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) - Q_PROPERTY(QDeclarativeMapLineProperties *border READ border CONSTANT) - Q_PROPERTY(Backend backend READ backend WRITE setBackend NOTIFY backendChanged REVISION 15) - -public: - enum Backend { - Software = 0, - OpenGL = 1 - }; - - explicit QDeclarativeRectangleMapItem(QQuickItem *parent = nullptr); - ~QDeclarativeRectangleMapItem() override; - - void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) override; - //from QuickItem - QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) override; - - QGeoCoordinate topLeft(); - void setTopLeft(const QGeoCoordinate ¢er); - - QGeoCoordinate bottomRight(); - void setBottomRight(const QGeoCoordinate ¢er); - - QColor color() const; - void setColor(const QColor &color); - - QDeclarativeMapLineProperties *border(); - - bool contains(const QPointF &point) const override; - const QGeoShape &geoShape() const override; - void setGeoShape(const QGeoShape &shape) override; - - Backend backend() const; - void setBackend(Backend b); - -Q_SIGNALS: - void topLeftChanged(const QGeoCoordinate &topLeft); - void bottomRightChanged(const QGeoCoordinate &bottomRight); - void colorChanged(const QColor &color); - void backendChanged(); - -protected: - void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; - void updatePolish() override; - -protected Q_SLOTS: - void markSourceDirtyAndUpdate(); - void onLinePropertiesChanged(); - void afterViewportChanged(const QGeoMapViewportChangeEvent &event) override; - -private: - QGeoRectangle m_rectangle; - QDeclarativeMapLineProperties m_border; - QColor m_color = Qt::transparent; - bool m_dirtyMaterial = true; - - bool m_updatingGeometry = false; - Backend m_backend = Software; - - std::unique_ptr<QDeclarativeRectangleMapItemPrivate> m_d; - - friend class QDeclarativeRectangleMapItemPrivate; - friend class QDeclarativeRectangleMapItemPrivateCPU; - friend class QDeclarativeRectangleMapItemPrivateOpenGL; -}; - -////////////////////////////////////////////////////////////////////// - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativeRectangleMapItem) - -#endif /* QDECLARATIVERECTANGLEMAPITEM_H_ */ diff --git a/src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h b/src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h deleted file mode 100644 index 09d8b3d2..00000000 --- a/src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h +++ /dev/null @@ -1,420 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com> -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVERECTANGLEMAPITEM_P_P_H -#define QDECLARATIVERECTANGLEMAPITEM_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 <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qdeclarativepolygonmapitem_p_p.h> -#include <QtLocation/private/qdeclarativerectanglemapitem_p.h> -#include <QtPositioning/private/qwebmercator_p.h> - -QT_BEGIN_NAMESPACE - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRectangleMapItemPrivate -{ -public: - QDeclarativeRectangleMapItemPrivate(QDeclarativeRectangleMapItem &rect) : m_rect(rect) - { - - } - QDeclarativeRectangleMapItemPrivate(QDeclarativeRectangleMapItemPrivate &other) : m_rect(other.m_rect) - { - } - - virtual ~QDeclarativeRectangleMapItemPrivate(); - virtual void onLinePropertiesChanged() = 0; - virtual void markSourceDirtyAndUpdate() = 0; - virtual void onMapSet() = 0; - virtual void onGeoGeometryChanged() = 0; - virtual void onItemGeometryChanged() = 0; - virtual void updatePolish() = 0; - virtual void afterViewportChanged() = 0; - virtual QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0; - virtual bool contains(const QPointF &point) const = 0; - - QDeclarativeRectangleMapItem &m_rect; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRectangleMapItemPrivateCPU: public QDeclarativeRectangleMapItemPrivate -{ -public: - QDeclarativeRectangleMapItemPrivateCPU(QDeclarativeRectangleMapItem &rect) : QDeclarativeRectangleMapItemPrivate(rect) - { - } - - QDeclarativeRectangleMapItemPrivateCPU(QDeclarativeRectangleMapItemPrivate &other) - : QDeclarativeRectangleMapItemPrivate(other) - { - } - - ~QDeclarativeRectangleMapItemPrivateCPU() override; - - void onLinePropertiesChanged() override - { - // mark dirty just in case we're a width change - markSourceDirtyAndUpdate(); - } - void markSourceDirtyAndUpdate() override - { - m_geometry.markSourceDirty(); - m_borderGeometry.markSourceDirty(); - m_rect.polishAndUpdate(); - } - void onMapSet() override - { - markSourceDirtyAndUpdate(); - } - void onGeoGeometryChanged() override - { - markSourceDirtyAndUpdate(); - } - void onItemGeometryChanged() override - { - m_geometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); - m_borderGeometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); - markSourceDirtyAndUpdate(); - } - void afterViewportChanged() override - { - m_geometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); - m_borderGeometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); - markSourceDirtyAndUpdate(); - } - void updatePolish() override - { - if (!m_rect.topLeft().isValid() || !m_rect.bottomRight().isValid()) { - m_geometry.clear(); - m_borderGeometry.clear(); - m_rect.setWidth(0); - m_rect.setHeight(0); - return; - } - - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_rect.map()->geoProjection()); - - QScopedValueRollback<bool> rollback(m_rect.m_updatingGeometry); - m_rect.m_updatingGeometry = true; - - const QList<QGeoCoordinate> perimeter = path(m_rect.m_rectangle); - const QList<QDoubleVector2D> pathMercator_ = pathMercator(perimeter); - m_geometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); - m_geometry.updateSourcePoints(*m_rect.map(), pathMercator_); - m_geometry.updateScreenPoints(*m_rect.map(), m_rect.m_border.width()); - - QList<QGeoMapItemGeometry *> geoms; - geoms << &m_geometry; - m_borderGeometry.clear(); - - if (m_rect.m_border.color().alpha() != 0 && m_rect.m_border.width() > 0) { - QList<QDoubleVector2D> closedPath = pathMercator_; - closedPath << closedPath.first(); - - m_borderGeometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); - const QGeoCoordinate &geometryOrigin = m_geometry.origin(); - - m_borderGeometry.srcPoints_.clear(); - m_borderGeometry.srcPointTypes_.clear(); - - QDoubleVector2D borderLeftBoundWrapped; - QList<QList<QDoubleVector2D > > clippedPaths = m_borderGeometry.clipPath(*m_rect.map(), closedPath, borderLeftBoundWrapped); - if (clippedPaths.size()) { - borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin); - m_borderGeometry.pathToScreen(*m_rect.map(), clippedPaths, borderLeftBoundWrapped); - m_borderGeometry.updateScreenPoints(*m_rect.map(), m_rect.m_border.width()); - - geoms << &m_borderGeometry; - } else { - m_borderGeometry.clear(); - } - } - - QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms); - m_rect.setWidth(combined.width() + 2 * m_rect.m_border.width()); // ToDo: fix this! 2 is incorrect - m_rect.setHeight(combined.height() + 2 * m_rect.m_border.width()); - - m_rect.setPositionOnMap(m_geometry.origin(), m_geometry.firstPointOffset()); - } - - QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override - { - Q_UNUSED(data); - if (!m_node || !oldNode) { - m_node = new MapPolygonNode(); - if (oldNode) { - delete oldNode; - oldNode = nullptr; - } - } else { - m_node = static_cast<MapPolygonNode *>(oldNode); - } - - //TODO: update only material - if (m_geometry.isScreenDirty() || m_borderGeometry.isScreenDirty() || m_rect.m_dirtyMaterial) { - m_node->update(m_rect.m_color, m_rect.m_border.color(), &m_geometry, &m_borderGeometry); - m_geometry.setPreserveGeometry(false); - m_borderGeometry.setPreserveGeometry(false); - m_geometry.markClean(); - m_borderGeometry.markClean(); - m_rect.m_dirtyMaterial = false; - } - return m_node; - } - bool contains(const QPointF &point) const override - { - return (m_geometry.contains(point) || m_borderGeometry.contains(point)); - } - - static QList<QGeoCoordinate> path(const QGeoRectangle &rect) - { - QList<QGeoCoordinate> res; - res << rect.topLeft(); - res << QGeoCoordinate(rect.topLeft().latitude(), rect.bottomRight().longitude()); - res << rect.bottomRight(); - res << QGeoCoordinate(rect.bottomRight().latitude(), rect.topLeft().longitude()); - return res; - } - - static QList<QGeoCoordinate> perimeter(const QGeoRectangle &rect) - { - QList<QGeoCoordinate> res; - res << rect.topLeft(); - res << QGeoCoordinate(rect.topLeft().latitude(), rect.bottomRight().longitude()); - res << rect.bottomRight(); - res << QGeoCoordinate(rect.bottomRight().latitude(), rect.topLeft().longitude()); - res << res.first(); - return res; - } - - static QList<QDoubleVector2D> pathMercator(const QList<QGeoCoordinate> &p) - { - QList<QDoubleVector2D> res; - for (const auto &c: p) - res << QWebMercator::coordToMercator(c); - return res; - } - - QGeoMapPolygonGeometry m_geometry; - QGeoMapPolylineGeometry m_borderGeometry; - MapPolygonNode *m_node = nullptr; -}; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRectangleMapItemPrivateOpenGL: public QDeclarativeRectangleMapItemPrivate -{ -public: - QDeclarativeRectangleMapItemPrivateOpenGL(QDeclarativeRectangleMapItem &rect) : QDeclarativeRectangleMapItemPrivate(rect) - { - } - - QDeclarativeRectangleMapItemPrivateOpenGL(QDeclarativeRectangleMapItemPrivate &other) - : QDeclarativeRectangleMapItemPrivate(other) - { - } - - ~QDeclarativeRectangleMapItemPrivateOpenGL() override; - - void markScreenDirtyAndUpdate() - { - // preserveGeometry is cleared in updateMapItemPaintNode - m_geometry.markScreenDirty(); - m_borderGeometry.markScreenDirty(); - m_rect.polishAndUpdate(); - } - void onLinePropertiesChanged() override - { - m_rect.m_dirtyMaterial = true; - afterViewportChanged(); - } - void markSourceDirtyAndUpdate() override - { - m_geometry.markSourceDirty(); - m_borderGeometry.markSourceDirty(); - m_rect.polishAndUpdate(); - } - void preserveGeometry() - { - m_geometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); - m_borderGeometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft()); - } - void onMapSet() override - { - markSourceDirtyAndUpdate(); - } - void onGeoGeometryChanged() override - { - preserveGeometry(); - markSourceDirtyAndUpdate(); - } - void onItemGeometryChanged() override - { - onGeoGeometryChanged(); - } - void afterViewportChanged() override - { - preserveGeometry(); - markScreenDirtyAndUpdate(); - } - void updatePolish() override - { - if (!m_rect.topLeft().isValid() || !m_rect.bottomRight().isValid()) { - m_geometry.clear(); - m_borderGeometry.clear(); - m_rect.setWidth(0); - m_rect.setHeight(0); - return; - } - - QScopedValueRollback<bool> rollback(m_rect.m_updatingGeometry); - m_rect.m_updatingGeometry = true; - const qreal lineWidth = m_rect.m_border.width(); - const QColor &lineColor = m_rect.m_border.color(); - const QColor &fillColor = m_rect.color(); - if (fillColor.alpha() != 0) { - m_geometry.updateSourcePoints(*m_rect.map(), m_rect.m_rectangle); - m_geometry.markScreenDirty(); - m_geometry.updateScreenPoints(*m_rect.map(), lineWidth, lineColor); - } else { - m_geometry.clearBounds(); - } - - QGeoMapItemGeometry * geom = &m_geometry; - m_borderGeometry.clearScreen(); - if (lineColor.alpha() != 0 && lineWidth > 0) { - m_borderGeometry.updateSourcePoints(*m_rect.map(), m_rect.m_rectangle); - m_borderGeometry.markScreenDirty(); - m_borderGeometry.updateScreenPoints(*m_rect.map(), lineWidth); - geom = &m_borderGeometry; - } - m_rect.setWidth(geom->sourceBoundingBox().width()); - m_rect.setHeight(geom->sourceBoundingBox().height()); - m_rect.setPosition(1.0 * geom->firstPointOffset() - QPointF(lineWidth * 0.5,lineWidth * 0.5)); - } - - QSGNode * updateMapItemPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) override - { - Q_UNUSED(data); - - if (!m_rootNode || !oldNode) { - m_rootNode = new QDeclarativePolygonMapItemPrivateOpenGL::RootNode(); - m_node = new MapPolygonNodeGL(); - m_rootNode->appendChildNode(m_node); - m_polylinenode = new MapPolylineNodeOpenGLExtruded(); - m_rootNode->appendChildNode(m_polylinenode); - m_rootNode->markDirty(QSGNode::DirtyNodeAdded); - if (oldNode) - delete oldNode; - } else { - m_rootNode = static_cast<QDeclarativePolygonMapItemPrivateOpenGL::RootNode *>(oldNode); - } - - const QGeoMap *map = m_rect.map(); - const QMatrix4x4 &combinedMatrix = map->geoProjection().qsgTransform(); - const QDoubleVector3D &cameraCenter = map->geoProjection().centerMercator(); - - if (m_borderGeometry.isScreenDirty()) { - /* Do the border update first */ - m_polylinenode->update(m_rect.m_border.color(), - float(m_rect.m_border.width()), - &m_borderGeometry, - combinedMatrix, - cameraCenter, - Qt::SquareCap, - true, - 30); // No LOD for rectangles - m_borderGeometry.setPreserveGeometry(false); - m_borderGeometry.markClean(); - } else { - m_polylinenode->setSubtreeBlocked(true); - } - if (m_geometry.isScreenDirty()) { - m_node->update(m_rect.m_color, - &m_geometry, - combinedMatrix, - cameraCenter); - m_geometry.setPreserveGeometry(false); - m_geometry.markClean(); - } else { - m_node->setSubtreeBlocked(true); - } - - m_rootNode->setSubtreeBlocked(false); - return m_rootNode; - } - bool contains(const QPointF &point) const override - { - const qreal lineWidth = m_rect.m_border.width(); - const QColor &lineColor = m_rect.m_border.color(); - const QRectF &bounds = (lineColor.alpha() != 0 && lineWidth > 0) ? m_borderGeometry.sourceBoundingBox() : m_geometry.sourceBoundingBox(); - if (bounds.contains(point)) { - QDeclarativeGeoMap *m = m_rect.quickMap(); - if (m) { - const QGeoCoordinate crd = m->toCoordinate(m->mapFromItem(&m_rect, point)); - return m_rect.m_rectangle.contains(crd) || m_borderGeometry.contains(m_rect.mapToItem(m_rect.quickMap(), point), - m_rect.border()->width(), - static_cast<const QGeoProjectionWebMercator&>(m_rect.map()->geoProjection())); - } else { - return true; - } - } - return false; - } - - QGeoMapPolygonGeometryOpenGL m_geometry; - QGeoMapPolylineGeometryOpenGL m_borderGeometry; - QDeclarativePolygonMapItemPrivateOpenGL::RootNode *m_rootNode = nullptr; - MapPolygonNodeGL *m_node = nullptr; - MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr; -}; - -QT_END_NAMESPACE - -#endif // QDECLARATIVERECTANGLEMAPITEM_P_P_H - diff --git a/src/location/declarativemaps/qdeclarativeroutemapitem.cpp b/src/location/declarativemaps/qdeclarativeroutemapitem.cpp deleted file mode 100644 index 2d013e1a..00000000 --- a/src/location/declarativemaps/qdeclarativeroutemapitem.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qdeclarativeroutemapitem_p.h" -#include "qdeclarativepolylinemapitem_p.h" -#include "qdeclarativegeoroute_p.h" - -#include <QtQml/QQmlInfo> -#include <QtGui/QPainter> - -QT_BEGIN_NAMESPACE - -/*! - \qmltype MapRoute - \instantiates QDeclarativeRouteMapItem - \inqmlmodule QtLocation - \ingroup qml-QtLocation5-maps - \since QtLocation 5.0 - - \brief The MapRoute type displays a Route on a Map. - - The MapRoute type displays a Route obtained through a RouteModel or - other means, on the Map as a Polyline following the path of the Route. - - MapRoute is really a \l MapPolyline, but with the path specified using the - \l route property instead of directly in \l {coordinate}{coordinates}. - - By default, the route is displayed as a 1-pixel thick black line. This can - be changed using the \l line.width and \l line.color properties. - - \section2 Performance - - For notes about the performance on MapRoute, refer to the documentation for - \l MapPolyline. - - \section2 Example Usage - - Here is how to draw a \l{Route}{route} on a \l{Map}{map}: - - \snippet declarative/maps.qml QtQuick import - \snippet declarative/maps.qml QtLocation import - \codeline - \snippet declarative/maps.qml MapRoute -*/ - -/*! - \qmlpropertygroup Location::MapRoute::line - \qmlproperty int MapRoute::line.width - \qmlproperty color MapRoute::line.color - - This property is part of the line property group. The line - property group holds the width and color used to draw the line. - - The width is in pixels and is independent of the zoom level of the map. - The default values correspond to a black border with a width of 1 pixel. - - For no line, use a width of 0 or a transparent color. -*/ - - -QDeclarativeRouteMapItem::QDeclarativeRouteMapItem(QQuickItem *parent) -: QDeclarativePolylineMapItem(parent) -{ - setFlag(ItemHasContents, true); -} - -QDeclarativeRouteMapItem::~QDeclarativeRouteMapItem() -{ -} - -/*! - \qmlproperty Route MapRoute::route - - This property holds the route to be drawn which can be used - to represent one geographical route. -*/ -QDeclarativeGeoRoute *QDeclarativeRouteMapItem::route() const -{ - return route_; -} - -void QDeclarativeRouteMapItem::setRoute(QDeclarativeGeoRoute *route) -{ - if (route_ == route) - return; - - route_ = route; - - connect(route_, &QDeclarativeGeoRoute::pathChanged, - this, &QDeclarativeRouteMapItem::updateRoutePath); - - if (route_) - setPathFromGeoList(route_->routePath()); - - emit routeChanged(route_); -} - -void QDeclarativeRouteMapItem::updateRoutePath() -{ - setPathFromGeoList(route_->routePath()); -} - -/*! - \internal void QDeclarativeRouteMapItem::setPath(const QList<QGeoCoordinate> &value) - - Used to disable path property on the RouteMapItem - */ -void QDeclarativeRouteMapItem::setPath(const QList<QGeoCoordinate> &value) -{ - Q_UNUSED(value); - qWarning() << "Can not set the path on QDeclarativeRouteMapItem." - << "Please use the route property instead."; -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativeroutemapitem_p.h b/src/location/declarativemaps/qdeclarativeroutemapitem_p.h deleted file mode 100644 index 94cc844a..00000000 --- a/src/location/declarativemaps/qdeclarativeroutemapitem_p.h +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEROUTEMAPITEM_H_ -#define QDECLARATIVEROUTEMAPITEM_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 <QtLocation/private/qlocationglobal_p.h> -#include <QtLocation/private/qdeclarativegeomapitembase_p.h> -#include <QtLocation/private/qdeclarativegeomap_p.h> -#include <QtLocation/private/qdeclarativepolylinemapitem_p.h> -#include <QPen> -#include <QBrush> - -Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeoroute_p.h>) - -QT_BEGIN_NAMESPACE - -class QDeclarativeGeoRoute; - -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRouteMapItem : public QDeclarativePolylineMapItem -{ - Q_OBJECT - - Q_PROPERTY(QDeclarativeGeoRoute *route READ route WRITE setRoute NOTIFY routeChanged) - -public: - explicit QDeclarativeRouteMapItem(QQuickItem *parent = nullptr); - ~QDeclarativeRouteMapItem(); - - QDeclarativeGeoRoute *route() const; - void setRoute(QDeclarativeGeoRoute *route); - -Q_SIGNALS: - void routeChanged(const QDeclarativeGeoRoute *route); - -private slots: - void updateRoutePath(); - -protected: - void setPath(const QList<QGeoCoordinate> &value) override; - -private: - QDeclarativeGeoRoute *route_ = nullptr; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QDeclarativeRouteMapItem) - -#endif /* QDECLARATIVEROUTEMAPITEM_H_ */ diff --git a/src/location/declarativemaps/qgeomapitemgeometry.cpp b/src/location/declarativemaps/qgeomapitemgeometry.cpp deleted file mode 100644 index 60ff4eec..00000000 --- a/src/location/declarativemaps/qgeomapitemgeometry.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgeomapitemgeometry_p.h" -#include "qdeclarativegeomap_p.h" -#include <QtQuick/QSGGeometry> - -#include <QtPositioning/private/qlocationutils_p.h> -#include <QtPositioning/private/qdoublevector2d_p.h> -#include <QtLocation/private/qgeomap_p.h> -#include <QtLocation/private/qgeoprojection_p.h> - -QT_BEGIN_NAMESPACE - -QGeoMapItemGeometry::QGeoMapItemGeometry() -{ -} - -QGeoMapItemGeometry::~QGeoMapItemGeometry() -{ - -} - -/*! - \internal -*/ -void QGeoMapItemGeometry::translate(const QPointF &offset) -{ - for (qsizetype i = 0; i < screenVertices_.size(); ++i) - screenVertices_[i] += offset; - - firstPointOffset_ += offset; - screenOutline_.translate(offset); - screenBounds_.translate(offset); -} - -/*! - \internal -*/ -void QGeoMapItemGeometry::allocateAndFill(QSGGeometry *geom) const -{ - const QList<QPointF> &vx = screenVertices_; - const QList<quint32> &ix = screenIndices_; - - if (isIndexed()) { - geom->allocate(vx.size(), ix.size()); - if (geom->indexType() == QSGGeometry::UnsignedShortType) { - quint16 *its = geom->indexDataAsUShort(); - for (qsizetype i = 0; i < ix.size(); ++i) - its[i] = ix[i]; - } else if (geom->indexType() == QSGGeometry::UnsignedIntType) { - quint32 *its = geom->indexDataAsUInt(); - for (qsizetype i = 0; i < ix.size(); ++i) - its[i] = ix[i]; - } - } else { - geom->allocate(vx.size()); - } - - QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D(); - for (qsizetype i = 0; i < vx.size(); ++i) - pts[i].set(vx[i].x(), vx[i].y()); -} - -/*! - \internal -*/ -QRectF QGeoMapItemGeometry::translateToCommonOrigin(const QList<QGeoMapItemGeometry *> &geoms) -{ - QGeoCoordinate origin = geoms.at(0)->origin(); - - QPainterPath brects; - - // first get max offset - QPointF maxOffset = geoms.at(0)->firstPointOffset(); - for (const QGeoMapItemGeometry *g : geoms) { - QPointF o = g->firstPointOffset(); - maxOffset.setX(qMax(o.x(), maxOffset.x())); - maxOffset.setY(qMax(o.y(), maxOffset.y())); - } - - // then translate everything - for (QGeoMapItemGeometry *g : geoms) { - g->translate(maxOffset - g->firstPointOffset()); - brects.addRect(g->sourceBoundingBox()); - } - - return brects.boundingRect(); -} - -/*! - \internal -*/ -double QGeoMapItemGeometry::geoDistanceToScreenWidth(const QGeoMap &map, - const QGeoCoordinate &fromCoord, - const QGeoCoordinate &toCoord) -{ - // Do not wrap around half the globe - Q_ASSERT(!qFuzzyCompare(fromCoord.longitude(), toCoord.longitude())); - - QGeoCoordinate mapMid = map.geoProjection().itemPositionToCoordinate(QDoubleVector2D(map.viewportWidth()/2.0, 0)); - double halfGeoDist = toCoord.longitude() - fromCoord.longitude(); - if (toCoord.longitude() < fromCoord.longitude()) - halfGeoDist += 360; - halfGeoDist /= 2.0; - QGeoCoordinate geoDelta = QGeoCoordinate(0, - QLocationUtils::wrapLong(mapMid.longitude() + halfGeoDist)); - QDoubleVector2D halfScreenDist = map.geoProjection().coordinateToItemPosition(geoDelta, false) - - QDoubleVector2D(map.viewportWidth()/2.0, 0); - return halfScreenDist.x() * 2.0; -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qgeomapitemgeometry_p.h b/src/location/declarativemaps/qgeomapitemgeometry_p.h deleted file mode 100644 index b6c4a515..00000000 --- a/src/location/declarativemaps/qgeomapitemgeometry_p.h +++ /dev/null @@ -1,164 +0,0 @@ -/**************************************************************************** - ** - ** Copyright (C) 2022 The Qt Company Ltd. - ** Contact: https://www.qt.io/licensing/ - ** - ** This file is part of the QtLocation module of the Qt Toolkit. - ** - ** $QT_BEGIN_LICENSE:LGPL$ - ** Commercial License Usage - ** Licensees holding valid commercial Qt licenses may use this file in - ** accordance with the commercial license agreement provided with the - ** Software or, alternatively, in accordance with the terms contained in - ** a written agreement between you and The Qt Company. For licensing terms - ** and conditions see https://www.qt.io/terms-conditions. For further - ** information use the contact form at https://www.qt.io/contact-us. - ** - ** GNU Lesser General Public License Usage - ** Alternatively, this file may be used under the terms of the GNU Lesser - ** General Public License version 3 as published by the Free Software - ** Foundation and appearing in the file LICENSE.LGPL3 included in the - ** packaging of this file. Please review the following information to - ** ensure the GNU Lesser General Public License version 3 requirements - ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. - ** - ** GNU General Public License Usage - ** Alternatively, this file may be used under the terms of the GNU - ** General Public License version 2.0 or (at your option) the GNU General - ** Public license version 3 or any later version approved by the KDE Free - ** Qt Foundation. The licenses are as published by the Free Software - ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 - ** included in the packaging of this file. Please review the following - ** information to ensure the GNU General Public License requirements will - ** be met: https://www.gnu.org/licenses/gpl-2.0.html and - ** https://www.gnu.org/licenses/gpl-3.0.html. - ** - ** $QT_END_LICENSE$ - ** - ****************************************************************************/ - -#ifndef QGEOMAPITEMGEOMETRY_H -#define QGEOMAPITEMGEOMETRY_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 <QtLocation/private/qlocationglobal_p.h> - -#include <QPainterPath> -#include <QPointF> -#include <QRectF> -#include <QList> -#include <QGeoCoordinate> -#include <QVector2D> -#include <QList> - -QT_BEGIN_NAMESPACE - -class QSGGeometry; -class QGeoMap; - -class Q_LOCATION_PRIVATE_EXPORT QGeoMapItemGeometry -{ -public: - QGeoMapItemGeometry(); - virtual ~QGeoMapItemGeometry(); - - inline bool isSourceDirty() const { return sourceDirty_; } - inline bool isScreenDirty() const { return screenDirty_; } - inline void markSourceDirty() { sourceDirty_ = true; screenDirty_ = true; } - inline void markScreenDirty() { screenDirty_ = true; clipToViewport_ = true; } - inline void markFullScreenDirty() { screenDirty_ = true; clipToViewport_ = false;} - inline void markClean() { screenDirty_ = (sourceDirty_ = false); clipToViewport_ = true;} - inline void clearScreen() { screenDirty_ = false; } - - inline void setPreserveGeometry(bool value, const QGeoCoordinate &geoLeftBound = QGeoCoordinate()) - { - preserveGeometry_ = value; - if (preserveGeometry_) - geoLeftBound_ = geoLeftBound; - } - inline QGeoCoordinate geoLeftBound() { return geoLeftBound_; } - - inline QRectF sourceBoundingBox() const { return sourceBounds_; } - inline QRectF screenBoundingBox() const { return screenBounds_; } - inline void clearBounds() { sourceBounds_ = screenBounds_ = QRectF(); firstPointOffset_ = QPointF(); } - - inline QPointF firstPointOffset() const { return firstPointOffset_; } - void translate(const QPointF &offset); - - inline const QGeoCoordinate &origin() const { return srcOrigin_; } - - QPainterPath screenOutline() const { - return screenOutline_; - } - - virtual bool contains(const QPointF &screenPoint) const { - return screenOutline_.contains(screenPoint); - } - - inline QVector2D vertex(quint32 index) const { - return QVector2D(screenVertices_[index]); - } - - inline QList<QPointF> vertices() const { return screenVertices_; } - inline QList<quint32> indices() const { return screenIndices_; } - - inline bool isIndexed() const { return (!screenIndices_.isEmpty()); } - - /* Size is # of triangles */ - inline quint32 size() const - { - if (isIndexed()) - return screenIndices_.size() / 3; - else - return screenVertices_.size() / 3; - } - - inline void clear() { firstPointOffset_ = QPointF(0,0); - screenVertices_.clear(); screenIndices_.clear(); } - - void allocateAndFill(QSGGeometry *geom) const; - - double geoDistanceToScreenWidth(const QGeoMap &map, - const QGeoCoordinate &fromCoord, - const QGeoCoordinate &toCoord); - - static QRectF translateToCommonOrigin(const QList<QGeoMapItemGeometry *> &geoms); - - mutable bool m_dataChanged = false; - -private: - Q_DISABLE_COPY(QGeoMapItemGeometry); - -protected: - bool sourceDirty_ = true; - bool screenDirty_ = true; - bool clipToViewport_ = true; - bool preserveGeometry_ = false; - QGeoCoordinate geoLeftBound_; - - QPointF firstPointOffset_; - - QPainterPath screenOutline_; - - QRectF sourceBounds_; - QRectF screenBounds_; - - QGeoCoordinate srcOrigin_; - - QList<QPointF> screenVertices_; - QList<quint32> screenIndices_; -}; - -QT_END_NAMESPACE - -#endif // QGEOMAPITEMGEOMETRY_H diff --git a/src/location/declarativemaps/qgeosimplify.cpp b/src/location/declarativemaps/qgeosimplify.cpp deleted file mode 100644 index ad5a3c5d..00000000 --- a/src/location/declarativemaps/qgeosimplify.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/**************************************************************************** -** -** Qt adaptation of geosimplify-js -** Copyright (C) 2017 Daniel Patterson -** See 3rdParty/geosimplify.js for the original license. -** -** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com> -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgeosimplify_p.h" -#include <QtPositioning/private/qlocationutils_p.h> -#include <QtPositioning/private/qdoublevector2d_p.h> -#include <QtPositioning/private/qwebmercator_p.h> - -QT_BEGIN_NAMESPACE - -namespace { - -// p, a and b are intended as "unwrapped" around the left bound -inline QDoubleVector2D closestPoint(const QDoubleVector2D &p, - const QDoubleVector2D &a, - const QDoubleVector2D &b) -{ - if (a == b) - return a; - - const double u = ((p.x() - a.x()) * (b.x() - a.x()) + (p.y() - a.y()) * (b.y() - a.y())) - / (b - a).lengthSquared(); - const QDoubleVector2D intersection(a.x() + u * (b.x() - a.x()) , a.y() + u * (b.y() - a.y())); - QDoubleVector2D candidate = ((p - a).length() < (p - b).length()) ? a : b; - if (u > 0 && u < 1 - && (p - intersection).length() < (p - candidate).length()) { // And it falls in the segment - candidate = intersection; - } - return candidate; -} - -inline double getDist(QDoubleVector2D a, QDoubleVector2D b, double leftBound) -{ - if (a.x() > 1.0) - a.setX(a.x() - leftBound); // wrap X - if (b.x() > 1.0) - b.setX(b.x() - leftBound); // wrap X - return QWebMercator::mercatorToCoord(a).distanceTo(QWebMercator::mercatorToCoord(b)); -} - -// doublevectors Intended as wrapped -inline double getSegDist(const QDoubleVector2D &p, - const QDoubleVector2D &a, - const QDoubleVector2D &b, - double leftBound) -{ - const QDoubleVector2D intersection = closestPoint(p, a, b); - return getDist(intersection, p, leftBound); -} - -inline QGeoCoordinate unwrappedToGeo(QDoubleVector2D p, double leftBound) -{ - if (p.x() > 1.0) - p.setX(p.x() - leftBound); - return QWebMercator::mercatorToCoord(p); -} - -double pixelDistanceAtZoomAndLatitude(int zoom, double latitude) -{ - const double den = double((1 << (zoom + 8))); - const double pixelDist = (QLocationUtils::earthMeanCircumference() - * std::cos(QLocationUtils::radians(latitude))) - / den; - return pixelDist; -} - -// simplification using Ramer-Douglas-Peucker algorithm -void simplifyDouglasPeuckerStepZL(const QList<QDoubleVector2D> &points, double leftBound, - qsizetype first, qsizetype last, int zoomLevel, - QList<QDoubleVector2D> &simplified) -{ - const QGeoCoordinate firstC = unwrappedToGeo(points.at(first), leftBound); - const QGeoCoordinate lastC = unwrappedToGeo(points.at(last), leftBound); - double maxDistanceFound = (pixelDistanceAtZoomAndLatitude(zoomLevel, firstC.latitude()) - + pixelDistanceAtZoomAndLatitude(zoomLevel, lastC.latitude())) * 0.5; - qsizetype index = -1; - - const auto &firstPoint = points.at(first); - const auto &lastPoint = points.at(last); - for (qsizetype i = first + 1; i < last; i++) { - const double distance = getSegDist(points.at(i), - firstPoint, - lastPoint, - leftBound); - - if (distance > maxDistanceFound) { - index = i; - maxDistanceFound = distance; - } - } - - if (index > 0) { - if (index - first > 1) { - simplifyDouglasPeuckerStepZL(points, leftBound, - first, index, zoomLevel, - simplified); - } - simplified.append(points.at(index)); - if (last - index > 1) { - simplifyDouglasPeuckerStepZL(points, leftBound, - index, last, zoomLevel, - simplified); - } - } -} - -} // anonymous namespace - -namespace QGeoSimplify { - -QList<QDoubleVector2D> geoSimplifyZL(const QList<QDoubleVector2D> &points, - double leftBound, int zoomLevel) -{ - if (points.size() <= 2) - return points; - - const qsizetype last = points.size() - 1; - QList<QDoubleVector2D> simplified { points.first() }; - simplifyDouglasPeuckerStepZL(points, leftBound, 0, last, zoomLevel, simplified); - simplified.append(points.at(last)); - return simplified; -} - -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qgeosimplify_p.h b/src/location/declarativemaps/qgeosimplify_p.h deleted file mode 100644 index 1f5c9783..00000000 --- a/src/location/declarativemaps/qgeosimplify_p.h +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** Qt adaptation of geosimplify.js, https://github.com/mapbox/geosimplify-js, (c) 2017, Mapbox -** -** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com> -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGEOSIMPLIFY_P_H -#define QGEOSIMPLIFY_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 <QtCore/QList> - -QT_BEGIN_NAMESPACE - -class QDoubleVector2D; - -namespace QGeoSimplify -{ - // offsetTolerance - how far outside the straight line a point - // needs to be for it to be "kept" - // This function tries to be adaptive in the offsetTolerance across latitudes, - // and return a simplification adequate for the given zoomLevel. - QList<QDoubleVector2D> geoSimplifyZL(const QList<QDoubleVector2D> &points, - double leftBound, int zoomLevel); // in meters -} - -QT_END_NAMESPACE - -#endif // QGEOSIMPLIFY_P_H diff --git a/src/location/declarativemaps/qquickgeomapgesturearea.cpp b/src/location/declarativemaps/qquickgeomapgesturearea.cpp deleted file mode 100644 index c5547278..00000000 --- a/src/location/declarativemaps/qquickgeomapgesturearea.cpp +++ /dev/null @@ -1,1876 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquickgeomapgesturearea_p.h" -#include "qdeclarativegeomap_p.h" -#include "error_messages_p.h" - -#include <QDebug> -#include <QPropertyAnimation> -#include <QtGui/QGuiApplication> -#include <QtGui/qevent.h> -#if QT_CONFIG(wheelevent) -#include <QtGui/QWheelEvent> -#endif -#include <QtGui/QMatrix4x4> -#include <QtGui/QStyleHints> -#include <QtQml/qqmlinfo.h> -#include <QtQuick/QQuickWindow> -#include "qgeomap_p.h" -#include <QtPositioning/private/qdoublevector2d_p.h> -#include <QtPositioning/private/qlocationutils_p.h> -#include <QtPositioningQuick/private/qquickgeocoordinateanimation_p.h> - -#include "math.h" -#include <cmath> - -#define QML_MAP_FLICK_DEFAULTMAXVELOCITY 2500 -#define QML_MAP_FLICK_MINIMUMDECELERATION 500 -#define QML_MAP_FLICK_DEFAULTDECELERATION 2500 -#define QML_MAP_FLICK_MAXIMUMDECELERATION 10000 - -#define QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD 38 -// FlickThreshold determines how far the "mouse" must have moved -// before we perform a flick. -static const int FlickThreshold = 20; -// Really slow flicks can be annoying. -static const qreal MinimumFlickVelocity = 75.0; -// Tolerance for detecting two finger sliding start -static const qreal MaximumParallelPosition = 40.0; // in degrees -// Tolerance for detecting parallel sliding -static const qreal MaximumParallelSlidingAngle = 4.0; // in degrees -// Tolerance for starting rotation -static const qreal MinimumRotationStartingAngle = 15.0; // in degrees -// Tolerance for starting pinch -static const qreal MinimumPinchDelta = 40; // in pixels -// Tolerance for starting tilt when sliding vertical -static const qreal MinimumPanToTiltDelta = 80; // in pixels; - -static qreal distanceBetweenTouchPoints(const QPointF &p1, const QPointF &p2) -{ - return QLineF(p1, p2).length(); -} - -static qreal angleFromPoints(const QPointF &p1, const QPointF &p2) -{ - return QLineF(p1, p2).angle(); -} - -// Keeps it in +- 180 -static qreal touchAngle(const QPointF &p1, const QPointF &p2) -{ - qreal angle = angleFromPoints(p1, p2); - if (angle > 180) - angle -= 360; - return angle; -} - -// Deals with angles crossing the +-180 edge, assumes that the delta can't be > 180 -static qreal angleDelta(const qreal angle1, const qreal angle2) -{ - qreal delta = angle1 - angle2; - if (delta > 180.0) // detect crossing angle1 positive, angle2 negative, rotation counterclockwise, difference negative - delta = angle1 - angle2 - 360.0; - else if (delta < -180.0) // detect crossing angle1 negative, angle2 positive, rotation clockwise, difference positive - delta = angle1 - angle2 + 360.0; - - return delta; -} - -static bool pointDragged(const QPointF &pOld, const QPointF &pNew) -{ - static const int startDragDistance = qApp->styleHints()->startDragDistance(); - return ( qAbs(pNew.x() - pOld.x()) > startDragDistance - || qAbs(pNew.y() - pOld.y()) > startDragDistance); -} - -static qreal vectorSize(const QPointF &vector) -{ - return std::sqrt(vector.x() * vector.x() + vector.y() * vector.y()); -} - -// This linearizes the angles around 0, and keep it linear around 180, allowing to differentiate -// touch angles that are supposed to be parallel (0 or 180 depending on what finger goes first) -static qreal touchAngleTilting(const QPointF &p1, const QPointF &p2) -{ - qreal angle = angleFromPoints(p1, p2); - if (angle > 270) - angle -= 360; - return angle; -} - -static bool movingParallelVertical(const QPointF &p1old, const QPointF &p1new, const QPointF &p2old, const QPointF &p2new) -{ - if (!pointDragged(p1old, p1new) || !pointDragged(p2old, p2new)) - return false; - - QPointF v1 = p1new - p1old; - QPointF v2 = p2new - p2old; - qreal v1v2size = vectorSize(v1 + v2); - - if (v1v2size < vectorSize(v1) || v1v2size < vectorSize(v2)) // going in opposite directions - return false; - - const qreal newAngle = touchAngleTilting(p1new, p2new); - const qreal oldAngle = touchAngleTilting(p1old, p2old); - const qreal angleDiff = angleDelta(newAngle, oldAngle); - - if (qAbs(angleDiff) > MaximumParallelSlidingAngle) - return false; - - return true; -} - -QT_BEGIN_NAMESPACE - - -/*! - \qmltype MapPinchEvent - \instantiates QGeoMapPinchEvent - \inqmlmodule QtLocation - - \brief MapPinchEvent type provides basic information about pinch event. - - MapPinchEvent type provides basic information about pinch event. They are - present in handlers of MapPinch (for example pinchStarted/pinchUpdated). Events are only - guaranteed to be valid for the duration of the handler. - - Except for the \l accepted property, all properties are read-only. - - \section2 Example Usage - - The following example enables the pinch gesture on a map and reacts to the - finished event. - - \code - Map { - id: map - gesture.enabled: true - gesture.onPinchFinished:{ - var coordinate1 = map.toCoordinate(gesture.point1) - var coordinate2 = map.toCoordinate(gesture.point2) - console.log("Pinch started at:") - console.log(" Points (" + gesture.point1.x + ", " + gesture.point1.y + ") - (" + gesture.point2.x + ", " + gesture.point2.y + ")") - console.log(" Coordinates (" + coordinate1.latitude + ", " + coordinate1.longitude + ") - (" + coordinate2.latitude + ", " + coordinate2.longitude + ")") - } - } - \endcode - - \ingroup qml-QtLocation5-maps - \since QtLocation 5.0 -*/ - -/*! - \qmlproperty QPoint QtLocation::MapPinchEvent::center - - This read-only property holds the current center point. -*/ - -/*! - \qmlproperty real QtLocation::MapPinchEvent::angle - - This read-only property holds the current angle between the two points in - the range -180 to 180. Positive values for the angles mean counter-clockwise - while negative values mean the clockwise direction. Zero degrees is at the - 3 o'clock position. -*/ - -/*! - \qmlproperty QPoint QtLocation::MapPinchEvent::point1 - \qmlproperty QPoint QtLocation::MapPinchEvent::point2 - - These read-only properties hold the actual touch points generating the pinch. - The points are not in any particular order. -*/ - -/*! - \qmlproperty int QtLocation::MapPinchEvent::pointCount - - This read-only property holds the number of points currently touched. - The MapPinch will not react until two touch points have initiated a gesture, - but will remain active until all touch points have been released. -*/ - -/*! - \qmlproperty bool QtLocation::MapPinchEvent::accepted - - Setting this property to false in the \c MapPinch::onPinchStarted handler - will result in no further pinch events being generated, and the gesture - ignored. -*/ - -/*! - \qmltype MapGestureArea - \instantiates QQuickGeoMapGestureArea - - \inqmlmodule QtLocation - - \brief The MapGestureArea type provides Map gesture interaction. - - MapGestureArea objects are used as part of a Map, to provide for panning, - flicking and pinch-to-zoom gesture used on touch displays, as well as two finger rotation - and two finger parallel vertical sliding to tilt the map. - On platforms supporting \l QWheelEvent, using the scroll wheel alone, or in combination with - key modifiers Shift or Control will also zoom, rotate or tilt the map, respectively. - - A MapGestureArea is automatically created with a new Map and available with - the \l{Map::gesture}{gesture} property. This is the only way - to create a MapGestureArea, and once created this way cannot be destroyed - without its parent Map. - - The two most commonly used properties of the MapGestureArea are the \l enabled - and \l acceptedGestures properties. Both of these must be set before a - MapGestureArea will have any effect upon interaction with the Map. - The \l flickDeceleration property controls how quickly the map pan slows after contact - is released while panning the map. - - \section2 Performance - - The MapGestureArea, when enabled, must process all incoming touch events in - order to track the shape and size of the "pinch". The overhead added on - touch events can be considered constant time. - - \section2 Example Usage - - The following example enables the pinch and pan gestures on the map, but not flicking. So the - map scrolling will halt immediately on releasing the mouse button / touch. - - \code - Map { - gesture.enabled: true - gesture.acceptedGestures: MapGestureArea.PinchGesture | MapGestureArea.PanGesture - } - \endcode - - \ingroup qml-QtLocation5-maps - \since QtLocation 5.0 -*/ - -/*! - \qmlproperty bool QtLocation::MapGestureArea::enabled - - This property holds whether the gestures are enabled. -*/ - -/*! - \qmlproperty bool QtLocation::MapGestureArea::pinchActive - - This read-only property holds whether the pinch gesture is active. -*/ - -/*! - \qmlproperty bool QtLocation::MapGestureArea::panActive - - This read-only property holds whether the pan gesture is active. - - \note Change notifications for this property were introduced in Qt 5.5. -*/ - -/*! - \qmlproperty bool QtLocation::MapGestureArea::rotationActive - - This read-only property holds whether the two-finger rotation gesture is active. - - \since QtLocation 5.9 -*/ - -/*! - \qmlproperty bool QtLocation::MapGestureArea::tiltActive - - This read-only property holds whether the two-finger tilt gesture is active. - - \since QtLocation 5.9 -*/ - -/*! - \qmlproperty real QtLocation::MapGestureArea::maximumZoomLevelChange - - This property holds the maximum zoom level change per pinch, essentially - meant to be used for setting the zoom sensitivity. - - It is an indicative measure calculated from the dimensions of the - map area, roughly corresponding how much zoom level could change with - maximum pinch zoom. Default value is 4.0, maximum value is 10.0 -*/ - -/*! - \qmlproperty real MapGestureArea::flickDeceleration - - This property holds the rate at which a flick will decelerate. - - The default value is 2500. -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::pinchStarted(PinchEvent event) - - This signal is emitted when a pinch gesture is started. - - Information about the pinch event is provided in \a event. - - The corresponding handler is \c onPinchStarted. - - \sa pinchUpdated, pinchFinished -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::pinchUpdated(PinchEvent event) - - This signal is emitted as the user's fingers move across the map, - after the \l pinchStarted signal is emitted. - - Information about the pinch event is provided in \a event. - - The corresponding handler is \c onPinchUpdated. - - \sa pinchStarted, pinchFinished -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::pinchFinished(PinchEvent event) - - This signal is emitted at the end of a pinch gesture. - - Information about the pinch event is provided in \a event. - - The corresponding handler is \c onPinchFinished. - - \sa pinchStarted, pinchUpdated -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::panStarted() - - This signal is emitted when the map begins to move due to user - interaction. Typically this means that the user is dragging a finger - - or a mouse with one of more mouse buttons pressed - on the map. - - The corresponding handler is \c onPanStarted. -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::panFinished() - - This signal is emitted when the map stops moving due to user - interaction. If a flick was generated, this signal is - emitted before flick starts. If a flick was not - generated, this signal is emitted when the - user stops dragging - that is a mouse or touch release. - - The corresponding handler is \c onPanFinished. - -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::flickStarted() - - This signal is emitted when the map is flicked. A flick - starts from the point where the mouse or touch was released, - while still in motion. - - The corresponding handler is \c onFlickStarted. -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::flickFinished() - - This signal is emitted when the map stops moving due to a flick. - - The corresponding handler is \c onFlickFinished. -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::rotationStarted(PinchEvent event) - - This signal is emitted when a two-finger rotation gesture is started. - - Information about the pinch event is provided in \a event. - - The corresponding handler is \c onRotationStarted. - - \sa rotationUpdated(), rotationFinished() - - \since QtLocation 5.9 -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::rotationUpdated(PinchEvent event) - - This signal is emitted as the user's fingers move across the map, - after the \l rotationStarted() signal is emitted. - - Information about the pinch event is provided in \a event. - - The corresponding handler is \c onRotationUpdated. - - \sa rotationStarted(), rotationFinished() - - \since QtLocation 5.9 -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::rotationFinished(PinchEvent event) - - This signal is emitted at the end of a two-finger rotation gesture. - - Information about the pinch event is provided in \a event. - - The corresponding handler is \c onRotationFinished. - - \sa rotationStarted(), rotationUpdated() - - \since QtLocation 5.9 -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::tiltStarted(PinchEvent event) - - This signal is emitted when a two-finger tilt gesture is started. - - Information about the pinch event is provided in \a event. - - The corresponding handler is \c onTiltStarted. - - \sa tiltUpdated(), tiltFinished() - - \since QtLocation 5.9 -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::tiltUpdated(PinchEvent event) - - This signal is emitted as the user's fingers move across the map, - after the \l tiltStarted signal is emitted. - - Information about the pinch event is provided in \a event. - - The corresponding handler is \c onTiltUpdated. - - \sa tiltStarted(), tiltFinished() - - \since QtLocation 5.9 -*/ - -/*! - \qmlsignal QtLocation::MapGestureArea::tiltFinished(PinchEvent event) - - This signal is emitted at the end of a two-finger tilt gesture. - - Information about the pinch event is provided in \a event. - - The corresponding handler is \c onTiltFinished. - - \sa tiltStarted(), tiltUpdated() - - \since QtLocation 5.9 -*/ - -QQuickGeoMapGestureArea::QQuickGeoMapGestureArea(QDeclarativeGeoMap *map) - : QQuickItem(map), m_declarativeMap(map) -{ - m_touchPointState = touchPoints0; - m_pinchState = pinchInactive; - m_flickState = flickInactive; - m_rotationState = rotationInactive; - m_tiltState = tiltInactive; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::setMap(QGeoMap *map) -{ - if (m_map || !map) - return; - - m_map = map; - m_flick.m_animation = new QQuickGeoCoordinateAnimation(this); - m_flick.m_animation->setTargetObject(m_declarativeMap); - m_flick.m_animation->setProperty(QStringLiteral("center")); - m_flick.m_animation->setEasing(QEasingCurve(QEasingCurve::OutQuad)); - connect(m_flick.m_animation, &QQuickAbstractAnimation::stopped, this, &QQuickGeoMapGestureArea::handleFlickAnimationStopped); - m_map->setAcceptedGestures(panEnabled(), flickEnabled(), pinchEnabled(), rotationEnabled(), tiltEnabled()); -} - -/*! - \qmlproperty bool QtQuick::MapGestureArea::preventStealing - This property holds whether the mouse events may be stolen from this - MapGestureArea. - - If a Map is placed within an item that filters child mouse - and touch events, such as Flickable, the mouse and touch events - may be stolen from the MapGestureArea if a gesture is recognized - by the parent item, e.g. a flick gesture. If preventStealing is - set to \c true, no item will steal the mouse and touch events. - - Note that setting preventStealing to \c true once an item has started - stealing events has no effect until the next press event. - - By default this property is set to \c false. -*/ - -bool QQuickGeoMapGestureArea::preventStealing() const -{ - return m_preventStealing; -} - -void QQuickGeoMapGestureArea::setPreventStealing(bool prevent) -{ - if (prevent != m_preventStealing) { - m_preventStealing = prevent; - m_declarativeMap->setKeepMouseGrab(m_preventStealing && m_enabled); - m_declarativeMap->setKeepTouchGrab(m_preventStealing && m_enabled); - emit preventStealingChanged(); - } -} - -QQuickGeoMapGestureArea::~QQuickGeoMapGestureArea() -{ -} - -/*! - \qmlproperty enumeration QtLocation::MapGestureArea::acceptedGestures - - This property holds a bit field of gestures that are accepted. By default, - all gestures are enabled. - - \value MapGestureArea.NoGesture - Don't support any additional gestures (value: 0x0000). - - \value MapGestureArea.PinchGesture - Support the map pinch gesture (value: 0x0001). - - \value MapGestureArea.PanGesture - Support the map pan gesture (value: 0x0002). - - \value MapGestureArea.FlickGesture - Support the map flick gesture (value: 0x0004). - - \value MapGestureArea.RotationGesture - Support the map rotation gesture (value: 0x0008). - - \value MapGestureArea.TiltGesture - Support the map tilt gesture (value: 0x0010). -*/ - -QQuickGeoMapGestureArea::AcceptedGestures QQuickGeoMapGestureArea::acceptedGestures() const -{ - return m_acceptedGestures; -} - - -void QQuickGeoMapGestureArea::setAcceptedGestures(AcceptedGestures acceptedGestures) -{ - if (acceptedGestures == m_acceptedGestures) - return; - m_acceptedGestures = acceptedGestures; - - if (enabled()) { - setPanEnabled(acceptedGestures & PanGesture); - setFlickEnabled(acceptedGestures & FlickGesture); - setPinchEnabled(acceptedGestures & PinchGesture); - setRotationEnabled(acceptedGestures & RotationGesture); - setTiltEnabled(acceptedGestures & TiltGesture); - } - - if (m_map) - m_map->setAcceptedGestures(panEnabled(), flickEnabled(), pinchEnabled(), rotationEnabled(), tiltEnabled()); - - emit acceptedGesturesChanged(); -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::isPinchActive() const -{ - return m_pinchState == pinchActive; -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::isRotationActive() const -{ - return m_rotationState == rotationActive; -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::isTiltActive() const -{ - return m_tiltState == tiltActive; -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::isPanActive() const -{ - return m_flickState == panActive || m_flickState == flickActive; -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::enabled() const -{ - return m_enabled; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::setEnabled(bool enabled) -{ - if (enabled == m_enabled) - return; - m_enabled = enabled; - - if (enabled) { - setPanEnabled(m_acceptedGestures & PanGesture); - setFlickEnabled(m_acceptedGestures & FlickGesture); - setPinchEnabled(m_acceptedGestures & PinchGesture); - setRotationEnabled(m_acceptedGestures & RotationGesture); - setTiltEnabled(m_acceptedGestures & TiltGesture); - } else { - setPanEnabled(false); - setFlickEnabled(false); - setPinchEnabled(false); - setRotationEnabled(false); - setTiltEnabled(false); - } - if (m_map) - m_map->setAcceptedGestures(panEnabled(), flickEnabled(), pinchEnabled(), rotationEnabled(), tiltEnabled()); - - emit enabledChanged(); -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::pinchEnabled() const -{ - return m_pinch.m_pinchEnabled; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::setPinchEnabled(bool enabled) -{ - m_pinch.m_pinchEnabled = enabled; -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::rotationEnabled() const -{ - return m_pinch.m_rotationEnabled; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::setRotationEnabled(bool enabled) -{ - m_pinch.m_rotationEnabled = enabled; -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::tiltEnabled() const -{ - return m_pinch.m_tiltEnabled; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::setTiltEnabled(bool enabled) -{ - m_pinch.m_tiltEnabled = enabled; -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::panEnabled() const -{ - return m_flick.m_panEnabled; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::setPanEnabled(bool enabled) -{ - if (enabled == m_flick.m_panEnabled) - return; - m_flick.m_panEnabled = enabled; - - // unlike the pinch, the pan existing functionality is to stop immediately - if (!enabled) { - stopPan(); - m_flickState = flickInactive; - } -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::flickEnabled() const -{ - return m_flick.m_flickEnabled; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::setFlickEnabled(bool enabled) -{ - if (enabled == m_flick.m_flickEnabled) - return; - m_flick.m_flickEnabled = enabled; - // unlike the pinch, the flick existing functionality is to stop immediately - if (!enabled) { - bool stateActive = (m_flickState != flickInactive); - stopFlick(); - if (stateActive) { - if (m_flick.m_panEnabled) - m_flickState = panActive; - else - m_flickState = flickInactive; - } - } -} - -/*! - \internal - Used internally to set the minimum zoom level of the gesture area. - The caller is responsible to only send values that are valid - for the map plugin. Negative values are ignored. - */ -void QQuickGeoMapGestureArea::setMinimumZoomLevel(qreal min) -{ - // TODO: remove m_zoom.m_minimum and m_maximum and use m_declarativeMap directly instead. - if (min >= 0) - m_pinch.m_zoom.m_minimum = min; -} - -/*! - \internal - */ -qreal QQuickGeoMapGestureArea::minimumZoomLevel() const -{ - return m_pinch.m_zoom.m_minimum; -} - -/*! - \internal - Used internally to set the maximum zoom level of the gesture area. - The caller is responsible to only send values that are valid - for the map plugin. Negative values are ignored. - */ -void QQuickGeoMapGestureArea::setMaximumZoomLevel(qreal max) -{ - if (max >= 0) - m_pinch.m_zoom.m_maximum = max; -} - -/*! - \internal - */ -qreal QQuickGeoMapGestureArea::maximumZoomLevel() const -{ - return m_pinch.m_zoom.m_maximum; -} - -/*! - \internal -*/ -qreal QQuickGeoMapGestureArea::maximumZoomLevelChange() const -{ - return m_pinch.m_zoom.maximumChange; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::setMaximumZoomLevelChange(qreal maxChange) -{ - if (maxChange == m_pinch.m_zoom.maximumChange || maxChange < 0.1 || maxChange > 10.0) - return; - m_pinch.m_zoom.maximumChange = maxChange; - emit maximumZoomLevelChangeChanged(); -} - -/*! - \internal -*/ -qreal QQuickGeoMapGestureArea::flickDeceleration() const -{ - return m_flick.m_deceleration; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::setFlickDeceleration(qreal deceleration) -{ - if (deceleration < QML_MAP_FLICK_MINIMUMDECELERATION) - deceleration = QML_MAP_FLICK_MINIMUMDECELERATION; - else if (deceleration > QML_MAP_FLICK_MAXIMUMDECELERATION) - deceleration = QML_MAP_FLICK_MAXIMUMDECELERATION; - if (deceleration == m_flick.m_deceleration) - return; - m_flick.m_deceleration = deceleration; - emit flickDecelerationChanged(); -} - - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::handleMousePressEvent(QMouseEvent *event) -{ - if (m_map && m_map->handleEvent(event)) { - event->accept(); - return; - } - - handleTouchEvent(event); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::handleMouseMoveEvent(QMouseEvent *event) -{ - if (m_map && m_map->handleEvent(event)) { - event->accept(); - return; - } - - handleTouchEvent(event); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::handleMouseReleaseEvent(QMouseEvent *event) -{ - if (m_map && m_map->handleEvent(event)) { - event->accept(); - return; - } - - handleTouchEvent(event); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::handleTouchUngrabEvent() -{ - m_touchPoints.clear(); - update(); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::handleTouchEvent(QPointerEvent *event) -{ - if (m_map && m_map->handleEvent(event)) { - event->accept(); - return; - } - - // m_touchPoints.clear(); - - // Update the points we are going to use ourselves. - for (const auto &point: event->points()){ - auto grabber = qobject_cast<QQuickItem*>(event->exclusiveGrabber(point)); - // qDebug() << event->type() << point.state() << point << grabber; - - bool canBeGrabbed = grabber == nullptr || grabber == m_declarativeMap || (!grabber->keepTouchGrab() && !grabber->keepMouseGrab()); - // if (canBeGrabbed) m_touchPoints << point; - - //TODO: Testing shows that events are not always propagated with full set of points. - // Therefore, it can happen that our first point is a different point for a moment - // and that will trigger pan or pinch right away. So we keep track of points by their states - // an IDs but then testing shows that sometimes not all points are finished with Release. - // They just dissapear. Child MouseArea will 'eat up' second touch point if first point - // is grabbed by child ListView, for example. Maybe it's a bug in 6.2 RC? - if (point.state() == QEventPoint::Released || !canBeGrabbed){ - for (qsizetype i = 0; i < m_touchPoints.count(); ++i) { - if (m_touchPoints.at(i).id() == point.id()){ - m_touchPoints.removeAt(i); - } - } - }else{ - bool replaced = false; - for (qsizetype i = 0; i < m_touchPoints.count(); ++i) { - if (m_touchPoints.at(i).id() == point.id()){ - m_touchPoints.replace(i, point); - replaced = true; - } - } - if (!replaced){ - m_touchPoints << point; - } - } - - } - // qDebug() << "m_touchPoints.count=" << m_touchPoints.count(); - update(); - - if (isPanActive()){ - // In case we are pannin, we are using only the first point - // We let others to grab the second, if needed. - if (m_touchPoints.count() > 0){ - event->setExclusiveGrabber(m_touchPoints.at(0), m_declarativeMap); - } - }else if (isActive()){ - for (const auto &point: m_touchPoints) { - event->setExclusiveGrabber(point, m_declarativeMap); - } - } -} - -#if QT_CONFIG(wheelevent) -void QQuickGeoMapGestureArea::handleWheelEvent(QWheelEvent *event) -{ - if (!m_map) - return; - - if (m_map->handleEvent(event)) { - event->accept(); - return; - } - - const QGeoCoordinate &wheelGeoPos = m_declarativeMap->toCoordinate(event->position(), false); - const QPointF &preZoomPoint = event->position(); - - // Not using AltModifier as, for some reason, it causes angleDelta to be 0 - if (event->modifiers() & Qt::ShiftModifier && rotationEnabled()) { - emit rotationStarted(&m_pinch.m_event); - // First set bearing - const double bearingDelta = event->angleDelta().y() * qreal(0.05); - m_declarativeMap->setBearing(m_declarativeMap->bearing() + bearingDelta, wheelGeoPos); - emit rotationUpdated(&m_pinch.m_event); - emit rotationFinished(&m_pinch.m_event); - } else if (event->modifiers() & Qt::ControlModifier && tiltEnabled()) { - emit tiltStarted(&m_pinch.m_event); - const double tiltDelta = event->angleDelta().y() * qreal(0.05); - m_declarativeMap->setTilt(m_declarativeMap->tilt() + tiltDelta); - emit tiltUpdated(&m_pinch.m_event); - emit tiltFinished(&m_pinch.m_event); - } else if (pinchEnabled()) { - const double zoomLevelDelta = event->angleDelta().y() * qreal(0.001); - // Gesture area should always honor maxZL, but Map might not. - m_declarativeMap->setZoomLevel(qMin<qreal>(m_declarativeMap->zoomLevel() + zoomLevelDelta, maximumZoomLevel()), - false); - const QPointF &postZoomPoint = m_declarativeMap->fromCoordinate(wheelGeoPos, false); - - if (preZoomPoint != postZoomPoint) // need to re-anchor the wheel geoPos to the event position - m_declarativeMap->alignCoordinateToPoint(wheelGeoPos, preZoomPoint); - } - // event->accept(); -} -#endif - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::clearTouchData() -{ - m_flickVector = QVector2D(); - m_touchPointsCentroid.setX(0); - m_touchPointsCentroid.setY(0); - m_touchCenterCoord.setLongitude(0); - m_touchCenterCoord.setLatitude(0); - m_startCoord.setLongitude(0); - m_startCoord.setLatitude(0); -} - - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::updateFlickParameters(const QPointF &pos) -{ - // Take velocity samples every sufficient period of time, used later to determine the flick - // duration and speed (when mouse is released). - qreal elapsed = qreal(m_lastPosTime.elapsed()); - - if (elapsed >= QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD) { - elapsed /= 1000.; - qreal vel = distanceBetweenTouchPoints(pos, m_lastPos) / elapsed; - m_flickVector = (QVector2D(pos) - QVector2D(m_lastPos)).normalized(); - m_flickVector *= qBound<qreal>(-m_flick.m_maxVelocity, vel, m_flick.m_maxVelocity); - - m_lastPos = pos; - m_lastPosTime.restart(); - } -} - -void QQuickGeoMapGestureArea::setTouchPointState(const QQuickGeoMapGestureArea::TouchPointState state) -{ - m_touchPointState = state; -} - -void QQuickGeoMapGestureArea::setFlickState(const QQuickGeoMapGestureArea::FlickState state) -{ - m_flickState = state; -} - -void QQuickGeoMapGestureArea::setTiltState(const QQuickGeoMapGestureArea::TiltState state) -{ - m_tiltState = state; -} - -void QQuickGeoMapGestureArea::setRotationState(const QQuickGeoMapGestureArea::RotationState state) -{ - m_rotationState = state; -} - -void QQuickGeoMapGestureArea::setPinchState(const QQuickGeoMapGestureArea::PinchState state) -{ - m_pinchState = state; -} - -/*! - \internal -*/ - -bool QQuickGeoMapGestureArea::isActive() const -{ - return isPanActive() || isPinchActive() || isRotationActive() || isTiltActive(); -} - -/*! - \internal -*/ -// simplify the gestures by using a state-machine format (easy to move to a future state machine) -void QQuickGeoMapGestureArea::update() -{ - if (!m_map) - return; - // First state machine is for the number of touch points - - //combine touch with mouse event - m_allPoints.clear(); - m_allPoints << m_touchPoints; - std::sort(m_allPoints.begin(), m_allPoints.end(), [](const QTouchEvent::TouchPoint &tp1, const QTouchEvent::TouchPoint &tp2) { return tp1.id() < tp2.id(); }); - - touchPointStateMachine(); - - // Parallel state machine for tilt. Tilt goes first as it blocks anything else, when started. - // But tilting can also only start if nothing else is active. - if (isTiltActive() || m_pinch.m_tiltEnabled) - tiltStateMachine(); - - // Parallel state machine for pinch - if (isPinchActive() || m_pinch.m_pinchEnabled) - pinchStateMachine(); - - // Parallel state machine for rotation. - if (isRotationActive() || m_pinch.m_rotationEnabled) - rotationStateMachine(); - - // Parallel state machine for pan (since you can pan at the same time as pinching) - // The stopPan function ensures that pan stops immediately when disabled, - // but the isPanActive() below allows pan continue its current gesture if you disable - // the whole gesture. - // Pan goes last because it does reanchoring in updatePan() which makes the map - // properly rotate around the touch point centroid. - if (isPanActive() || m_flick.m_flickEnabled || m_flick.m_panEnabled) - panStateMachine(); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::touchPointStateMachine() -{ - // Transitions: - switch (m_touchPointState) { - case touchPoints0: - if (m_allPoints.count() == 1) { - clearTouchData(); - startOneTouchPoint(); - setTouchPointState(touchPoints1); - } else if (m_allPoints.count() >= 2) { - clearTouchData(); - startTwoTouchPoints(); - setTouchPointState(touchPoints2); - } - break; - case touchPoints1: - if (m_allPoints.count() == 0) { - setTouchPointState(touchPoints0); - } else if (m_allPoints.count() == 2) { - m_touchCenterCoord = m_declarativeMap->toCoordinate(m_touchPointsCentroid, false); - startTwoTouchPoints(); - setTouchPointState(touchPoints2); - } - break; - case touchPoints2: - if (m_allPoints.count() == 0) { - setTouchPointState(touchPoints0); - } else if (m_allPoints.count() == 1) { - m_touchCenterCoord = m_declarativeMap->toCoordinate(m_touchPointsCentroid, false); - startOneTouchPoint(); - setTouchPointState(touchPoints1); - } - break; - }; - - // Update - switch (m_touchPointState) { - case touchPoints0: - break; // do nothing if no touch points down - case touchPoints1: - updateOneTouchPoint(); - break; - case touchPoints2: - updateTwoTouchPoints(); - break; - } -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::startOneTouchPoint() -{ - m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePosition()); - m_lastPos = m_sceneStartPoint1; - m_lastPosTime.start(); - QGeoCoordinate startCoord = m_declarativeMap->toCoordinate(m_sceneStartPoint1, false); - // ensures a smooth transition for panning - m_startCoord.setLongitude(m_startCoord.longitude() + startCoord.longitude() - - m_touchCenterCoord.longitude()); - m_startCoord.setLatitude(m_startCoord.latitude() + startCoord.latitude() - - m_touchCenterCoord.latitude()); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::updateOneTouchPoint() -{ - m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePressPosition()); - m_touchPointsCentroid = mapFromScene(m_allPoints.at(0).scenePosition()); - updateFlickParameters(m_touchPointsCentroid); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::startTwoTouchPoints() -{ - m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePosition()); - m_sceneStartPoint2 = mapFromScene(m_allPoints.at(1).scenePosition()); - QPointF startPos = (m_sceneStartPoint1 + m_sceneStartPoint2) * 0.5; - m_lastPos = startPos; - m_lastPosTime.start(); - QGeoCoordinate startCoord = m_declarativeMap->toCoordinate(startPos, false); - m_startCoord.setLongitude(m_startCoord.longitude() + startCoord.longitude() - - m_touchCenterCoord.longitude()); - m_startCoord.setLatitude(m_startCoord.latitude() + startCoord.latitude() - - m_touchCenterCoord.latitude()); - m_twoTouchAngleStart = touchAngle(m_sceneStartPoint1, m_sceneStartPoint2); // Initial angle used for calculating rotation - m_distanceBetweenTouchPointsStart = distanceBetweenTouchPoints(m_sceneStartPoint1, m_sceneStartPoint2); - m_twoTouchPointsCentroidStart = (m_sceneStartPoint1 + m_sceneStartPoint2) / 2; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::updateTwoTouchPoints() -{ - m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePressPosition()); - QPointF p1 = mapFromScene(m_allPoints.at(0).scenePosition()); - m_sceneStartPoint2 = mapFromScene(m_allPoints.at(1).scenePressPosition()); - QPointF p2 = mapFromScene(m_allPoints.at(1).scenePosition()); - m_distanceBetweenTouchPoints = distanceBetweenTouchPoints(p1, p2); - m_touchPointsCentroid = (p1 + p2) / 2; - updateFlickParameters(m_touchPointsCentroid); - - m_twoTouchAngle = touchAngle(p1, p2); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::tiltStateMachine() -{ - TiltState lastState = m_tiltState; - // Transitions: - switch (m_tiltState) { - case tiltInactive: - if (m_allPoints.count() >= 2) { - if (!isRotationActive() && !isPinchActive() && canStartTilt()) { // only gesture that can be overridden: pan/flick - m_declarativeMap->setKeepTouchGrab(true); - startTilt(); - setTiltState(tiltActive); - } else { - setTiltState(tiltInactiveTwoPoints); - } - } - break; - case tiltInactiveTwoPoints: - if (m_allPoints.count() <= 1) { - setTiltState(tiltInactive); - } else { - if (!isRotationActive() && !isPinchActive() && canStartTilt()) { // only gesture that can be overridden: pan/flick - m_declarativeMap->setKeepTouchGrab(true); - startTilt(); - setTiltState(tiltActive); - } - } - break; - case tiltActive: - if (m_allPoints.count() <= 1) { - setTiltState(tiltInactive); - m_declarativeMap->setKeepTouchGrab(m_preventStealing); - endTilt(); - } - break; - } - // This line implements an exclusive state machine, where the transitions and updates don't - // happen on the same frame - if (m_tiltState != lastState) { - emit tiltActiveChanged(); - return; - } - - // Update - switch (m_tiltState) { - case tiltInactive: - case tiltInactiveTwoPoints: - break; // do nothing - case tiltActive: - updateTilt(); - break; - } -} - -bool validateTouchAngleForTilting(const qreal angle) -{ - return ((qAbs(angle) - 180.0) < MaximumParallelPosition) || (qAbs(angle) < MaximumParallelPosition); -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::canStartTilt() -{ - if (m_allPoints.count() >= 2) { - QPointF p1 = mapFromScene(m_allPoints.at(0).scenePosition()); - QPointF p2 = mapFromScene(m_allPoints.at(1).scenePosition()); - if (validateTouchAngleForTilting(m_twoTouchAngle) - && movingParallelVertical(m_sceneStartPoint1, p1, m_sceneStartPoint2, p2) - && qAbs(m_twoTouchPointsCentroidStart.y() - m_touchPointsCentroid.y()) > MinimumPanToTiltDelta) { - m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid)); - m_pinch.m_event.setAngle(m_twoTouchAngle); - m_pinch.m_event.setPoint1(p1); - m_pinch.m_event.setPoint2(p2); - m_pinch.m_event.setPointCount(m_allPoints.count()); - m_pinch.m_event.setAccepted(true); - emit tiltStarted(&m_pinch.m_event); - return true; - } - } - return false; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::startTilt() -{ - if (isPanActive()) { - stopPan(); - setFlickState(flickInactive); - } - - m_pinch.m_tilt.m_startTouchCentroid = m_touchPointsCentroid; - m_pinch.m_tilt.m_startTilt = m_declarativeMap->tilt(); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::updateTilt() -{ - // Calculate the new tilt - qreal verticalDisplacement = (m_touchPointsCentroid - m_pinch.m_tilt.m_startTouchCentroid).y(); - - // Approach: 10pixel = 1 degree. - qreal tilt = verticalDisplacement / 10.0; - qreal newTilt = m_pinch.m_tilt.m_startTilt - tilt; - m_declarativeMap->setTilt(newTilt); - - m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid)); - m_pinch.m_event.setAngle(m_twoTouchAngle); - m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePosition()); - m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePosition()); - m_pinch.m_event.setPoint1(m_pinch.m_lastPoint1); - m_pinch.m_event.setPoint2(m_pinch.m_lastPoint2); - m_pinch.m_event.setPointCount(m_allPoints.count()); - m_pinch.m_event.setAccepted(true); - - emit tiltUpdated(&m_pinch.m_event); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::endTilt() -{ - QPointF p1 = mapFromScene(m_pinch.m_lastPoint1); - QPointF p2 = mapFromScene(m_pinch.m_lastPoint2); - m_pinch.m_event.setCenter((p1 + p2) / 2); - m_pinch.m_event.setAngle(m_pinch.m_lastAngle); - m_pinch.m_event.setPoint1(p1); - m_pinch.m_event.setPoint2(p2); - m_pinch.m_event.setAccepted(true); - m_pinch.m_event.setPointCount(0); - emit tiltFinished(&m_pinch.m_event); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::rotationStateMachine() -{ - RotationState lastState = m_rotationState; - // Transitions: - switch (m_rotationState) { - case rotationInactive: - if (m_allPoints.count() >= 2) { - if (!isTiltActive() && canStartRotation()) { - m_declarativeMap->setKeepTouchGrab(true); - startRotation(); - setRotationState(rotationActive); - } else { - setRotationState(rotationInactiveTwoPoints); - } - } - break; - case rotationInactiveTwoPoints: - if (m_allPoints.count() <= 1) { - setRotationState(rotationInactive); - } else { - if (!isTiltActive() && canStartRotation()) { - m_declarativeMap->setKeepTouchGrab(true); - startRotation(); - setRotationState(rotationActive); - } - } - break; - case rotationActive: - if (m_allPoints.count() <= 1) { - setRotationState(rotationInactive); - m_declarativeMap->setKeepTouchGrab(m_preventStealing); - endRotation(); - } - break; - } - // This line implements an exclusive state machine, where the transitions and updates don't - // happen on the same frame - if (m_rotationState != lastState) { - emit rotationActiveChanged(); - return; - } - - // Update - switch (m_rotationState) { - case rotationInactive: - case rotationInactiveTwoPoints: - break; // do nothing - case rotationActive: - updateRotation(); - break; - } -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::canStartRotation() -{ - if (m_allPoints.count() >= 2) { - QPointF p1 = mapFromScene(m_allPoints.at(0).scenePosition()); - QPointF p2 = mapFromScene(m_allPoints.at(1).scenePosition()); - if (pointDragged(m_sceneStartPoint1, p1) || pointDragged(m_sceneStartPoint2, p2)) { - qreal delta = angleDelta(m_twoTouchAngleStart, m_twoTouchAngle); - if (qAbs(delta) < MinimumRotationStartingAngle) { - return false; - } - m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid)); - m_pinch.m_event.setAngle(m_twoTouchAngle); - m_pinch.m_event.setPoint1(p1); - m_pinch.m_event.setPoint2(p2); - m_pinch.m_event.setPointCount(m_allPoints.count()); - m_pinch.m_event.setAccepted(true); - emit rotationStarted(&m_pinch.m_event); - return m_pinch.m_event.accepted(); - } - } - return false; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::startRotation() -{ - m_pinch.m_rotation.m_startBearing = m_declarativeMap->bearing(); - m_pinch.m_rotation.m_previousTouchAngle = m_twoTouchAngle; - m_pinch.m_rotation.m_totalAngle = 0.0; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::updateRotation() -{ - // Calculate the new bearing - qreal angle = angleDelta(m_pinch.m_rotation.m_previousTouchAngle, m_twoTouchAngle); - if (qAbs(angle) < 0.2) // avoiding too many updates - return; - - m_pinch.m_rotation.m_previousTouchAngle = m_twoTouchAngle; - m_pinch.m_rotation.m_totalAngle += angle; - qreal newBearing = m_pinch.m_rotation.m_startBearing - m_pinch.m_rotation.m_totalAngle; - m_declarativeMap->setBearing(newBearing); - - m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid)); - m_pinch.m_event.setAngle(m_twoTouchAngle); - m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePosition()); - m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePosition()); - m_pinch.m_event.setPoint1(m_pinch.m_lastPoint1); - m_pinch.m_event.setPoint2(m_pinch.m_lastPoint2); - m_pinch.m_event.setPointCount(m_allPoints.count()); - m_pinch.m_event.setAccepted(true); - - emit rotationUpdated(&m_pinch.m_event); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::endRotation() -{ - QPointF p1 = mapFromScene(m_pinch.m_lastPoint1); - QPointF p2 = mapFromScene(m_pinch.m_lastPoint2); - m_pinch.m_event.setCenter((p1 + p2) / 2); - m_pinch.m_event.setAngle(m_pinch.m_lastAngle); - m_pinch.m_event.setPoint1(p1); - m_pinch.m_event.setPoint2(p2); - m_pinch.m_event.setAccepted(true); - m_pinch.m_event.setPointCount(0); - emit rotationFinished(&m_pinch.m_event); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::pinchStateMachine() -{ - PinchState lastState = m_pinchState; - // Transitions: - switch (m_pinchState) { - case pinchInactive: - if (m_allPoints.count() >= 2) { - if (!isTiltActive() && canStartPinch()) { - m_declarativeMap->setKeepTouchGrab(true); - startPinch(); - setPinchState(pinchActive); - } else { - setPinchState(pinchInactiveTwoPoints); - } - } - break; - case pinchInactiveTwoPoints: - if (m_allPoints.count() <= 1) { - setPinchState(pinchInactive); - } else { - if (!isTiltActive() && canStartPinch()) { - m_declarativeMap->setKeepTouchGrab(true); - startPinch(); - setPinchState(pinchActive); - } - } - break; - case pinchActive: - if (m_allPoints.count() <= 1) { // Once started, pinch goes off only when finger(s) are release - setPinchState(pinchInactive); - m_declarativeMap->setKeepTouchGrab(m_preventStealing); - endPinch(); - } - break; - } - // This line implements an exclusive state machine, where the transitions and updates don't - // happen on the same frame - if (m_pinchState != lastState) { - emit pinchActiveChanged(); - return; - } - - // Update - switch (m_pinchState) { - case pinchInactive: - case pinchInactiveTwoPoints: - break; // do nothing - case pinchActive: - updatePinch(); - break; - } -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::canStartPinch() -{ - if (m_allPoints.count() >= 2) { - QPointF p1 = mapFromScene(m_allPoints.at(0).scenePosition()); - QPointF p2 = mapFromScene(m_allPoints.at(1).scenePosition()); - if (qAbs(m_distanceBetweenTouchPoints - m_distanceBetweenTouchPointsStart) > MinimumPinchDelta) { - m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid)); - m_pinch.m_event.setAngle(m_twoTouchAngle); - m_pinch.m_event.setPoint1(p1); - m_pinch.m_event.setPoint2(p2); - m_pinch.m_event.setPointCount(m_allPoints.count()); - m_pinch.m_event.setAccepted(true); - emit pinchStarted(&m_pinch.m_event); - return m_pinch.m_event.accepted(); - } - } - return false; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::startPinch() -{ - m_pinch.m_startDist = m_distanceBetweenTouchPoints; - m_pinch.m_zoom.m_previous = m_declarativeMap->zoomLevel(); - m_pinch.m_lastAngle = m_twoTouchAngle; - - m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePosition()); - m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePosition()); - - m_pinch.m_zoom.m_start = m_declarativeMap->zoomLevel(); -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::updatePinch() -{ - // Calculate the new zoom level if we have distance ( >= 2 touchpoints), otherwise stick with old. - qreal newZoomLevel = m_pinch.m_zoom.m_previous; - if (m_distanceBetweenTouchPoints) { - newZoomLevel = - // How much further/closer the current touchpoints are (in pixels) compared to pinch start - ((m_distanceBetweenTouchPoints - m_pinch.m_startDist) * - // How much one pixel corresponds in units of zoomlevel (and multiply by above delta) - (m_pinch.m_zoom.maximumChange / ((width() + height()) / 2))) + - // Add to starting zoom level. Sign of (dist-pinchstartdist) takes care of zoom in / out - m_pinch.m_zoom.m_start; - } - - m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid)); - m_pinch.m_event.setAngle(m_twoTouchAngle); - - m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePosition()); - m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePosition()); - m_pinch.m_event.setPoint1(m_pinch.m_lastPoint1); - m_pinch.m_event.setPoint2(m_pinch.m_lastPoint2); - m_pinch.m_event.setPointCount(m_allPoints.count()); - m_pinch.m_event.setAccepted(true); - - m_pinch.m_lastAngle = m_twoTouchAngle; - emit pinchUpdated(&m_pinch.m_event); - - if (m_acceptedGestures & PinchGesture) { - // Take maximum and minimumzoomlevel into account - qreal perPinchMinimumZoomLevel = qMax(m_pinch.m_zoom.m_start - m_pinch.m_zoom.maximumChange, m_pinch.m_zoom.m_minimum); - qreal perPinchMaximumZoomLevel = qMin(m_pinch.m_zoom.m_start + m_pinch.m_zoom.maximumChange, m_pinch.m_zoom.m_maximum); - newZoomLevel = qMin(qMax(perPinchMinimumZoomLevel, newZoomLevel), perPinchMaximumZoomLevel); - m_declarativeMap->setZoomLevel(qMin<qreal>(newZoomLevel, maximumZoomLevel()), false); - m_pinch.m_zoom.m_previous = newZoomLevel; - } -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::endPinch() -{ - QPointF p1 = mapFromScene(m_pinch.m_lastPoint1); - QPointF p2 = mapFromScene(m_pinch.m_lastPoint2); - m_pinch.m_event.setCenter((p1 + p2) / 2); - m_pinch.m_event.setAngle(m_pinch.m_lastAngle); - m_pinch.m_event.setPoint1(p1); - m_pinch.m_event.setPoint2(p2); - m_pinch.m_event.setAccepted(true); - m_pinch.m_event.setPointCount(0); - emit pinchFinished(&m_pinch.m_event); - m_pinch.m_startDist = 0; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::panStateMachine() -{ - FlickState lastState = m_flickState; - - // Transitions - switch (m_flickState) { - case flickInactive: - if (!isTiltActive() && canStartPan()) { - // Update startCoord_ to ensure smooth start for panning when going over startDragDistance - QGeoCoordinate newStartCoord = m_declarativeMap->toCoordinate(m_touchPointsCentroid, false); - m_startCoord.setLongitude(newStartCoord.longitude()); - m_startCoord.setLatitude(newStartCoord.latitude()); - m_declarativeMap->setKeepMouseGrab(true); - m_declarativeMap->setKeepTouchGrab(true); - setFlickState(panActive); - } - break; - case panActive: - if (m_allPoints.count() == 0) { - if (!tryStartFlick()) - { - setFlickState(flickInactive); - // mark as inactive for use by camera - if (m_pinchState == pinchInactive && m_rotationState == rotationInactive && m_tiltState == tiltInactive) { - m_declarativeMap->setKeepMouseGrab(m_preventStealing); - m_declarativeMap->setKeepTouchGrab(m_preventStealing); - m_map->prefetchData(); - } - emit panFinished(); - } else { - setFlickState(flickActive); - emit panFinished(); - emit flickStarted(); - } - } - break; - case flickActive: - if (m_allPoints.count() > 0) { // re touched before movement ended - stopFlick(); - m_declarativeMap->setKeepMouseGrab(true); - m_declarativeMap->setKeepTouchGrab(true); - setFlickState(panActive); - } - break; - } - - if (m_flickState != lastState) - emit panActiveChanged(); - - // Update - switch (m_flickState) { - case flickInactive: // do nothing - break; - case panActive: - updatePan(); - // this ensures 'panStarted' occurs after the pan has actually started - if (lastState != panActive) - emit panStarted(); - break; - case flickActive: - break; - } -} -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::canStartPan() -{ - if (m_allPoints.count() == 0 || (m_acceptedGestures & PanGesture) == 0) - return false; - - // Check if thresholds for normal panning are met. - // (normal panning vs flicking: flicking will start from mouse release event). - const int startDragDistance = qApp->styleHints()->startDragDistance() * 2; - QPointF p1 = mapFromScene(m_allPoints.at(0).scenePosition()); - int dyFromPress = int(p1.y() - m_sceneStartPoint1.y()); - int dxFromPress = int(p1.x() - m_sceneStartPoint1.x()); - if ((qAbs(dyFromPress) >= startDragDistance || qAbs(dxFromPress) >= startDragDistance)) - return true; - - return false; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::updatePan() -{ - m_declarativeMap->alignCoordinateToPoint(m_startCoord, m_touchPointsCentroid); -} - -/*! - \internal -*/ -bool QQuickGeoMapGestureArea::tryStartFlick() -{ - if ((m_acceptedGestures & FlickGesture) == 0) - return false; - // if we drag then pause before release we should not cause a flick. - qreal flickSpeed = 0.0; - if (m_lastPosTime.elapsed() < QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD) - flickSpeed = m_flickVector.length(); - - int flickTime = 0; - int flickPixels = 0; - QVector2D flickVector; - - if (qAbs(flickSpeed) > MinimumFlickVelocity - && distanceBetweenTouchPoints(m_touchPointsCentroid, m_sceneStartPoint1) > FlickThreshold) { - qreal acceleration = m_flick.m_deceleration; - if ((flickSpeed > 0.0f) == (m_flick.m_deceleration > 0.0f)) - acceleration = acceleration * -1.0f; - flickTime = static_cast<int>(-1000 * flickSpeed / acceleration); - flickPixels = (flickTime * flickSpeed) / 2000.0; - flickVector = m_flickVector.normalized() * flickPixels; - } - - if (flickTime > 0) { - startFlick(flickVector.x(), flickVector.y(), flickTime); - return true; - } - return false; -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::startFlick(int dx, int dy, int timeMs) -{ - if (!m_flick.m_animation) - return; - if (timeMs < 0) - return; - - QGeoCoordinate animationStartCoordinate = m_declarativeMap->center(); - - if (m_flick.m_animation->isRunning()) - m_flick.m_animation->stop(); - QGeoCoordinate animationEndCoordinate = m_declarativeMap->center(); - m_flick.m_animation->setDuration(timeMs); - - QPointF delta(dx, dy); - QMatrix4x4 matBearing; - matBearing.rotate(m_map->cameraData().bearing(), 0, 0, 1); - delta = matBearing.map(delta); - - double zoom = pow(2.0, m_declarativeMap->zoomLevel()); - double longitude = animationStartCoordinate.longitude() - (delta.x() / zoom); - double latitude = animationStartCoordinate.latitude() + (delta.y() / zoom); - - if (delta.x() > 0) - m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::West); - else - m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::East); - - //keep animation in correct bounds - animationEndCoordinate.setLongitude(QLocationUtils::wrapLong(longitude)); - animationEndCoordinate.setLatitude(QLocationUtils::clipLat(latitude, QLocationUtils::mercatorMaxLatitude())); - - m_flick.m_animation->setFrom(animationStartCoordinate); - m_flick.m_animation->setTo(animationEndCoordinate); - m_flick.m_animation->start(); -} - -void QQuickGeoMapGestureArea::stopPan() -{ - if (m_flickState == flickActive) { - stopFlick(); - } else if (m_flickState == panActive) { - m_flickVector = QVector2D(); - setFlickState(flickInactive); - m_declarativeMap->setKeepMouseGrab(m_preventStealing); - emit panFinished(); - emit panActiveChanged(); - m_map->prefetchData(); - } -} - -/*! - \internal -*/ -void QQuickGeoMapGestureArea::stopFlick() -{ - if (!m_flick.m_animation) - return; - m_flickVector = QVector2D(); - if (m_flick.m_animation->isRunning()) - m_flick.m_animation->stop(); - else - handleFlickAnimationStopped(); -} - -void QQuickGeoMapGestureArea::handleFlickAnimationStopped() -{ - m_declarativeMap->setKeepMouseGrab(m_preventStealing); - if (m_flickState == flickActive) { - setFlickState(flickInactive); - emit flickFinished(); - emit panActiveChanged(); - m_map->prefetchData(); - } -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qquickgeomapgesturearea_p.h b/src/location/declarativemaps/qquickgeomapgesturearea_p.h deleted file mode 100644 index e8735761..00000000 --- a/src/location/declarativemaps/qquickgeomapgesturearea_p.h +++ /dev/null @@ -1,388 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKGEOMAPGESTUREAREA_P_H -#define QQUICKGEOMAPGESTUREAREA_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 <QtLocation/private/qlocationglobal_p.h> - -#include <QtCore/QPointer> -#include <QtQuick/QQuickItem> -#include <QTouchEvent> -#include <QDebug> -#include <QElapsedTimer> -#include <QtPositioning/qgeocoordinate.h> -#include <QtGui/QVector2D> - -QT_BEGIN_NAMESPACE - -class QGraphicsSceneMouseEvent; -class QQuickGeoCoordinateAnimation; -class QDeclarativeGeoMap; -class QTouchEvent; -class QWheelEvent; -class QGeoMap; - -class Q_LOCATION_PRIVATE_EXPORT QGeoMapPinchEvent : public QObject -{ - Q_OBJECT - - Q_PROPERTY(QPointF center READ center) - Q_PROPERTY(qreal angle READ angle) - Q_PROPERTY(QPointF point1 READ point1) - Q_PROPERTY(QPointF point2 READ point2) - Q_PROPERTY(int pointCount READ pointCount) - Q_PROPERTY(bool accepted READ accepted WRITE setAccepted) - -public: - QGeoMapPinchEvent(const QPointF ¢er, qreal angle, - const QPointF &point1, const QPointF &point2, - int pointCount = 0, bool accepted = true) - : QObject(), m_center(center), m_angle(angle), - m_point1(point1), m_point2(point2), - m_pointCount(pointCount), m_accepted(accepted) - {} - QGeoMapPinchEvent() = default; - - QPointF center() const { return m_center; } - void setCenter(const QPointF ¢er) { m_center = center; } - qreal angle() const { return m_angle; } - void setAngle(qreal angle) { m_angle = angle; } - QPointF point1() const { return m_point1; } - void setPoint1(const QPointF &p) { m_point1 = p; } - QPointF point2() const { return m_point2; } - void setPoint2(const QPointF &p) { m_point2 = p; } - int pointCount() const { return m_pointCount; } - void setPointCount(int count) { m_pointCount = count; } - bool accepted() const { return m_accepted; } - void setAccepted(bool a) { m_accepted = a; } - -private: - QPointF m_center; - qreal m_angle = 0.0; - QPointF m_point1; - QPointF m_point2; - int m_pointCount = 0; - bool m_accepted = true; -}; - -class Q_LOCATION_PRIVATE_EXPORT QQuickGeoMapGestureArea: public QQuickItem -{ - Q_OBJECT - Q_ENUMS(GeoMapGesture) - Q_FLAGS(AcceptedGestures) - - Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) - Q_PROPERTY(bool pinchActive READ isPinchActive NOTIFY pinchActiveChanged) - Q_PROPERTY(bool panActive READ isPanActive NOTIFY panActiveChanged) - Q_PROPERTY(bool rotationActive READ isRotationActive NOTIFY rotationActiveChanged) - Q_PROPERTY(bool tiltActive READ isTiltActive NOTIFY tiltActiveChanged) - Q_PROPERTY(AcceptedGestures acceptedGestures READ acceptedGestures WRITE setAcceptedGestures NOTIFY acceptedGesturesChanged) - Q_PROPERTY(qreal maximumZoomLevelChange READ maximumZoomLevelChange WRITE setMaximumZoomLevelChange NOTIFY maximumZoomLevelChangeChanged) - Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged) - Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged REVISION 1) - -public: - QQuickGeoMapGestureArea(QDeclarativeGeoMap *map); - ~QQuickGeoMapGestureArea(); - - enum GeoMapGesture { - NoGesture = 0x0000, - PinchGesture = 0x0001, - PanGesture = 0x0002, - FlickGesture = 0x0004, - RotationGesture = 0x0008, - TiltGesture = 0x0010, - AllGestures = 0xffff - }; - - Q_DECLARE_FLAGS(AcceptedGestures, GeoMapGesture) - - AcceptedGestures acceptedGestures() const; - void setAcceptedGestures(AcceptedGestures acceptedGestures); - - bool isPinchActive() const; - bool isRotationActive() const; - bool isTiltActive() const; - bool isPanActive() const; - bool isActive() const; - - bool enabled() const; - void setEnabled(bool enabled); - - qreal maximumZoomLevelChange() const; - void setMaximumZoomLevelChange(qreal maxChange); - - qreal flickDeceleration() const; - void setFlickDeceleration(qreal deceleration); - - void handleTouchEvent(QPointerEvent *event); -#if QT_CONFIG(wheelevent) - void handleWheelEvent(QWheelEvent *event); -#endif - void handleMousePressEvent(QMouseEvent *event); - void handleMouseMoveEvent(QMouseEvent *event); - void handleMouseReleaseEvent(QMouseEvent *event); - void handleTouchUngrabEvent(); - - void setMinimumZoomLevel(qreal min); - qreal minimumZoomLevel() const; - - void setMaximumZoomLevel(qreal max); - qreal maximumZoomLevel() const; - - void setMap(QGeoMap* map); - - bool preventStealing() const; - void setPreventStealing(bool prevent); - -Q_SIGNALS: - void panActiveChanged(); - void pinchActiveChanged(); - void rotationActiveChanged(); - void tiltActiveChanged(); - void enabledChanged(); - void maximumZoomLevelChangeChanged(); - void acceptedGesturesChanged(); - void flickDecelerationChanged(); - void pinchStarted(QGeoMapPinchEvent *pinch); - void pinchUpdated(QGeoMapPinchEvent *pinch); - void pinchFinished(QGeoMapPinchEvent *pinch); - void panStarted(); - void panFinished(); - void flickStarted(); - void flickFinished(); - void rotationStarted(QGeoMapPinchEvent *pinch); - void rotationUpdated(QGeoMapPinchEvent *pinch); - void rotationFinished(QGeoMapPinchEvent *pinch); - void tiltStarted(QGeoMapPinchEvent *pinch); - void tiltUpdated(QGeoMapPinchEvent *pinch); - void tiltFinished(QGeoMapPinchEvent *pinch); - void preventStealingChanged(); -private: - void update(); - - // Create general data relating to the touch points - void touchPointStateMachine(); - void startOneTouchPoint(); - void updateOneTouchPoint(); - void startTwoTouchPoints(); - void updateTwoTouchPoints(); - - // All two fingers vertical parallel panning related code, which encompasses tilting - void tiltStateMachine(); - bool canStartTilt(); - void startTilt(); - void updateTilt(); - void endTilt(); - - // All two fingers rotation related code, which encompasses rotation - void rotationStateMachine(); - bool canStartRotation(); - void startRotation(); - void updateRotation(); - void endRotation(); - - // All pinch related code, which encompasses zoom - void pinchStateMachine(); - bool canStartPinch(); - void startPinch(); - void updatePinch(); - void endPinch(); - - // Pan related code (regardles of number of touch points), - // includes the flick based panning after letting go - void panStateMachine(); - bool canStartPan(); - void updatePan(); - bool tryStartFlick(); - void startFlick(int dx, int dy, int timeMs = 0); - void stopFlick(); - - bool pinchEnabled() const; - void setPinchEnabled(bool enabled); - bool rotationEnabled() const; - void setRotationEnabled(bool enabled); - bool tiltEnabled() const; - void setTiltEnabled(bool enabled); - bool panEnabled() const; - void setPanEnabled(bool enabled); - bool flickEnabled() const; - void setFlickEnabled(bool enabled); - -private Q_SLOTS: - void handleFlickAnimationStopped(); - - -private: - void stopPan(); - void clearTouchData(); - void updateFlickParameters(const QPointF &pos); - -private: - QGeoMap* m_map = nullptr; - QDeclarativeGeoMap *m_declarativeMap = nullptr; - bool m_enabled = true; - - // This should be intended as a "two fingers gesture" struct - struct Pinch - { - QGeoMapPinchEvent m_event; - bool m_pinchEnabled = true; - bool m_rotationEnabled = true; - bool m_tiltEnabled = true; - struct Zoom - { - qreal m_minimum = 0.0; - qreal m_maximum = 30.0; - qreal m_start = 0.0; - qreal m_previous = 0.0; - qreal maximumChange = 4.0; - } m_zoom; - - struct Rotation - { - qreal m_startBearing = 0.0; - qreal m_previousTouchAngle = 0.0; // needed for detecting crossing +- 180 in a safer way - qreal m_totalAngle = 0.0; - } m_rotation; - - struct Tilt - { - QPointF m_startTouchCentroid; - qreal m_startTilt; - } m_tilt; - - QPointF m_lastPoint1; - QPointF m_lastPoint2; - qreal m_startDist = 0.0; - qreal m_lastAngle = 0.0; - } m_pinch; - - AcceptedGestures m_acceptedGestures = AllGestures; - - struct Pan - { - qreal m_maxVelocity = 2500; - qreal m_deceleration = 2500; - QQuickGeoCoordinateAnimation *m_animation = nullptr; - bool m_flickEnabled = true; - bool m_panEnabled = true; - } m_flick; - - - // these are calculated regardless of gesture or number of touch points - QVector2D m_flickVector; - QElapsedTimer m_lastPosTime; - QPointF m_lastPos; - QList<QTouchEvent::TouchPoint> m_allPoints; - QList<QTouchEvent::TouchPoint> m_touchPoints; - QPointF m_sceneStartPoint1; - - // only set when two points in contact - QPointF m_sceneStartPoint2; - QGeoCoordinate m_startCoord; - QGeoCoordinate m_touchCenterCoord; - qreal m_twoTouchAngle; - qreal m_twoTouchAngleStart; - qreal m_distanceBetweenTouchPoints; - qreal m_distanceBetweenTouchPointsStart; - QPointF m_twoTouchPointsCentroidStart; - QPointF m_touchPointsCentroid; - bool m_preventStealing = false; - -private: - // prototype state machine... - enum TouchPointState - { - touchPoints0, - touchPoints1, - touchPoints2 - } m_touchPointState; - - enum PinchState - { - pinchInactive, - pinchInactiveTwoPoints, - pinchActive - } m_pinchState; - - enum RotationState - { - rotationInactive, - rotationInactiveTwoPoints, - rotationActive - } m_rotationState; - - enum TiltState - { - tiltInactive, - tiltInactiveTwoPoints, - tiltActive - } m_tiltState; - - enum FlickState - { - flickInactive, - panActive, - flickActive - } m_flickState; - - inline void setTouchPointState(TouchPointState state); - inline void setFlickState(FlickState state); - inline void setTiltState(TiltState state); - inline void setRotationState(RotationState state); - inline void setPinchState(PinchState state); -}; - -QT_END_NAMESPACE -QML_DECLARE_TYPE(QQuickGeoMapGestureArea) - -#endif // QQUICKGEOMAPGESTUREAREA_P_H diff --git a/src/location/declarativemaps/shaders/polygon.frag b/src/location/declarativemaps/shaders/polygon.frag deleted file mode 100644 index 9b9727b6..00000000 --- a/src/location/declarativemaps/shaders/polygon.frag +++ /dev/null @@ -1,16 +0,0 @@ -#version 440 - -layout(location = 0) out vec4 fragColor; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - mat4 mapProjection; - vec4 center; - vec4 center_lowpart; - float wrapOffset; - vec4 color; -}; - -void main() { - fragColor = color; -} diff --git a/src/location/declarativemaps/shaders/polygon.vert b/src/location/declarativemaps/shaders/polygon.vert deleted file mode 100644 index 06dab03e..00000000 --- a/src/location/declarativemaps/shaders/polygon.vert +++ /dev/null @@ -1,20 +0,0 @@ -#version 440 - -layout(location = 0) in highp vec4 vertex; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - mat4 mapProjection; - vec4 center; - vec4 center_lowpart; - float wrapOffset; - vec4 color; -}; - -vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); } - -void main() { - vec4 vtx = wrapped(vertex) - center; - vtx = vtx - center_lowpart; - gl_Position = qt_Matrix * mapProjection * vtx; -} diff --git a/src/location/declarativemaps/shaders/polyline_extruded.frag b/src/location/declarativemaps/shaders/polyline_extruded.frag deleted file mode 100644 index 3530f093..00000000 --- a/src/location/declarativemaps/shaders/polyline_extruded.frag +++ /dev/null @@ -1,20 +0,0 @@ -#version 440 - -layout(location = 0) in vec4 primitivecolor; -layout(location = 0) out vec4 fragColor; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - mat4 mapProjection; - vec4 center; - vec4 center_lowpart; - float lineWidth; - float aspect; - int miter; // currently unused - vec4 color; - float wrapOffset; -}; - -void main() { - fragColor = primitivecolor; -} diff --git a/src/location/declarativemaps/shaders/polyline_extruded.vert b/src/location/declarativemaps/shaders/polyline_extruded.vert deleted file mode 100644 index 27b69b60..00000000 --- a/src/location/declarativemaps/shaders/polyline_extruded.vert +++ /dev/null @@ -1,104 +0,0 @@ -#version 440 - -layout(location = 0) in vec4 vertex; -layout(location = 1) in vec4 previous; -layout(location = 2) in vec4 next; -layout(location = 3) in float direction; -layout(location = 4) in float triangletype; -layout(location = 5) in float vertextype; // -1.0 if it is the "left" end of the segment, 1.0 if it is the "right" end. -layout(location = 0) out vec4 primitivecolor; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - mat4 mapProjection; - vec4 center; - vec4 center_lowpart; - float lineWidth; - float aspect; - int miter; // currently unused - vec4 color; - float wrapOffset; -}; - - -vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); } -void main() { // ln 22 - primitivecolor = color; - vec2 aspectVec = vec2(aspect, 1.0); - mat4 projViewModel = qt_Matrix * mapProjection; - vec4 cur = wrapped(vertex) - center; - cur = cur - center_lowpart; - vec4 prev = wrapped(previous) - center; - prev = prev - center_lowpart; - vec4 nex = wrapped(next) - center; - nex = nex - center_lowpart; - - vec4 centerProjected = projViewModel * (center + vec4(0.0, 0.0, 0.0, 1.0)); - vec4 previousProjected = projViewModel * prev; - vec4 currentProjected = projViewModel * cur; - vec4 nextProjected = projViewModel * nex; - - //get 2D screen space with W divide and aspect correction - vec2 currentScreen = (currentProjected.xy / currentProjected.w) * aspectVec; - vec2 previousScreen = (previousProjected.xy / previousProjected.w) * aspectVec; - vec2 nextScreen = (nextProjected.xy / nextProjected.w) * aspectVec; - float len = (lineWidth); - float orientation = direction; - bool clipped = false; - bool otherEndBelowFrustum = false; - //starting point uses (next - current) - vec2 dir = vec2(0.0); - if (vertextype < 0.0) { - dir = normalize(nextScreen - currentScreen); - if (nextProjected.z < 0.0) dir = -dir; - } else { - dir = normalize(currentScreen - previousScreen); - if (previousProjected.z < 0.0) dir = -dir; - } -// first, clip current, and make sure currentProjected.z is > 0 - if (currentProjected.z < 0.0) { - if ((nextProjected.z > 0.0 && vertextype < 0.0) || (vertextype > 0.0 && previousProjected.z > 0.0)) { - dir = -dir; - clipped = true; - if (vertextype < 0.0 && nextProjected.y / nextProjected.w < -1.0) otherEndBelowFrustum = true; - else if (vertextype > 0.0 && previousProjected.y / previousProjected.w < -1.0) otherEndBelowFrustum = true; - } else { - primitivecolor = vec4(0.0,0.0,0.0,0.0); - gl_Position = vec4(-10000000.0, -1000000000.0, -1000000000.0, 1); // get the vertex out of the way if the segment is fully invisible - return; - } - } else if (triangletype < 2.0) { // vertex in the view, try to miter - //get directions from (C - B) and (B - A) - vec2 dirA = normalize((currentScreen - previousScreen)); - if (previousProjected.z < 0.0) dirA = -dirA; - vec2 dirB = normalize((nextScreen - currentScreen)); - //now compute the miter join normal and length - if (nextProjected.z < 0.0) dirB = -dirB; - vec2 tangent = normalize(dirA + dirB); - vec2 perp = vec2(-dirA.y, dirA.x); - vec2 vmiter = vec2(-tangent.y, tangent.x); - len = lineWidth / dot(vmiter, perp); -// The following is an attempt to have a segment-length based miter threshold. -// A mediocre workaround until better mitering will be added. - float lenTreshold = clamp( min(length((currentProjected.xy - previousProjected.xy) / aspectVec), - length((nextProjected.xy - currentProjected.xy) / aspectVec)), 3.0, 6.0 ) * 0.5; - if (len < lineWidth * lenTreshold && len > -lineWidth * lenTreshold) { - dir = tangent; - } else { - len = lineWidth; - } - } - vec4 offset; - if (!clipped) { - vec2 normal = normalize(vec2(-dir.y, dir.x)); - normal *= len; // fracZL apparently was needed before the (-2.0 / qt_Matrix[1][1]) factor was introduced - normal /= aspectVec; // straighten the normal up again - float scaleFactor = currentProjected.w / centerProjected.w; - offset = vec4(normal * orientation * scaleFactor * (centerProjected.w / (-2.0 / qt_Matrix[1][1])), 0.0, 0.0); // ToDo: figure out why (-2.0 / qt_Matrix[1][1]), that is empirically what works - gl_Position = currentProjected + offset; - } else { - if (otherEndBelowFrustum) offset = vec4((dir * 1.0) / aspectVec, 0.0, 0.0); // the if is necessary otherwise it seems the direction vector still flips in some obscure cases. - else offset = vec4((dir * 500000000000.0) / aspectVec, 0.0, 0.0); // Hack alert: just 1 triangle, long enough to look like a rectangle. - if (vertextype < 0.0) gl_Position = nextProjected - offset; else gl_Position = previousProjected + offset; - } -} diff --git a/src/location/declarativemaps/shaders/polyline_linestrip.frag b/src/location/declarativemaps/shaders/polyline_linestrip.frag deleted file mode 100644 index e9124d27..00000000 --- a/src/location/declarativemaps/shaders/polyline_linestrip.frag +++ /dev/null @@ -1,17 +0,0 @@ -#version 440 - -layout(location = 0) out vec4 fragColor; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - mat4 mapProjection; - vec4 center; - vec4 center_lowpart; - float opacity; - float wrapOffset; - vec4 color; -}; - -void main() { - fragColor = color; -} diff --git a/src/location/declarativemaps/shaders/polyline_linestrip.vert b/src/location/declarativemaps/shaders/polyline_linestrip.vert deleted file mode 100644 index 86b4f3a3..00000000 --- a/src/location/declarativemaps/shaders/polyline_linestrip.vert +++ /dev/null @@ -1,21 +0,0 @@ -#version 440 - -layout(location = 0) in vec4 qt_Vertex; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - mat4 mapProjection; - vec4 center; - vec4 center_lowpart; - float opacity; - float wrapOffset; - vec4 color; -}; - -vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); } - -void main() { - vec4 vtx = wrapped(qt_Vertex) - center; - vtx = vtx - center_lowpart; - gl_Position = qt_Matrix * mapProjection * vtx; -} |