summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap_p.h2
-rw-r--r--src/location/labs/qmappolygonobject.cpp3
-rw-r--r--src/location/labs/qmappolylineobject.cpp6
-rw-r--r--src/location/labs/qmappolylineobject_p_p.h3
-rw-r--r--src/location/labs/qsg/qgeomapobjectqsgsupport.cpp2
-rw-r--r--src/location/labs/qsg/qmapcircleobjectqsg.cpp266
-rw-r--r--src/location/labs/qsg/qmapcircleobjectqsg_p_p.h40
-rw-r--r--src/location/labs/qsg/qmappolygonobjectqsg.cpp186
-rw-r--r--src/location/labs/qsg/qmappolygonobjectqsg_p_p.h11
-rw-r--r--src/location/labs/qsg/qmappolylineobjectqsg.cpp91
-rw-r--r--src/location/labs/qsg/qmappolylineobjectqsg_p_p.h7
-rw-r--r--tests/manual/mapobjects_tester/main.cpp48
-rw-r--r--tests/manual/mapobjects_tester/main.qml515
-rw-r--r--tests/manual/mapobjects_tester/mapobjects_tester.pro29
-rw-r--r--tests/manual/mapobjects_tester/qml.qrc5
15 files changed, 1018 insertions, 196 deletions
diff --git a/src/location/declarativemaps/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h
index 7dcb60aa..8f5cb6ec 100644
--- a/src/location/declarativemaps/qdeclarativegeomap_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomap_p.h
@@ -182,7 +182,7 @@ public:
Q_INVOKABLE void clearMapParameters();
QList<QObject *> mapParameters();
- void addMapObject(QGeoMapObject *object);
+ 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();
diff --git a/src/location/labs/qmappolygonobject.cpp b/src/location/labs/qmappolygonobject.cpp
index 5a8ce228..9d679f31 100644
--- a/src/location/labs/qmappolygonobject.cpp
+++ b/src/location/labs/qmappolygonobject.cpp
@@ -145,10 +145,9 @@ void QMapPolygonObjectPrivateDefault::setGeoShape(const QGeoShape &shape)
return;
const QGeoPolygon poly(shape);
- setPath(poly.path()); // to handle overrides
for (int i = 0; i < poly.holesCount(); i++)
m_path.addHole(poly.holePath(i));
- emit static_cast<QMapPolygonObject *>(q)->pathChanged();
+ setPath(poly.path()); // to handle overrides. Last as it normally emits static_cast<QMapPolygonObject *>(q)->pathChanged();
}
bool QMapPolygonObjectPrivate::equals(const QGeoMapObjectPrivate &other) const
diff --git a/src/location/labs/qmappolylineobject.cpp b/src/location/labs/qmappolylineobject.cpp
index 81390d7c..acfe6609 100644
--- a/src/location/labs/qmappolylineobject.cpp
+++ b/src/location/labs/qmappolylineobject.cpp
@@ -76,7 +76,7 @@ QMapPolylineObjectPrivateDefault::QMapPolylineObjectPrivateDefault(QGeoMapObject
QMapPolylineObjectPrivateDefault::QMapPolylineObjectPrivateDefault(const QMapPolylineObjectPrivate &other) : QMapPolylineObjectPrivate(other.q)
{
- m_path = other.path();
+ m_path.setPath(other.path());
m_color = other.color();
m_width = other.width();
}
@@ -88,12 +88,12 @@ QMapPolylineObjectPrivateDefault::~QMapPolylineObjectPrivateDefault()
QList<QGeoCoordinate> QMapPolylineObjectPrivateDefault::path() const
{
- return m_path;
+ return m_path.path();
}
void QMapPolylineObjectPrivateDefault::setPath(const QList<QGeoCoordinate> &path)
{
- m_path = path;
+ m_path.setPath(path);
}
QColor QMapPolylineObjectPrivateDefault::color() const
diff --git a/src/location/labs/qmappolylineobject_p_p.h b/src/location/labs/qmappolylineobject_p_p.h
index a0eb3711..3fdf1a1f 100644
--- a/src/location/labs/qmappolylineobject_p_p.h
+++ b/src/location/labs/qmappolylineobject_p_p.h
@@ -51,6 +51,7 @@
#include <QtLocation/private/qlocationglobal_p.h>
#include <QtLocation/private/qgeomapobject_p_p.h>
#include <QGeoCoordinate>
+#include <QGeoPath>
#include <QColor>
QT_BEGIN_NAMESPACE
@@ -95,7 +96,7 @@ public:
QGeoMapObjectPrivate *clone() override;
public:
- QList<QGeoCoordinate> m_path;
+ QGeoPath m_path; // small overhead compared to plain QList<QGeoCoordinate>
QColor m_color;
qreal m_width = 0;
diff --git a/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp b/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp
index 6cb2c44a..f965efb7 100644
--- a/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp
+++ b/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp
@@ -152,6 +152,7 @@ void QGeoMapObjectQSGSupport::removeMapObject(QGeoMapObject *obj)
}
}
+// called in the render thread
void QGeoMapObjectQSGSupport::updateMapObjects(QSGNode *root, QQuickWindow *window)
{
if (!m_mapObjectsRootNode) {
@@ -216,6 +217,7 @@ void QGeoMapObjectQSGSupport::updateMapObjects(QSGNode *root, QQuickWindow *wind
m_mapObjectsRootNode->setSubtreeBlocked(false);
}
+// called in GUI thread
void QGeoMapObjectQSGSupport::updateObjectsGeometry()
{
for (int i = 0; i < m_mapObjects.size(); ++i) {
diff --git a/src/location/labs/qsg/qmapcircleobjectqsg.cpp b/src/location/labs/qsg/qmapcircleobjectqsg.cpp
index 6c69ce5a..5b1f5361 100644
--- a/src/location/labs/qsg/qmapcircleobjectqsg.cpp
+++ b/src/location/labs/qsg/qmapcircleobjectqsg.cpp
@@ -41,16 +41,19 @@ QT_BEGIN_NAMESPACE
static const int CircleSamples = 128;
QMapCircleObjectPrivateQSG::QMapCircleObjectPrivateQSG(QGeoMapObject *q)
- : QMapCircleObjectPrivateDefault(q)
+ : QMapCircleObjectPrivateDefault(q), m_dataCPU(new CircleDataCPU)
{
}
QMapCircleObjectPrivateQSG::QMapCircleObjectPrivateQSG(const QMapCircleObjectPrivate &other)
- : QMapCircleObjectPrivateDefault(other)
+ : QMapCircleObjectPrivateDefault(other), m_dataCPU(new CircleDataCPU)
{
// Data already cloned by the *Default copy constructor, but necessary
// update operations triggered only by setters overrides
+ if (!QDeclarativeCircleMapItemPrivateCPU::crossEarthPole(center(), radius()))
+ switchToGL(); // this marks source dirty
+
updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -62,47 +65,54 @@ QMapCircleObjectPrivateQSG::~QMapCircleObjectPrivateQSG()
m_map->removeMapObject(q);
}
-void QMapCircleObjectPrivateQSG::updateCirclePath()
+void QMapCircleObjectPrivateQSG::updateGeometry()
+{
+ if (!m_dataGL.isNull())
+ updateGeometryGL();
+ else
+ updateGeometryCPU();
+}
+
+void QMapCircleObjectPrivateQSG::CircleDataCPU::updateCirclePath(const QGeoCoordinate &center, qreal radius, const QGeoProjectionWebMercator &p)
{
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection());
QList<QGeoCoordinate> path;
- QDeclarativeCircleMapItemPrivateCPU::calculatePeripheralPoints(path, center(), radius(), CircleSamples, m_leftBound);
+ QDeclarativeCircleMapItemPrivateCPU::calculatePeripheralPoints(path, center, radius, CircleSamples, m_leftBound);
m_circlePath.clear();
for (const QGeoCoordinate &c : path)
m_circlePath << p.geoToMapProjection(c);
}
-void QMapCircleObjectPrivateQSG::updateGeometry()
+void QMapCircleObjectPrivateQSG::updateGeometryCPU()
{
if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator
|| !qIsFinite(radius()) || !center().isValid())
return;
const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection());
- QScopedValueRollback<bool> rollback(m_updatingGeometry);
- m_updatingGeometry = true;
+ QScopedValueRollback<bool> rollback(m_dataCPU->m_updatingGeometry);
+ m_dataCPU->m_updatingGeometry = true;
- updateCirclePath();
- QList<QDoubleVector2D> circlePath = m_circlePath;
+ m_dataCPU->updateCirclePath(center(), radius(), p);
+ QList<QDoubleVector2D> circlePath = m_dataCPU->m_circlePath;
int pathCount = circlePath.size();
bool preserve = QDeclarativeCircleMapItemPrivateCPU::preserveCircleGeometry(circlePath, center(), radius(), p);
// using leftBound_ instead of the analytically calculated circle_.boundingGeoRectangle().topLeft());
// to fix QTBUG-62154
- m_geometry.markSourceDirty();
- m_geometry.setPreserveGeometry(true, m_leftBound); // to set the geoLeftBound_
- m_geometry.setPreserveGeometry(preserve, m_leftBound);
+ m_dataCPU->m_geometry.markSourceDirty();
+ m_dataCPU->m_geometry.setPreserveGeometry(true, m_dataCPU->m_leftBound); // to set the geoLeftBound_
+ m_dataCPU->m_geometry.setPreserveGeometry(preserve, m_dataCPU->m_leftBound);
bool invertedCircle = false;
if (QDeclarativeCircleMapItemPrivateCPU::crossEarthPole(center(), radius()) && circlePath.size() == pathCount) {
- m_geometry.updateScreenPointsInvert(circlePath, *m_map); // invert fill area for really huge circles
+ m_dataCPU->m_geometry.updateScreenPointsInvert(circlePath, *m_map); // invert fill area for really huge circles
invertedCircle = true;
} else {
- m_geometry.updateSourcePoints(*m_map, circlePath);
- m_geometry.updateScreenPoints(*m_map);
+ m_dataCPU->m_geometry.updateSourcePoints(*m_map, circlePath);
+ m_dataCPU->m_geometry.updateScreenPoints(*m_map);
}
- m_borderGeometry.clear();
+ m_dataCPU->m_borderGeometry.clear();
//if (borderColor() != Qt::transparent && borderWidth() > 0)
{
@@ -110,35 +120,76 @@ void QMapCircleObjectPrivateQSG::updateGeometry()
closedPath << closedPath.first();
if (invertedCircle) {
- closedPath = m_circlePath;
+ closedPath = m_dataCPU->m_circlePath;
closedPath << closedPath.first();
std::reverse(closedPath.begin(), closedPath.end());
}
- m_borderGeometry.markSourceDirty();
- m_borderGeometry.setPreserveGeometry(true, m_leftBound);
- m_borderGeometry.setPreserveGeometry(preserve, m_leftBound);
+ m_dataCPU->m_borderGeometry.markSourceDirty();
+ m_dataCPU->m_borderGeometry.setPreserveGeometry(true, m_dataCPU->m_leftBound);
+ m_dataCPU->m_borderGeometry.setPreserveGeometry(preserve, m_dataCPU->m_leftBound);
// Use srcOrigin_ from fill geometry after clipping to ensure that translateToCommonOrigin won't fail.
- const QGeoCoordinate &geometryOrigin = m_geometry.origin();
+ const QGeoCoordinate &geometryOrigin = m_dataCPU->m_geometry.origin();
- m_borderGeometry.clearSource();
+ m_dataCPU->m_borderGeometry.clearSource();
QDoubleVector2D borderLeftBoundWrapped;
QList<QList<QDoubleVector2D > > clippedPaths =
- m_borderGeometry.clipPath(*m_map, closedPath, borderLeftBoundWrapped);
+ m_dataCPU->m_borderGeometry.clipPath(*m_map, closedPath, borderLeftBoundWrapped);
if (clippedPaths.size()) {
borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin);
- m_borderGeometry.pathToScreen(*m_map, clippedPaths, borderLeftBoundWrapped);
- m_borderGeometry.updateScreenPoints(*m_map, borderWidth(), false);
+ m_dataCPU->m_borderGeometry.pathToScreen(*m_map, clippedPaths, borderLeftBoundWrapped);
+ m_dataCPU->m_borderGeometry.updateScreenPoints(*m_map, borderWidth(), false);
} else {
- m_borderGeometry.clear();
+ m_dataCPU->m_borderGeometry.clear();
}
}
- QPointF origin = m_map->geoProjection().coordinateToItemPosition(m_geometry.origin(), false).toPointF();
- m_geometry.translate(origin - m_geometry.firstPointOffset());
- m_borderGeometry.translate(origin - m_borderGeometry.firstPointOffset());
+ QPointF origin = m_map->geoProjection().coordinateToItemPosition(m_dataCPU->m_geometry.origin(), false).toPointF();
+ m_dataCPU->m_geometry.translate(origin - m_dataCPU->m_geometry.firstPointOffset());
+ m_dataCPU->m_borderGeometry.translate(origin - m_dataCPU->m_borderGeometry.firstPointOffset());
+}
+
+void QMapCircleObjectPrivateQSG::CircleDataGL::updateCirclePath(const QGeoCoordinate &center, qreal radius, const QGeoProjectionWebMercator &p)
+{
+ m_circlePath.clear();
+ if (radius < 0.001) // 1mm is small enough, probably already way too small.
+ return;
+ QDeclarativeCircleMapItemPrivate::calculatePeripheralPoints(m_circlePath,
+ center,
+ radius,
+ CircleSamples,
+ m_leftBound);
+
+ m_leftBoundMercator = p.geoToMapProjection(m_leftBound);
+ m_geometry.setPreserveGeometry(true, m_leftBound);
+ m_borderGeometry.setPreserveGeometry(true, m_leftBound);
+}
+
+void QMapCircleObjectPrivateQSG::updateGeometryGL()
+{
+ if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
+ return;
+
+ const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection());
+ if (m_dataGL->m_geometry.isSourceDirty()
+ || m_dataGL->m_borderGeometry.isSourceDirty()) {
+ m_dataGL->updateCirclePath(center(), radius(), p);
+
+ if (m_dataGL->m_circlePath.length() == 0) { // Possibly cleared
+ m_dataGL->m_geometry.clear();
+ m_dataGL->m_borderGeometry.clear();
+ return;
+ }
+ m_dataGL->m_geometry.m_dataChanged = m_dataGL->m_borderGeometry.m_dataChanged = true;
+ m_dataGL->m_geometry.updateSourcePoints(*m_map, m_dataGL->m_circlePath);
+ m_dataGL->m_borderGeometry.updateSourcePoints(*m_map, QGeoCircle(center(), radius()));
+ m_dataGL->m_circlePath.clear(); // not needed anymore
+ }
+ m_dataGL->m_geometry.markScreenDirty(); // ToDo: this needs refactor. It's useless, remove screenDirty_ altogether.
+ m_dataGL->m_borderGeometry.markScreenDirty();
+ m_dataGL->m_borderGeometry.m_wrapOffset = m_dataGL->m_geometry.m_wrapOffset = p.projectionWrapFactor(m_dataGL->m_leftBoundMercator) + 1;
}
QGeoMapObjectPrivate *QMapCircleObjectPrivateQSG::clone()
@@ -146,45 +197,144 @@ QGeoMapObjectPrivate *QMapCircleObjectPrivateQSG::clone()
return new QMapCircleObjectPrivateQSG(static_cast<QMapCircleObjectPrivate &>(*this));
}
+void QMapCircleObjectPrivateQSG::switchToGL()
+{
+ if (!m_dataGL.isNull())
+ return;
+ QScopedPointer<CircleDataGL> data(new CircleDataGL);
+ m_dataGL.swap(data);
+ m_dataGL->markSourceDirty();
+ m_dataCPU.reset(nullptr);
+}
+
+void QMapCircleObjectPrivateQSG::switchToCPU()
+{
+ if (!m_dataCPU.isNull())
+ return;
+ QScopedPointer<CircleDataCPU> data(new CircleDataCPU);
+ m_dataCPU.swap(data);
+ m_dataGL.reset(nullptr);
+}
+
QSGNode *QMapCircleObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
VisibleNode **visibleNode,
QSGNode *root,
- QQuickWindow * /*window*/)
+ QQuickWindow * window)
{
-// Q_UNUSED(visibleNode); // coz of -Werror=unused-but-set-parameter
- MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
+ if (!m_dataGL.isNull())
+ return updateMapObjectNodeGL(oldNode, visibleNode, root, window);
+ else
+ return updateMapObjectNodeCPU(oldNode, visibleNode, root, window);
+}
- if (!node) {
- if (!m_geometry.size() && !m_borderGeometry.size()) {
- return nullptr;
- }
- node = new MapPolygonNode();
- *visibleNode = static_cast<VisibleNode *>(node);
+QSGNode *QMapCircleObjectPrivateQSG::updateMapObjectNodeCPU(QSGNode *oldNode,
+ VisibleNode **visibleNode,
+ QSGNode *root,
+ QQuickWindow */*window*/)
+{
+ if (!m_dataCPU->m_node || !oldNode) {
+ m_dataCPU->m_node = new MapPolygonNode();
+ *visibleNode = static_cast<VisibleNode *>(m_dataCPU->m_node);
+ if (oldNode)
+ delete oldNode;
+ } else {
+ m_dataCPU->m_node = static_cast<MapPolygonNode *>(oldNode);
+ }
+
+ if (!m_dataCPU->m_geometry.size() && !m_dataCPU->m_borderGeometry.size()) {
+ visibleNode = nullptr;
+ return nullptr;
}
//TODO: update only material
- if (m_geometry.isScreenDirty() || !m_borderGeometry.isScreenDirty() || !oldNode) {
+ if (m_dataCPU->m_geometry.isScreenDirty() || m_dataCPU->m_borderGeometry.isScreenDirty() || oldNode != m_dataCPU->m_node) {
//QMapPolygonObject *p = static_cast<QMapPolygonObject *>(q);
- node->update(color(), borderColor(), &m_geometry, &m_borderGeometry);
- m_geometry.setPreserveGeometry(false);
- m_borderGeometry.setPreserveGeometry(false);
- m_geometry.markClean();
- m_borderGeometry.markClean();
+ m_dataCPU->m_node->update(color(), borderColor(), &m_dataCPU->m_geometry, &m_dataCPU->m_borderGeometry);
+ m_dataCPU->m_geometry.setPreserveGeometry(false);
+ m_dataCPU->m_borderGeometry.setPreserveGeometry(false);
+ m_dataCPU->m_geometry.markClean();
+ m_dataCPU->m_borderGeometry.markClean();
}
- if (m_geometry.size() || m_borderGeometry.size()) {
- root->appendChildNode(node);
+ if (m_dataCPU->m_geometry.size() || m_dataCPU->m_borderGeometry.size()) {
+ root->appendChildNode(m_dataCPU->m_node);
} else {
- delete node;
+ delete m_dataCPU->m_node;
+ m_dataCPU->m_node = nullptr;
+ visibleNode = nullptr;
return nullptr;
}
- return node;
+ return m_dataCPU->m_node;
}
+QSGNode *QMapCircleObjectPrivateQSG::updateMapObjectNodeGL(QSGNode *oldNode,
+ VisibleNode **visibleNode,
+ QSGNode *root,
+ QQuickWindow */*window*/)
+{
+ if (!m_dataGL->m_rootNode || !oldNode) {
+ m_dataGL->m_rootNode = new QDeclarativePolygonMapItemPrivateOpenGL::RootNode();
+ m_dataGL->m_node = new MapPolygonNodeGL();
+ m_dataGL->m_rootNode->appendChildNode(m_dataGL->m_node);
+ m_dataGL->m_polylinenode = new MapPolylineNodeOpenGLExtruded();
+ m_dataGL->m_rootNode->appendChildNode(m_dataGL->m_polylinenode);
+ m_dataGL->m_rootNode->markDirty(QSGNode::DirtyNodeAdded);
+ *visibleNode = static_cast<VisibleNode *>(m_dataGL->m_rootNode);
+ if (oldNode)
+ delete oldNode;
+ } else {
+ m_dataGL->m_rootNode = static_cast<QDeclarativePolygonMapItemPrivateOpenGL::RootNode *>(oldNode);
+ }
+
+ const QMatrix4x4 &combinedMatrix = m_map->geoProjection().qsgTransform();
+ const QDoubleVector3D &cameraCenter = m_map->geoProjection().centerMercator();
+
+ if (m_dataGL->m_borderGeometry.isScreenDirty()) {
+ /* Do the border update first */
+ m_dataGL->m_polylinenode->update(borderColor(),
+ float(borderWidth()),
+ &m_dataGL->m_borderGeometry,
+ combinedMatrix,
+ cameraCenter,
+ Qt::SquareCap,
+ true);
+ m_dataGL->m_borderGeometry.setPreserveGeometry(false);
+ m_dataGL->m_borderGeometry.markClean();
+ }
+ if (m_dataGL->m_geometry.isScreenDirty()) {
+ m_dataGL->m_node->update(color(),
+ &m_dataGL->m_geometry,
+ combinedMatrix,
+ cameraCenter);
+ m_dataGL->m_geometry.setPreserveGeometry(false);
+ m_dataGL->m_geometry.markClean();
+ }
+
+ if (!m_dataGL->m_polylinenode->isSubtreeBlocked() || !m_dataGL->m_node->isSubtreeBlocked()) {
+ m_dataGL->m_rootNode->setSubtreeBlocked(false);
+ root->appendChildNode(m_dataGL->m_rootNode);
+ return m_dataGL->m_rootNode;
+ } else {
+ delete m_dataGL->m_rootNode;
+ m_dataGL->m_rootNode = nullptr;
+ m_dataGL->m_node = nullptr;
+ m_dataGL->m_polylinenode = nullptr;
+ *visibleNode = nullptr;
+ return nullptr;
+ }
+}
void QMapCircleObjectPrivateQSG::setCenter(const QGeoCoordinate &center)
{
QMapCircleObjectPrivateDefault::setCenter(center);
+ if (!QDeclarativeCircleMapItemPrivate::crossEarthPole(this->center(), this->radius())) // Switching implementation for circles crossing/not crossing poles
+ switchToGL();
+ else
+ switchToCPU();
+
+ if (!m_dataGL.isNull())
+ m_dataGL->markSourceDirty();
+
updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -193,6 +343,14 @@ void QMapCircleObjectPrivateQSG::setCenter(const QGeoCoordinate &center)
void QMapCircleObjectPrivateQSG::setRadius(qreal radius)
{
QMapCircleObjectPrivateDefault::setRadius(radius);
+ if (!QDeclarativeCircleMapItemPrivate::crossEarthPole(this->center(), this->radius())) // Switching implementation for circles crossing/not crossing poles
+ switchToGL();
+ else
+ switchToCPU();
+
+ if (!m_dataGL.isNull())
+ m_dataGL->markSourceDirty();
+
updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -201,7 +359,8 @@ void QMapCircleObjectPrivateQSG::setRadius(qreal radius)
void QMapCircleObjectPrivateQSG::setColor(const QColor &color)
{
QMapCircleObjectPrivateDefault::setColor(color);
- updateGeometry();
+ if (!m_dataCPU.isNull())
+ updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
}
@@ -209,7 +368,8 @@ void QMapCircleObjectPrivateQSG::setColor(const QColor &color)
void QMapCircleObjectPrivateQSG::setBorderColor(const QColor &color)
{
QMapCircleObjectPrivateDefault::setBorderColor(color);
- updateGeometry();
+ if (!m_dataCPU.isNull())
+ updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
}
@@ -217,10 +377,10 @@ void QMapCircleObjectPrivateQSG::setBorderColor(const QColor &color)
void QMapCircleObjectPrivateQSG::setBorderWidth(qreal width)
{
QMapCircleObjectPrivateDefault::setBorderWidth(width);
- updateGeometry();
+ if (!m_dataCPU.isNull())
+ updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
}
-
QT_END_NAMESPACE
diff --git a/src/location/labs/qsg/qmapcircleobjectqsg_p_p.h b/src/location/labs/qsg/qmapcircleobjectqsg_p_p.h
index 6bbeb397..dc057c0b 100644
--- a/src/location/labs/qsg/qmapcircleobjectqsg_p_p.h
+++ b/src/location/labs/qsg/qmapcircleobjectqsg_p_p.h
@@ -68,14 +68,22 @@ public:
QMapCircleObjectPrivateQSG(const QMapCircleObjectPrivate &other);
~QMapCircleObjectPrivateQSG() override;
- void updateCirclePath();
-
// QQSGMapObject
void updateGeometry() override;
+ void updateGeometryCPU();
+ void updateGeometryGL();
QSGNode *updateMapObjectNode(QSGNode *oldNode,
VisibleNode **visibleNode,
QSGNode *root,
QQuickWindow *window) override;
+ QSGNode *updateMapObjectNodeCPU(QSGNode *oldNode,
+ VisibleNode **visibleNode,
+ QSGNode *root,
+ QQuickWindow *window);
+ QSGNode *updateMapObjectNodeGL(QSGNode *oldNode,
+ VisibleNode **visibleNode,
+ QSGNode *root,
+ QQuickWindow *window);
// QGeoMapCirclePrivate interface
void setCenter(const QGeoCoordinate &center) override;
@@ -87,15 +95,43 @@ public:
// QGeoMapObjectPrivate
QGeoMapObjectPrivate *clone() override;
+ void switchToGL();
+ void switchToCPU();
+
public:
// Data Members
+struct CircleDataCPU {
+ MapPolygonNode *m_node = nullptr;
QList<QDoubleVector2D> m_circlePath;
QGeoCoordinate m_leftBound;
QGeoMapCircleGeometry m_geometry;
QGeoMapPolylineGeometry m_borderGeometry;
bool m_updatingGeometry = false;
+
+ void updateCirclePath(const QGeoCoordinate &center, qreal radius, const QGeoProjectionWebMercator &p);
+};
+struct CircleDataGL {
+ QList<QGeoCoordinate> m_circlePath;
+ QGeoCoordinate m_leftBound;
+ QDoubleVector2D m_leftBoundMercator;
+ QGeoMapPolygonGeometryOpenGL m_geometry;
+ QGeoMapPolylineGeometryOpenGL m_borderGeometry;
+ QDeclarativePolygonMapItemPrivateOpenGL::RootNode *m_rootNode = nullptr;
+ MapPolygonNodeGL *m_node = nullptr;
+ MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr;
+
+ void updateCirclePath(const QGeoCoordinate &center, qreal radius, const QGeoProjectionWebMercator &p);
+ void markSourceDirty()
+ {
+ m_geometry.markSourceDirty();
+ m_borderGeometry.markSourceDirty();
+ }
+};
+ QScopedPointer<CircleDataCPU> m_dataCPU;
+ QScopedPointer<CircleDataGL> m_dataGL;
};
QT_END_NAMESPACE
#endif // QMAPCIRCLEOBJECT_P_P_H
+
diff --git a/src/location/labs/qsg/qmappolygonobjectqsg.cpp b/src/location/labs/qsg/qmappolygonobjectqsg.cpp
index 25473478..a8a1cb4b 100644
--- a/src/location/labs/qsg/qmappolygonobjectqsg.cpp
+++ b/src/location/labs/qsg/qmappolygonobjectqsg.cpp
@@ -52,6 +52,7 @@ QMapPolygonObjectPrivateQSG::QMapPolygonObjectPrivateQSG(const QMapPolygonObject
{
// Data already cloned by the *Default copy constructor, but necessary
// update operations triggered only by setters overrides
+ markSourceDirty();
updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -63,67 +64,22 @@ QMapPolygonObjectPrivateQSG::~QMapPolygonObjectPrivateQSG()
m_map->removeMapObject(q);
}
-QList<QDoubleVector2D> QMapPolygonObjectPrivateQSG::projectPath()
+void QMapPolygonObjectPrivateQSG::setPath(const QList<QGeoCoordinate> &p)
{
- QList<QDoubleVector2D> geopathProjected_;
- if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
- return geopathProjected_;
-
- const QGeoProjectionWebMercator &p =
- static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection());
- geopathProjected_.reserve(m_path.path().size());
- for (const QGeoCoordinate &c : m_path.path())
- geopathProjected_ << p.geoToMapProjection(c);
- return geopathProjected_;
-}
-
-QSGNode *QMapPolygonObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
- VisibleNode **visibleNode,
- QSGNode *root,
- QQuickWindow * /*window*/)
-{
- Q_UNUSED(visibleNode);
- MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
-
- if (!node) {
- if (!m_geometry.size() && !m_borderGeometry.size()) {
- return nullptr;
- }
- node = new MapPolygonNode();
- *visibleNode = static_cast<VisibleNode *>(node);
- }
-
- //TODO: update only material
- if (m_geometry.isScreenDirty() || !m_borderGeometry.isScreenDirty() || !oldNode) {
- node->update(fillColor(), borderColor(), &m_geometry, &m_borderGeometry);
- m_geometry.setPreserveGeometry(false);
- m_borderGeometry.setPreserveGeometry(false);
- m_geometry.markClean();
- m_borderGeometry.markClean();
- }
-
- if (m_geometry.size() || m_borderGeometry.size()) {
- root->appendChildNode(node);
- } else {
- delete node;
- return nullptr;
- }
- return node;
-}
-
-void QMapPolygonObjectPrivateQSG::setPath(const QList<QGeoCoordinate> &path)
-{
- QMapPolygonObjectPrivateDefault::setPath(path);
+ if (p == path())
+ return;
+ QMapPolygonObjectPrivateDefault::setPath(p);
+ markSourceDirty();
updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
+ emit static_cast<QMapPolygonObject *>(q)->pathChanged();
}
void QMapPolygonObjectPrivateQSG::setFillColor(const QColor &color)
{
QMapPolygonObjectPrivateDefault::setFillColor(color);
- updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -132,7 +88,6 @@ void QMapPolygonObjectPrivateQSG::setFillColor(const QColor &color)
void QMapPolygonObjectPrivateQSG::setBorderColor(const QColor &color)
{
QMapPolygonObjectPrivateDefault::setBorderColor(color);
- updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -141,7 +96,6 @@ void QMapPolygonObjectPrivateQSG::setBorderColor(const QColor &color)
void QMapPolygonObjectPrivateQSG::setBorderWidth(qreal width)
{
QMapPolygonObjectPrivateDefault::setBorderWidth(width);
- updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -158,59 +112,111 @@ void QMapPolygonObjectPrivateQSG::setGeoShape(const QGeoShape &shape)
return;
m_path = QGeoPathEager(shape);
+ markSourceDirty();
updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
emit static_cast<QMapPolygonObject *>(q)->pathChanged();
}
+// This is called both when data changes and when viewport changes.
+// so handle both cases (sourceDirty, !sourceDirty)
void QMapPolygonObjectPrivateQSG::updateGeometry()
{
- if (!m_map || m_path.path().length() == 0
- || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
+ if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
return;
- QScopedValueRollback<bool> rollback(m_updatingGeometry);
- m_updatingGeometry = true;
-
- const QList<QDoubleVector2D> &geopathProjected = projectPath();
-
- m_geometry.markSourceDirty();
- m_geometry.setPreserveGeometry(true, m_path.boundingGeoRectangle().topLeft());
- m_geometry.updateSourcePoints(*m_map, geopathProjected);
- m_geometry.updateScreenPoints(*m_map);
-
- m_borderGeometry.clear();
-
- //if (border_.color() != Qt::transparent && border_.width() > 0)
- {
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection());
- QList<QDoubleVector2D> closedPath = geopathProjected;
- closedPath << closedPath.first();
-
- m_borderGeometry.markSourceDirty();
+ if (m_path.path().length() == 0) { // Possibly cleared
+ m_geometry.clear();
+ m_borderGeometry.clear();
+ return;
+ }
+ const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection());
+ if (m_geometry.isSourceDirty() || m_borderGeometry.isSourceDirty()) {
+ // This works a bit differently than MapPolygon:
+ // the "screen bounds" aren't needed, so update only sources,
+ // regardless of the color, as color changes won't trigger polish(),
+ // and remember to flag m_dataChanged, that is in principle the same as
+ // sourceDirty_, but in practice is cleared in two different codepaths.
+ // sourceDirty_ is cleared in any case, dataChanged only if the primitive
+ // is effectively visible (e.g., not transparent or border not null)
+ m_geometry.setPreserveGeometry(true, m_path.boundingGeoRectangle().topLeft());
m_borderGeometry.setPreserveGeometry(true, m_path.boundingGeoRectangle().topLeft());
+ m_geometry.m_dataChanged = m_borderGeometry.m_dataChanged = true;
+ m_geometry.updateSourcePoints(*m_map, m_path);
+ m_borderGeometry.updateSourcePoints(*m_map, m_path);
+ m_leftBoundMercator = p.geoToMapProjection(m_geometry.origin());
+ }
+ m_geometry.markScreenDirty(); // ToDo: this needs refactor. It's useless, remove screenDirty_ altogether.
+ m_borderGeometry.markScreenDirty();
+ m_borderGeometry.m_wrapOffset = m_geometry.m_wrapOffset = p.projectionWrapFactor(m_leftBoundMercator) + 1;
+}
- const QGeoCoordinate &geometryOrigin = m_geometry.origin();
-
- m_borderGeometry.clearSource();
+QSGNode *QMapPolygonObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
+ VisibleNode **visibleNode,
+ QSGNode *root,
+ QQuickWindow * /*window*/)
+{
+ 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);
+ *visibleNode = static_cast<VisibleNode *>(m_rootNode);
+ if (oldNode)
+ delete oldNode;
+ } else {
+ m_rootNode = static_cast<QDeclarativePolygonMapItemPrivateOpenGL::RootNode *>(oldNode);
+ }
- QDoubleVector2D borderLeftBoundWrapped;
- QList<QList<QDoubleVector2D > > clippedPaths =
- m_borderGeometry.clipPath(*m_map.data(), closedPath, borderLeftBoundWrapped);
+ const QMatrix4x4 &combinedMatrix = m_map->geoProjection().qsgTransform();
+ const QDoubleVector3D &cameraCenter = m_map->geoProjection().centerMercator();
+
+ if (m_borderGeometry.isScreenDirty()) {
+ /* Do the border update first */
+ m_polylinenode->update(borderColor(),
+ float(borderWidth()),
+ &m_borderGeometry,
+ combinedMatrix,
+ cameraCenter,
+ Qt::SquareCap,
+ true);
+ m_borderGeometry.setPreserveGeometry(false);
+ m_borderGeometry.markClean();
+ }
+ if (m_geometry.isScreenDirty()) {
+ m_node->update(fillColor(),
+ &m_geometry,
+ combinedMatrix,
+ cameraCenter);
+ m_geometry.setPreserveGeometry(false);
+ m_geometry.markClean();
+ }
- if (clippedPaths.size()) {
- borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin);
- m_borderGeometry.pathToScreen(*m_map.data(), clippedPaths, borderLeftBoundWrapped);
- m_borderGeometry.updateScreenPoints(*m_map.data(), borderWidth(), false);
- } else {
- m_borderGeometry.clear();
- }
+ if (!m_polylinenode->isSubtreeBlocked() || !m_node->isSubtreeBlocked()) {
+ m_rootNode->setSubtreeBlocked(false);
+ root->appendChildNode(m_rootNode);
+ return m_rootNode;
+ } else {
+ m_rootNode->setSubtreeBlocked(true);
+ // If the object is currently invisible, but not gone,
+ // it is reasonable to assume it will become visible again.
+ // However, better not to retain unused data.
+ delete m_rootNode;
+ m_rootNode = nullptr;
+ m_node = nullptr;
+ m_polylinenode = nullptr;
+ *visibleNode = nullptr;
+ return nullptr;
}
+}
- QPointF origin = m_map->geoProjection().coordinateToItemPosition(m_geometry.origin(), false).toPointF();
- m_geometry.translate(origin - m_geometry.firstPointOffset());
- m_borderGeometry.translate(origin - m_borderGeometry.firstPointOffset());
+void QMapPolygonObjectPrivateQSG::markSourceDirty()
+{
+ m_geometry.markSourceDirty();
+ m_borderGeometry.markSourceDirty();
}
QT_END_NAMESPACE
diff --git a/src/location/labs/qsg/qmappolygonobjectqsg_p_p.h b/src/location/labs/qsg/qmappolygonobjectqsg_p_p.h
index 8e6ae8a8..9dcece74 100644
--- a/src/location/labs/qsg/qmappolygonobjectqsg_p_p.h
+++ b/src/location/labs/qsg/qmappolygonobjectqsg_p_p.h
@@ -67,6 +67,7 @@ public:
QList<QDoubleVector2D> projectPath();
// QQSGMapObject
+ void markSourceDirty();
void updateGeometry() override;
QSGNode *updateMapObjectNode(QSGNode *oldNode,
VisibleNode **visibleNode,
@@ -84,10 +85,12 @@ public:
virtual void setGeoShape(const QGeoShape &shape) override;
// Data Members
- QGeoMapPolygonGeometry m_geometry;
- QGeoMapPolylineGeometry m_borderGeometry;
-
- bool m_updatingGeometry = false;
+ QDoubleVector2D m_leftBoundMercator;
+ QGeoMapPolygonGeometryOpenGL m_geometry;
+ QGeoMapPolylineGeometryOpenGL m_borderGeometry;
+ QDeclarativePolygonMapItemPrivateOpenGL::RootNode *m_rootNode = nullptr;
+ MapPolygonNodeGL *m_node = nullptr;
+ MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/location/labs/qsg/qmappolylineobjectqsg.cpp b/src/location/labs/qsg/qmappolylineobjectqsg.cpp
index 96f66565..817d4df5 100644
--- a/src/location/labs/qsg/qmappolylineobjectqsg.cpp
+++ b/src/location/labs/qsg/qmappolylineobjectqsg.cpp
@@ -53,9 +53,9 @@ QMapPolylineObjectPrivateQSG::QMapPolylineObjectPrivateQSG(QGeoMapObject *q)
QMapPolylineObjectPrivateQSG::QMapPolylineObjectPrivateQSG(const QMapPolylineObjectPrivate &other)
: QMapPolylineObjectPrivateDefault(other)
{
- m_geoPath.setPath(m_path);
// rest of the data already cloned by the *Default copy constructor, but necessary
// update operations triggered only by setters overrides
+ markSourceDirty();
updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -75,28 +75,31 @@ QList<QDoubleVector2D> QMapPolylineObjectPrivateQSG::projectPath()
const QGeoProjectionWebMercator &p =
static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection());
- geopathProjected_.reserve(m_geoPath.path().size());
- for (const QGeoCoordinate &c : m_geoPath.path())
+ geopathProjected_.reserve(m_path.path().size());
+ for (const QGeoCoordinate &c : m_path.path())
geopathProjected_ << p.geoToMapProjection(c);
return geopathProjected_;
}
void QMapPolylineObjectPrivateQSG::updateGeometry()
{
- if (!m_map || m_geoPath.path().length() == 0
- || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
+ if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
return;
- QScopedValueRollback<bool> rollback(m_updatingGeometry);
- m_updatingGeometry = true;
- m_geometry.markSourceDirty();
- const QList<QDoubleVector2D> &geopathProjected = projectPath();
- m_geometry.setPreserveGeometry(true, m_geoPath.boundingGeoRectangle().topLeft());
- m_geometry.updateSourcePoints(*m_map.data(), geopathProjected, m_geoPath.boundingGeoRectangle().topLeft());
- m_geometry.updateScreenPoints(*m_map.data(), width(), false);
+ if (m_path.path().length() == 0) { // Possibly cleared
+ m_borderGeometry.clear();
+ return;
+ }
- QPointF origin = m_map->geoProjection().coordinateToItemPosition(m_geometry.origin(), false).toPointF();
- m_geometry.translate(origin - m_geometry.firstPointOffset());
+ const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection());
+ if (m_borderGeometry.isSourceDirty()) {
+ m_borderGeometry.setPreserveGeometry(true, m_path.boundingGeoRectangle().topLeft());
+ m_borderGeometry.m_dataChanged = true;
+ m_borderGeometry.updateSourcePoints(*m_map, m_path);
+ m_leftBoundMercator = p.geoToMapProjection(m_borderGeometry.origin());
+ }
+ m_borderGeometry.markScreenDirty();
+ m_borderGeometry.m_wrapOffset = p.projectionWrapFactor(m_leftBoundMercator) + 1;
}
QSGNode *QMapPolylineObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
@@ -104,41 +107,52 @@ QSGNode *QMapPolylineObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
QSGNode *root,
QQuickWindow * /*window*/)
{
- Q_UNUSED(visibleNode);
- MapPolylineNode *node = static_cast<MapPolylineNode *>(oldNode);
-
- if (!node) {
- if (!m_geometry.size()) // condition to block the subtree
- return nullptr;
- node = new MapPolylineNode();
- *visibleNode = static_cast<VisibleNode *>(node);
+ if (!m_polylinenode || !oldNode) {
+ m_polylinenode = new MapPolylineNodeOpenGLExtruded();
+ *visibleNode = static_cast<VisibleNode *>(m_polylinenode);
+ if (oldNode)
+ delete oldNode;
+ } else {
+ m_polylinenode = static_cast<MapPolylineNodeOpenGLExtruded *>(oldNode);
}
- //TODO: update only material
- if (m_geometry.isScreenDirty() || !oldNode) {
- node->update(color(), &m_geometry);
- m_geometry.setPreserveGeometry(false);
- m_geometry.markClean();
+ const QMatrix4x4 &combinedMatrix = m_map->geoProjection().qsgTransform();
+ const QDoubleVector3D &cameraCenter = m_map->geoProjection().centerMercator();
+
+ if (m_borderGeometry.isScreenDirty()) {
+ /* Do the border update first */
+ m_polylinenode->update(color(),
+ float(width()),
+ &m_borderGeometry,
+ combinedMatrix,
+ cameraCenter,
+ Qt::SquareCap,
+ true);
+ m_borderGeometry.setPreserveGeometry(false);
+ m_borderGeometry.markClean();
}
- if (m_geometry.size()) {
- root->appendChildNode(node);
+ if (!m_polylinenode->isSubtreeBlocked() ) {
+ m_polylinenode->setSubtreeBlocked(false);
+ root->appendChildNode(m_polylinenode);
+ return m_polylinenode;
} else {
- delete node;
+ delete m_polylinenode;
+ m_polylinenode = nullptr;
+ *visibleNode = nullptr;
return nullptr;
}
- return node;
}
QList<QGeoCoordinate> QMapPolylineObjectPrivateQSG::path() const
{
- return m_geoPath.path();
+ return m_path.path();
}
void QMapPolylineObjectPrivateQSG::setPath(const QList<QGeoCoordinate> &path)
{
- m_path = path;
- m_geoPath.setPath(path);
+ m_path.setPath(path);
+ markSourceDirty();
updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -147,7 +161,6 @@ void QMapPolylineObjectPrivateQSG::setPath(const QList<QGeoCoordinate> &path)
void QMapPolylineObjectPrivateQSG::setColor(const QColor &color)
{
QMapPolylineObjectPrivateDefault::setColor(color);
- updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -156,7 +169,6 @@ void QMapPolylineObjectPrivateQSG::setColor(const QColor &color)
void QMapPolylineObjectPrivateQSG::setWidth(qreal width)
{
QMapPolylineObjectPrivateDefault::setWidth(width);
- updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -169,7 +181,12 @@ QGeoMapObjectPrivate *QMapPolylineObjectPrivateQSG::clone()
QGeoShape QMapPolylineObjectPrivateQSG::geoShape() const
{
- return m_geoPath;
+ return m_path;
+}
+
+void QMapPolylineObjectPrivateQSG::markSourceDirty()
+{
+ m_borderGeometry.markSourceDirty();
}
QT_END_NAMESPACE
diff --git a/src/location/labs/qsg/qmappolylineobjectqsg_p_p.h b/src/location/labs/qsg/qmappolylineobjectqsg_p_p.h
index e8eb5839..63ebcde9 100644
--- a/src/location/labs/qsg/qmappolylineobjectqsg_p_p.h
+++ b/src/location/labs/qsg/qmappolylineobjectqsg_p_p.h
@@ -68,6 +68,7 @@ public:
QList<QDoubleVector2D> projectPath();
// QQSGMapObject
+ void markSourceDirty();
void updateGeometry() override;
QSGNode *updateMapObjectNode(QSGNode *oldNode,
VisibleNode **visibleNode,
@@ -85,9 +86,9 @@ public:
virtual QGeoShape geoShape() const override;
// Data Members
- QGeoPathEager m_geoPath;
- QGeoMapPolylineGeometry m_geometry;
- bool m_updatingGeometry = false;
+ QDoubleVector2D m_leftBoundMercator;
+ QGeoMapPolylineGeometryOpenGL m_borderGeometry;
+ MapPolylineNodeOpenGLExtruded *m_polylinenode = nullptr;
};
QT_END_NAMESPACE
diff --git a/tests/manual/mapobjects_tester/main.cpp b/tests/manual/mapobjects_tester/main.cpp
new file mode 100644
index 00000000..c04944d0
--- /dev/null
+++ b/tests/manual/mapobjects_tester/main.cpp
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ const QUrl url(QStringLiteral("qrc:/main.qml"));
+ QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
+ &app, [url](QObject *obj, const QUrl &objUrl) {
+ if (!obj && url == objUrl)
+ QCoreApplication::exit(-1);
+ }, Qt::QueuedConnection);
+ engine.load(url);
+
+ return app.exec();
+}
diff --git a/tests/manual/mapobjects_tester/main.qml b/tests/manual/mapobjects_tester/main.qml
new file mode 100644
index 00000000..4695df3a
--- /dev/null
+++ b/tests/manual/mapobjects_tester/main.qml
@@ -0,0 +1,515 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.7
+import QtQuick.Window 2.2
+import QtQuick.Controls 2.2 as C2
+import QtPositioning 5.6
+import QtLocation 5.15
+import Qt.labs.location 1.0
+
+Window {
+ id: win
+ objectName: "win"
+ visible: true
+ width: 1440
+ height: 720
+ title: qsTr("MapItems backends")
+
+
+ property real initialZL: 5
+ property var initialCenter: QtPositioning.coordinate(66.9961, -175.012)
+ property real rotation : 0
+
+ Shortcut {
+ sequence: "Ctrl+R"
+ onActivated: {
+ rotation = 57
+ }
+ }
+
+ function syncMaps(mFrom, mTo, propName)
+ {
+ if (mTo[propName] !== mFrom[propName]) {
+ mTo[propName] = mFrom[propName]
+ }
+ }
+
+ Plugin {
+ id: osm // use only one plugin, to avoid messing up the cache
+ name: "osm"
+ }
+ Rectangle {
+ id: mapContainer
+ rotation: win.rotation
+ anchors.fill: parent
+ color: "lightsteelblue"
+
+ Map {
+ id: map
+ rotation: win.rotation
+ gesture.enabled: true
+ objectName: "map1"
+ anchors {
+ bottom: parent.bottom
+ top: parent.top
+ left: parent.left
+ right: parent.horizontalCenter
+ }
+
+ onCenterChanged: syncMaps(map, map2, "center")
+ onTiltChanged: syncMaps(map, map2, "tilt")
+ onBearingChanged: syncMaps(map, map2, "bearing")
+ onZoomLevelChanged: syncMaps(map, map2, "zoomLevel")
+ onFieldOfViewChanged: syncMaps(map, map2, "fieldOfView")
+
+ opacity: 1.0
+ color: 'transparent'
+ plugin: osm
+ center: initialCenter
+ activeMapType: map.supportedMapTypes[2]
+ zoomLevel: initialZL
+ z : parent.z + 1
+ copyrightsVisible: false
+
+ Component.onCompleted: {
+ var o = movComponent.createObject(map1MainMOV)
+ map1MainMOV.addMapObject(o);
+ }
+ MapObjectView {
+ id: map1MainMOV
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ mouse.accepted = false
+ var crd = map.toCoordinate(Qt.point(mouse.x, mouse.y))
+ var s = crd.toString(0)
+ console.log("Clicked on ",s)
+ }
+ }
+ }
+ Map {
+ id: map2
+ rotation: win.rotation
+ gesture.enabled: true
+ objectName: "map2"
+ anchors {
+ bottom: parent.bottom
+ top: parent.top
+ left: parent.horizontalCenter
+ right: parent.right
+ }
+
+ onCenterChanged: syncMaps(map2, map, "center")
+ onTiltChanged: syncMaps(map2, map, "tilt")
+ onBearingChanged: syncMaps(map2, map, "bearing")
+ onZoomLevelChanged: syncMaps(map2, map, "zoomLevel")
+ onFieldOfViewChanged: syncMaps(map2, map, "fieldOfView")
+
+ color: 'transparent'
+ plugin: osm
+ activeMapType: map.supportedMapTypes[2]
+ center: initialCenter
+ zoomLevel: initialZL
+ copyrightsVisible: false
+
+ Component.onCompleted: {
+ var o = migComponent.createObject(map2)
+ o.glPolygons = Qt.binding(function() {return switchPolygons2.checked})
+ o.glPolylines = Qt.binding(function() {return switchPolylines2.currentText})
+ o.glCircles = Qt.binding(function() {return switchCircles2.checked})
+ o.glRectangles = Qt.binding(function() {return switchRectangles2.checked})
+ map2.addMapItemGroup(o);
+ }
+
+ C2.Switch {
+ text: qsTr("OGL Polygons")
+ id: switchPolygons2
+ checked: false
+ anchors {
+ top: parent.top
+ right: parent.right
+ topMargin: 12
+ rightMargin: 12
+ }
+ }
+ C2.ComboBox {
+ model: ['Software','OpenGL','Triangulated']
+ id: switchPolylines2
+ anchors {
+ top: switchPolygons2.bottom
+ right: parent.right
+ topMargin: 12
+ rightMargin: 12
+ }
+ onCurrentTextChanged: console.log("CURRENT TEXT CHANGED ",currentText)
+ }
+ C2.Switch {
+ text: qsTr("OGL Circles")
+ id: switchCircles2
+ anchors {
+ top: switchPolylines2.bottom
+ right: parent.right
+ topMargin: 12
+ rightMargin: 12
+ }
+ }
+ C2.Switch {
+ text: qsTr("OGL Rectangles")
+ id: switchRectangles2
+ anchors {
+ top: switchCircles2.bottom
+ right: parent.right
+ topMargin: 12
+ rightMargin: 12
+ }
+ }
+ }
+ }
+
+ Component {
+ id: migComponent
+ MapItemGroup {
+ id: polyGroup
+ property bool glPolygons : true
+ property string glPolylines : "Software"
+ property bool glCircles : true
+ property bool glRectangles : true
+ objectName: parent.objectName + "_MIG_"
+ function polylineBackend()
+ {
+ return (polyGroup.glPolylines === "OpenGL")
+ ? MapPolyline.OpenGLLineStrip
+ : ((polyGroup.glPolylines === "Software")
+ ? MapPolyline.Software : MapPolyline.OpenGLExtruded)
+ }
+
+ function polygonBackend()
+ {
+ return (polyGroup.glPolygons)
+ ? MapPolygon.OpenGL : MapPolygon.Software
+ }
+
+ function rectangleBackend()
+ {
+ return (polyGroup.glRectangles)
+ ? MapRectangle.OpenGL : MapRectangle.Software
+ }
+
+ function circleBackend()
+ {
+ return (polyGroup.glCircles)
+ ? MapCircle.OpenGL : MapCircle.Software
+ }
+ MapPolyline {
+ id: tstPolyLine // to verify the polygon stays where it's supposed to
+ line.color: 'black'
+ objectName: parent.objectName + "black"
+ line.width: 1
+ opacity: 1.0
+ backend: polylineBackend()
+ path: [
+ { latitude: 76.9965, longitude: -175.012 },
+ { latitude: 26.9965, longitude: -175.012 }
+ ]
+ }
+
+ MapPolyline {
+ id: timeline
+ line.color: "red"
+ objectName: parent.objectName + "timeline"
+ line.width: 4
+ backend: polylineBackend()
+ path: [
+ { latitude: 90, longitude: 180 },
+ { latitude: -90, longitude: -180 }
+ ]
+ }
+
+ MapPolygon {
+ id: poly1
+ color: "red"
+ objectName: parent.objectName + "red"
+ backend: polygonBackend()
+ path: [
+ { latitude: 55, longitude: 170 },
+ { latitude: 66.9965, longitude: -175.012 },
+ { latitude: 55, longitude: -160 },
+ { latitude: 40, longitude: -165 },
+ { latitude: 45, longitude: 178 }
+ ]
+ MouseArea {
+ anchors.fill: parent
+ onClicked: console.log("poly1 in "+parent.parent.objectName + "clicked")
+
+ Rectangle { // this is technically unsupported, but practically works.
+ color: "transparent"
+ border.color: "red"
+ anchors.fill: parent
+ }
+ }
+ }
+
+ MapPolygon {
+ id: selfIntersectingPolygon
+ color: 'darkmagenta'
+ objectName: parent.objectName + "darkmagenta"
+ backend: polygonBackend()
+ opacity: 1.0
+ path: [
+ { latitude: 19, longitude: 49 },
+ { latitude: 18, longitude: 49 },
+ { latitude: 18, longitude: 51 },
+ { latitude: 20, longitude: 51 },
+ { latitude: 20, longitude: 50 },
+ { latitude: 18.5, longitude: 50 },
+ { latitude: 18.5, longitude: 52 },
+ { latitude: 19, longitude: 52 }
+ ]
+
+ MouseArea{
+ anchors.fill: parent
+ drag.target: parent // This one might glitch as the tessellation done by earcut might be
+ // inaccurate, so clicking in an area that is covered by earcut but
+ // does not exist will not trigger the panning
+
+ Rectangle { // this is technically unsupported, but practically works.
+ color: "transparent"
+ border.color: "red"
+ anchors.fill: parent
+ }
+ }
+ }
+
+ MapPolygon {
+ id: poly2
+ color: "green"
+ border.color: "black"
+ border.width: 8
+ objectName: parent.objectName + "green"
+ backend: polygonBackend()
+ path: [
+ { latitude: -45, longitude: -170 },
+ { latitude: -55, longitude: -155 },
+ { latitude: -45, longitude: -130 },
+ { latitude: -35, longitude: -155 }
+ ]
+ MouseArea{
+ anchors.fill: parent
+ drag.target: parent
+ Rectangle { // this is technically unsupported, but practically works.
+ color: "transparent"
+ border.color: "red"
+ anchors.fill: parent
+ }
+ }
+ }
+
+ MapPolygon {
+ id: poly3
+ color: "deepskyblue"
+ objectName: parent.objectName + "deepskyblue"
+ backend: polygonBackend()
+ opacity: 0.2
+ path: [
+ { latitude: 65, longitude: -20 },
+ { latitude: 75, longitude: 140 },
+ { latitude: 65, longitude: 80 },
+ { latitude: 55, longitude: -30 }
+ ]
+ }
+
+ MapRectangle {
+ id: rect
+ color: 'tomato'
+ border.color: 'black'
+ border.width: 6
+ topLeft: QtPositioning.coordinate(10,-10)
+ bottomRight: QtPositioning.coordinate(-10,10)
+ backend: rectangleBackend()
+ MouseArea {
+ anchors.fill: parent
+ Rectangle {
+ color: "transparent"
+ border.color: "red"
+ border.width: 1
+ anchors.fill: parent
+ }
+ }
+ }
+
+ MapCircle {
+ center: QtPositioning.coordinate(52, 0)
+ radius: sliRadius.value
+ color: 'deepskyblue'
+ border.width: 6
+ border.color: 'firebrick'
+ backend: circleBackend()
+ MouseArea {
+ anchors.fill: parent
+ Rectangle {
+ color: "transparent"
+ border.color: "red"
+ border.width: 1
+ anchors.fill: parent
+ }
+ }
+ }
+
+ MapCircle {
+ id: circle1
+ border.color: 'deepskyblue'
+ border.width: 26
+ backend: circleBackend()
+ center: QtPositioning.coordinate(17, 44);
+ radius: 200*1000
+ color: "firebrick"
+ layer.enabled: (backend == MapCircle.Software)
+ layer.samples: 4
+ }
+ }
+ }
+
+ Component {
+ id: movComponent
+ MapObjectView {
+ id: polyGroup
+ MapPolylineObject {
+ id: tstPolyLine // to verify the polygon stays where it's supposed to
+ line.color: 'black'
+ objectName: parent.objectName + "black"
+ line.width: 1
+ path: [
+ { latitude: 76.9965, longitude: -175.012 },
+ { latitude: 26.9965, longitude: -175.012 }
+ ]
+ }
+
+ MapPolylineObject {
+ id: timeline
+ line.color: "red"
+ objectName: parent.objectName + "timeline"
+ line.width: 4
+ path: [
+ { latitude: 90, longitude: 180 },
+ { latitude: -90, longitude: -180 }
+ ]
+ }
+
+ MapPolygonObject {
+ id: poly1
+ color: "red"
+ objectName: parent.objectName + "red"
+ path: [
+ { latitude: 55, longitude: 170 },
+ { latitude: 66.9965, longitude: -175.012 },
+ { latitude: 55, longitude: -160 },
+ { latitude: 40, longitude: -165 },
+ { latitude: 45, longitude: 178 }
+ ]
+ }
+
+ MapPolygonObject {
+ id: selfIntersectingPolygon
+ color: 'darkmagenta'
+ objectName: parent.objectName + "darkmagenta"
+ path: [
+ { latitude: 19, longitude: 49 },
+ { latitude: 18, longitude: 49 },
+ { latitude: 18, longitude: 51 },
+ { latitude: 20, longitude: 51 },
+ { latitude: 20, longitude: 50 },
+ { latitude: 18.5, longitude: 50 },
+ { latitude: 18.5, longitude: 52 },
+ { latitude: 19, longitude: 52 }
+ ]
+ }
+
+ MapPolygonObject {
+ id: poly2
+ color: "green"
+ border.color: "black"
+ border.width: 8
+ objectName: parent.objectName + "green"
+ path: [
+ { latitude: -45, longitude: -170 },
+ { latitude: -55, longitude: -155 },
+ { latitude: -45, longitude: -130 },
+ { latitude: -35, longitude: -155 }
+ ]
+ }
+
+ MapPolygonObject {
+ id: poly3
+ color: Qt.rgba(0, 191.0/255.0, 1, 0.3) //"deepskyblue"
+ objectName: parent.objectName + "deepskyblue"
+ path: [
+ { latitude: 65, longitude: -20 },
+ { latitude: 75, longitude: 140 },
+ { latitude: 65, longitude: 80 },
+ { latitude: 55, longitude: -30 }
+ ]
+ }
+
+ MapCircleObject {
+ center: QtPositioning.coordinate(52, 0)
+ radius: sliRadius.value
+ color: 'deepskyblue'
+ border.width: 6
+ border.color: 'firebrick'
+ }
+
+// MapCircleObject {
+// id: circle1
+// border.color: 'deepskyblue'
+// border.width: 26
+// center: QtPositioning.coordinate(17, 44);
+// radius: 200*1000
+// color: "firebrick"
+// }
+ }
+ }
+
+ C2.Slider {
+ id: sliRadius
+ orientation: Qt.Vertical
+ anchors {
+ left: parent.left
+ top: parent.top
+ bottom: parent.bottom
+ topMargin: 10
+ leftMargin: 10
+ bottomMargin: 10
+ }
+ from: 30 * 1000
+ to: 600 * 1000
+ value: 100 * 1000
+ }
+}
diff --git a/tests/manual/mapobjects_tester/mapobjects_tester.pro b/tests/manual/mapobjects_tester/mapobjects_tester.pro
new file mode 100644
index 00000000..a517b750
--- /dev/null
+++ b/tests/manual/mapobjects_tester/mapobjects_tester.pro
@@ -0,0 +1,29 @@
+QT += quick
+CONFIG += c++11
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Refer to the documentation for the
+# deprecated API to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ main.cpp
+
+RESOURCES += qml.qrc
+
+# Additional import path used to resolve QML modules in Qt Creator's code model
+QML_IMPORT_PATH =
+
+# Additional import path used to resolve QML modules just for Qt Quick Designer
+QML_DESIGNER_IMPORT_PATH =
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
diff --git a/tests/manual/mapobjects_tester/qml.qrc b/tests/manual/mapobjects_tester/qml.qrc
new file mode 100644
index 00000000..5f6483ac
--- /dev/null
+++ b/tests/manual/mapobjects_tester/qml.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>