summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-03-31 03:03:41 +0200
committerAlex Blasche <alexander.blasche@qt.io>2020-04-02 08:20:37 +0200
commitb06a07cf9fd474e11fbe467047e5fe0322b677f0 (patch)
treeba8b1dd84c3d263b27a1865fff84a659b5273091
parent4cfed13377ababcfaa7dacb055bcd3dd0f2cf7d4 (diff)
parent29816a3aaa3f368422a3b19983add62673bb6960 (diff)
downloadqtlocation-b06a07cf9fd474e11fbe467047e5fe0322b677f0.tar.gz
Merge 5.15 to dev and fix resulting compile issues
Conflicts: src/imports/location/location.cpp The change fixes the bare minimum of what needs to be done to compile and run. This includes the following issues: 1. Fix build failures as a result of QMetaType changes in qtbase moc now stores the QMetaType of properties as a result of 46f407126ef3e94d59254012cdc34d6a4ad2faf2 in qtbase, which requires full type information about the property type inside the moc generated source file. Many of the property types were forward-declared, and this resulted in build errors like: "invalid application of 'sizeof' to an incomplete type 'QDeclarativeGeoMap'" 2. Adopts QtQML API changes. A private QJSValue ctor was removed. The "replacement" is QJSValuePrivate::fromReturnedValue(..). 3. The mapboxgl 3rdparty backend does not compile at this point in time and seems unmaintained. For the time being, the mapboxgl backend is disabled in the interest of keeping qtlocation closer to dev HEAD of other Qt modules. Change-Id: I756e1c2effb29eaaf96a61a28c1c17338774b77c
-rw-r--r--dependencies.yaml10
-rw-r--r--examples/location/geojson_viewer/GeoJsonDelegate.qml12
-rw-r--r--examples/location/geojson_viewer/GeoJsonDelegateMapObject.qml152
-rw-r--r--examples/location/geojson_viewer/geojson_viewer.pro2
-rw-r--r--examples/location/geojson_viewer/main.cpp23
-rw-r--r--examples/location/geojson_viewer/main.qml54
-rw-r--r--examples/location/geojson_viewer/qml.qrc1
-rw-r--r--examples/location/minimal_map/main.qml6
-rw-r--r--examples/positioning/weatherinfo/appmodel.cpp46
-rw-r--r--examples/positioning/weatherinfo/appmodel.h1
-rw-r--r--examples/positioning/weatherinfo/doc/src/weatherinfo.qdoc14
-rw-r--r--examples/positioning/weatherinfo/weatherinfo.pro1
-rw-r--r--src/3rdparty/geosimplify.js/LICENSE27
-rw-r--r--src/3rdparty/geosimplify.js/qt_attribution.json13
-rw-r--r--src/imports/location/location.cpp8
-rw-r--r--src/location/declarativemaps/declarativemaps.pri15
-rw-r--r--src/location/declarativemaps/locationvaluetypehelper.cpp2
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem.cpp391
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem_p.h57
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem_p_p.h449
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap.cpp37
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap_p.h8
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h3
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitembase.cpp29
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitembase_p.h30
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemutils.cpp180
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemutils_p.h122
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroute.cpp2
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroute_p.h2
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutemodel.cpp2
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutesegment.cpp2
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem.cpp639
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem_p.h91
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem_p_p.h668
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem.cpp1077
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem_p.h120
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h890
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem.cpp236
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem_p.h41
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h417
-rw-r--r--src/location/declarativemaps/qdeclarativeroutemapitem_p.h2
-rw-r--r--src/location/declarativemaps/qgeomapitemgeometry.cpp5
-rw-r--r--src/location/declarativemaps/qgeomapitemgeometry_p.h5
-rw-r--r--src/location/declarativemaps/qgeosimplify.cpp313
-rw-r--r--src/location/declarativemaps/qgeosimplify_p.h147
-rw-r--r--src/location/declarativeplaces/qdeclarativecategory_p.h2
-rw-r--r--src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h2
-rw-r--r--src/location/labs/qdeclarativenavigator.cpp4
-rw-r--r--src/location/labs/qdeclarativenavigator_p.h7
-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/qmaprouteobject_p.h2
-rw-r--r--src/location/labs/qsg/qgeomapobjectqsgsupport.cpp16
-rw-r--r--src/location/labs/qsg/qgeomapobjectqsgsupport_p.h3
-rw-r--r--src/location/labs/qsg/qmapcircleobjectqsg.cpp272
-rw-r--r--src/location/labs/qsg/qmapcircleobjectqsg_p_p.h42
-rw-r--r--src/location/labs/qsg/qmapiconobjectqsg.cpp5
-rw-r--r--src/location/labs/qsg/qmappolygonobjectqsg.cpp184
-rw-r--r--src/location/labs/qsg/qmappolygonobjectqsg_p_p.h13
-rw-r--r--src/location/labs/qsg/qmappolylineobjectqsg.cpp109
-rw-r--r--src/location/labs/qsg/qmappolylineobjectqsg_p_p.h9
-rw-r--r--src/location/labs/qsg/qqsgmapobject_p.h2
-rw-r--r--src/location/maps/qgeomap.cpp7
-rw-r--r--src/location/maps/qgeomap_p.h3
-rw-r--r--src/location/maps/qgeoprojection.cpp72
-rw-r--r--src/location/maps/qgeoprojection_p.h25
-rw-r--r--src/location/maps/qgeotiledmap.cpp4
-rw-r--r--src/plugins/geoservices/esri/geocodereply_esri.cpp4
-rw-r--r--src/plugins/geoservices/esri/georoutereply_esri.cpp4
-rw-r--r--src/plugins/geoservices/esri/geotiledmapreply_esri.cpp4
-rw-r--r--src/plugins/geoservices/esri/placemanagerengine_esri.cpp2
-rw-r--r--src/plugins/geoservices/esri/placesearchreply_esri.cpp4
-rw-r--r--src/plugins/geoservices/geoservices.pro3
-rw-r--r--src/plugins/geoservices/mapbox/qgeocodereplymapbox.cpp5
-rw-r--r--src/plugins/geoservices/mapbox/qgeomapreplymapbox.cpp4
-rw-r--r--src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp4
-rw-r--r--src/plugins/geoservices/mapbox/qplacesearchreplymapbox.cpp5
-rw-r--r--src/plugins/geoservices/mapbox/qplacesearchsuggestionreplymapbox.cpp5
-rw-r--r--src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp7
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.cpp4
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.cpp4
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp4
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.cpp4
-rw-r--r--src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp4
-rw-r--r--src/plugins/geoservices/nokia/qgeomapreply_nokia.cpp4
-rw-r--r--src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp6
-rw-r--r--src/plugins/geoservices/nokia/qgeotilefetcher_nokia.cpp8
-rw-r--r--src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp4
-rw-r--r--src/plugins/geoservices/osm/qgeocodereplyosm.cpp4
-rw-r--r--src/plugins/geoservices/osm/qgeomapreplyosm.cpp4
-rw-r--r--src/plugins/geoservices/osm/qgeoroutereplyosm.cpp4
-rw-r--r--src/plugins/geoservices/osm/qgeotileproviderosm.cpp6
-rw-r--r--src/plugins/geoservices/osm/qplacemanagerengineosm.cpp2
-rw-r--r--src/plugins/geoservices/osm/qplacesearchreplyosm.cpp5
-rw-r--r--src/plugins/position/serialnmea/qiopipe.cpp15
-rw-r--r--src/plugins/position/serialnmea/qiopipe_p.h1
-rw-r--r--src/positioning/qgeopolygon.cpp1
-rw-r--r--src/positioning/qlocationutils_p.h7
-rw-r--r--src/positioningquick/qdeclarativepositionsource.cpp2
-rw-r--r--tests/auto/nokia_services/routing/tst_routing.cpp4
-rw-r--r--tests/manual/mapitems_backends/main.cpp48
-rw-r--r--tests/manual/mapitems_backends/main.qml552
-rw-r--r--tests/manual/mapitems_backends/mapitems_backends.pro29
-rw-r--r--tests/manual/mapitems_backends/qml.qrc6
-rw-r--r--tests/manual/mapobjects_tester/main.cpp48
-rw-r--r--tests/manual/mapobjects_tester/main.qml531
-rw-r--r--tests/manual/mapobjects_tester/mapobjects_tester.pro29
-rw-r--r--tests/manual/mapobjects_tester/qml.qrc6
-rw-r--r--tests/manual/mappolyline_tester/LongPolyline.qml92745
-rw-r--r--tests/manual/mappolyline_tester/main.cpp56
-rw-r--r--tests/manual/mappolyline_tester/main.qml327
-rw-r--r--tests/manual/mappolyline_tester/mappolyline_tester.pro29
-rw-r--r--tests/manual/mappolyline_tester/qml.qrc6
114 files changed, 100546 insertions, 1161 deletions
diff --git a/dependencies.yaml b/dependencies.yaml
index 8715b2f6..bc94f4e2 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -1,16 +1,16 @@
dependencies:
../qtbase:
- ref: 06bb315beb6c2c398223cfe52cbc7f66e14a8557
+ ref: e0b89899e3c505edbdece60d6a2d2368a7ef9a01
required: true
../qtdeclarative:
- ref: be7e33e5dd59c0b8c077cdcb7849af3907455afc
+ ref: dbc6b9bfc7e6f1c7e212460105b426b8e80db671
required: false
../qtquickcontrols:
- ref: 2a8e875910728653cb8dd1c61578d2e76bd26d03
+ ref: e5658a34159ae32cff7a6c0e1295171c00fe923a
required: false
../qtquickcontrols2:
- ref: d9fd55a9d431be07bd6946afe8855b19c06bde97
+ ref: cc562c491ae6344d5956dbe4962b1dd09744551a
required: false
../qtserialport:
- ref: 3ffa5b013c8b94a50b4695a36077f0c83c43e3d3
+ ref: 0be470fd433e7514f3285ebdb1de776836048596
required: false
diff --git a/examples/location/geojson_viewer/GeoJsonDelegate.qml b/examples/location/geojson_viewer/GeoJsonDelegate.qml
index ff0fbffa..afbafe95 100644
--- a/examples/location/geojson_viewer/GeoJsonDelegate.qml
+++ b/examples/location/geojson_viewer/GeoJsonDelegate.qml
@@ -51,14 +51,15 @@
import QtQuick 2.12
import QtPositioning 5.12
-import QtLocation 5.12
+import QtLocation 5.15
import Qt.labs.qmlmodels 1.0
DelegateChooser {
id: dc
role: "type"
property color defaultColor: "grey"
- property real defaultOpacity: 0.7
+ property real defaultOpacity: 0.6
+ property bool openGLBackends: false
DelegateChoice {
roleValue: "Point"
@@ -82,8 +83,9 @@ DelegateChooser {
delegate: MapPolyline {
property string geojsonType: "LineString"
property var props: modelData.properties
+ backend: (dc.openGLBackends) ? MapPolyline.OpenGLExtruded : MapPolyline.Software
geoShape: modelData.data
- line.width: 3
+ line.width: 4
opacity: dc.defaultOpacity
line.color: (props && props.color) || (parent && parent.props && parent.props.color) || dc.defaultColor
}
@@ -97,7 +99,9 @@ DelegateChooser {
geoShape: modelData.data
opacity: dc.defaultOpacity
color: (props && props.color) || (parent && parent.props && parent.props.color) || dc.defaultColor
- border.width: 0
+ border.width: 4
+ border.color: 'black'
+ backend: (dc.openGLBackends) ? MapPolygon.OpenGL : MapPolygon.Software
MouseArea {
anchors.fill: parent
onClicked: {
diff --git a/examples/location/geojson_viewer/GeoJsonDelegateMapObject.qml b/examples/location/geojson_viewer/GeoJsonDelegateMapObject.qml
new file mode 100644
index 00000000..d1a144c8
--- /dev/null
+++ b/examples/location/geojson_viewer/GeoJsonDelegateMapObject.qml
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** 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 examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtPositioning 5.12
+import Qt.labs.location 1.0
+import Qt.labs.qmlmodels 1.0
+
+DelegateChooser {
+ id: dc
+ role: "type"
+ property color defaultColor: "grey"
+
+ DelegateChoice {
+ roleValue: "Point"
+ delegate: MapCircleObject {
+ property string geojsonType: "Point"
+ property var props: modelData.properties
+ geoShape: modelData.data
+ radius: 20*1000
+ border.width: 3
+ /* The expression below is equivalent to:
+ ((props !== undefined && props["color"] !== undefined) ? props["color"] :
+ ((parent && parent.props !== undefined && parent.props["color"] !== undefined) ? parent.props["color"] : dc.defaultColor))
+ */
+ color: (props && props.color) || (parent && parent.props && parent.props.color) || dc.defaultColor
+ }
+ }
+
+ DelegateChoice {
+ roleValue: "LineString"
+ delegate: MapPolylineObject {
+ property string geojsonType: "LineString"
+ property var props: modelData.properties
+ geoShape: modelData.data
+ line.width: 4
+ line.color: (props && props.color) || (parent && parent.props && parent.props.color) || dc.defaultColor
+ }
+ }
+
+ DelegateChoice {
+ roleValue: "Polygon"
+ delegate: MapPolygonObject {
+ property string geojsonType: "Polygon"
+ property var props: modelData.properties
+ geoShape: modelData.data
+ color: (props && props.color) || (parent && parent.props && parent.props.color) || dc.defaultColor
+ border.width: 4
+ border.color: 'black'
+ }
+ }
+
+ DelegateChoice {
+ roleValue: "MultiPoint"
+ delegate: MapObjectView {
+ property string geojsonType: "MultiPoint"
+ property var props: modelData.properties
+ model: modelData.data
+ delegate: dc
+ }
+ }
+
+ DelegateChoice {
+ roleValue: "MultiLineString"
+ delegate: MapObjectView {
+ property string geojsonType: "MultiLineString"
+ property var props: modelData.properties
+ model: modelData.data
+ delegate: dc
+ }
+ }
+
+ DelegateChoice {
+ roleValue: "MultiPolygon"
+ delegate: MapObjectView {
+ property string geojsonType: "MultiPolygon"
+ property var props: modelData.properties
+ model: modelData.data
+ delegate: dc
+ }
+ }
+
+ DelegateChoice {
+ roleValue: "GeometryCollection"
+ delegate: MapObjectView {
+ property string geojsonType: "GeometryCollection"
+ property var props: modelData.properties
+ model: modelData.data
+ delegate: dc
+ }
+ }
+
+ // Features are explicitly not generated by the parser, but converted straight to their content + the properties.
+
+ DelegateChoice {
+ roleValue: "FeatureCollection"
+ delegate: MapObjectView {
+ property string geojsonType: "FeatureCollection"
+ property var props: modelData.properties
+ model: modelData.data
+ delegate: dc
+ }
+ }
+}
diff --git a/examples/location/geojson_viewer/geojson_viewer.pro b/examples/location/geojson_viewer/geojson_viewer.pro
index cf261b36..08b28144 100644
--- a/examples/location/geojson_viewer/geojson_viewer.pro
+++ b/examples/location/geojson_viewer/geojson_viewer.pro
@@ -2,6 +2,8 @@ TARGET = qml_location_geojsonviewer
TEMPLATE = app
QT += core qml network quick positioning location-private widgets
+android: QT += androidextras
+
SOURCES += main.cpp
CONFIG += c++11
CONFIG += install_ok
diff --git a/examples/location/geojson_viewer/main.cpp b/examples/location/geojson_viewer/main.cpp
index 996c0925..61f7d233 100644
--- a/examples/location/geojson_viewer/main.cpp
+++ b/examples/location/geojson_viewer/main.cpp
@@ -70,6 +70,9 @@
#include <QJsonArray>
#include <QFileInfo>
#include <QtCore/qobjectdefs.h>
+#ifdef Q_OS_ANDROID
+#include <QtAndroid>
+#endif
class extractor
{
@@ -247,10 +250,30 @@ public:
#include "main.moc"
+#ifdef Q_OS_ANDROID
+// Request permissions because we're using QStandardPaths::writableLocation()
+bool requestStoragePermissions() {
+ using namespace QtAndroid;
+
+ QString permission = QStringLiteral("android.permission.WRITE_EXTERNAL_STORAGE");
+ const QHash<QString, PermissionResult> results = requestPermissionsSync(QStringList({permission}));
+ if (!results.contains(permission) || results[permission] == PermissionResult::Denied) {
+ qWarning() << "Couldn't get permission: " << permission;
+ return false;
+ }
+
+ return true;
+}
+#endif
+
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
+#ifdef Q_OS_ANDROID
+ if (!requestStoragePermissions())
+ return -1;
+#endif
QQmlApplicationEngine engine;
QUrl absoluteFilePath = argc > 1 ?
diff --git a/examples/location/geojson_viewer/main.qml b/examples/location/geojson_viewer/main.qml
index 01faef5f..1b55ef8b 100644
--- a/examples/location/geojson_viewer/main.qml
+++ b/examples/location/geojson_viewer/main.qml
@@ -58,14 +58,17 @@ import QtQuick.Window 2.11
import QtPositioning 5.12
import QtLocation 5.12
import Qt.labs.qmlmodels 1.0
+import Qt.labs.location 1.0
import Qt.GeoJson 1.0
C1.ApplicationWindow {
+ id: win
visible: true
width: 1024
height: 1024
menuBar: mainMenu
title: qsTr("GeoJSON Viewer")
+ property bool openGLBackends: glBackendSelector.checked
FileDialog {
visible: false
@@ -141,6 +144,33 @@ C1.ApplicationWindow {
geoJsoner.print(miv)
}
}
+ C1.MenuItem {
+ text: "OpenGL Item backends"
+ id: glBackendSelector
+ checkable: true
+ checked: false
+ }
+
+ C1.MenuItem {
+ text: "Map Object Delegates"
+ id: mapObjectsSelector
+ checkable: true
+ checked: false
+
+ onCheckedChanged: {
+ if (checked) {
+ miv.model = undefined
+ map.removeMapItemView(miv)
+ rootMoV.addMapObject(mov)
+ mov.model = geoJsoner.model
+ } else {
+ mov.model = undefined
+ rootMoV.removeMapObject(mov)
+ map.addMapItemView(miv)
+ miv.model = geoJsoner.model
+ }
+ }
+ }
}
}
@@ -149,17 +179,37 @@ C1.ApplicationWindow {
id: geoJsoner
}
+ Shortcut {
+ sequence: "Ctrl+P"
+ onActivated: {
+
+ console.log("Center : QtPositioning.coordinate(",map.center.latitude,",",map.center.longitude,")")
+ console.log("Zoom : ",map.zoomLevel)
+ }
+ }
+
+ MapObjectView {
+ id: mov
+ delegate: GeoJsonDelegateMapObject {}
+ }
+
Map {
id: map
anchors.fill: parent
center: QtPositioning.coordinate(43.59, 13.50) // Starting coordinates: Ancona, the city where I am studying :)
- plugin: Plugin { name: "mapboxgl" }
+ plugin: Plugin { name: "osm" }
zoomLevel: 4
+ MapObjectView {
+ id: rootMoV
+ }
+
MapItemView {
id: miv
model: geoJsoner.model
- delegate: GeoJsonDelegate {}
+ delegate: GeoJsonDelegate {
+ openGLBackends: win.openGLBackends
+ }
}
}
}
diff --git a/examples/location/geojson_viewer/qml.qrc b/examples/location/geojson_viewer/qml.qrc
index ea443bb0..794a2093 100644
--- a/examples/location/geojson_viewer/qml.qrc
+++ b/examples/location/geojson_viewer/qml.qrc
@@ -2,5 +2,6 @@
<qresource prefix="/">
<file>main.qml</file>
<file>GeoJsonDelegate.qml</file>
+ <file>GeoJsonDelegateMapObject.qml</file>
</qresource>
</RCC>
diff --git a/examples/location/minimal_map/main.qml b/examples/location/minimal_map/main.qml
index 40e1bb46..285eb31e 100644
--- a/examples/location/minimal_map/main.qml
+++ b/examples/location/minimal_map/main.qml
@@ -49,13 +49,13 @@
****************************************************************************/
import QtQuick 2.0
-import QtQuick.Window 2.0
+import QtQuick.Window 2.14
import QtLocation 5.6
import QtPositioning 5.6
Window {
- width: 512
- height: 512
+ width: Qt.platform.os == "android" ? Screen.width : 512
+ height: Qt.platform.os == "android" ? Screen.height : 512
visible: true
Plugin {
diff --git a/examples/positioning/weatherinfo/appmodel.cpp b/examples/positioning/weatherinfo/appmodel.cpp
index 93186aea..6d31d5ba 100644
--- a/examples/positioning/weatherinfo/appmodel.cpp
+++ b/examples/positioning/weatherinfo/appmodel.cpp
@@ -55,7 +55,6 @@
#include <qnmeapositioninfosource.h>
#include <qgeopositioninfo.h>
#include <qnetworkconfigmanager.h>
-#include <qnetworksession.h>
#include <QJsonDocument>
#include <QJsonObject>
@@ -150,7 +149,6 @@ public:
QString longitude, latitude;
QString city;
QNetworkAccessManager *nam;
- QNetworkSession *ns;
WeatherData now;
QList<WeatherData*> forecast;
QQmlListProperty<WeatherData> *fcProp;
@@ -166,7 +164,6 @@ public:
AppModelPrivate() :
src(NULL),
nam(NULL),
- ns(NULL),
fcProp(NULL),
ready(false),
useGps(true),
@@ -225,31 +222,7 @@ AppModel::AppModel(QObject *parent) :
//! [1]
- // make sure we have an active network session
d->nam = new QNetworkAccessManager(this);
-
- QNetworkConfigurationManager ncm;
- d->ns = new QNetworkSession(ncm.defaultConfiguration(), this);
- connect(d->ns, SIGNAL(opened()), this, SLOT(networkSessionOpened()));
- // the session may be already open. if it is, run the slot directly
- if (d->ns->isOpen())
- this->networkSessionOpened();
- // tell the system we want network
- d->ns->open();
-}
-//! [1]
-
-AppModel::~AppModel()
-{
- d->ns->close();
- if (d->src)
- d->src->stopUpdates();
- delete d;
-}
-
-//! [2]
-void AppModel::networkSessionOpened()
-{
d->src = QGeoPositionInfoSource::createDefaultSource(this);
if (d->src) {
@@ -266,9 +239,16 @@ void AppModel::networkSessionOpened()
this->refreshWeather();
}
}
-//! [2]
+//! [1]
+
+AppModel::~AppModel()
+{
+ if (d->src)
+ d->src->stopUpdates();
+ delete d;
+}
-//! [3]
+//! [2]
void AppModel::positionUpdated(QGeoPositionInfo gpsPos)
{
d->coord = gpsPos.coordinate();
@@ -278,7 +258,7 @@ void AppModel::positionUpdated(QGeoPositionInfo gpsPos)
queryCity();
}
-//! [3]
+//! [2]
void AppModel::queryCity()
{
@@ -347,7 +327,7 @@ void AppModel::handleGeoNetworkData(QNetworkReply *networkReply)
return;
}
- if (!networkReply->networkError()) {
+ if (!networkReply->error()) {
d->nErrors = 0;
if (!d->throttle.isValid())
d->throttle.start();
@@ -403,7 +383,7 @@ void AppModel::handleWeatherNetworkData(QNetworkReply *networkReply)
if (!networkReply)
return;
- if (!networkReply->networkError()) {
+ if (!networkReply->error()) {
foreach (WeatherData *inf, d->forecast)
delete inf;
d->forecast.clear();
@@ -455,7 +435,7 @@ void AppModel::handleForecastNetworkData(QNetworkReply *networkReply)
if (!networkReply)
return;
- if (!networkReply->networkError()) {
+ if (!networkReply->error()) {
QJsonDocument document = QJsonDocument::fromJson(networkReply->readAll());
QJsonObject jo;
diff --git a/examples/positioning/weatherinfo/appmodel.h b/examples/positioning/weatherinfo/appmodel.h
index a4d4e87a..f6657a59 100644
--- a/examples/positioning/weatherinfo/appmodel.h
+++ b/examples/positioning/weatherinfo/appmodel.h
@@ -156,7 +156,6 @@ public slots:
//! [2]
private slots:
void queryCity();
- void networkSessionOpened();
void positionUpdated(QGeoPositionInfo gpsPos);
void positionError(QGeoPositionInfoSource::Error e);
void handleGeoNetworkData(QNetworkReply *networkReply);
diff --git a/examples/positioning/weatherinfo/doc/src/weatherinfo.qdoc b/examples/positioning/weatherinfo/doc/src/weatherinfo.qdoc
index 089ae9d3..33a95f70 100644
--- a/examples/positioning/weatherinfo/doc/src/weatherinfo.qdoc
+++ b/examples/positioning/weatherinfo/doc/src/weatherinfo.qdoc
@@ -55,19 +55,13 @@
\snippet weatherinfo/appmodel.h 0
\snippet weatherinfo/appmodel.h 1
- AppModel models the state of the entire application. At startup, the
- application first begins by waiting for network connectivity. We do
- this using the QNetworkConfigurationManager and QNetworkSession family
- of C++ APIs.
+ AppModel models the state of the entire application. At startup, we
+ get the platform's default position source using
+ QGeoPositionInfo::createDefaultSource()
\snippet weatherinfo/appmodel.cpp 0
\snippet weatherinfo/appmodel.cpp 1
- Once the network session is open, we proceed to get the platform's
- default position source using QGeoPositionInfo::createDefaultSource()
-
- \snippet weatherinfo/appmodel.cpp 2
-
If no default source is available, we take a static position and fetch
weather for that. If, however, we do have a position source, we connect
its positionUpdated() signal to a slot on the AppModel and call
@@ -77,7 +71,7 @@
of the returned coordinate to retrieve the current "city" name for use
in the weather lookup.
- \snippet weatherinfo/appmodel.cpp 3
+ \snippet weatherinfo/appmodel.cpp 2
To inform the UI about this process, the cityChanged() signal is emitted
when a new city is used, and the weatherChanged() signal whenever a
diff --git a/examples/positioning/weatherinfo/weatherinfo.pro b/examples/positioning/weatherinfo/weatherinfo.pro
index d8f9675a..e2b2102d 100644
--- a/examples/positioning/weatherinfo/weatherinfo.pro
+++ b/examples/positioning/weatherinfo/weatherinfo.pro
@@ -2,7 +2,6 @@ TEMPLATE = app
TARGET = weatherinfo
QT += core network positioning qml quick
-requires(qtConfig(bearermanagement))
SOURCES += main.cpp \
appmodel.cpp
diff --git a/src/3rdparty/geosimplify.js/LICENSE b/src/3rdparty/geosimplify.js/LICENSE
new file mode 100644
index 00000000..bd04cc24
--- /dev/null
+++ b/src/3rdparty/geosimplify.js/LICENSE
@@ -0,0 +1,27 @@
+Qt port of geosimplify.js, https://github.com/mapbox/geosimplify-js
+
+Copyright (c) 2017, Daniel Patterson
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ of conditions and the following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+---------------------------------
+Based on simplify-js by Vladimir Agafonkin - http://mourner.github.io/simplify-js/
diff --git a/src/3rdparty/geosimplify.js/qt_attribution.json b/src/3rdparty/geosimplify.js/qt_attribution.json
new file mode 100644
index 00000000..bc8046e0
--- /dev/null
+++ b/src/3rdparty/geosimplify.js/qt_attribution.json
@@ -0,0 +1,13 @@
+{
+ "Id": "geosimplify-js",
+ "Name": "geosimplify-js polyline simplification library",
+ "QDocModule": "qtlocation",
+ "QtUsage": "Used in the QML plugin of Qt Location.",
+
+ "Description": "Based on https://github.com/mourner/simplify-js, geosimplify-js fixes the problem that the simple pythagorean measure used in simplify-js changes size if you simply give it longitude/latitude sequences to simplify.",
+ "Homepage": "https://github.com/mapbox/geosimplify-js",
+ "LicenseId": "geosimplify-js",
+ "License": "geosimplify-js License",
+ "LicenseFile": "LICENSE",
+ "Copyright": "Copyright (c) 2017 Daniel Patterson"
+}
diff --git a/src/imports/location/location.cpp b/src/imports/location/location.cpp
index 917ad25a..d4606066 100644
--- a/src/imports/location/location.cpp
+++ b/src/imports/location/location.cpp
@@ -206,6 +206,14 @@ public:
qmlRegisterUncreatableType<QDeclarativeGeoMapItemBase, 14>(uri, major, minor, "GeoMapItemBase",
QStringLiteral("GeoMapItemBase is not intended instantiable by developer."));
+ minor = 15;
+ qmlRegisterType<QDeclarativePolylineMapItem, 15>(uri, major, minor, "MapPolyline");
+ qmlRegisterType<QDeclarativePolygonMapItem, 15>(uri, major, minor, "MapPolygon");
+ qmlRegisterType<QDeclarativeRectangleMapItem, 15>(uri, major, minor, "MapRectangle");
+ qmlRegisterType<QDeclarativeCircleMapItem, 15>(uri, major, minor, "MapCircle");
+ qmlRegisterUncreatableType<QDeclarativeGeoMapItemBase, 15>(uri, major, minor, "GeoMapItemBase",
+ QStringLiteral("GeoMapItemBase is not intended instantiable by developer."));
+
// The minor version used to be the current Qt 5 minor. For compatibility it is the last
// Qt 5 release.
qmlRegisterModule(uri, 5, 15);
diff --git a/src/location/declarativemaps/declarativemaps.pri b/src/location/declarativemaps/declarativemaps.pri
index 54a0824b..e2a922f4 100644
--- a/src/location/declarativemaps/declarativemaps.pri
+++ b/src/location/declarativemaps/declarativemaps.pri
@@ -29,12 +29,19 @@ PRIVATE_HEADERS += \
declarativemaps/qgeomapobject_p.h \
declarativemaps/qgeomapobject_p_p.h \
declarativemaps/qparameterizableobject_p.h \
+ declarativemaps/qdeclarativegeomapitemutils_p.h \
+ declarativemaps/qdeclarativepolylinemapitem_p_p.h \
+ declarativemaps/qdeclarativepolygonmapitem_p_p.h \
+ declarativemaps/qdeclarativerectanglemapitem_p_p.h \
+ declarativemaps/qdeclarativecirclemapitem_p_p.h \
+ declarativemaps/qgeosimplify_p.h \
declarativemaps/qquickgeomapgesturearea_p.h
SOURCES += \
declarativemaps/error_messages.cpp \
declarativemaps/locationvaluetypehelper.cpp \
- declarativemaps/qdeclarativecirclemapitem.cpp \
+ declarativemaps/qdeclarativepolylinemapitem.cpp \
+ declarativemaps/qdeclarativepolygonmapitem.cpp \
declarativemaps/qdeclarativegeocodemodel.cpp \
declarativemaps/qdeclarativegeomaneuver.cpp \
declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp \
@@ -50,14 +57,16 @@ SOURCES += \
declarativemaps/qdeclarativegeoroutemodel.cpp \
declarativemaps/qdeclarativegeoroutesegment.cpp \
declarativemaps/qdeclarativegeoserviceprovider.cpp \
- declarativemaps/qdeclarativepolygonmapitem.cpp \
- declarativemaps/qdeclarativepolylinemapitem.cpp \
+ declarativemaps/qdeclarativecirclemapitem.cpp \
declarativemaps/qdeclarativerectanglemapitem.cpp \
declarativemaps/qdeclarativeroutemapitem.cpp \
declarativemaps/qgeomapitemgeometry.cpp \
declarativemaps/qgeomapobject.cpp \
+ declarativemaps/qdeclarativegeomapitemutils.cpp \
declarativemaps/qparameterizableobject.cpp \
+ declarativemaps/qgeosimplify.cpp \
declarativemaps/qquickgeomapgesturearea.cpp
load(qt_build_paths)
LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lpoly2tri$$qtPlatformTargetSuffix() -lclip2tri$$qtPlatformTargetSuffix()
+
diff --git a/src/location/declarativemaps/locationvaluetypehelper.cpp b/src/location/declarativemaps/locationvaluetypehelper.cpp
index 3e2f3658..e1ef7f59 100644
--- a/src/location/declarativemaps/locationvaluetypehelper.cpp
+++ b/src/location/declarativemaps/locationvaluetypehelper.cpp
@@ -164,7 +164,7 @@ QJSValue fromList(const QObject *object, const QList<QGeoCoordinate> &list)
pathArray->put(i++, cv);
}
- return QJSValue(v4, pathArray.asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(pathArray.asReturnedValue());
}
QList<QGeoCoordinate> toList(const QObject *object, const QJSValue &value)
diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem.cpp b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
index 846fccbf..f0ba122c 100644
--- a/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
@@ -57,6 +57,7 @@
#include <sweep/cdt.h>
#include <QtPositioning/private/qclipperutils_p.h>
+#include "qdeclarativecirclemapitem_p_p.h"
QT_BEGIN_NAMESPACE
@@ -274,83 +275,36 @@ void QGeoMapCircleGeometry::updateScreenPointsInvert(const QList<QDoubleVector2D
sourceBounds_ = screenBounds_;
}
-bool QDeclarativeCircleMapItem::crossEarthPole(const QGeoCoordinate &center, qreal distance)
+struct CircleBackendSelector
{
- 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 QDeclarativeCircleMapItem::calculatePeripheralPoints(QList<QGeoCoordinate> &path,
- const QGeoCoordinate &center,
- 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) {
- qreal azimuthRad = 2 * M_PI * i / steps;
- qreal resultLatRad = std::asin(sinLatRad_x_cosRatio
- + cosLatRad_x_sinRatio * std::cos(azimuthRad));
- qreal resultLonRad = lonRad + std::atan2(std::sin(azimuthRad) * cosLatRad_x_sinRatio,
- cosRatio - sinLatRad * std::sin(resultLatRad));
- 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;
- }
- }
+ CircleBackendSelector()
+ {
+ backend = (qgetenv("QTLOCATION_OPENGL_ITEMS").toInt()) ? QDeclarativeCircleMapItem::OpenGL : QDeclarativeCircleMapItem::Software;
}
- leftBound = path.at(idx);
-}
+ QDeclarativeCircleMapItem::Backend backend = QDeclarativeCircleMapItem::Software;
+};
+
+Q_GLOBAL_STATIC(CircleBackendSelector, mapCircleBackendSelector)
QDeclarativeCircleMapItem::QDeclarativeCircleMapItem(QQuickItem *parent)
-: QDeclarativeGeoMapItemBase(parent), border_(this), color_(Qt::transparent), dirtyMaterial_(true),
- updatingGeometry_(false)
+: 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(&border_, SIGNAL(colorChanged(QColor)),
- this, SLOT(markSourceDirtyAndUpdate()));
- QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
- this, SLOT(markSourceDirtyAndUpdate()));
+ QObject::connect(&m_border, SIGNAL(colorChanged(QColor)),
+ this, SLOT(onLinePropertiesChanged()));
+ QObject::connect(&m_border, SIGNAL(widthChanged(qreal)),
+ this, SLOT(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()
@@ -371,23 +325,24 @@ QDeclarativeCircleMapItem::~QDeclarativeCircleMapItem()
*/
QDeclarativeMapLineProperties *QDeclarativeCircleMapItem::border()
{
- return &border_;
+ return &m_border;
}
void QDeclarativeCircleMapItem::markSourceDirtyAndUpdate()
{
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- polishAndUpdate();
+ m_d->markSourceDirtyAndUpdate();
+}
+
+void QDeclarativeCircleMapItem::onLinePropertiesChanged()
+{
+ m_d->onLinePropertiesChanged();
}
void QDeclarativeCircleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
{
QDeclarativeGeoMapItemBase::setMap(quickMap,map);
- if (!map)
- return;
- updateCirclePath();
- markSourceDirtyAndUpdate();
+ if (map)
+ m_d->onMapSet();
}
/*!
@@ -399,18 +354,18 @@ void QDeclarativeCircleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *ma
*/
void QDeclarativeCircleMapItem::setCenter(const QGeoCoordinate &center)
{
- if (circle_.center() == center)
+ if (m_circle.center() == center)
return;
- circle_.setCenter(center);
- updateCirclePath();
- markSourceDirtyAndUpdate();
+ 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 circle_.center();
+ return m_circle.center();
}
/*!
@@ -421,17 +376,17 @@ QGeoCoordinate QDeclarativeCircleMapItem::center()
*/
void QDeclarativeCircleMapItem::setColor(const QColor &color)
{
- if (color_ == color)
+ if (m_color == color)
return;
- color_ = color;
- dirtyMaterial_ = true;
+ m_color = color;
+ m_dirtyMaterial = true;
update();
- emit colorChanged(color_);
+ emit colorChanged(m_color);
}
QColor QDeclarativeCircleMapItem::color() const
{
- return color_;
+ return m_color;
}
/*!
@@ -443,18 +398,18 @@ QColor QDeclarativeCircleMapItem::color() const
*/
void QDeclarativeCircleMapItem::setRadius(qreal radius)
{
- if (circle_.radius() == radius)
+ if (m_circle.radius() == radius)
return;
- circle_.setRadius(radius);
- updateCirclePath();
- markSourceDirtyAndUpdate();
+ 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 circle_.radius();
+ return m_circle.radius();
}
/*!
@@ -472,23 +427,7 @@ qreal QDeclarativeCircleMapItem::radius() const
*/
QSGNode *QDeclarativeCircleMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
{
- Q_UNUSED(data);
-
- MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
-
- if (!node)
- node = new MapPolygonNode();
-
- //TODO: update only material
- if (geometry_.isScreenDirty() || borderGeometry_.isScreenDirty() || dirtyMaterial_) {
- node->update(color_, border_.color(), &geometry_, &borderGeometry_);
- geometry_.setPreserveGeometry(false);
- borderGeometry_.setPreserveGeometry(false);
- geometry_.markClean();
- borderGeometry_.markClean();
- dirtyMaterial_ = false;
- }
- return node;
+ return m_d->updateMapItemPaintNode(oldNode, data);
}
/*!
@@ -498,111 +437,41 @@ void QDeclarativeCircleMapItem::updatePolish()
{
if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
return;
- if (!circle_.isValid()) {
- geometry_.clear();
- borderGeometry_.clear();
- setWidth(0);
- setHeight(0);
- return;
- }
-
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
- QScopedValueRollback<bool> rollback(updatingGeometry_);
- updatingGeometry_ = true;
-
- QList<QDoubleVector2D> circlePath = circlePath_;
-
- int pathCount = circlePath.size();
- bool preserve = preserveCircleGeometry(circlePath, circle_.center(), circle_.radius(), p);
- // using leftBound_ instead of the analytically calculated circle_.boundingGeoRectangle().topLeft());
- // to fix QTBUG-62154
- geometry_.setPreserveGeometry(true, leftBound_); // to set the geoLeftBound_
- geometry_.setPreserveGeometry(preserve, leftBound_);
-
- bool invertedCircle = false;
- if (crossEarthPole(circle_.center(), circle_.radius()) && circlePath.size() == pathCount) {
- geometry_.updateScreenPointsInvert(circlePath, *map()); // invert fill area for really huge circles
- invertedCircle = true;
- } else {
- geometry_.updateSourcePoints(*map(), circlePath);
- geometry_.updateScreenPoints(*map(), border_.width());
- }
-
- borderGeometry_.clear();
- QList<QGeoMapItemGeometry *> geoms;
- geoms << &geometry_;
-
- if (border_.color() != Qt::transparent && border_.width() > 0) {
- QList<QDoubleVector2D> closedPath = circlePath;
- closedPath << closedPath.first();
-
- if (invertedCircle) {
- closedPath = circlePath_;
- closedPath << closedPath.first();
- std::reverse(closedPath.begin(), closedPath.end());
- }
-
- borderGeometry_.setPreserveGeometry(true, leftBound_);
- borderGeometry_.setPreserveGeometry(preserve, leftBound_);
-
- // Use srcOrigin_ from fill geometry after clipping to ensure that translateToCommonOrigin won't fail.
- const QGeoCoordinate &geometryOrigin = geometry_.origin();
-
- borderGeometry_.srcPoints_.clear();
- borderGeometry_.srcPointTypes_.clear();
-
- QDoubleVector2D borderLeftBoundWrapped;
- QList<QList<QDoubleVector2D > > clippedPaths = borderGeometry_.clipPath(*map(), closedPath, borderLeftBoundWrapped);
- if (clippedPaths.size()) {
- borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin);
- borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
- borderGeometry_.updateScreenPoints(*map(), border_.width());
- geoms << &borderGeometry_;
- } else {
- borderGeometry_.clear();
- }
- }
-
- QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
-
- if (invertedCircle || !preserve) {
- setWidth(combined.width());
- setHeight(combined.height());
- setPositionOnMap(geometry_.origin(), geometry_.firstPointOffset());
- } else {
- setWidth(combined.width() + 2 * border_.width());
- setHeight(combined.height() + 2 * border_.width());
- }
-
- // No offsetting here, even in normal case, because first point offset is already translated
- setPositionOnMap(geometry_.origin(), geometry_.firstPointOffset());
+ 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::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+void QDeclarativeCircleMapItem::possiblySwitchBackend(const QGeoCoordinate &oldCenter, qreal oldRadius, const QGeoCoordinate &newCenter, qreal newRadius)
{
- if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
+ if (m_backend != QDeclarativeCircleMapItem::OpenGL)
return;
- markSourceDirtyAndUpdate();
+ // if old does not cross and new crosses, move to CPU.
+ if (!QDeclarativeCircleMapItemPrivate::crossEarthPole(oldCenter, oldRadius)
+ && !QDeclarativeCircleMapItemPrivate::crossEarthPole(newCenter, newRadius)) {
+ QScopedPointer<QDeclarativeCircleMapItemPrivate> d(static_cast<QDeclarativeCircleMapItemPrivate *>(new QDeclarativeCircleMapItemPrivateCPU(*this)));
+ m_d.swap(d);
+ } else if (QDeclarativeCircleMapItemPrivate::crossEarthPole(oldCenter, oldRadius)
+ && !QDeclarativeCircleMapItemPrivate::crossEarthPole(newCenter, newRadius)) { // else if old crosses and new does not cross, move back to OpenGL
+ QScopedPointer<QDeclarativeCircleMapItemPrivate> d(static_cast<QDeclarativeCircleMapItemPrivate *>(new QDeclarativeCircleMapItemPrivateOpenGL(*this)));
+ m_d.swap(d);
+ }
}
/*!
\internal
*/
-void QDeclarativeCircleMapItem::updateCirclePath()
+void QDeclarativeCircleMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
{
- if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
+ if (event.mapSize.isEmpty())
return;
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
- QList<QGeoCoordinate> path;
- calculatePeripheralPoints(path, circle_.center(), circle_.radius(), CircleSamples, leftBound_);
- circlePath_.clear();
- for (const QGeoCoordinate &c : path)
- circlePath_ << p.geoToMapProjection(c);
+ m_d->afterViewportChanged();
}
/*!
@@ -610,30 +479,69 @@ void QDeclarativeCircleMapItem::updateCirclePath()
*/
bool QDeclarativeCircleMapItem::contains(const QPointF &point) const
{
- return (geometry_.contains(point) || borderGeometry_.contains(point));
+ return m_d->contains(point);
+ //
}
const QGeoShape &QDeclarativeCircleMapItem::geoShape() const
{
- return circle_;
+ return m_circle;
}
void QDeclarativeCircleMapItem::setGeoShape(const QGeoShape &shape)
{
- if (shape == circle_)
+ 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() != circle_.center();
- const bool radiusHasChanged = circle.radius() != circle_.radius();
- circle_ = 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;
- updateCirclePath();
- markSourceDirtyAndUpdate();
+ m_d->onGeoGeometryChanged();
if (centerHasChanged)
- emit centerChanged(circle_.center());
+ emit centerChanged(m_circle.center());
if (radiusHasChanged)
- emit radiusChanged(circle_.radius());
+ 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;
+ QScopedPointer<QDeclarativeCircleMapItemPrivate> d((m_backend == Software)
+ ? static_cast<QDeclarativeCircleMapItemPrivate *>(new QDeclarativeCircleMapItemPrivateCPU(*this))
+ : static_cast<QDeclarativeCircleMapItemPrivate * >(new QDeclarativeCircleMapItemPrivateOpenGL(*this)));
+ m_d.swap(d);
+ m_d->onGeoGeometryChanged();
+ emit backendChanged();
}
/*!
@@ -641,21 +549,27 @@ void QDeclarativeCircleMapItem::setGeoShape(const QGeoShape &shape)
*/
void QDeclarativeCircleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
- if (!map() || !circle_.isValid() || updatingGeometry_ || newGeometry == oldGeometry) {
+ if (!map() || !m_circle.isValid() || m_updatingGeometry || newGeometry == oldGeometry) {
QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
return;
}
- QDoubleVector2D newPoint = QDoubleVector2D(x(),y()) + QDoubleVector2D(width(), height()) / 2;
+ QDoubleVector2D newPoint = QDoubleVector2D(x(),y()) + QDoubleVector2D(width(), height()) * 0.5;
QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(newPoint, false);
if (newCoordinate.isValid())
- setCenter(newCoordinate);
+ setCenter(newCoordinate); // ToDo: this is incorrect. setting such center might yield to another geometry changed.
// Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
// call to this function.
}
-bool QDeclarativeCircleMapItem::preserveCircleGeometry (QList<QDoubleVector2D> &path,
+QDeclarativeCircleMapItemPrivate::~QDeclarativeCircleMapItemPrivate() {}
+
+QDeclarativeCircleMapItemPrivateCPU::~QDeclarativeCircleMapItemPrivateCPU() {}
+
+QDeclarativeCircleMapItemPrivateOpenGL::~QDeclarativeCircleMapItemPrivateOpenGL() {}
+
+bool QDeclarativeCircleMapItemPrivate::preserveCircleGeometry (QList<QDoubleVector2D> &path,
const QGeoCoordinate &center, qreal distance, const QGeoProjectionWebMercator &p)
{
// if circle crosses north/south pole, then don't preserve circular shape,
@@ -664,7 +578,6 @@ bool QDeclarativeCircleMapItem::preserveCircleGeometry (QList<QDoubleVector2D> &
return false;
}
return true;
-
}
/*
@@ -684,7 +597,7 @@ bool QDeclarativeCircleMapItem::preserveCircleGeometry (QList<QDoubleVector2D> &
* | ____ |
* \__/ \__/
*/
-void QDeclarativeCircleMapItem::updateCirclePathForRendering(QList<QDoubleVector2D> &path,
+void QDeclarativeCircleMapItemPrivate::updateCirclePathForRendering(QList<QDoubleVector2D> &path,
const QGeoCoordinate &center,
qreal distance, const QGeoProjectionWebMercator &p)
{
@@ -743,6 +656,66 @@ void QDeclarativeCircleMapItem::updateCirclePathForRendering(QList<QDoubleVector
}
}
+bool QDeclarativeCircleMapItemPrivate::crossEarthPole(const QGeoCoordinate &center, 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 &center,
+ 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) {
+ qreal azimuthRad = 2 * M_PI * i / steps;
+ qreal resultLatRad = std::asin(sinLatRad_x_cosRatio
+ + cosLatRad_x_sinRatio * std::cos(azimuthRad));
+ qreal resultLonRad = lonRad + std::atan2(std::sin(azimuthRad) * cosLatRad_x_sinRatio,
+ cosRatio - sinLatRad * std::sin(resultLatRad));
+ 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
index 4b3f81c0..a6715e30 100644
--- a/src/location/declarativemaps/qdeclarativecirclemapitem_p.h
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h
@@ -50,33 +50,33 @@
#include <QtLocation/private/qlocationglobal_p.h>
#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
-#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
-#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p_p.h>
#include <QSGGeometryNode>
#include <QSGFlatColorMaterial>
#include <QtPositioning/QGeoCircle>
QT_BEGIN_NAMESPACE
-class Q_LOCATION_PRIVATE_EXPORT QGeoMapCircleGeometry : public QGeoMapPolygonGeometry
-{
-public:
- QGeoMapCircleGeometry();
-
- void updateScreenPointsInvert(const QList<QDoubleVector2D> &circlePath, const QGeoMap &map);
-};
-
+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:
- explicit QDeclarativeCircleMapItem(QQuickItem *parent = 0);
- ~QDeclarativeCircleMapItem();
+ enum Backend {
+ Software = 0,
+ OpenGL = 1
+ };
+
+ explicit QDeclarativeCircleMapItem(QQuickItem *parent = nullptr);
+ ~QDeclarativeCircleMapItem() override;
virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) override;
virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) override;
@@ -96,40 +96,41 @@ public:
const QGeoShape &geoShape() const override;
void setGeoShape(const QGeoShape &shape) override;
- static bool crossEarthPole(const QGeoCoordinate &center, qreal distance);
- static void calculatePeripheralPoints(QList<QGeoCoordinate> &path, const QGeoCoordinate &center,
- qreal distance, int steps, QGeoCoordinate &leftBound);
- static bool preserveCircleGeometry(QList<QDoubleVector2D> &path, const QGeoCoordinate &center,
- qreal distance, const QGeoProjectionWebMercator &p);
- static void updateCirclePathForRendering(QList<QDoubleVector2D> &path, const QGeoCoordinate &center,
- qreal distance, const QGeoProjectionWebMercator &p);
+ Backend backend() const;
+ void setBackend(Backend b);
Q_SIGNALS:
void centerChanged(const QGeoCoordinate &center);
void radiusChanged(qreal radius);
void colorChanged(const QColor &color);
+ void backendChanged();
protected:
void geometryChanged(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();
virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) override;
private:
void updateCirclePath();
private:
- QGeoCircle circle_;
- QDeclarativeMapLineProperties border_;
- QColor color_;
- QList<QDoubleVector2D> circlePath_;
- QGeoCoordinate leftBound_;
- bool dirtyMaterial_;
- QGeoMapCircleGeometry geometry_;
- QGeoMapPolylineGeometry borderGeometry_;
- bool updatingGeometry_;
+ QGeoCircle m_circle;
+ QDeclarativeMapLineProperties m_border;
+ QColor m_color;
+ bool m_dirtyMaterial;
+ bool m_updatingGeometry;
+ Backend m_backend = Software;
+
+ QScopedPointer<QDeclarativeCircleMapItemPrivate> m_d;
+
+ friend class QDeclarativeCircleMapItemPrivate;
+ friend class QDeclarativeCircleMapItemPrivateCPU;
+ friend class QDeclarativeCircleMapItemPrivateOpenGL;
};
//////////////////////////////////////////////////////////////////////
diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem_p_p.h b/src/location/declarativemaps/qdeclarativecirclemapitem_p_p.h
new file mode 100644
index 00000000..4cf42173
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem_p_p.h
@@ -0,0 +1,449 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com>
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef 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 &center, qreal distance);
+
+ static bool preserveCircleGeometry(QList<QDoubleVector2D> &path, const QGeoCoordinate &center,
+ qreal distance, const QGeoProjectionWebMercator &p);
+ static void updateCirclePathForRendering(QList<QDoubleVector2D> &path, const QGeoCoordinate &center,
+ qreal distance, const QGeoProjectionWebMercator &p);
+
+ static void calculatePeripheralPoints(QList<QGeoCoordinate> &path, const QGeoCoordinate &center,
+ 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();
+ }
+ virtual 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);
+ }
+ virtual void onMapSet() override
+ {
+ markSourceDirtyAndUpdate();
+ }
+ virtual void onGeoGeometryChanged() override
+ {
+
+ markSourceDirtyAndUpdate();
+ }
+ virtual void onItemGeometryChanged() override
+ {
+ onGeoGeometryChanged();
+ }
+ virtual void afterViewportChanged() override
+ {
+ preserveGeometry();
+ markScreenDirtyAndUpdate();
+ }
+ virtual 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));
+ }
+
+ virtual 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;
+ }
+ virtual 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
index 167f1d5f..17baf811 100644
--- a/src/location/declarativemaps/qdeclarativegeomap.cpp
+++ b/src/location/declarativemaps/qdeclarativegeomap.cpp
@@ -198,7 +198,7 @@ QDeclarativeGeoMap::QDeclarativeGeoMap(QQuickItem *parent)
setAcceptHoverEvents(false);
setAcceptedMouseButtons(Qt::LeftButton);
setFlags(QQuickItem::ItemHasContents | QQuickItem::ItemClipsChildrenToShape);
- setFiltersChildMouseEvents(true);
+ setFiltersChildMouseEvents(true); // needed for childMouseEventFilter to work.
m_activeMapType = new QDeclarativeGeoMapType(QGeoMapType(QGeoMapType::NoMap,
tr("No Map"),
@@ -707,7 +707,8 @@ void QDeclarativeGeoMap::mappingManagerInitialized()
emit m_map->copyrightsChanged(copyrightImage);
- connect(m_map.data(), &QGeoMap::sgNodeChanged, this, &QQuickItem::update);
+ connect(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
@@ -2179,6 +2180,38 @@ bool QDeclarativeGeoMap::removeMapItemView_real(QDeclarativeGeoMapItemView *item
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)
diff --git a/src/location/declarativemaps/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h
index ee9f8ec2..2a7ea6b1 100644
--- a/src/location/declarativemaps/qdeclarativegeomap_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomap_p.h
@@ -63,6 +63,9 @@
#include <QtLocation/private/qgeomap_p.h>
#include <QtQuick/private/qquickitemchangelistener_p.h>
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeomaptype_p.h>)
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeoserviceprovider_p.h>)
+
QT_BEGIN_NAMESPACE
class QDeclarativeGeoServiceProvider;
@@ -182,7 +185,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();
@@ -267,6 +270,8 @@ protected:
bool removeMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup);
bool addMapItemView_real(QDeclarativeGeoMapItemView *itemView);
bool removeMapItemView_real(QDeclarativeGeoMapItemView *itemView);
+ void updateItemToWindowTransform();
+ void onSGNodeChanged();
private Q_SLOTS:
void mappingManagerInitialized();
@@ -308,6 +313,7 @@ private:
double m_maximumViewportLatitude;
double m_minimumViewportLatitude = 0.0;
bool m_initialized;
+ bool m_sgNodeHasChanged = false;
QList<QDeclarativeGeoMapParameter *> m_mapParameters;
QList<QGeoMapObject*> m_pendingMapObjects; // Used only in the initialization phase
QGeoCameraCapabilities m_cameraCapabilities;
diff --git a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h
index 0cf06d12..ca345743 100644
--- a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h
@@ -55,6 +55,9 @@
#include <QPointer>
#include <QtQuick/QQuickPaintedItem>
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeomap_p.h>)
+
+
QT_BEGIN_NAMESPACE
class QTextDocument;
diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
index 23993faf..70b67828 100644
--- a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
+++ b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
@@ -218,6 +218,33 @@ void QDeclarativeGeoMapItemBase::setAutoFadeIn(bool fadeIn)
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
*/
@@ -323,6 +350,8 @@ bool QDeclarativeGeoMapItemBase::isPolishScheduled() const
return QQuickItemPrivate::get(this)->polishScheduled;
}
+void QDeclarativeGeoMapItemBase::setMaterialDirty() {}
+
void QDeclarativeGeoMapItemBase::polishAndUpdate()
{
polish();
diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h
index 38a118e5..61a67f59 100644
--- a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h
@@ -85,6 +85,8 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemBase : public QQuickItem
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 = 0);
virtual ~QDeclarativeGeoMapItemBase();
@@ -92,14 +94,18 @@ public:
virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map);
virtual void setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset);
- QDeclarativeGeoMap *quickMap() { return quickMap_; }
- QGeoMap *map() { return map_; }
+ 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 *);
virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *);
@@ -108,10 +114,28 @@ public:
void setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup);
+ template <typename T = QObject>
+
+ QList<T*> quickChildren() const
+ {
+ QList<T*> res;
+ QObjectList kids = children();
+ QList<QQuickItem *> quickKids = childItems();
+ for (int i = 0; i < quickKids.count(); ++i)
+ kids.append(quickKids.at(i));
+ for (auto kid : qAsConst(kids)) {
+ auto val = qobject_cast<T*>(kid);
+ if (val)
+ 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();
@@ -122,6 +146,7 @@ protected:
float zoomLevelOpacity() const;
bool childMouseEventFilter(QQuickItem *item, QEvent *event);
bool isPolishScheduled() const;
+ virtual void setMaterialDirty();
QGeoMap::ItemType m_itemType = QGeoMap::NoItem;
@@ -140,6 +165,7 @@ private:
QScopedPointer<QDeclarativeGeoMapItemTransitionManager> m_transitionManager;
bool m_autoFadeIn = true;
+ int m_lodThreshold = 0;
friend class QDeclarativeGeoMap;
friend class QDeclarativeGeoMapItemView;
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemutils.cpp b/src/location/declarativemaps/qdeclarativegeomapitemutils.cpp
new file mode 100644
index 00000000..e2774559
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemutils.cpp
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com>
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeomapitemutils_p.h"
+#include <QtPositioning/private/qdoublevector3d_p.h>
+#include <QtPositioning/private/qdoublematrix4x4_p.h>
+#include <QtPositioning/QGeoCoordinate>
+#include <QPointF>
+#include <QMatrix4x4>
+#include <QPainterPath>
+#include <QPainterPathStroker>
+#include <QtGui/private/qvectorpath_p.h>
+#include <QtGui/private/qtriangulatingstroker_p.h>
+#include <QtGui/private/qtriangulator_p.h>
+#include <QtPositioning/private/qclipperutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QDeclarativeGeoMapItemUtils::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 (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D coord = path.at(i);
+
+ // 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 QDeclarativeGeoMapItemUtils::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 QDeclarativeGeoMapItemUtils::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 (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D coord = path.at(i);
+
+ // 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 QDeclarativeGeoMapItemUtils::clipPolygon(const QList<QDoubleVector2D> &wrappedPath, const QGeoProjectionWebMercator &p, QList<QList<QDoubleVector2D> > &clippedPaths, QDoubleVector2D *leftBoundWrapped, const bool closed)
+{
+ // 2) Clip bounding box
+ clippedPaths.clear();
+ const QList<QDoubleVector2D> &visibleRegion = p.projectableGeometry();
+ if (visibleRegion.size()) {
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(wrappedPath), closed);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(visibleRegion));
+ Paths res = clipper.execute(c2t::clip2tri::Intersection, QtClipperLib::pftEvenOdd, QtClipperLib::pftEvenOdd);
+ clippedPaths = QClipperUtils::pathsToQList(res);
+
+ 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 QDeclarativeGeoMapItemUtils::projectBbox(const QList<QDoubleVector2D> &clippedBbox, const QGeoProjectionWebMercator &p, QPainterPath &projectedBbox)
+{
+ projectedBbox = QPainterPath(); // clear() is added in 5.13..
+ for (int i = 0; i < clippedBbox.size(); ++i) {
+ QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(clippedBbox.at(i));
+ if (i == 0)
+ projectedBbox.moveTo(point.toPointF());
+ else
+ projectedBbox.lineTo(point.toPointF());
+ }
+ projectedBbox.closeSubpath();
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemutils_p.h b/src/location/declarativemaps/qdeclarativegeomapitemutils_p.h
new file mode 100644
index 00000000..48ece6b2
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemutils_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com>
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef 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
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemUtils
+{
+public:
+ 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));
+ }
+ };
+
+ static void wrapPath(const QList<QGeoCoordinate> &perimeter
+ ,const QGeoCoordinate &geoLeftBound
+ ,const QGeoProjectionWebMercator &p
+ ,QList<QDoubleVector2D> &wrappedPath
+ ,QList<QDoubleVector2D> &wrappedPathMinus1
+ ,QList<QDoubleVector2D> &wrappedPathPlus1
+ ,QDoubleVector2D *leftBoundWrapped = nullptr);
+
+ static void wrapPath(const QList<QGeoCoordinate> &perimeter
+ ,const QGeoCoordinate &geoLeftBound
+ ,const QGeoProjectionWebMercator &p
+ ,QList<QDoubleVector2D> &wrappedPath
+ ,QDoubleVector2D *leftBoundWrapped = nullptr);
+
+ static void wrapPath(const QList<QDoubleVector2D> &path
+ , const QDoubleVector2D &geoLeftBound
+ , QList<QDoubleVector2D> &wrappedPath);
+
+
+ static void clipPolygon(const QList<QDoubleVector2D> &wrappedPath
+ ,const QGeoProjectionWebMercator &p
+ ,QList<QList<QDoubleVector2D> > &clippedPaths
+ ,QDoubleVector2D *leftBoundWrapped = nullptr
+ ,const bool closed = true);
+
+ static void projectBbox(const QList<QDoubleVector2D> &clippedBbox
+ ,const QGeoProjectionWebMercator &p
+ ,QPainterPath &projectedBbox);
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEGEOMAPITEMUTILS_P_H
diff --git a/src/location/declarativemaps/qdeclarativegeoroute.cpp b/src/location/declarativemaps/qdeclarativegeoroute.cpp
index c1f5264b..0144ade9 100644
--- a/src/location/declarativemaps/qdeclarativegeoroute.cpp
+++ b/src/location/declarativemaps/qdeclarativegeoroute.cpp
@@ -192,7 +192,7 @@ QJSValue QDeclarativeGeoRoute::path() const
pathArray->put(i, cv);
}
- return QJSValue(v4, pathArray.asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(pathArray.asReturnedValue());
}
void QDeclarativeGeoRoute::setPath(const QJSValue &value)
diff --git a/src/location/declarativemaps/qdeclarativegeoroute_p.h b/src/location/declarativemaps/qdeclarativegeoroute_p.h
index f455d027..9d89760a 100644
--- a/src/location/declarativemaps/qdeclarativegeoroute_p.h
+++ b/src/location/declarativemaps/qdeclarativegeoroute_p.h
@@ -55,6 +55,8 @@
#include <QtQml/QQmlListProperty>
#include <QtLocation/QGeoRoute>
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeoroutemodel_p.h>)
+
QT_BEGIN_NAMESPACE
class QDeclarativeGeoRouteQuery;
diff --git a/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
index 910e7026..a3a7fe85 100644
--- a/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
+++ b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
@@ -959,7 +959,7 @@ QJSValue QDeclarativeGeoRouteQuery::excludedAreas() const
excludedAreasArray->put(i, cv);
}
- return QJSValue(v4, excludedAreasArray.asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(excludedAreasArray.asReturnedValue());
}
void QDeclarativeGeoRouteQuery::setExcludedAreas(const QJSValue &value)
diff --git a/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp
index 6751a47b..713d434b 100644
--- a/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp
+++ b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp
@@ -158,7 +158,7 @@ QJSValue QDeclarativeGeoRouteSegment::path() const
pathArray->put(i, cv);
}
- return QJSValue(v4, pathArray.asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(pathArray.asReturnedValue());
}
QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
index 86ff04af..fa6ee174 100644
--- a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
@@ -34,7 +34,11 @@
**
****************************************************************************/
+#include "qdeclarativegeomapitemutils_p.h"
#include "qdeclarativepolygonmapitem_p.h"
+#include "qdeclarativepolylinemapitem_p_p.h"
+#include "qdeclarativepolygonmapitem_p_p.h"
+#include "qdeclarativerectanglemapitem_p_p.h"
#include "qlocationutils_p.h"
#include "error_messages_p.h"
#include "locationvaluetypehelper_p.h"
@@ -51,6 +55,10 @@
#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QtPositioning/private/qclipperutils_p.h>
#include <QtPositioning/private/qgeopolygon_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
+#include <QtQuick/private/qsgmaterialshader_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/qsgnode.h>
/* poly2tri triangulator includes */
#include <clip2tri.h>
@@ -326,17 +334,307 @@ void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map, qreal stroke
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 (int i = 0; i < 1+poly.holesCount(); ++i) {
+ QList<QDoubleVector2D> path;
+ if (!i) {
+ for (const QGeoCoordinate &c : poly.path())
+ 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 (int j = 0; j < paths.size(); ++j) {
+ const QList<QDoubleVector2D> &path = paths.at(j);
+ wrappedPath.clear();
+ for (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D coord = path.at(i);
+
+ // 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,
+ QVector<QDeclarativeGeoMapItemUtils::vec2> &screenVertices,
+ QVector<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,
+ QVector<QDeclarativeGeoMapItemUtils::vec2> &screenVertices,
+ QVector<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.path(), 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 geometryChanged 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.path(), 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 geometryChanged 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), border_(this), color_(Qt::transparent), dirtyMaterial_(true),
- updatingGeometry_(false)
+: 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;
- geopath_ = QGeoPolygonEager();
+ m_geopoly = QGeoPolygonEager();
setFlag(ItemHasContents, true);
- QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
- this, SLOT(markSourceDirtyAndUpdate()));
- QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
- this, SLOT(markSourceDirtyAndUpdate()));
+ QObject::connect(&m_border, SIGNAL(colorChanged(QColor)),
+ this, SLOT(onLinePropertiesChanged())); // ToDo: fix this, only flag material?
+ QObject::connect(&m_border, SIGNAL(widthChanged(qreal)),
+ this, SLOT(onLinePropertiesChanged()));
+ setBackend(mapPolygonBackendSelector->backend);
}
QDeclarativePolygonMapItem::~QDeclarativePolygonMapItem()
@@ -359,7 +657,44 @@ QDeclarativePolygonMapItem::~QDeclarativePolygonMapItem()
QDeclarativeMapLineProperties *QDeclarativePolygonMapItem::border()
{
- return &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;
+ QScopedPointer<QDeclarativePolygonMapItemPrivate> d((m_backend == Software)
+ ? static_cast<QDeclarativePolygonMapItemPrivate *>(new QDeclarativePolygonMapItemPrivateCPU(*this))
+ : static_cast<QDeclarativePolygonMapItemPrivate * >(new QDeclarativePolygonMapItemPrivateOpenGL(*this)));
+ m_d.swap(d);
+ m_d->onGeoGeometryChanged();
+ emit backendChanged();
}
/*!
@@ -368,12 +703,8 @@ QDeclarativeMapLineProperties *QDeclarativePolygonMapItem::border()
void QDeclarativePolygonMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
{
QDeclarativeGeoMapItemBase::setMap(quickMap,map);
- if (map) {
- regenerateCache();
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- polishAndUpdate();
- }
+ if (map)
+ m_d->onMapSet();
}
/*!
@@ -387,7 +718,7 @@ void QDeclarativePolygonMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *m
*/
QJSValue QDeclarativePolygonMapItem::path() const
{
- return fromList(this, geopath_.path());
+ return fromList(this, m_geopoly.path());
}
void QDeclarativePolygonMapItem::setPath(const QJSValue &value)
@@ -398,15 +729,12 @@ void QDeclarativePolygonMapItem::setPath(const QJSValue &value)
QList<QGeoCoordinate> pathList = toList(this, value);
// Equivalent to QDeclarativePolylineMapItem::setPathFromGeoList
- if (geopath_.path() == pathList)
+ if (m_geopoly.path() == pathList)
return;
- geopath_.setPath(pathList);
+ m_geopoly.setPath(pathList);
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_d->onGeoGeometryChanged();
emit pathChanged();
}
@@ -423,11 +751,8 @@ void QDeclarativePolygonMapItem::addCoordinate(const QGeoCoordinate &coordinate)
if (!coordinate.isValid())
return;
- geopath_.addCoordinate(coordinate);
- updateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_geopoly.addCoordinate(coordinate);
+ m_d->onGeoGeometryUpdated();
emit pathChanged();
}
@@ -443,15 +768,12 @@ void QDeclarativePolygonMapItem::addCoordinate(const QGeoCoordinate &coordinate)
*/
void QDeclarativePolygonMapItem::removeCoordinate(const QGeoCoordinate &coordinate)
{
- int length = geopath_.path().length();
- geopath_.removeCoordinate(coordinate);
- if (geopath_.path().length() == length)
+ int length = m_geopoly.path().length();
+ m_geopoly.removeCoordinate(coordinate);
+ if (m_geopoly.path().length() == length)
return;
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_d->onGeoGeometryChanged();
emit pathChanged();
}
@@ -465,18 +787,18 @@ void QDeclarativePolygonMapItem::removeCoordinate(const QGeoCoordinate &coordina
QColor QDeclarativePolygonMapItem::color() const
{
- return color_;
+ return m_color;
}
void QDeclarativePolygonMapItem::setColor(const QColor &color)
{
- if (color_ == color)
+ if (m_color == color)
return;
- color_ = color;
- dirtyMaterial_ = true;
- update();
- emit colorChanged(color_);
+ m_color = color;
+ m_dirtyMaterial = true;
+ polishAndUpdate(); // in case color was transparent and now is not or vice versa
+ emit colorChanged(m_color);
}
/*!
@@ -484,22 +806,7 @@ void QDeclarativePolygonMapItem::setColor(const QColor &color)
*/
QSGNode *QDeclarativePolygonMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
{
- Q_UNUSED(data);
- MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
-
- if (!node)
- node = new MapPolygonNode();
-
- //TODO: update only material
- if (geometry_.isScreenDirty() || borderGeometry_.isScreenDirty() || dirtyMaterial_) {
- node->update(color_, border_.color(), &geometry_, &borderGeometry_);
- geometry_.setPreserveGeometry(false);
- borderGeometry_.setPreserveGeometry(false);
- geometry_.markClean();
- borderGeometry_.markClean();
- dirtyMaterial_ = false;
- }
- return node;
+ return m_d->updateMapItemPaintNode(oldNode, data);
}
/*!
@@ -509,102 +816,34 @@ void QDeclarativePolygonMapItem::updatePolish()
{
if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
return;
- if (geopath_.path().length() == 0) { // Possibly cleared
- geometry_.clear();
- borderGeometry_.clear();
- setWidth(0);
- setHeight(0);
- return;
- }
-
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
- QScopedValueRollback<bool> rollback(updatingGeometry_);
- updatingGeometry_ = true;
-
- geometry_.updateSourcePoints(*map(), geopathProjected_);
- geometry_.updateScreenPoints(*map(), border_.width());
-
- QList<QGeoMapItemGeometry *> geoms;
- geoms << &geometry_;
- borderGeometry_.clear();
-
- if (border_.color() != Qt::transparent && border_.width() > 0) {
- QList<QDoubleVector2D> closedPath = geopathProjected_;
- closedPath << closedPath.first();
-
- borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
-
- const QGeoCoordinate &geometryOrigin = geometry_.origin();
-
- borderGeometry_.srcPoints_.clear();
- borderGeometry_.srcPointTypes_.clear();
-
- QDoubleVector2D borderLeftBoundWrapped;
- QList<QList<QDoubleVector2D > > clippedPaths = borderGeometry_.clipPath(*map(), closedPath, borderLeftBoundWrapped);
- if (clippedPaths.size()) {
- borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin);
- borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
- borderGeometry_.updateScreenPoints(*map(), border_.width());
-
- geoms << &borderGeometry_;
- } else {
- borderGeometry_.clear();
- }
- }
-
- QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
- setWidth(combined.width() + 2 * border_.width());
- setHeight(combined.height() + 2 * border_.width());
-
- setPositionOnMap(geometry_.origin(), -1 * geometry_.sourceBoundingBox().topLeft()
- + QPointF(border_.width(), border_.width()));
+ m_d->updatePolish();
}
-void QDeclarativePolygonMapItem::markSourceDirtyAndUpdate()
+void QDeclarativePolygonMapItem::setMaterialDirty()
{
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- polishAndUpdate();
+ m_dirtyMaterial = true;
+ update();
}
-/*!
- \internal
-*/
-void QDeclarativePolygonMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+void QDeclarativePolygonMapItem::markSourceDirtyAndUpdate()
{
- if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
- return;
-
- geometry_.setPreserveGeometry(true, geometry_.geoLeftBound());
- borderGeometry_.setPreserveGeometry(true, borderGeometry_.geoLeftBound());
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- polishAndUpdate();
+ m_d->markSourceDirtyAndUpdate();
}
-/*!
- \internal
-*/
-void QDeclarativePolygonMapItem::regenerateCache()
+void QDeclarativePolygonMapItem::onLinePropertiesChanged()
{
- if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
- return;
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
- geopathProjected_.clear();
- geopathProjected_.reserve(geopath_.path().size());
- for (const QGeoCoordinate &c : geopath_.path())
- geopathProjected_ << p.geoToMapProjection(c);
+ m_d->onLinePropertiesChanged();
}
/*!
\internal
*/
-void QDeclarativePolygonMapItem::updateCache()
+void QDeclarativePolygonMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
{
- if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
+ if (event.mapSize.isEmpty())
return;
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
- geopathProjected_ << p.geoToMapProjection(geopath_.path().last());
+
+ m_d->afterViewportChanged();
}
/*!
@@ -612,24 +851,21 @@ void QDeclarativePolygonMapItem::updateCache()
*/
bool QDeclarativePolygonMapItem::contains(const QPointF &point) const
{
- return (geometry_.contains(point) || borderGeometry_.contains(point));
+ return m_d->contains(point);
}
const QGeoShape &QDeclarativePolygonMapItem::geoShape() const
{
- return geopath_;
+ return m_geopoly;
}
void QDeclarativePolygonMapItem::setGeoShape(const QGeoShape &shape)
{
- if (shape == geopath_)
+ if (shape == m_geopoly)
return;
- geopath_ = QGeoPolygonEager(shape);
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_geopoly = QGeoPolygonEager(shape);
+ m_d->onGeoGeometryChanged();
emit pathChanged();
}
@@ -638,7 +874,7 @@ void QDeclarativePolygonMapItem::setGeoShape(const QGeoShape &shape)
*/
void QDeclarativePolygonMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
- if (!map() || !geopath_.isValid() || updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) {
+ if (newGeometry.topLeft() == oldGeometry.topLeft() || !map() || !m_geopoly.isValid() || m_updatingGeometry) {
QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
return;
}
@@ -652,11 +888,8 @@ void QDeclarativePolygonMapItem::geometryChanged(const QRectF &newGeometry, cons
if (offsetLati == 0.0 && offsetLongi == 0.0)
return;
- geopath_.translate(offsetLati, offsetLongi);
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_geopoly.translate(offsetLati, offsetLongi);
+ m_d->onGeoGeometryChanged();
emit pathChanged();
// Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
@@ -665,6 +898,25 @@ void QDeclarativePolygonMapItem::geometryChanged(const QRectF &newGeometry, cons
//////////////////////////////////////////////////////////////////////
+QSGMaterialShader *MapPolygonMaterial::createShader() const
+{
+ 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)
@@ -701,6 +953,9 @@ void MapPolygonNode::update(const QColor &fillColor, const QColor &borderColor,
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);
@@ -712,4 +967,90 @@ void MapPolygonNode::update(const QColor &fillColor, const QColor &borderColor,
}
}
+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 &center)
+{
+ 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)
+{
+
+}
+
+void MapPolygonShader::updateState(const QSGMaterialShader::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 &center = newMaterial->center();
+
+ QVector3D vecCenter, vecCenter_lowpart;
+ for (int i = 0; i < 3; i++)
+ QLocationUtils::split_double(center.get(i), &vecCenter[i], &vecCenter_lowpart[i]);
+
+ 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);
+ program()->setUniformValue(m_color_id, v);
+ }
+
+ if (state.isMatrixDirty())
+ {
+ program()->setUniformValue(m_matrix_id, state.projectionMatrix());
+ }
+
+ program()->setUniformValue(m_mapProjection_id, geoProjection);
+
+ program()->setUniformValue(m_center_id, vecCenter);
+ program()->setUniformValue(m_center_lowpart_id, vecCenter_lowpart);
+ program()->setUniformValue(m_wrapOffset_id, float(newMaterial->wrapOffset()));
+}
+
QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h b/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h
index 810a8d35..efc1a137 100644
--- a/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h
@@ -51,44 +51,29 @@
#include <QtLocation/private/qlocationglobal_p.h>
#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
-#include <QtLocation/private/qgeomapitemgeometry_p.h>
#include <QtPositioning/qgeopolygon.h>
-#include <QSGGeometryNode>
-#include <QSGFlatColorMaterial>
-
QT_BEGIN_NAMESPACE
-class MapPolygonNode;
-
-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_;
-};
-
+class QDeclarativePolygonMapItemPrivate;
class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItem : public QDeclarativeGeoMapItemBase
{
Q_OBJECT
+ Q_ENUMS(Backend)
Q_PROPERTY(QJSValue 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:
- explicit QDeclarativePolygonMapItem(QQuickItem *parent = 0);
- ~QDeclarativePolygonMapItem();
+ enum Backend {
+ Software = 0,
+ OpenGL = 1
+ };
+
+ explicit QDeclarativePolygonMapItem(QQuickItem *parent = nullptr);
+ ~QDeclarativePolygonMapItem() override;
virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) override;
//from QuickItem
@@ -105,6 +90,9 @@ public:
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;
@@ -112,45 +100,34 @@ public:
Q_SIGNALS:
void pathChanged();
void colorChanged(const QColor &color);
-
-protected:
- void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
- void updatePolish() override;
+ void backendChanged();
protected Q_SLOTS:
void markSourceDirtyAndUpdate();
+ void onLinePropertiesChanged();
virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) override;
-private:
- void regenerateCache();
- void updateCache();
-
- QGeoPolygon geopath_;
- QList<QDoubleVector2D> geopathProjected_;
- QDeclarativeMapLineProperties border_;
- QColor color_;
- bool dirtyMaterial_;
- QGeoMapPolygonGeometry geometry_;
- QGeoMapPolylineGeometry borderGeometry_;
- bool updatingGeometry_;
-};
-
-//////////////////////////////////////////////////////////////////////
-
-class Q_LOCATION_PRIVATE_EXPORT MapPolygonNode : public MapItemGeometryNode
-{
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void updatePolish() override;
+ void setMaterialDirty() override;
+#ifdef QT_LOCATION_DEBUG
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_;
+#endif
+ QGeoPolygon m_geopoly;
+ QDeclarativeMapLineProperties m_border;
+ QColor m_color;
+ Backend m_backend = Software;
+ bool m_dirtyMaterial;
+// bool m_dirtyGeometry = false;
+ bool m_updatingGeometry;
+
+ QScopedPointer<QDeclarativePolygonMapItemPrivate> m_d;
+
+ friend class QDeclarativePolygonMapItemPrivate;
+ friend class QDeclarativePolygonMapItemPrivateCPU;
+ friend class QDeclarativePolygonMapItemPrivateOpenGL;
};
QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem_p_p.h b/src/location/declarativemaps/qdeclarativepolygonmapitem_p_p.h
new file mode 100644
index 00000000..8d566e69
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem_p_p.h
@@ -0,0 +1,668 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com>
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef 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 <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 <QSGGeometryNode>
+#include <QSGFlatColorMaterial>
+#include <QtPositioning/QGeoPath>
+#include <QtPositioning/QGeoRectangle>
+#include <QtPositioning/QGeoPolygon>
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QSGFlatColorMaterial>
+#include <QSGSimpleMaterial>
+#include <QtGui/QMatrix4x4>
+#include <QColor>
+#include <QList>
+#include <QVector>
+#include <QtCore/QScopedValueRollback>
+
+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_;
+};
+
+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 QVector<QDeclarativeGeoMapItemUtils::vec2> &vx = m_screenVertices;
+ const QVector<quint32> &ix = m_screenIndices;
+
+ geom->allocate(vx.size(), ix.size());
+ if (geom->indexType() == QSGGeometry::UnsignedShortType) {
+ quint16 *its = geom->indexDataAsUShort();
+ for (int i = 0; i < ix.size(); ++i)
+ its[i] = ix[i];
+ } else if (geom->indexType() == QSGGeometry::UnsignedIntType) {
+ quint32 *its = geom->indexDataAsUInt();
+ for (int i = 0; i < ix.size(); ++i)
+ its[i] = ix[i];
+ }
+
+ QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D();
+ for (int i = 0; i < vx.size(); ++i)
+ pts[i].set(vx[i].x, vx[i].y);
+ }
+
+ QVector<QDeclarativeGeoMapItemUtils::vec2> m_screenVertices;
+ QVector<quint32> m_screenIndices;
+ QDoubleVector2D m_bboxLeftBoundWrapped;
+ QVector<WrappedPolygon> m_wrappedPolygons;
+ int m_wrapOffset;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT MapPolygonShader : public QSGMaterialShader
+{
+public:
+ MapPolygonShader();
+
+ const char *vertexShader() const override {
+ return
+ "attribute highp vec4 vertex; \n"
+ "uniform highp mat4 qt_Matrix; \n"
+ "uniform highp mat4 mapProjection; \n"
+ "uniform highp vec3 center; \n"
+ "uniform highp vec3 center_lowpart; \n"
+ "uniform lowp float wrapOffset; \n"
+ "vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); }\n"
+ "void main() { \n"
+ " vec4 vtx = wrapped(vertex) - vec4(center, 0.0); \n"
+ " vtx = vtx - vec4(center_lowpart, 0.0); \n"
+ " gl_Position = qt_Matrix * mapProjection * vtx; \n"
+ "}";
+ }
+
+ const char *fragmentShader() const override {
+ return
+ "uniform lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color; \n"
+ "}";
+ }
+
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override
+ {
+ static char const *const attr[] = { "vertex", nullptr };
+ return attr;
+ }
+
+private:
+ void initialize() override
+ {
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+ m_color_id = program()->uniformLocation("color");
+ m_mapProjection_id = program()->uniformLocation("mapProjection");
+ m_center_id = program()->uniformLocation("center");
+ m_center_lowpart_id = program()->uniformLocation("center_lowpart");
+ m_wrapOffset_id = program()->uniformLocation("wrapOffset");
+ }
+ int m_center_id;
+ int m_center_lowpart_id;
+ int m_mapProjection_id;
+ int m_matrix_id;
+ int m_color_id;
+ int m_wrapOffset_id;
+};
+
+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 | CustomCompileStep);
+ }
+
+ QSGMaterialShader *createShader() 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 &center);
+
+ 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.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_geopoly.path().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.path().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.path().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
index 10f3f0c3..d59704dc 100644
--- a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
@@ -35,11 +35,16 @@
****************************************************************************/
#include "qdeclarativepolylinemapitem_p.h"
+#include "qdeclarativepolylinemapitem_p_p.h"
+#include "qdeclarativerectanglemapitem_p_p.h"
+#include "qdeclarativecirclemapitem_p_p.h"
#include "qlocationutils_p.h"
+#include "qdeclarativegeomapitemutils_p.h"
#include "error_messages_p.h"
#include "locationvaluetypehelper_p.h"
#include "qdoublevector2d_p.h"
#include <QtLocation/private/qgeomap_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
#include <QtCore/QScopedValueRollback>
#include <QtQml/QQmlInfo>
@@ -55,10 +60,32 @@
#include <QtPositioning/private/qclipperutils_p.h>
#include <QtPositioning/private/qgeopath_p.h>
+#include <QtQuick/private/qsgmaterialshader_p.h>
#include <array>
+#include <QThreadPool>
+#include <QRunnable>
+#include <QtLocation/private/qgeomapparameter_p.h>
+#include "qgeosimplify_p.h"
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 const double kClipperScaleFactor = 281474976710656.0; // 48 bits of precision
@@ -125,7 +152,7 @@ static QList<QList<QDoubleVector2D> > clipLine(
const QList<QDoubleVector2D> &poly)
{
QList<QList<QDoubleVector2D> > res;
- if (poly.size() < 3 || l.size() < 2)
+ if (poly.size() < 2 || l.size() < 2)
return res;
// Step 1: build edges
@@ -355,11 +382,6 @@ void QDeclarativeMapLineProperties::setWidth(qreal width)
emit widthChanged(width_);
}
-struct Vertex
-{
- QVector2D position;
-};
-
QGeoMapPolylineGeometry::QGeoMapPolylineGeometry()
{
}
@@ -661,7 +683,7 @@ void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
// Create the viewport rect in the same coordinate system
// as the actual points
QRectF viewport(0, 0, map.viewportWidth(), map.viewportHeight());
- viewport.adjust(-strokeWidth, -strokeWidth, strokeWidth, strokeWidth);
+ viewport.adjust(-strokeWidth, -strokeWidth, strokeWidth * 2, strokeWidth * 2);
viewport.translate(-1 * origin);
QVector<qreal> points;
@@ -719,7 +741,7 @@ void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
}
screenBounds_ = bb;
- const QPointF strokeOffset = (adjustTranslation) ? QPointF(strokeWidth, strokeWidth) : QPointF();
+ const QPointF strokeOffset = (adjustTranslation) ? QPointF(strokeWidth, strokeWidth) * 0.5: QPointF();
this->translate( -1 * sourceBounds_.topLeft() + strokeOffset);
}
@@ -747,16 +769,202 @@ bool QGeoMapPolylineGeometry::contains(const QPointF &point) const
return false;
}
+void QGeoMapPolylineGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QGeoPolygon &poly)
+{
+ if (!sourceDirty_)
+ return;
+ QGeoPath p(poly.path());
+ if (poly.path().size() && poly.path().last() != poly.path().first())
+ p.addCoordinate(poly.path().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.path(), 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), line_(this), dirtyMaterial_(true), updatingGeometry_(false)
+: QDeclarativeGeoMapItemBase(parent),
+ m_line(this),
+ m_dirtyMaterial(true),
+ m_updatingGeometry(false),
+ m_d(new QDeclarativePolylineMapItemPrivateCPU(*this))
{
m_itemType = QGeoMap::MapPolyline;
- geopath_ = QGeoPathEager();
+ m_geopath = QGeoPathEager();
setFlag(ItemHasContents, true);
- QObject::connect(&line_, SIGNAL(colorChanged(QColor)),
+ QObject::connect(&m_line, SIGNAL(colorChanged(QColor)),
this, SLOT(updateAfterLinePropertiesChanged()));
- QObject::connect(&line_, SIGNAL(widthChanged(qreal)),
+ QObject::connect(&m_line, SIGNAL(widthChanged(qreal)),
this, SLOT(updateAfterLinePropertiesChanged()));
+ setBackend(mapPolylineBackendSelector->backend);
}
QDeclarativePolylineMapItem::~QDeclarativePolylineMapItem()
@@ -768,9 +976,7 @@ QDeclarativePolylineMapItem::~QDeclarativePolylineMapItem()
*/
void QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged()
{
- // mark dirty just in case we're a width change
- geometry_.markSourceDirty();
- polishAndUpdate();
+ m_d->onLinePropertiesChanged();
}
/*!
@@ -779,11 +985,8 @@ void QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged()
void QDeclarativePolylineMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
{
QDeclarativeGeoMapItemBase::setMap(quickMap,map);
- if (map) {
- regenerateCache();
- geometry_.markSourceDirty();
- polishAndUpdate();
- }
+ if (map)
+ m_d->onMapSet();
}
/*!
@@ -795,7 +998,7 @@ void QDeclarativePolylineMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *
QJSValue QDeclarativePolylineMapItem::path() const
{
- return fromList(this, geopath_.path());
+ return fromList(this, m_geopath.path());
}
void QDeclarativePolylineMapItem::setPath(const QJSValue &value)
@@ -807,7 +1010,7 @@ void QDeclarativePolylineMapItem::setPath(const QJSValue &value)
}
/*!
- \qmlmethod int MapPolyline::setPath(geopath path)
+ \qmlmethod void MapPolyline::setPath(geopath path)
Sets the \a path using a geopath type.
@@ -817,13 +1020,11 @@ void QDeclarativePolylineMapItem::setPath(const QJSValue &value)
*/
void QDeclarativePolylineMapItem::setPath(const QGeoPath &path)
{
- if (geopath_.path() == path.path())
+ if (m_geopath.path() == path.path())
return;
- geopath_ = QGeoPathEager(path);
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_geopath = QGeoPathEager(path);
+ m_d->onGeoGeometryChanged();
emit pathChanged();
}
@@ -832,14 +1033,12 @@ void QDeclarativePolylineMapItem::setPath(const QGeoPath &path)
*/
void QDeclarativePolylineMapItem::setPathFromGeoList(const QList<QGeoCoordinate> &path)
{
- if (geopath_.path() == path)
+ if (m_geopath.path() == path)
return;
- geopath_.setPath(path);
+ m_geopath.setPath(path);
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_d->onGeoGeometryChanged();
emit pathChanged();
}
@@ -854,7 +1053,7 @@ void QDeclarativePolylineMapItem::setPathFromGeoList(const QList<QGeoCoordinate>
*/
int QDeclarativePolylineMapItem::pathLength() const
{
- return geopath_.path().length();
+ return m_geopath.path().length();
}
/*!
@@ -869,11 +1068,9 @@ void QDeclarativePolylineMapItem::addCoordinate(const QGeoCoordinate &coordinate
if (!coordinate.isValid())
return;
- geopath_.addCoordinate(coordinate);
+ m_geopath.addCoordinate(coordinate);
- updateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_d->onGeoGeometryUpdated();
emit pathChanged();
}
@@ -888,14 +1085,12 @@ void QDeclarativePolylineMapItem::addCoordinate(const QGeoCoordinate &coordinate
*/
void QDeclarativePolylineMapItem::insertCoordinate(int index, const QGeoCoordinate &coordinate)
{
- if (index < 0 || index > geopath_.path().length())
+ if (index < 0 || index > m_geopath.path().length())
return;
- geopath_.insertCoordinate(index, coordinate);
+ m_geopath.insertCoordinate(index, coordinate);
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_d->onGeoGeometryChanged();
emit pathChanged();
}
@@ -911,14 +1106,12 @@ void QDeclarativePolylineMapItem::insertCoordinate(int index, const QGeoCoordina
*/
void QDeclarativePolylineMapItem::replaceCoordinate(int index, const QGeoCoordinate &coordinate)
{
- if (index < 0 || index >= geopath_.path().length())
+ if (index < 0 || index >= m_geopath.path().length())
return;
- geopath_.replaceCoordinate(index, coordinate);
+ m_geopath.replaceCoordinate(index, coordinate);
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_d->onGeoGeometryChanged();
emit pathChanged();
}
@@ -933,10 +1126,10 @@ void QDeclarativePolylineMapItem::replaceCoordinate(int index, const QGeoCoordin
*/
QGeoCoordinate QDeclarativePolylineMapItem::coordinateAt(int index) const
{
- if (index < 0 || index >= geopath_.path().length())
+ if (index < 0 || index >= m_geopath.path().length())
return QGeoCoordinate();
- return geopath_.coordinateAt(index);
+ return m_geopath.coordinateAt(index);
}
/*!
@@ -948,7 +1141,7 @@ QGeoCoordinate QDeclarativePolylineMapItem::coordinateAt(int index) const
*/
bool QDeclarativePolylineMapItem::containsCoordinate(const QGeoCoordinate &coordinate)
{
- return geopath_.containsCoordinate(coordinate);
+ return m_geopath.containsCoordinate(coordinate);
}
/*!
@@ -963,13 +1156,12 @@ bool QDeclarativePolylineMapItem::containsCoordinate(const QGeoCoordinate &coord
*/
void QDeclarativePolylineMapItem::removeCoordinate(const QGeoCoordinate &coordinate)
{
- int length = geopath_.path().length();
- geopath_.removeCoordinate(coordinate);
- if (geopath_.path().length() == length)
+ int length = m_geopath.path().length();
+ m_geopath.removeCoordinate(coordinate);
+ if (m_geopath.path().length() == length)
return;
- regenerateCache();
- markSourceDirtyAndUpdate();
+ m_d->onGeoGeometryChanged();
emit pathChanged();
}
@@ -986,14 +1178,12 @@ void QDeclarativePolylineMapItem::removeCoordinate(const QGeoCoordinate &coordin
*/
void QDeclarativePolylineMapItem::removeCoordinate(int index)
{
- if (index < 0 || index >= geopath_.path().length())
+ if (index < 0 || index >= m_geopath.path().length())
return;
- geopath_.removeCoordinate(index);
+ m_geopath.removeCoordinate(index);
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_d->onGeoGeometryChanged();
emit pathChanged();
}
@@ -1013,7 +1203,47 @@ void QDeclarativePolylineMapItem::removeCoordinate(int index)
QDeclarativeMapLineProperties *QDeclarativePolylineMapItem::line()
{
- return &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;
+ QScopedPointer<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();
}
/*!
@@ -1021,7 +1251,7 @@ QDeclarativeMapLineProperties *QDeclarativePolylineMapItem::line()
*/
void QDeclarativePolylineMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
- if (!map() || !geopath_.isValid() || updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) {
+ if (newGeometry.topLeft() == oldGeometry.topLeft() || !map() || !m_geopath.isValid() || m_updatingGeometry) {
QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
return;
}
@@ -1035,10 +1265,8 @@ void QDeclarativePolylineMapItem::geometryChanged(const QRectF &newGeometry, con
if (offsetLati == 0.0 && offsetLongi == 0.0)
return;
- geopath_.translate(offsetLati, offsetLongi);
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
+ m_geopath.translate(offsetLati, offsetLongi);
+ m_d->onGeoGeometryChanged();
emit pathChanged();
// Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
@@ -1050,68 +1278,78 @@ void QDeclarativePolylineMapItem::geometryChanged(const QRectF &newGeometry, con
*/
void QDeclarativePolylineMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
{
- if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
+ if (event.mapSize.isEmpty())
return;
- geometry_.setPreserveGeometry(true, geometry_.geoLeftBound());
- markSourceDirtyAndUpdate();
+ m_d->afterViewportChanged();
}
/*!
\internal
*/
-void QDeclarativePolylineMapItem::regenerateCache()
+void QDeclarativePolylineMapItem::updatePolish()
{
if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
return;
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
- geopathProjected_.clear();
- geopathProjected_.reserve(geopath_.path().size());
- for (const QGeoCoordinate &c : geopath_.path())
- geopathProjected_ << p.geoToMapProjection(c);
+ m_d->updatePolish();
}
-/*!
- \internal
-*/
-void QDeclarativePolylineMapItem::updateCache()
+void QDeclarativePolylineMapItem::updateLineStyleParameter(QGeoMapParameter *p,
+ const char *propertyName,
+ bool update)
{
- if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
- return;
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
- geopathProjected_ << p.geoToMapProjection(geopath_.path().last());
+ 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;
+ }
+ }
}
-/*!
- \internal
-*/
-void QDeclarativePolylineMapItem::updatePolish()
+void QDeclarativePolylineMapItem::updateLineStyleParameter(QGeoMapParameter *p, const char *propertyName)
{
- if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
- return;
- if (geopath_.path().length() == 0) { // Possibly cleared
- geometry_.clear();
- setWidth(0);
- setHeight(0);
- return;
- }
-
- QScopedValueRollback<bool> rollback(updatingGeometry_);
- updatingGeometry_ = true;
-
- geometry_.updateSourcePoints(*map(), geopathProjected_, geopath_.boundingGeoRectangle().topLeft());
- geometry_.updateScreenPoints(*map(), line_.width());
-
- setWidth(geometry_.sourceBoundingBox().width() + 2 * line_.width());
- setHeight(geometry_.sourceBoundingBox().height() + 2 * line_.width());
+ updateLineStyleParameter(p, propertyName, true);
+}
- setPositionOnMap(geometry_.origin(), -1 * geometry_.sourceBoundingBox().topLeft() + QPointF(line_.width(), line_.width()));
+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()
{
- geometry_.markSourceDirty();
- polishAndUpdate();
+ m_d->markSourceDirtyAndUpdate();
}
/*!
@@ -1119,32 +1357,17 @@ void QDeclarativePolylineMapItem::markSourceDirtyAndUpdate()
*/
QSGNode *QDeclarativePolylineMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
{
- Q_UNUSED(data);
-
- MapPolylineNode *node = static_cast<MapPolylineNode *>(oldNode);
-
- if (!node) {
- node = new MapPolylineNode();
- }
-
- //TODO: update only material
- if (geometry_.isScreenDirty() || dirtyMaterial_ || !oldNode) {
- node->update(line_.color(), &geometry_);
- geometry_.setPreserveGeometry(false);
- geometry_.markClean();
- dirtyMaterial_ = false;
- }
- return node;
+ return m_d->updateMapItemPaintNode(oldNode, data);
}
bool QDeclarativePolylineMapItem::contains(const QPointF &point) const
{
- return geometry_.contains(point);
+ return m_d->contains(point);
}
const QGeoShape &QDeclarativePolylineMapItem::geoShape() const
{
- return geopath_;
+ return m_geopath;
}
void QDeclarativePolylineMapItem::setGeoShape(const QGeoShape &shape)
@@ -1254,4 +1477,608 @@ void MapPolylineNode::update(const QColor &fillColor,
}
}
+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 &center,
+ 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)
+{
+
+}
+
+void MapPolylineShaderLineStrip::updateState(const 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 &center = newMaterial->center();
+
+ QVector3D vecCenter, vecCenter_lowpart;
+ for (int i = 0; i < 3; i++)
+ QLocationUtils::split_double(center.get(i), &vecCenter[i], &vecCenter_lowpart[i]);
+
+ 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);
+ program()->setUniformValue(m_color_id, v);
+ }
+
+ if (state.isMatrixDirty())
+ {
+ program()->setUniformValue(m_matrix_id, state.projectionMatrix());
+ }
+
+ program()->setUniformValue(m_mapProjection_id, geoProjection);
+
+ program()->setUniformValue(m_center_id, vecCenter);
+ program()->setUniformValue(m_center_lowpart_id, vecCenter_lowpart);
+ program()->setUniformValue(m_wrapOffset_id, float(newMaterial->wrapOffset()));
+}
+
+const char * const *MapPolylineShaderLineStrip::attributeNames() const
+{
+ static char const *const attr[] = { "vertex", nullptr };
+ return attr;
+}
+
+QSGMaterialShader *MapPolylineMaterial::createShader() const
+{
+ 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 QVector<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 QVector<QDeclarativeGeoMapItemUtils::vec2> &vx = *m_screenVertices;
+ geom->allocate(vx.size());
+
+ QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D();
+ for (int i = 0; i < vx.size(); ++i)
+ pts[i].set(vx[i].x, vx[i].y);
+}
+
+void MapPolylineNodeOpenGLExtruded::update(const QColor &fillColor,
+ const float lineWidth,
+ const QGeoMapPolylineGeometryOpenGL *shape,
+ const QMatrix4x4 geoProjection,
+ const QDoubleVector3D center,
+ 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)
+{
+
+}
+
+void MapPolylineShaderExtruded::updateState(const 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 &center = newMaterial->center();
+
+ QVector3D vecCenter, vecCenter_lowpart;
+ for (int i = 0; i < 3; i++)
+ QLocationUtils::split_double(center.get(i), &vecCenter[i], &vecCenter_lowpart[i]);
+
+ 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);
+ program()->setUniformValue(m_color_id, v);
+ }
+
+ if (state.isMatrixDirty())
+ {
+ program()->setUniformValue(m_matrix_id, state.projectionMatrix());
+ }
+
+ // ToDo: dirty-flag all this
+ program()->setUniformValue(m_mapProjection_id, geoProjection);
+
+ program()->setUniformValue(m_center_id, vecCenter);
+ program()->setUniformValue(m_center_lowpart_id, vecCenter_lowpart);
+ program()->setUniformValue(m_miter_id, newMaterial->miter());
+ program()->setUniformValue(m_lineWidth_id, newMaterial->lineWidth());
+ program()->setUniformValue(m_wrapOffset_id, float(newMaterial->wrapOffset()));
+
+ const QRectF viewportRect = state.viewportRect();
+ const float aspect = float(viewportRect.width() / viewportRect.height());
+ program()->setUniformValue(m_aspect_id, aspect);
+}
+
+const char * const *MapPolylineShaderExtruded::attributeNames() const
+{
+ return MapPolylineNodeOpenGLExtruded::MapPolylineEntry::attributeNames();
+}
+
+QSGMaterialShader *MapPolylineMaterialExtruded::createShader() const
+{
+ 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;
+}
+
+const char *MapPolylineShaderExtruded::vertexShaderMiteredSegments() const
+{
+ return
+ "attribute highp vec4 vertex;\n"
+ "attribute highp vec4 previous;\n"
+ "attribute highp vec4 next;\n"
+ "attribute lowp float direction;\n"
+ "attribute lowp float triangletype;\n"
+ "attribute lowp float vertextype;\n" // -1.0 if it is the "left" end of the segment, 1.0 if it is the "right" end.
+ "\n"
+ "uniform highp mat4 qt_Matrix;\n"
+ "uniform highp mat4 mapProjection;\n"
+ "uniform highp vec3 center;\n"
+ "uniform highp vec3 center_lowpart;\n"
+ "uniform lowp float lineWidth;\n"
+ "uniform lowp float aspect;\n"
+ "uniform lowp int miter;\n" // currently unused
+ "uniform lowp vec4 color;\n"
+ "uniform lowp float wrapOffset;\n"
+ "\n"
+ "varying vec4 primitivecolor;\n"
+ "\n"
+ " \n"
+ "vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); }\n"
+ "void main() {\n" // ln 22
+ " primitivecolor = color;\n"
+ " vec2 aspectVec = vec2(aspect, 1.0);\n"
+ " mat4 projViewModel = qt_Matrix * mapProjection;\n"
+ " vec4 cur = wrapped(vertex) - vec4(center, 0.0);\n"
+ " cur = cur - vec4(center_lowpart, 0.0);\n"
+ " vec4 prev = wrapped(previous) - vec4(center, 0.0);\n"
+ " prev = prev - vec4(center_lowpart, 0.0);\n"
+ " vec4 nex = wrapped(next) - vec4(center, 0.0);\n"
+ " nex = nex - vec4(center_lowpart, 0.0);\n"
+ "\n"
+ " vec4 centerProjected = projViewModel * vec4(center, 1.0);\n"
+ " vec4 previousProjected = projViewModel * prev;\n"
+ " vec4 currentProjected = projViewModel * cur;\n"
+ " vec4 nextProjected = projViewModel * nex;\n"
+ "\n"
+ " //get 2D screen space with W divide and aspect correction\n"
+ " vec2 currentScreen = (currentProjected.xy / currentProjected.w) * aspectVec;\n"
+ " vec2 previousScreen = (previousProjected.xy / previousProjected.w) * aspectVec;\n"
+ " vec2 nextScreen = (nextProjected.xy / nextProjected.w) * aspectVec;\n"
+ " float len = (lineWidth);\n"
+ " float orientation = direction;\n"
+ " bool clipped = false;\n"
+ " bool otherEndBelowFrustum = false;\n"
+ " //starting point uses (next - current)\n"
+ " vec2 dir = vec2(0.0);\n"
+ " if (vertextype < 0.0) {\n"
+ " dir = normalize(nextScreen - currentScreen);\n"
+ " if (nextProjected.z < 0.0) dir = -dir;\n"
+ " } else { \n"
+ " dir = normalize(currentScreen - previousScreen);\n"
+ " if (previousProjected.z < 0.0) dir = -dir;\n"
+ " }\n"
+ // first, clip current, and make sure currentProjected.z is > 0
+ " if (currentProjected.z < 0.0) {\n"
+ " if ((nextProjected.z > 0.0 && vertextype < 0.0) || (vertextype > 0.0 && previousProjected.z > 0.0)) {\n"
+ " dir = -dir;\n"
+ " clipped = true;\n"
+ " if (vertextype < 0.0 && nextProjected.y / nextProjected.w < -1.0) otherEndBelowFrustum = true;\n"
+ " else if (vertextype > 0.0 && previousProjected.y / previousProjected.w < -1.0) otherEndBelowFrustum = true;\n"
+ " } else {\n"
+ " primitivecolor = vec4(0.0,0.0,0.0,0.0);\n"
+ " gl_Position = vec4(-10000000.0, -1000000000.0, -1000000000.0, 1);\n" // get the vertex out of the way if the segment is fully invisible
+ " return;\n"
+ " }\n"
+ " } else if (triangletype < 2.0) {\n" // vertex in the view, try to miter
+ " //get directions from (C - B) and (B - A)\n"
+ " vec2 dirA = normalize((currentScreen - previousScreen));\n"
+ " if (previousProjected.z < 0.0) dirA = -dirA;\n"
+ " vec2 dirB = normalize((nextScreen - currentScreen));\n"
+ " //now compute the miter join normal and length\n"
+ " if (nextProjected.z < 0.0) dirB = -dirB;\n"
+ " vec2 tangent = normalize(dirA + dirB);\n"
+ " vec2 perp = vec2(-dirA.y, dirA.x);\n"
+ " vec2 vmiter = vec2(-tangent.y, tangent.x);\n"
+ " len = lineWidth / dot(vmiter, perp);\n"
+ // 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;\n"
+ " if (len < lineWidth * lenTreshold && len > -lineWidth * lenTreshold \n"
+ " ) {\n"
+ " dir = tangent;\n"
+ " } else {\n"
+ " len = lineWidth;\n"
+ " }\n"
+ " }\n"
+ " vec4 offset;\n"
+ " if (!clipped) {\n"
+ " vec2 normal = normalize(vec2(-dir.y, dir.x));\n"
+ " normal *= len;\n" // fracZL apparently was needed before the (-2.0 / qt_Matrix[1][1]) factor was introduced
+ " normal /= aspectVec;\n" // straighten the normal up again
+ " float scaleFactor = currentProjected.w / centerProjected.w;\n"
+ " offset = vec4(normal * orientation * scaleFactor * (centerProjected.w / (-2.0 / qt_Matrix[1][1])), 0.0, 0.0);\n" // ToDo: figure out why (-2.0 / qt_Matrix[1][1]), that is empirically what works
+ " gl_Position = currentProjected + offset;\n"
+ " } else {\n"
+ " if (otherEndBelowFrustum) offset = vec4((dir * 1.0) / aspectVec, 0.0, 0.0);\n" // 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);\n" // 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;\n"
+ " }\n"
+ "}\n";
+}
+
+QVector<QDeclarativeGeoMapItemUtils::vec2> QGeoMapItemLODGeometry::getSimplified(
+ QVector<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();
+ QVector<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<QVector<QDeclarativeGeoMapItemUtils::vec2> > &input, // reference as it gets copied in the nested call
+ const QSharedPointer<QVector<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 QVector<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<QVector<QDeclarativeGeoMapItemUtils::vec2> > m_input, m_output;
+ QSharedPointer<unsigned int> m_working;
+};
+
+void QGeoMapItemLODGeometry::enqueueSimplificationTask(const QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2> > &input,
+ const QSharedPointer<QVector<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<QVector<QDeclarativeGeoMapItemUtils::vec2>>(
+ new QVector<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<QVector<QDeclarativeGeoMapItemUtils::vec2>>(
+ new QVector<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<QVector<QDeclarativeGeoMapItemUtils::vec2>>(
+ new QVector<QDeclarativeGeoMapItemUtils::vec2>);
+ *m_verticesLOD[1] = getSimplified( *m_verticesLOD[0],
+ leftBound,
+ zoomForLOD(0));
+ }
+ if (lod > 1) {
+ if (!m_verticesLOD[lod])
+ m_verticesLOD[lod] = QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2>>(
+ new QVector<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
index 3aa0f96b..9cd20ea5 100644
--- a/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h
@@ -59,8 +59,6 @@
QT_BEGIN_NAMESPACE
-class MapPolylineNode;
-
class Q_LOCATION_PRIVATE_EXPORT QDeclarativeMapLineProperties : public QObject
{
Q_OBJECT
@@ -86,53 +84,23 @@ private:
QColor color_;
};
-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:
- QVector<qreal> srcPoints_;
- QVector<QPainterPath::ElementType> srcPointTypes_;
-
-#ifdef QT_LOCATION_DEBUG
- QList<QDoubleVector2D> m_wrappedPath;
- QList<QList<QDoubleVector2D>> m_clippedPaths;
-#endif
-
- friend class QDeclarativeCircleMapItem;
- friend class QDeclarativePolygonMapItem;
- friend class QDeclarativeRectangleMapItem;
-};
-
+class QDeclarativePolylineMapItemPrivate;
class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItem : public QDeclarativeGeoMapItemBase
{
Q_OBJECT
+ Q_ENUMS(Backend)
Q_PROPERTY(QJSValue 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 = 0);
~QDeclarativePolylineMapItem();
@@ -159,70 +127,42 @@ public:
QDeclarativeMapLineProperties *line();
+ Backend backend() const;
+ void setBackend(Backend b);
+
Q_SIGNALS:
void pathChanged();
-
-protected:
- void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
- void setPathFromGeoList(const QList<QGeoCoordinate> &path);
- void updatePolish() override;
+ void backendChanged();
protected Q_SLOTS:
void markSourceDirtyAndUpdate();
void updateAfterLinePropertiesChanged();
virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) override;
-private:
- void regenerateCache();
- void updateCache();
+protected:
+ void geometryChanged(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 geopath_;
- QList<QDoubleVector2D> geopathProjected_;
- QDeclarativeMapLineProperties line_;
- QColor color_;
- bool dirtyMaterial_;
- QGeoMapPolylineGeometry geometry_;
- bool updatingGeometry_;
-};
+ QGeoPath m_geopath;
+ QDeclarativeMapLineProperties m_line;
-//////////////////////////////////////////////////////////////////////
-
-class Q_LOCATION_PRIVATE_EXPORT VisibleNode
-{
-public:
- VisibleNode();
- virtual ~VisibleNode();
+ Backend m_backend = Software;
+ bool m_dirtyMaterial;
+ bool m_updatingGeometry;
- bool subtreeBlocked() const;
- void setSubtreeBlocked(bool blocked);
- bool visible() const;
- void setVisible(bool visible);
+ QScopedPointer<QDeclarativePolylineMapItemPrivate> m_d;
- 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 MapPolylineNode : public MapItemGeometryNode
-{
-public:
- MapPolylineNode();
- ~MapPolylineNode() override;
-
- void update(const QColor &fillColor, const QGeoMapItemGeometry *shape);
-
-private:
- QSGFlatColorMaterial fill_material_;
- QSGGeometry geometry_;
+ friend class QDeclarativePolylineMapItemPrivate;
+ friend class QDeclarativePolylineMapItemPrivateCPU;
+ friend class QDeclarativePolylineMapItemPrivateOpenGLLineStrip;
+ friend class QDeclarativePolylineMapItemPrivateOpenGLExtruded;
};
QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h b/src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h
new file mode 100644
index 00000000..2a588222
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem_p_p.h
@@ -0,0 +1,890 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com>
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef 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 <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 <QSGGeometryNode>
+#include <QSGFlatColorMaterial>
+#include <QtPositioning/QGeoPath>
+#include <QtPositioning/QGeoPolygon>
+#include <QtPositioning/QGeoRectangle>
+#include <QtPositioning/QGeoCircle>
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QtCore/QScopedValueRollback>
+#include <QSharedPointer>
+#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:
+ QVector<qreal> srcPoints_;
+ QVector<QPainterPath::ElementType> srcPointTypes_;
+
+#ifdef QT_LOCATION_DEBUG
+ QList<QDoubleVector2D> m_wrappedPath;
+ QList<QList<QDoubleVector2D>> m_clippedPaths;
+#endif
+
+ friend class QDeclarativeCircleMapItem;
+ friend class QDeclarativePolygonMapItem;
+ friend class QDeclarativeRectangleMapItem;
+};
+
+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 | CustomCompileStep);
+ }
+
+ QSGMaterialShader *createShader() 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;
+ }
+
+ void setColor(const QColor &color)
+ {
+ QSGFlatColorMaterial::setColor(color);
+ setFlag(Blending, true); // ToDo: Needed only temporarily, can be removed after debugging
+ }
+
+ int wrapOffset() const
+ {
+ return m_wrapOffset;
+ }
+
+ void setWrapOffset(int wrapOffset)
+ {
+ m_wrapOffset = wrapOffset;
+ }
+
+ void setLineWidth(const 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<QVector<QDeclarativeGeoMapItemUtils::vec2>>, 7> m_verticesLOD; // fix it to 7,
+ // do not allow simplifications beyond ZL 20. This could actually be limited even further
+ mutable QVector<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<QVector<QDeclarativeGeoMapItemUtils::vec2>>(
+ new QVector<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 QVector<QDeclarativeGeoMapItemUtils::vec2> getSimplified (
+ QVector<QDeclarativeGeoMapItemUtils::vec2> &wrappedPath,
+ double leftBoundWrapped,
+ unsigned int zoom);
+
+ static void enqueueSimplificationTask(const QSharedPointer<QVector<QDeclarativeGeoMapItemUtils::vec2> > &input, // reference as it gets copied in the nested call
+ const QSharedPointer<QVector<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 (int i = 1; i < m_screenVertices->size(); ++i)
+ {
+ if (!a.isFinite()) {
+ a = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(m_screenVertices->at(i).toDoubleVector2D()));
+ continue;
+ }
+
+ b = p.wrappedMapProjectionToItemPosition(p.wrapMapProjection(m_screenVertices->at(i).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;
+ QVector<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();
+
+ const char *vertexShader() const override {
+ return
+ "attribute highp vec4 vertex; \n"
+ "uniform highp mat4 qt_Matrix; \n"
+ "uniform highp mat4 mapProjection; \n"
+ "uniform highp vec3 center; \n"
+ "uniform highp vec3 center_lowpart; \n"
+ "uniform lowp float wrapOffset; \n"
+ "vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); }\n"
+ "void main() { \n"
+ " vec4 vtx = wrapped(vertex) - vec4(center, 0.0); \n"
+ " vtx = vtx - vec4(center_lowpart, 0.0); \n"
+ " gl_Position = qt_Matrix * mapProjection * vtx; \n"
+ "}";
+ }
+
+ const char *fragmentShader() const {
+ return
+ "uniform lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color; \n"
+ "}";
+ }
+
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
+
+protected:
+ void initialize() override
+ {
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+ m_color_id = program()->uniformLocation("color");
+ m_mapProjection_id = program()->uniformLocation("mapProjection");
+ m_center_id = program()->uniformLocation("center");
+ m_center_lowpart_id = program()->uniformLocation("center_lowpart");
+ m_wrapOffset_id = program()->uniformLocation("wrapOffset");
+ }
+ int m_center_id;
+ int m_center_lowpart_id;
+ int m_mapProjection_id;
+ int m_matrix_id;
+ int m_color_id;
+ int m_wrapOffset_id;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT MapPolylineShaderExtruded : public QSGMaterialShader
+{
+public:
+ MapPolylineShaderExtruded();
+
+ // 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.
+ const char *vertexShaderMiteredSegments() const;
+
+ const char *vertexShader() const override
+ {
+ return vertexShaderMiteredSegments();
+ }
+
+ const char *fragmentShader() const override
+ {
+ return
+ "varying vec4 primitivecolor; \n"
+ "void main() { \n"
+ " gl_FragColor = primitivecolor; \n"
+ "}";
+ }
+
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
+
+protected:
+ void initialize() override
+ {
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+ m_color_id = program()->uniformLocation("color");
+ m_mapProjection_id = program()->uniformLocation("mapProjection");
+ m_center_id = program()->uniformLocation("center");
+ m_center_lowpart_id = program()->uniformLocation("center_lowpart");
+ m_lineWidth_id = program()->uniformLocation("lineWidth");
+ m_aspect_id = program()->uniformLocation("aspect");
+ m_miter_id = program()->uniformLocation("miter");
+ m_wrapOffset_id = program()->uniformLocation("wrapOffset");
+ }
+ int m_center_id;
+ int m_center_lowpart_id;
+ int m_mapProjection_id;
+ int m_matrix_id;
+ int m_color_id;
+ int m_lineWidth_id;
+ int m_aspect_id;
+ int m_miter_id;
+ int m_wrapOffset_id;
+};
+
+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 &center,
+ 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() const override;
+
+ void setMiter(const 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 {
+ QDeclarativeGeoMapItemUtils::vec2 pos;
+ QDeclarativeGeoMapItemUtils::vec2 prev;
+ QDeclarativeGeoMapItemUtils::vec2 next;
+ float direction;
+ float triangletype; // es2 does not support int attribs
+ float vertextype;
+
+ static const char * const *attributeNames()
+ {
+ static char const *const attr[] = { "vertex", "previous", "next", "direction", "triangletype", "vertextype", nullptr };
+ return attr;
+ }
+ 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,
+ const float lineWidth,
+ const QGeoMapPolylineGeometryOpenGL *shape,
+ const QMatrix4x4 geoProjection,
+ const QDoubleVector3D center,
+ 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
index fd4109a7..74d2cc13 100644
--- a/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp
@@ -35,6 +35,7 @@
****************************************************************************/
#include "qdeclarativerectanglemapitem_p.h"
+#include "qdeclarativerectanglemapitem_p_p.h"
#include "qdeclarativepolygonmapitem_p.h"
#include "qlocationutils_p.h"
#include <QPainterPath>
@@ -125,16 +126,30 @@ QT_BEGIN_NAMESPACE
\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), border_(this), color_(Qt::transparent), dirtyMaterial_(true),
- updatingGeometry_(false)
+: QDeclarativeGeoMapItemBase(parent), m_border(this), m_color(Qt::transparent), m_dirtyMaterial(true),
+ m_updatingGeometry(false)
+ , m_d(new QDeclarativeRectangleMapItemPrivateCPU(*this))
{
+ // ToDo: handle envvar, and switch implementation.
m_itemType = QGeoMap::MapRectangle;
setFlag(ItemHasContents, true);
- QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
- this, SLOT(markSourceDirtyAndUpdate()));
- QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
- this, SLOT(markSourceDirtyAndUpdate()));
+ QObject::connect(&m_border, SIGNAL(colorChanged(QColor)),
+ this, SLOT(onLinePropertiesChanged()));
+ QObject::connect(&m_border, SIGNAL(widthChanged(qreal)),
+ this, SLOT(onLinePropertiesChanged()));
+ setBackend(mapRectangleBackendSelector->backend);
}
QDeclarativeRectangleMapItem::~QDeclarativeRectangleMapItem()
@@ -142,6 +157,43 @@ 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;
+ QScopedPointer<QDeclarativeRectangleMapItemPrivate> d((m_backend == Software)
+ ? static_cast<QDeclarativeRectangleMapItemPrivate *>(new QDeclarativeRectangleMapItemPrivateCPU(*this))
+ : static_cast<QDeclarativeRectangleMapItemPrivate * >(new QDeclarativeRectangleMapItemPrivateOpenGL(*this)));
+ m_d.swap(d);
+ m_d->onGeoGeometryChanged();
+ emit backendChanged();
+}
+
+/*!
\internal
*/
void QDeclarativeRectangleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
@@ -149,8 +201,7 @@ void QDeclarativeRectangleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap
QDeclarativeGeoMapItemBase::setMap(quickMap,map);
if (!map)
return;
- updatePath();
- markSourceDirtyAndUpdate();
+ m_d->onMapSet();
}
/*!
@@ -167,7 +218,7 @@ void QDeclarativeRectangleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap
*/
QDeclarativeMapLineProperties *QDeclarativeRectangleMapItem::border()
{
- return &border_;
+ return &m_border;
}
/*!
@@ -178,18 +229,17 @@ QDeclarativeMapLineProperties *QDeclarativeRectangleMapItem::border()
*/
void QDeclarativeRectangleMapItem::setTopLeft(const QGeoCoordinate &topLeft)
{
- if (rectangle_.topLeft() == topLeft)
+ if (m_rectangle.topLeft() == topLeft)
return;
- rectangle_.setTopLeft(topLeft);
- updatePath();
- markSourceDirtyAndUpdate();
+ m_rectangle.setTopLeft(topLeft);
+ m_d->onGeoGeometryChanged();
emit topLeftChanged(topLeft);
}
QGeoCoordinate QDeclarativeRectangleMapItem::topLeft()
{
- return rectangle_.topLeft();
+ return m_rectangle.topLeft();
}
/*!
@@ -197,9 +247,12 @@ QGeoCoordinate QDeclarativeRectangleMapItem::topLeft()
*/
void QDeclarativeRectangleMapItem::markSourceDirtyAndUpdate()
{
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- polishAndUpdate();
+ m_d->markSourceDirtyAndUpdate();
+}
+
+void QDeclarativeRectangleMapItem::onLinePropertiesChanged()
+{
+ m_d->onLinePropertiesChanged();
}
/*!
@@ -210,18 +263,17 @@ void QDeclarativeRectangleMapItem::markSourceDirtyAndUpdate()
*/
void QDeclarativeRectangleMapItem::setBottomRight(const QGeoCoordinate &bottomRight)
{
- if (rectangle_.bottomRight() == bottomRight)
+ if (m_rectangle.bottomRight() == bottomRight)
return;
- rectangle_.setBottomRight(bottomRight);
- updatePath();
- markSourceDirtyAndUpdate();
+ m_rectangle.setBottomRight(bottomRight);
+ m_d->onGeoGeometryChanged();
emit bottomRightChanged(bottomRight);
}
QGeoCoordinate QDeclarativeRectangleMapItem::bottomRight()
{
- return rectangle_.bottomRight();
+ return m_rectangle.bottomRight();
}
/*!
@@ -232,17 +284,17 @@ QGeoCoordinate QDeclarativeRectangleMapItem::bottomRight()
*/
QColor QDeclarativeRectangleMapItem::color() const
{
- return color_;
+ return m_color;
}
void QDeclarativeRectangleMapItem::setColor(const QColor &color)
{
- if (color_ == color)
+ if (m_color == color)
return;
- color_ = color;
- dirtyMaterial_ = true;
+ m_color = color;
+ m_dirtyMaterial = true;
polishAndUpdate();
- emit colorChanged(color_);
+ emit colorChanged(m_color);
}
/*!
@@ -260,24 +312,7 @@ void QDeclarativeRectangleMapItem::setColor(const QColor &color)
*/
QSGNode *QDeclarativeRectangleMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
{
- Q_UNUSED(data);
-
- MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
-
- if (!node) {
- node = new MapPolygonNode();
- }
-
- //TODO: update only material
- if (geometry_.isScreenDirty() || borderGeometry_.isScreenDirty() || dirtyMaterial_) {
- node->update(color_, border_.color(), &geometry_, &borderGeometry_);
- geometry_.setPreserveGeometry(false);
- borderGeometry_.setPreserveGeometry(false);
- geometry_.markClean();
- borderGeometry_.markClean();
- dirtyMaterial_ = false;
- }
- return node;
+ return m_d->updateMapItemPaintNode(oldNode, data);
}
/*!
@@ -287,55 +322,7 @@ void QDeclarativeRectangleMapItem::updatePolish()
{
if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
return;
- if (!topLeft().isValid() || !bottomRight().isValid()) {
- geometry_.clear();
- borderGeometry_.clear();
- setWidth(0);
- setHeight(0);
- return;
- }
-
- const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
-
- QScopedValueRollback<bool> rollback(updatingGeometry_);
- updatingGeometry_ = true;
-
- geometry_.setPreserveGeometry(true, rectangle_.topLeft());
- geometry_.updateSourcePoints(*map(), pathMercator_);
- geometry_.updateScreenPoints(*map(), border_.width());
-
- QList<QGeoMapItemGeometry *> geoms;
- geoms << &geometry_;
- borderGeometry_.clear();
-
- if (border_.color() != Qt::transparent && border_.width() > 0) {
- QList<QDoubleVector2D> closedPath = pathMercator_;
- closedPath << closedPath.first();
-
- borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
- const QGeoCoordinate &geometryOrigin = geometry_.origin();
-
- borderGeometry_.srcPoints_.clear();
- borderGeometry_.srcPointTypes_.clear();
-
- QDoubleVector2D borderLeftBoundWrapped;
- QList<QList<QDoubleVector2D > > clippedPaths = borderGeometry_.clipPath(*map(), closedPath, borderLeftBoundWrapped);
- if (clippedPaths.size()) {
- borderLeftBoundWrapped = p.geoToWrappedMapProjection(geometryOrigin);
- borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
- borderGeometry_.updateScreenPoints(*map(), border_.width());
-
- geoms << &borderGeometry_;
- } else {
- borderGeometry_.clear();
- }
- }
-
- QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
- setWidth(combined.width() + 2 * border_.width());
- setHeight(combined.height() + 2 * border_.width());
-
- setPositionOnMap(geometry_.origin(), geometry_.firstPointOffset());
+ m_d->updatePolish();
}
/*!
@@ -345,10 +332,7 @@ void QDeclarativeRectangleMapItem::afterViewportChanged(const QGeoMapViewportCha
{
if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
return;
-
- geometry_.setPreserveGeometry(true, rectangle_.topLeft());
- borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
- markSourceDirtyAndUpdate();
+ m_d->afterViewportChanged();
}
/*!
@@ -356,46 +340,29 @@ void QDeclarativeRectangleMapItem::afterViewportChanged(const QGeoMapViewportCha
*/
bool QDeclarativeRectangleMapItem::contains(const QPointF &point) const
{
- return (geometry_.contains(point) || borderGeometry_.contains(point));
+ return m_d->contains(point);
}
const QGeoShape &QDeclarativeRectangleMapItem::geoShape() const
{
- return rectangle_;
+ return m_rectangle;
}
void QDeclarativeRectangleMapItem::setGeoShape(const QGeoShape &shape)
{
- if (shape == rectangle_)
+ if (shape == m_rectangle)
return;
- const QGeoRectangle rectangle = rectangle_.boundingGeoRectangle();
- const bool tlHasChanged = rectangle.topLeft() != rectangle_.topLeft();
- const bool brHasChanged = rectangle.bottomRight() != rectangle_.bottomRight();
- rectangle_ = rectangle;
+ 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;
- updatePath();
- markSourceDirtyAndUpdate();
+ m_d->onGeoGeometryChanged();
if (tlHasChanged)
- emit topLeftChanged(rectangle_.topLeft());
+ emit topLeftChanged(m_rectangle.topLeft());
if (brHasChanged)
- emit bottomRightChanged(rectangle_.bottomRight());
-}
-
-/*!
- \internal
-*/
-void QDeclarativeRectangleMapItem::updatePath()
-{
- if (!map())
- return;
- pathMercator_.clear();
- pathMercator_ << QWebMercator::coordToMercator(rectangle_.topLeft());
- pathMercator_ << QWebMercator::coordToMercator(
- QGeoCoordinate(rectangle_.topLeft().latitude(), rectangle_.bottomRight().longitude()));
- pathMercator_ << QWebMercator::coordToMercator(rectangle_.bottomRight());
- pathMercator_ << QWebMercator::coordToMercator(
- QGeoCoordinate(rectangle_.bottomRight().latitude(), rectangle_.topLeft().longitude()));
+ emit bottomRightChanged(m_rectangle.bottomRight());
}
/*!
@@ -403,7 +370,7 @@ void QDeclarativeRectangleMapItem::updatePath()
*/
void QDeclarativeRectangleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
- if (!map() || !rectangle_.isValid() || updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) {
+ if (!map() || !m_rectangle.isValid() || m_updatingGeometry || newGeometry.topLeft() == oldGeometry.topLeft()) {
QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
return;
}
@@ -417,16 +384,19 @@ void QDeclarativeRectangleMapItem::geometryChanged(const QRectF &newGeometry, co
if (offsetLati == 0.0 && offsetLongi == 0.0)
return;
- rectangle_.translate(offsetLati, offsetLongi);
- updatePath();
- geometry_.setPreserveGeometry(true, rectangle_.topLeft());
- borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
- markSourceDirtyAndUpdate();
- emit topLeftChanged(rectangle_.topLeft());
- emit bottomRightChanged(rectangle_.bottomRight());
+ m_rectangle.translate(offsetLati, offsetLongi);
+ m_d->onItemGeometryChanged();
+ emit topLeftChanged(m_rectangle.topLeft());
+ emit bottomRightChanged(m_rectangle.bottomRight());
// Not calling QDeclarativeGeoMapItemBase::geometryChanged() 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
index 790b99d9..a9ce2f4c 100644
--- a/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h
@@ -52,7 +52,7 @@
#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
#include <QtLocation/private/qgeomapitemgeometry_p.h>
#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
-#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
+#include <QtLocation/private/qdeclarativepolygonmapitem_p_p.h>
#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QSGGeometryNode>
@@ -60,18 +60,26 @@
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:
- explicit QDeclarativeRectangleMapItem(QQuickItem *parent = 0);
- ~QDeclarativeRectangleMapItem();
+ enum Backend {
+ Software = 0,
+ OpenGL = 1
+ };
+
+ explicit QDeclarativeRectangleMapItem(QQuickItem *parent = nullptr);
+ ~QDeclarativeRectangleMapItem() override;
virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) override;
//from QuickItem
@@ -92,29 +100,38 @@ public:
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 updatePath();
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
void updatePolish() override;
protected Q_SLOTS:
void markSourceDirtyAndUpdate();
+ void onLinePropertiesChanged();
virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) override;
private:
- QGeoRectangle rectangle_;
- QDeclarativeMapLineProperties border_;
- QColor color_;
- bool dirtyMaterial_;
- QGeoMapPolygonGeometry geometry_;
- QGeoMapPolylineGeometry borderGeometry_;
- bool updatingGeometry_;
- QList<QDoubleVector2D> pathMercator_;
+ QGeoRectangle m_rectangle;
+ QDeclarativeMapLineProperties m_border;
+ QColor m_color;
+ bool m_dirtyMaterial;
+
+ bool m_updatingGeometry;
+ Backend m_backend = Software;
+
+ QScopedPointer<QDeclarativeRectangleMapItemPrivate> m_d;
+
+ friend class QDeclarativeRectangleMapItemPrivate;
+ friend class QDeclarativeRectangleMapItemPrivateCPU;
+ friend class QDeclarativeRectangleMapItemPrivateOpenGL;
};
//////////////////////////////////////////////////////////////////////
diff --git a/src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h b/src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h
new file mode 100644
index 00000000..65d2f618
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem_p_p.h
@@ -0,0 +1,417 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com>
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef 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();
+ }
+ virtual void markSourceDirtyAndUpdate() override
+ {
+ m_geometry.markSourceDirty();
+ m_borderGeometry.markSourceDirty();
+ m_rect.polishAndUpdate();
+ }
+ virtual void onMapSet() override
+ {
+ markSourceDirtyAndUpdate();
+ }
+ virtual void onGeoGeometryChanged() override
+ {
+ markSourceDirtyAndUpdate();
+ }
+ virtual void onItemGeometryChanged() override
+ {
+ m_geometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft());
+ m_borderGeometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft());
+ markSourceDirtyAndUpdate();
+ }
+ virtual void afterViewportChanged() override
+ {
+ m_geometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft());
+ m_borderGeometry.setPreserveGeometry(true, m_rect.m_rectangle.topLeft());
+ markSourceDirtyAndUpdate();
+ }
+ virtual 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());
+ }
+
+ virtual 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;
+ }
+ virtual 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();
+ }
+ virtual 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());
+ }
+ virtual void onMapSet() override
+ {
+ markSourceDirtyAndUpdate();
+ }
+ virtual void onGeoGeometryChanged() override
+ {
+ preserveGeometry();
+ markSourceDirtyAndUpdate();
+ }
+ virtual void onItemGeometryChanged() override
+ {
+ onGeoGeometryChanged();
+ }
+ virtual void afterViewportChanged() override
+ {
+ preserveGeometry();
+ markScreenDirtyAndUpdate();
+ }
+ virtual 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));
+ }
+
+ virtual 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;
+ }
+ virtual 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_p.h b/src/location/declarativemaps/qdeclarativeroutemapitem_p.h
index a0b171b0..f0759b66 100644
--- a/src/location/declarativemaps/qdeclarativeroutemapitem_p.h
+++ b/src/location/declarativemaps/qdeclarativeroutemapitem_p.h
@@ -55,6 +55,8 @@
#include <QPen>
#include <QBrush>
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeoroute_p.h>)
+
QT_BEGIN_NAMESPACE
class QDeclarativeGeoRoute;
diff --git a/src/location/declarativemaps/qgeomapitemgeometry.cpp b/src/location/declarativemaps/qgeomapitemgeometry.cpp
index 2883c2bb..28e9fa67 100644
--- a/src/location/declarativemaps/qgeomapitemgeometry.cpp
+++ b/src/location/declarativemaps/qgeomapitemgeometry.cpp
@@ -48,6 +48,11 @@ QGeoMapItemGeometry::QGeoMapItemGeometry()
{
}
+QGeoMapItemGeometry::~QGeoMapItemGeometry()
+{
+
+}
+
/*!
\internal
*/
diff --git a/src/location/declarativemaps/qgeomapitemgeometry_p.h b/src/location/declarativemaps/qgeomapitemgeometry_p.h
index ab81ff0b..aa5ea4ac 100644
--- a/src/location/declarativemaps/qgeomapitemgeometry_p.h
+++ b/src/location/declarativemaps/qgeomapitemgeometry_p.h
@@ -67,6 +67,7 @@ class Q_LOCATION_PRIVATE_EXPORT QGeoMapItemGeometry
{
public:
QGeoMapItemGeometry();
+ virtual ~QGeoMapItemGeometry();
inline bool isSourceDirty() const { return sourceDirty_; }
inline bool isScreenDirty() const { return screenDirty_; }
@@ -74,6 +75,7 @@ public:
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())
{
@@ -85,6 +87,7 @@ public:
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);
@@ -128,6 +131,8 @@ public:
static QRectF translateToCommonOrigin(const QList<QGeoMapItemGeometry *> &geoms);
+ mutable bool m_dataChanged = false;
+
private:
QGeoMapItemGeometry(const QGeoMapItemGeometry &other); // Or else it may crash on copy
QGeoMapItemGeometry &operator= (const QGeoMapItemGeometry & other); // Or else it may crash on copy
diff --git a/src/location/declarativemaps/qgeosimplify.cpp b/src/location/declarativemaps/qgeosimplify.cpp
new file mode 100644
index 00000000..9414a1cf
--- /dev/null
+++ b/src/location/declarativemaps/qgeosimplify.cpp
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** 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) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeosimplify_p.h"
+#include <QtPositioning/private/qlocationutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+double QGeoSimplify::getDist(const QGeoCoordinate &p1, const QGeoCoordinate &p2)
+{
+ return p1.distanceTo(p2);
+}
+
+QDoubleVector2D QGeoSimplify::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;
+}
+
+QGeoCoordinate QGeoSimplify::closestPoint(const QGeoCoordinate &pc, const QGeoCoordinate &ac, const QGeoCoordinate &bc, const double &leftBound)
+{
+ QDoubleVector2D p = QWebMercator::coordToMercator(pc);
+ if (p.x() < leftBound)
+ p.setX(p.x() + leftBound); // unwrap X
+
+ QDoubleVector2D a = QWebMercator::coordToMercator(ac);
+ if (a.x() < leftBound)
+ a.setX(a.x() + leftBound); // unwrap X
+
+ QDoubleVector2D b = QWebMercator::coordToMercator(bc);
+ if (b.x() < leftBound)
+ b.setX(b.x() + leftBound); // unwrap X
+
+ QDoubleVector2D intersection = closestPoint(p, a, b);
+ if (intersection.x() > 1.0)
+ intersection.setX(intersection.x() - leftBound); // wrap X
+
+ const QGeoCoordinate closest = QWebMercator::mercatorToCoord(intersection);
+ return closest;
+}
+
+double QGeoSimplify::getSegDist(const QGeoCoordinate &pc, const QGeoCoordinate &ac, const QGeoCoordinate &bc, const double &leftBound)
+{
+ const QGeoCoordinate closest = closestPoint(pc, ac, bc, leftBound);
+ const double distanceMeters = pc.distanceTo(closest);
+ return distanceMeters;
+}
+
+double QGeoSimplify::getSegDist(const QDoubleVector2D &p, const QDoubleVector2D &a, const QDoubleVector2D &b, const double &leftBound)
+{
+ QDoubleVector2D intersection = closestPoint(p, a, b);
+ return getDist(intersection, p, leftBound);
+}
+
+void QGeoSimplify::simplifyDPStep(const QList<QGeoCoordinate> &points, const double &leftBound, int first, int last, double offsetTolerance, QList<QGeoCoordinate> &simplified)
+{
+ double maxDistanceFound = offsetTolerance;
+ int index = 0;
+
+ for (int i = first + 1; i < last; i++) {
+ const double distance = getSegDist(points.at(i),
+ points.at(first),
+ points.at(last),
+ leftBound);
+
+ if (distance > maxDistanceFound) {
+ index = i;
+ maxDistanceFound = distance;
+ }
+ }
+
+ if (index > 0) {
+ if (index - first > 1)
+ simplifyDPStep(points,
+ leftBound,
+ first,
+ index,
+ offsetTolerance,
+ simplified);
+ simplified.append(points.at(index));
+ if (last - index > 1)
+ simplifyDPStep(points,
+ leftBound,
+ index,
+ last,
+ offsetTolerance,
+ simplified);
+ }
+}
+
+double QGeoSimplify::getDist(QDoubleVector2D a, QDoubleVector2D b, const 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));
+}
+
+void QGeoSimplify::simplifyDPStep(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ int first,
+ int last,
+ double offsetTolerance,
+ QList<QDoubleVector2D> &simplified)
+{
+ double maxDistanceFound = offsetTolerance;
+ int index = 0;
+
+ for (int i = first + 1; i < last; i++) {
+ const double distance = getSegDist(points.at(i),
+ points.at(first),
+ points.at(last),
+ leftBound);
+
+ if (distance > maxDistanceFound) {
+ index = i;
+ maxDistanceFound = distance;
+ }
+ }
+
+ if (index > 0) {
+ if (index - first > 1)
+ simplifyDPStep(points,
+ leftBound,
+ first,
+ index,
+ offsetTolerance,
+ simplified);
+ simplified.append(points.at(index));
+ if (last - index > 1)
+ simplifyDPStep(points,
+ leftBound,
+ index,
+ last,
+ offsetTolerance,
+ simplified);
+ }
+}
+
+static 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;
+}
+
+static QGeoCoordinate unwrappedToGeo(QDoubleVector2D p, double leftBound)
+{
+ if (p.x() > 1.0)
+ p.setX(p.x() - leftBound);
+ return QWebMercator::mercatorToCoord(p);
+}
+
+void QGeoSimplify::simplifyDPStepZL(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ int first,
+ int 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;
+ int index = 0;
+
+ for (int i = first + 1; i < last; i++) {
+ const double distance = getSegDist(points.at(i),
+ points.at(first),
+ points.at(last),
+ leftBound);
+
+ if (distance > maxDistanceFound) {
+ index = i;
+ maxDistanceFound = distance;
+ }
+ }
+
+ if (index > 0) {
+ if (index - first > 1)
+ simplifyDPStepZL(points,
+ leftBound,
+ first,
+ index,
+ zoomLevel,
+ simplified);
+ simplified.append(points.at(index));
+ if (last - index > 1)
+ simplifyDPStepZL(points,
+ leftBound,
+ index,
+ last,
+ zoomLevel,
+ simplified);
+ }
+}
+
+QList<QGeoCoordinate> QGeoSimplify::simplifyDouglasPeucker(const QList<QGeoCoordinate> &points,
+ const double &leftBound,
+ double offsetTolerance) {
+ const int last = points.size() - 1;
+ QList<QGeoCoordinate> simplified { points.first() };
+ simplifyDPStep(points, leftBound, 0, last, offsetTolerance, simplified);
+ simplified.append(points.at(last));
+ return simplified;
+}
+
+QList<QDoubleVector2D> QGeoSimplify::simplifyDouglasPeucker(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ double offsetTolerance) {
+ const int last = points.size() - 1;
+ QList<QDoubleVector2D> simplified { points.first() };
+ simplifyDPStep(points, leftBound, 0, last, offsetTolerance, simplified);
+ simplified.append(points.at(last));
+ return simplified;
+}
+
+QList<QDoubleVector2D> QGeoSimplify::simplifyDouglasPeuckerZL(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ int zoomLevel)
+{
+ const int last = points.size() - 1;
+ QList<QDoubleVector2D> simplified { points.first() };
+ simplifyDPStepZL(points, leftBound, 0, last, zoomLevel, simplified);
+ simplified.append(points.at(last));
+ return simplified;
+}
+
+QList<QGeoCoordinate> QGeoSimplify::geoSimplify(const QList<QGeoCoordinate> &points,
+ const double &leftBound,
+ double offsetTolerance) // also in meters
+{
+ if (points.size() <= 2)
+ return points;
+ return simplifyDouglasPeucker(points,
+ leftBound,
+ offsetTolerance);
+}
+
+QList<QDoubleVector2D> QGeoSimplify::geoSimplify(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ double offsetTolerance) // also in meters
+{
+ if (points.size() <= 2)
+ return points;
+ return simplifyDouglasPeucker(points,
+ leftBound,
+ offsetTolerance);
+}
+
+QList<QDoubleVector2D> QGeoSimplify::geoSimplifyZL(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ int zoomLevel)
+{
+ if (points.size() <= 2)
+ return points;
+ return simplifyDouglasPeuckerZL(points,
+ leftBound,
+ zoomLevel);
+}
+
+
+QT_END_NAMESPACE
+
diff --git a/src/location/declarativemaps/qgeosimplify_p.h b/src/location/declarativemaps/qgeosimplify_p.h
new file mode 100644
index 00000000..19445552
--- /dev/null
+++ b/src/location/declarativemaps/qgeosimplify_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef 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 <QtPositioning/QGeoCoordinate>
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoSimplify {
+protected:
+ // Distance between two points in metres
+ static double getDist(const QGeoCoordinate &p1, const QGeoCoordinate &p2);
+
+ // p, a and b are intended as "unwrapped" around the left bound
+ static QDoubleVector2D closestPoint( const QDoubleVector2D &p,
+ const QDoubleVector2D &a,
+ const QDoubleVector2D &b);
+
+ static QGeoCoordinate closestPoint( const QGeoCoordinate &pc,
+ const QGeoCoordinate &ac,
+ const QGeoCoordinate &bc,
+ const double &leftBound);
+
+ // Distance from a point to a segment (line between two points) in metres
+ static double getSegDist(const QGeoCoordinate &pc,
+ const QGeoCoordinate &ac,
+ const QGeoCoordinate &bc,
+ const double &leftBound);
+
+ // doublevectors Intended as wrapped
+ static double getSegDist(const QDoubleVector2D &p,
+ const QDoubleVector2D &a,
+ const QDoubleVector2D &b,
+ const double &leftBound);
+
+ static void simplifyDPStep(const QList<QGeoCoordinate> &points,
+ const double &leftBound,
+ int first,
+ int last,
+ double offsetTolerance,
+ QList<QGeoCoordinate> &simplified);
+
+ static double getDist(QDoubleVector2D a,
+ QDoubleVector2D b,
+ const double &leftBound);
+
+ static void simplifyDPStep(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ int first,
+ int last,
+ double offsetTolerance,
+ QList<QDoubleVector2D> &simplified);
+
+ static void simplifyDPStepZL(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ int first,
+ int last,
+ int zoomLevel,
+ QList<QDoubleVector2D> &simplified);
+
+ // simplification using Ramer-Douglas-Peucker algorithm
+ static QList<QGeoCoordinate> simplifyDouglasPeucker(const QList<QGeoCoordinate> &points,
+ const double &leftBound,
+ double offsetTolerance);
+
+ static QList<QDoubleVector2D> simplifyDouglasPeucker(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ double offsetTolerance);
+
+ static QList<QDoubleVector2D> simplifyDouglasPeuckerZL(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ int zoomLevel);
+
+public:
+ /*
+ offsetTolerance - how far outside the straight line a point
+ needs to be for it to be "kept"
+ */
+ static QList<QGeoCoordinate> geoSimplify(const QList<QGeoCoordinate> &points,
+ const double &leftBound,
+ double offsetTolerance); // in meters
+
+ static QList<QDoubleVector2D> geoSimplify(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ double offsetTolerance); // in meters
+
+ // This overload tries to be adaptive in the offsetTolerance across latitudes,
+ // and return a simplification adequate for the given zoomLevel.
+ static QList<QDoubleVector2D> geoSimplifyZL(const QList<QDoubleVector2D> &points,
+ const double &leftBound,
+ int zoomLevel); // in meters
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOSIMPLIFY_P_H
diff --git a/src/location/declarativeplaces/qdeclarativecategory_p.h b/src/location/declarativeplaces/qdeclarativecategory_p.h
index c32072f4..96983c1f 100644
--- a/src/location/declarativeplaces/qdeclarativecategory_p.h
+++ b/src/location/declarativeplaces/qdeclarativecategory_p.h
@@ -57,6 +57,8 @@
#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativeplaceicon_p.h>)
+
QT_BEGIN_NAMESPACE
class QDeclarativePlaceIcon;
diff --git a/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h b/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h
index 05b559ae..53e24f42 100644
--- a/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h
+++ b/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h
@@ -54,6 +54,8 @@
#include <QtLocation/QPlaceContent>
#include <QtLocation/QPlaceContentReply>
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativeplace_p.h>)
+
QT_BEGIN_NAMESPACE
class QDeclarativePlace;
diff --git a/src/location/labs/qdeclarativenavigator.cpp b/src/location/labs/qdeclarativenavigator.cpp
index 69f450f3..546d0b01 100644
--- a/src/location/labs/qdeclarativenavigator.cpp
+++ b/src/location/labs/qdeclarativenavigator.cpp
@@ -52,9 +52,9 @@ QT_BEGIN_NAMESPACE
To use this module, import the module with the following line:
- \code
+ \qml
import Qt.labs.location 1.0
- \endcode
+ \endqml
\note These types are experimental and subject to source-incompatible changes from one
Qt minor release to the next, until they are ready to be moved to the stable QtLocation QML
diff --git a/src/location/labs/qdeclarativenavigator_p.h b/src/location/labs/qdeclarativenavigator_p.h
index 24ff798f..30dd7f11 100644
--- a/src/location/labs/qdeclarativenavigator_p.h
+++ b/src/location/labs/qdeclarativenavigator_p.h
@@ -54,6 +54,13 @@
#include <QtLocation/private/qparameterizableobject_p.h>
#include <QtLocation/qgeoserviceprovider.h>
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativenavigator_p_p.h>)
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeomap_p.h>)
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeoroute_p.h>)
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeoserviceprovider_p.h>)
+Q_MOC_INCLUDE(<QtLocation/private/qnavigationmanagerengine_p.h>)
+Q_MOC_INCLUDE(<QtPositioningQuick/private/qdeclarativepositionsource_p.h>)
+
QT_BEGIN_NAMESPACE
class QDeclarativeGeoServiceProvider;
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/qmaprouteobject_p.h b/src/location/labs/qmaprouteobject_p.h
index dcc35807..05354544 100644
--- a/src/location/labs/qmaprouteobject_p.h
+++ b/src/location/labs/qmaprouteobject_p.h
@@ -54,6 +54,8 @@
#include <QtLocation/private/qgeomapobject_p.h>
#include <QtLocation/private/qparameterizableobject_p.h>
+Q_MOC_INCLUDE(<QtLocation/private/qdeclarativegeoroute_p.h>)
+
QT_BEGIN_NAMESPACE
class QDeclarativeGeoRoute;
diff --git a/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp b/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp
index 1a1b102b..0e1df8f6 100644
--- a/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp
+++ b/src/location/labs/qsg/qgeomapobjectqsgsupport.cpp
@@ -152,12 +152,20 @@ void QGeoMapObjectQSGSupport::removeMapObject(QGeoMapObject *obj)
}
}
+// called in the render thread
void QGeoMapObjectQSGSupport::updateMapObjects(QSGNode *root, QQuickWindow *window)
{
+ if (!root)
+ return;
+ if (!m_mapObjectsRootNode) {
+ m_mapObjectsRootNode = new QDeclarativePolygonMapItemPrivateOpenGL::RootNode();
+ root->appendChildNode(m_mapObjectsRootNode);
+ }
+
+ m_mapObjectsRootNode->removeAllChildNodes();
for (int i = 0; i < m_removedMapObjects.size(); ++i) {
MapObject mo = m_removedMapObjects[i];
if (mo.qsgNode) {
- root->removeChildNode(mo.qsgNode);
delete mo.qsgNode;
mo.qsgNode = nullptr;
// mo.sgObject is now invalid as it is destroyed right after appending
@@ -176,7 +184,7 @@ void QGeoMapObjectQSGSupport::updateMapObjects(QSGNode *root, QQuickWindow *wind
MapObject &mo = m_mapObjects[i];
QQSGMapObject *sgo = mo.sgObject;
QSGNode *oldNode = mo.qsgNode;
- mo.qsgNode = sgo->updateMapObjectNode(oldNode, &mo.visibleNode, root, window);
+ mo.qsgNode = sgo->updateMapObjectNode(oldNode, &mo.visibleNode, m_mapObjectsRootNode, window);
if (Q_UNLIKELY(!mo.qsgNode)) {
qWarning() << "updateMapObjectNode for "<<mo.object->type() << " returned NULL";
} else if (mo.visibleNode && (mo.visibleNode->visible() != mo.object->visible())) {
@@ -192,7 +200,7 @@ void QGeoMapObjectQSGSupport::updateMapObjects(QSGNode *root, QQuickWindow *wind
QQSGMapObject *sgo = mo.sgObject;
QSGNode *oldNode = mo.qsgNode;
sgo->updateGeometry(); // or subtree will be blocked
- mo.qsgNode = sgo->updateMapObjectNode(oldNode, &mo.visibleNode, root, window);
+ mo.qsgNode = sgo->updateMapObjectNode(oldNode, &mo.visibleNode, m_mapObjectsRootNode, window);
if (mo.qsgNode) {
if (mo.visibleNode && (mo.visibleNode->visible() != mo.object->visible())) {
mo.visibleNode->setVisible(mo.object->visible());
@@ -208,8 +216,10 @@ void QGeoMapObjectQSGSupport::updateMapObjects(QSGNode *root, QQuickWindow *wind
for (int i: qAsConst(toRemove))
m_pendingMapObjects.removeAt(i);
+ 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/qgeomapobjectqsgsupport_p.h b/src/location/labs/qsg/qgeomapobjectqsgsupport_p.h
index bb0477c5..1ec966fa 100644
--- a/src/location/labs/qsg/qgeomapobjectqsgsupport_p.h
+++ b/src/location/labs/qsg/qgeomapobjectqsgsupport_p.h
@@ -57,10 +57,10 @@
#include <QtLocation/private/qmaprouteobjectqsg_p_p.h>
#include <QtLocation/private/qmapiconobjectqsg_p_p.h>
#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QtLocation/private/qdeclarativepolygonmapitem_p_p.h>
#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
-
struct Q_LOCATION_PRIVATE_EXPORT MapObject {
MapObject(QPointer<QGeoMapObject> &o, QQSGMapObject *sgo)
: object(o), sgObject(sgo) {}
@@ -85,6 +85,7 @@ public:
QList<MapObject> m_pendingMapObjects;
QList<MapObject> m_removedMapObjects;
QGeoMap *m_map = nullptr;
+ QDeclarativePolygonMapItemPrivateOpenGL::RootNode *m_mapObjectsRootNode = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/location/labs/qsg/qmapcircleobjectqsg.cpp b/src/location/labs/qsg/qmapcircleobjectqsg.cpp
index 32f3030b..750b20f2 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;
- QDeclarativeCircleMapItem::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 = QDeclarativeCircleMapItem::preserveCircleGeometry(circlePath, center(), radius(), p);
+ 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 (QDeclarativeCircleMapItem::crossEarthPole(center(), radius()) && circlePath.size() == pathCount) {
- m_geometry.updateScreenPointsInvert(circlePath, *m_map); // invert fill area for really huge circles
+ if (QDeclarativeCircleMapItemPrivateCPU::crossEarthPole(center(), radius()) && circlePath.size() == pathCount) {
+ 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,41 +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);
+}
- bool created = false;
- if (!node) {
- node = new MapPolygonNode();
- *visibleNode = static_cast<VisibleNode *>(node);
- created = true;
+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 || created) {
+ 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 (created)
- root->appendChildNode(node);
-
- return node;
+ if (m_dataCPU->m_geometry.size() || m_dataCPU->m_borderGeometry.size()) {
+ root->appendChildNode(m_dataCPU->m_node);
+ } else {
+ delete m_dataCPU->m_node;
+ m_dataCPU->m_node = nullptr;
+ visibleNode = nullptr;
+ return nullptr;
+ }
+ 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); // No LOD for circles ATM
+ 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();
@@ -189,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();
@@ -197,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();
}
@@ -205,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();
}
@@ -213,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 4e8162fa..dc057c0b 100644
--- a/src/location/labs/qsg/qmapcircleobjectqsg_p_p.h
+++ b/src/location/labs/qsg/qmapcircleobjectqsg_p_p.h
@@ -50,7 +50,7 @@
#include <QtLocation/private/qlocationglobal_p.h>
#include <QtLocation/private/qgeomapobject_p_p.h>
-#include <QtLocation/private/qdeclarativecirclemapitem_p.h>
+#include <QtLocation/private/qdeclarativecirclemapitem_p_p.h>
#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
#include <QtLocation/private/qmapcircleobject_p.h>
#include <QtLocation/private/qmapcircleobject_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/qmapiconobjectqsg.cpp b/src/location/labs/qsg/qmapiconobjectqsg.cpp
index d9a80c91..10948d82 100644
--- a/src/location/labs/qsg/qmapiconobjectqsg.cpp
+++ b/src/location/labs/qsg/qmapiconobjectqsg.cpp
@@ -102,7 +102,6 @@ QSGNode *QMapIconObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
QQuickWindow *window)
{
Q_UNUSED(visibleNode);
- bool created = false;
RootNode *node = static_cast<RootNode *>(oldNode);
if (!node) {
node = new RootNode();
@@ -110,7 +109,6 @@ QSGNode *QMapIconObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
m_imageNode->setOwnsTexture(true);
node->appendChildNode(m_imageNode);
*visibleNode = static_cast<VisibleNode *>(node);
- created = true;
}
if (m_imageDirty) {
@@ -131,8 +129,7 @@ QSGNode *QMapIconObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
}
}
- if (created)
- root->appendChildNode(node);
+ root->appendChildNode(node);
return node;
}
diff --git a/src/location/labs/qsg/qmappolygonobjectqsg.cpp b/src/location/labs/qsg/qmappolygonobjectqsg.cpp
index 9963cac9..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,65 +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);
-
- bool created = false;
- if (!node) {
- if (!m_geometry.size() && !m_borderGeometry.size())
- return nullptr;
- node = new MapPolygonNode();
- *visibleNode = static_cast<VisibleNode *>(node);
- created = true;
- }
-
- //TODO: update only material
- if (m_geometry.isScreenDirty() || !m_borderGeometry.isScreenDirty() || !oldNode || created) {
- node->update(fillColor(), borderColor(), &m_geometry, &m_borderGeometry);
- m_geometry.setPreserveGeometry(false);
- m_borderGeometry.setPreserveGeometry(false);
- m_geometry.markClean();
- m_borderGeometry.markClean();
- }
-
- if (created)
- root->appendChildNode(node);
-
- 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();
@@ -130,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();
@@ -139,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();
@@ -156,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 0f42a92e..9dcece74 100644
--- a/src/location/labs/qsg/qmappolygonobjectqsg_p_p.h
+++ b/src/location/labs/qsg/qmappolygonobjectqsg_p_p.h
@@ -52,7 +52,7 @@
#include <QtLocation/private/qmappolygonobject_p.h>
#include <QtLocation/private/qmappolygonobject_p_p.h>
#include <QtLocation/private/qqsgmapobject_p.h>
-#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
+#include <QtLocation/private/qdeclarativepolygonmapitem_p_p.h>
#include <QtCore/qscopedvaluerollback.h>
QT_BEGIN_NAMESPACE
@@ -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 2bf5b287..8efbfc2f 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,43 @@ 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;
+
+ if (m_path.path().length() == 0) { // Possibly cleared
+ m_borderGeometry.clear();
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);
+ 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;
+}
- QPointF origin = m_map->geoProjection().coordinateToItemPosition(m_geometry.origin(), false).toPointF();
- m_geometry.translate(origin - m_geometry.firstPointOffset());
+/*!
+ \internal
+*/
+unsigned int QMapPolylineObjectPrivateQSG::zoomForLOD(int zoom) const
+{
+ // LOD Threshold currently fixed to 12 for MapPolylineObject(QSG).
+ // ToDo: Consider allowing to change this via DynamicParameter.
+ if (zoom >= 12)
+ return 30;
+ return uint(zoom);
}
QSGNode *QMapPolylineObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
@@ -104,40 +119,53 @@ QSGNode *QMapPolylineObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
QSGNode *root,
QQuickWindow * /*window*/)
{
- Q_UNUSED(visibleNode);
- MapPolylineNode *node = static_cast<MapPolylineNode *>(oldNode);
-
- bool created = false;
- if (!node) {
- if (!m_geometry.size()) // condition to block the subtree
- return nullptr;
- node = new MapPolylineNode();
- *visibleNode = static_cast<VisibleNode *>(node);
- created = true;
+ 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 || created) {
- 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,
+ zoomForLOD(int(m_map->cameraData().zoomLevel())));
+ m_borderGeometry.setPreserveGeometry(false);
+ m_borderGeometry.markClean();
}
- if (created)
- root->appendChildNode(node);
-
- return node;
+ if (!m_polylinenode->isSubtreeBlocked() ) {
+ m_polylinenode->setSubtreeBlocked(false);
+ root->appendChildNode(m_polylinenode);
+ return m_polylinenode;
+ } else {
+ delete m_polylinenode;
+ m_polylinenode = nullptr;
+ *visibleNode = nullptr;
+ return nullptr;
+ }
}
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();
@@ -146,7 +174,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();
@@ -155,7 +182,6 @@ void QMapPolylineObjectPrivateQSG::setColor(const QColor &color)
void QMapPolylineObjectPrivateQSG::setWidth(qreal width)
{
QMapPolylineObjectPrivateDefault::setWidth(width);
- updateGeometry();
if (m_map)
emit m_map->sgNodeChanged();
@@ -168,7 +194,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..8bba2703 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,
@@ -84,10 +85,12 @@ public:
QGeoMapObjectPrivate *clone() override;
virtual QGeoShape geoShape() const override;
+ unsigned int zoomForLOD(int zoom) const;
+
// 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/src/location/labs/qsg/qqsgmapobject_p.h b/src/location/labs/qsg/qqsgmapobject_p.h
index 52036805..0a717e62 100644
--- a/src/location/labs/qsg/qqsgmapobject_p.h
+++ b/src/location/labs/qsg/qqsgmapobject_p.h
@@ -51,7 +51,7 @@
#include <QtLocation/private/qlocationglobal_p.h>
#include <QtQuick/QSGOpacityNode>
#include <QtLocation/private/qgeomapobject_p.h>
-#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/location/maps/qgeomap.cpp b/src/location/maps/qgeomap.cpp
index dc8aa2c8..51af9199 100644
--- a/src/location/maps/qgeomap.cpp
+++ b/src/location/maps/qgeomap.cpp
@@ -41,6 +41,7 @@
#include "qdeclarativegeomapitembase_p.h"
#include "qgeomapobject_p.h"
#include "qgeomapobject_p_p.h"
+#include <QtQuick/private/qquickitem_p.h>
#include <QDebug>
#include <QRectF>
@@ -310,6 +311,12 @@ QList<QObject *> QGeoMap::mapObjectsAt(const QGeoCoordinate &/*coordinate*/) con
return QList<QObject *>();
}
+void QGeoMap::setItemToWindowTransform(const QTransform &itemToWindowTransform)
+{
+ Q_D(QGeoMap);
+ d->m_geoProjection->setItemToWindowTransform(itemToWindowTransform);
+}
+
void QGeoMap::setVisibleArea(const QRectF &visibleArea)
{
Q_D(QGeoMap);
diff --git a/src/location/maps/qgeomap_p.h b/src/location/maps/qgeomap_p.h
index 216c8b64..e955b513 100644
--- a/src/location/maps/qgeomap_p.h
+++ b/src/location/maps/qgeomap_p.h
@@ -55,6 +55,7 @@
#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QtLocation/private/qgeoprojection_p.h>
#include <QtLocation/qgeoroute.h>
+#include <QTransform>
QT_BEGIN_NAMESPACE
@@ -67,6 +68,7 @@ class QQuickWindow;
class QGeoMapParameter;
class QDeclarativeGeoMapItemBase;
class QGeoMapObject;
+class QDeclarativeGeoMap;
class Q_LOCATION_PRIVATE_EXPORT QGeoMap : public QObject
{
@@ -155,6 +157,7 @@ public:
virtual void setCopyrightVisible(bool visible);
virtual void removeMapObject(QGeoMapObject *obj);
virtual QList<QObject *> mapObjectsAt(const QGeoCoordinate &coordinate) const;
+ virtual void setItemToWindowTransform(const QTransform &itemToWindowTransform);
void setVisibleArea(const QRectF &visibleArea);
QRectF visibleArea() const;
diff --git a/src/location/maps/qgeoprojection.cpp b/src/location/maps/qgeoprojection.cpp
index f64060e2..ff6a0b77 100644
--- a/src/location/maps/qgeoprojection.cpp
+++ b/src/location/maps/qgeoprojection.cpp
@@ -118,6 +118,19 @@ bool QGeoProjection::setBearing(qreal bearing, const QGeoCoordinate &coordinate)
return false;
}
+void QGeoProjection::setItemToWindowTransform(const QTransform &itemToWindowTransform)
+{
+ if (m_itemToWindowTransform == itemToWindowTransform)
+ return;
+ m_qsgTransformDirty = true;
+ m_itemToWindowTransform = itemToWindowTransform;
+}
+
+QTransform QGeoProjection::itemToWindowTransform() const
+{
+ return m_itemToWindowTransform;
+}
+
/*
* QGeoProjectionWebMercator implementation
@@ -188,6 +201,31 @@ double QGeoProjectionWebMercator::minimumZoom() const
return m_minimumZoom;
}
+QMatrix4x4 QGeoProjectionWebMercator::projectionTransformation() const
+{
+ return toMatrix4x4(m_transformation);
+}
+
+QMatrix4x4 QGeoProjectionWebMercator::projectionTransformation_centered() const
+{
+ return toMatrix4x4(m_transformation0);
+}
+
+const QMatrix4x4 &QGeoProjectionWebMercator::qsgTransform() const
+{
+ if (m_qsgTransformDirty) {
+ m_qsgTransformDirty = false;
+ m_qsgTransform = QMatrix4x4(m_itemToWindowTransform) * toMatrix4x4(m_transformation0);
+// qDebug() << "QGeoProjectionWebMercator::qsgTransform" << m_itemToWindowTransform << toMatrix4x4(m_transformation0);
+ }
+ return m_qsgTransform;
+}
+
+QDoubleVector3D QGeoProjectionWebMercator::centerMercator() const
+{
+ return geoToMapProjection(m_cameraData.center()).toVector3D();
+}
+
// This method recalculates the "no-trespassing" limits for the map center.
// This has to be used when:
// 1) the map is resized, because the meters per pixel remain the same, but
@@ -273,19 +311,23 @@ QGeoCoordinate QGeoProjectionWebMercator::mapProjectionToGeo(const QDoubleVector
return QWebMercator::mercatorToCoord(projection);
}
-//wraps around center
-QDoubleVector2D QGeoProjectionWebMercator::wrapMapProjection(const QDoubleVector2D &projection) const
+int QGeoProjectionWebMercator::projectionWrapFactor(const QDoubleVector2D &projection) const
{
- double x = projection.x();
+ const double &x = projection.x();
if (m_cameraCenterXMercator < 0.5) {
if (x - m_cameraCenterXMercator > 0.5 )
- x -= 1.0;
+ return -1;
} else if (m_cameraCenterXMercator > 0.5) {
if (x - m_cameraCenterXMercator < -0.5 )
- x += 1.0;
+ return 1;
}
+ return 0;
+}
- return QDoubleVector2D(x, projection.y());
+//wraps around center
+QDoubleVector2D QGeoProjectionWebMercator::wrapMapProjection(const QDoubleVector2D &projection) const
+{
+ return QDoubleVector2D(projection.x() + double(projectionWrapFactor(projection)), projection.y());
}
QDoubleVector2D QGeoProjectionWebMercator::unwrapMapProjection(const QDoubleVector2D &wrappedProjection) const
@@ -547,6 +589,7 @@ QGeoProjection::ProjectionType QGeoProjectionWebMercator::projectionType() const
void QGeoProjectionWebMercator::setupCamera()
{
+ m_qsgTransformDirty = true;
m_centerMercator = geoToMapProjection(m_cameraData.center());
m_cameraCenterXMercator = m_centerMercator.x();
m_cameraCenterYMercator = m_centerMercator.y();
@@ -571,6 +614,10 @@ void QGeoProjectionWebMercator::setupCamera()
// And in mercator space
m_eyeMercator = m_centerMercator;
m_eyeMercator.setZ(altitude_mercator / m_aperture);
+ m_eyeMercator0 = QDoubleVector3D(0,0,0);
+ m_eyeMercator0.setZ(altitude_mercator / m_aperture);
+ QDoubleVector3D eye0(0,0,0);
+ eye0.setZ(altitude * defaultTileSize / m_aperture);
m_view = m_eye - m_center;
QDoubleVector3D side = QDoubleVector3D::normal(m_view, QDoubleVector3D(0.0, 1.0, 0.0));
@@ -599,11 +646,13 @@ void QGeoProjectionWebMercator::setupCamera()
QDoubleMatrix4x4 mTilt;
mTilt.rotate(-m_cameraData.tilt(), m_side);
m_eye = mTilt * m_view + m_center;
+ eye0 = mTilt * m_view;
// In mercator space too
QDoubleMatrix4x4 mTiltMercator;
mTiltMercator.rotate(-m_cameraData.tilt(), m_sideMercator);
m_eyeMercator = mTiltMercator * m_viewMercator + m_centerMercator;
+ m_eyeMercator0 = mTiltMercator * m_viewMercator;
}
m_view = m_eye - m_center; // ToDo: this should be inverted (center - eye), and the rest should follow
@@ -634,8 +683,10 @@ void QGeoProjectionWebMercator::setupCamera()
double verticalHalfFOV = QLocationUtils::degrees(atan(m_aperture));
- QDoubleMatrix4x4 cameraMatrix;
- cameraMatrix.lookAt(m_eye, m_center, m_up);
+ m_cameraMatrix.setToIdentity();
+ m_cameraMatrix.lookAt(m_eye, m_center, m_up);
+ m_cameraMatrix0.setToIdentity();
+ m_cameraMatrix0.lookAt(eye0, QDoubleVector3D(0,0,0), m_up);
QDoubleMatrix4x4 projectionMatrix;
projectionMatrix.frustum(-m_halfWidth, m_halfWidth, -m_halfHeight, m_halfHeight, m_nearPlane, m_farPlane);
@@ -656,10 +707,13 @@ void QGeoProjectionWebMercator::setupCamera()
matScreenTransformation(0,3) = (0.5 + offsetPct.x()) * m_viewportWidth;
matScreenTransformation(1,3) = (0.5 + offsetPct.y()) * m_viewportHeight;
- m_transformation = matScreenTransformation * projectionMatrix * cameraMatrix;
+ m_transformation = matScreenTransformation * projectionMatrix * m_cameraMatrix;
m_quickItemTransformation = m_transformation;
m_transformation.scale(m_sideLengthPixels, m_sideLengthPixels, 1.0);
+ m_transformation0 = matScreenTransformation * projectionMatrix * m_cameraMatrix0;
+ m_transformation0.scale(m_sideLengthPixels, m_sideLengthPixels, 1.0);
+
m_centerNearPlane = m_eye - m_viewNormalized;
m_centerNearPlaneMercator = m_eyeMercator - m_viewNormalized * m_nearPlaneMercator;
diff --git a/src/location/maps/qgeoprojection_p.h b/src/location/maps/qgeoprojection_p.h
index 2e1af8c5..9a75246a 100644
--- a/src/location/maps/qgeoprojection_p.h
+++ b/src/location/maps/qgeoprojection_p.h
@@ -52,6 +52,8 @@
#include <QtLocation/private/qgeocameradata_p.h>
#include <QtPositioning/private/qdoublematrix4x4_p.h>
#include <QtPositioning/QGeoShape>
+#include <QMatrix4x4>
+#include <QTransform>
QT_BEGIN_NAMESPACE
@@ -107,6 +109,17 @@ public:
virtual QGeoShape visibleRegion() const;
virtual bool setBearing(qreal bearing, const QGeoCoordinate &coordinate);
+ virtual QMatrix4x4 projectionTransformation() const = 0; // This brings a mercator coord into the correct viewport coordinate.
+ virtual QMatrix4x4 projectionTransformation_centered() const = 0; // Same as projectionTransformation, but the center of the camera is around 0,0.
+ // Requires subsequent shifting of the geometry to fit such camera.
+ virtual const QMatrix4x4 &qsgTransform() const = 0;
+ virtual QDoubleVector3D centerMercator() const = 0;
+
+ void setItemToWindowTransform(const QTransform &itemToWindowTransform);
+ virtual QTransform itemToWindowTransform() const;
+
+ QTransform m_itemToWindowTransform;
+ mutable bool m_qsgTransformDirty = true;
};
class Q_LOCATION_PRIVATE_EXPORT QGeoProjectionWebMercator : public QGeoProjection
@@ -117,6 +130,11 @@ public:
// From QGeoProjection
double minimumZoom() const override;
+ QMatrix4x4 projectionTransformation() const override;
+ QMatrix4x4 projectionTransformation_centered() const override;
+ const QMatrix4x4 &qsgTransform() const override;
+ QDoubleVector3D centerMercator() const override;
+
double maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const override;
double minimumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const override;
@@ -144,6 +162,7 @@ public:
QDoubleVector2D geoToMapProjection(const QGeoCoordinate &coordinate) const;
QGeoCoordinate mapProjectionToGeo(const QDoubleVector2D &projection) const;
+ int projectionWrapFactor(const QDoubleVector2D &projection) const;
QDoubleVector2D wrapMapProjection(const QDoubleVector2D &projection) const;
QDoubleVector2D unwrapMapProjection(const QDoubleVector2D &wrappedProjection) const;
@@ -213,7 +232,10 @@ protected:
double m_1_viewportWidth;
double m_1_viewportHeight;
+ QDoubleMatrix4x4 m_cameraMatrix;
+ QDoubleMatrix4x4 m_cameraMatrix0;
QDoubleMatrix4x4 m_transformation;
+ QDoubleMatrix4x4 m_transformation0;
QDoubleMatrix4x4 m_quickItemTransformation;
QDoubleVector3D m_eye;
QDoubleVector3D m_up;
@@ -234,6 +256,7 @@ protected:
// For the clipping region
QDoubleVector3D m_centerMercator;
QDoubleVector3D m_eyeMercator;
+ QDoubleVector3D m_eyeMercator0;
QDoubleVector3D m_viewMercator;
QDoubleVector3D m_upMercator;
QDoubleVector3D m_sideMercator;
@@ -245,6 +268,8 @@ protected:
QList<QDoubleVector2D> m_visibleRegionExpanded;
QList<QDoubleVector2D> m_projectableRegion;
bool m_visibleRegionDirty;
+
+ mutable QMatrix4x4 m_qsgTransform;
QRectF m_visibleArea;
Q_DISABLE_COPY(QGeoProjectionWebMercator)
diff --git a/src/location/maps/qgeotiledmap.cpp b/src/location/maps/qgeotiledmap.cpp
index 74346fdb..e6c91042 100644
--- a/src/location/maps/qgeotiledmap.cpp
+++ b/src/location/maps/qgeotiledmap.cpp
@@ -329,7 +329,7 @@ void QGeoTiledMapPrivate::changeCameraData(const QGeoCameraData &cameraData)
m_mapScene->setCameraData(cam);
updateScene();
- q->sgNodeChanged();
+ q->sgNodeChanged(); // ToDo: explain why emitting twice
}
void QGeoTiledMapPrivate::updateScene()
@@ -371,7 +371,7 @@ void QGeoTiledMapPrivate::setVisibleArea(const QRectF &visibleArea)
if (m_copyrightVisible)
q->evaluateCopyrights(m_mapScene->visibleTiles());
updateScene();
- q->sgNodeChanged();
+ q->sgNodeChanged(); // ToDo: explain why emitting twice
}
QRectF QGeoTiledMapPrivate::visibleArea() const
diff --git a/src/plugins/geoservices/esri/geocodereply_esri.cpp b/src/plugins/geoservices/esri/geocodereply_esri.cpp
index 05f941d1..51d97882 100644
--- a/src/plugins/geoservices/esri/geocodereply_esri.cpp
+++ b/src/plugins/geoservices/esri/geocodereply_esri.cpp
@@ -58,7 +58,7 @@ GeoCodeReplyEsri::GeoCodeReplyEsri(QNetworkReply *reply, OperationType operation
return;
}
connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(this, &QGeoCodeReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -84,7 +84,7 @@ void GeoCodeReplyEsri::networkReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
diff --git a/src/plugins/geoservices/esri/georoutereply_esri.cpp b/src/plugins/geoservices/esri/georoutereply_esri.cpp
index 78e14a9b..8cadfb29 100644
--- a/src/plugins/geoservices/esri/georoutereply_esri.cpp
+++ b/src/plugins/geoservices/esri/georoutereply_esri.cpp
@@ -55,7 +55,7 @@ GeoRouteReplyEsri::GeoRouteReplyEsri(QNetworkReply *reply, const QGeoRouteReques
return;
}
connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(this, &QGeoRouteReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -70,7 +70,7 @@ void GeoRouteReplyEsri::networkReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
diff --git a/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp b/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp
index 2f4016a9..1f72b1ea 100644
--- a/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp
+++ b/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp
@@ -56,7 +56,7 @@ GeoTiledMapReplyEsri::GeoTiledMapReplyEsri(QNetworkReply *reply, const QGeoTileS
return;
}
connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(this, &QGeoTiledMapReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -71,7 +71,7 @@ void GeoTiledMapReplyEsri::networkReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QByteArray const& imageData = reply->readAll();
diff --git a/src/plugins/geoservices/esri/placemanagerengine_esri.cpp b/src/plugins/geoservices/esri/placemanagerengine_esri.cpp
index 8f973ff3..525ec785 100644
--- a/src/plugins/geoservices/esri/placemanagerengine_esri.cpp
+++ b/src/plugins/geoservices/esri/placemanagerengine_esri.cpp
@@ -261,7 +261,7 @@ void PlaceManagerEngineEsri::initializeGeocodeServer()
{
m_geocodeServerReply = m_networkManager->get(QNetworkRequest(kUrlGeocodeServer));
connect(m_geocodeServerReply, SIGNAL(finished()), this, SLOT(geocodeServerReplyFinished()));
- connect(m_geocodeServerReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(geocodeServerReplyError()));
+ connect(m_geocodeServerReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(geocodeServerReplyError()));
}
}
diff --git a/src/plugins/geoservices/esri/placesearchreply_esri.cpp b/src/plugins/geoservices/esri/placesearchreply_esri.cpp
index b674c136..72c080f5 100644
--- a/src/plugins/geoservices/esri/placesearchreply_esri.cpp
+++ b/src/plugins/geoservices/esri/placesearchreply_esri.cpp
@@ -87,7 +87,7 @@ PlaceSearchReplyEsri::PlaceSearchReplyEsri(const QPlaceSearchRequest &request, Q
setRequest(request);
connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkError(QNetworkReply::NetworkError)));
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(networkError(QNetworkReply::NetworkError)));
connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
@@ -109,7 +109,7 @@ void PlaceSearchReplyEsri::replyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
diff --git a/src/plugins/geoservices/geoservices.pro b/src/plugins/geoservices/geoservices.pro
index b81ad34a..c67b5f5b 100644
--- a/src/plugins/geoservices/geoservices.pro
+++ b/src/plugins/geoservices/geoservices.pro
@@ -8,7 +8,8 @@ qtConfig(geoservices_esri): SUBDIRS += esri
qtConfig(geoservices_itemsoverlay): SUBDIRS += itemsoverlay
qtConfig(geoservices_osm): SUBDIRS += osm
-qtConfig(geoservices_mapboxgl) {
+# for now turned off in Qt 6
+false:qtConfig(geoservices_mapboxgl) {
!exists(../../3rdparty/mapbox-gl-native/mapbox-gl-native.pro) {
warning("Submodule mapbox-gl-native does not exist. Run 'git submodule update --init' on qtlocation.")
} else {
diff --git a/src/plugins/geoservices/mapbox/qgeocodereplymapbox.cpp b/src/plugins/geoservices/mapbox/qgeocodereplymapbox.cpp
index 7e94e6e0..aabe82a4 100644
--- a/src/plugins/geoservices/mapbox/qgeocodereplymapbox.cpp
+++ b/src/plugins/geoservices/mapbox/qgeocodereplymapbox.cpp
@@ -60,8 +60,7 @@ QGeoCodeReplyMapbox::QGeoCodeReplyMapbox(QNetworkReply *reply, QObject *parent)
}
connect(reply, &QNetworkReply::finished, this, &QGeoCodeReplyMapbox::onNetworkReplyFinished);
- connect(reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
- this, &QGeoCodeReplyMapbox::onNetworkReplyError);
+ connect(reply, &QNetworkReply::errorOccurred, this, &QGeoCodeReplyMapbox::onNetworkReplyError);
connect(this, &QGeoCodeReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -76,7 +75,7 @@ void QGeoCodeReplyMapbox::onNetworkReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QList<QGeoLocation> locations;
diff --git a/src/plugins/geoservices/mapbox/qgeomapreplymapbox.cpp b/src/plugins/geoservices/mapbox/qgeomapreplymapbox.cpp
index c10aba19..4472fdc0 100644
--- a/src/plugins/geoservices/mapbox/qgeomapreplymapbox.cpp
+++ b/src/plugins/geoservices/mapbox/qgeomapreplymapbox.cpp
@@ -46,7 +46,7 @@ QGeoMapReplyMapbox::QGeoMapReplyMapbox(QNetworkReply *reply, const QGeoTileSpec
return;
}
connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(this, &QGeoTiledMapReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -61,7 +61,7 @@ void QGeoMapReplyMapbox::networkReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
setMapImageData(reply->readAll());
diff --git a/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp b/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp
index f10b0086..cc270181 100644
--- a/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp
+++ b/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp
@@ -101,7 +101,7 @@ QGeoRouteReplyMapbox::QGeoRouteReplyMapbox(QNetworkReply *reply, const QGeoRoute
return;
}
connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(this, &QGeoRouteReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -116,7 +116,7 @@ void QGeoRouteReplyMapbox::networkReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QGeoRoutingManagerEngineMapbox *engine = qobject_cast<QGeoRoutingManagerEngineMapbox *>(parent());
diff --git a/src/plugins/geoservices/mapbox/qplacesearchreplymapbox.cpp b/src/plugins/geoservices/mapbox/qplacesearchreplymapbox.cpp
index 7284b67a..6d37d803 100644
--- a/src/plugins/geoservices/mapbox/qplacesearchreplymapbox.cpp
+++ b/src/plugins/geoservices/mapbox/qplacesearchreplymapbox.cpp
@@ -142,8 +142,7 @@ QPlaceSearchReplyMapbox::QPlaceSearchReplyMapbox(const QPlaceSearchRequest &requ
setRequest(request);
connect(reply, &QNetworkReply::finished, this, &QPlaceSearchReplyMapbox::onReplyFinished);
- connect(reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
- this, &QPlaceSearchReplyMapbox::onNetworkError);
+ connect(reply, &QNetworkReply::errorOccurred, this, &QPlaceSearchReplyMapbox::onNetworkError);
connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -167,7 +166,7 @@ void QPlaceSearchReplyMapbox::onReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
const QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
diff --git a/src/plugins/geoservices/mapbox/qplacesearchsuggestionreplymapbox.cpp b/src/plugins/geoservices/mapbox/qplacesearchsuggestionreplymapbox.cpp
index 95296172..b8fc315f 100644
--- a/src/plugins/geoservices/mapbox/qplacesearchsuggestionreplymapbox.cpp
+++ b/src/plugins/geoservices/mapbox/qplacesearchsuggestionreplymapbox.cpp
@@ -61,8 +61,7 @@ QPlaceSearchSuggestionReplyMapbox::QPlaceSearchSuggestionReplyMapbox(QNetworkRep
}
connect(reply, &QNetworkReply::finished, this, &QPlaceSearchSuggestionReplyMapbox::onReplyFinished);
- connect(reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
- this, &QPlaceSearchSuggestionReplyMapbox::onNetworkError);
+ connect(reply, &QNetworkReply::errorOccurred, this, &QPlaceSearchSuggestionReplyMapbox::onNetworkError);
connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -86,7 +85,7 @@ void QPlaceSearchSuggestionReplyMapbox::onReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
diff --git a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
index cb8dc2be..6dc8ea70 100644
--- a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
+++ b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
@@ -43,6 +43,7 @@
#include <QtPositioning/QGeoPath>
#include <QtPositioning/QGeoPolygon>
#include <QtQml/QJSValue>
+#include <QtLocation/private/qdeclarativecirclemapitem_p_p.h>
namespace {
@@ -93,12 +94,12 @@ QMapbox::Feature featureFromMapCircle(QDeclarativeCircleMapItem *mapItem)
const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(mapItem->map()->geoProjection());
QList<QGeoCoordinate> path;
QGeoCoordinate leftBound;
- QDeclarativeCircleMapItem::calculatePeripheralPoints(path, mapItem->center(), mapItem->radius(), circleSamples, leftBound);
+ QDeclarativeCircleMapItemPrivateCPU::calculatePeripheralPoints(path, mapItem->center(), mapItem->radius(), circleSamples, leftBound);
QList<QDoubleVector2D> pathProjected;
for (const QGeoCoordinate &c : qAsConst(path))
pathProjected << p.geoToMapProjection(c);
- if (QDeclarativeCircleMapItem::crossEarthPole(mapItem->center(), mapItem->radius()))
- mapItem->preserveCircleGeometry(pathProjected, mapItem->center(), mapItem->radius(), p);
+ if (QDeclarativeCircleMapItemPrivateCPU::crossEarthPole(mapItem->center(), mapItem->radius()))
+ QDeclarativeCircleMapItemPrivateCPU::preserveCircleGeometry(pathProjected, mapItem->center(), mapItem->radius(), p);
path.clear();
for (const QDoubleVector2D &c : qAsConst(pathProjected))
path << p.mapProjectionToGeo(c);
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.cpp b/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.cpp
index 196b68d3..7569fbb8 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.cpp
+++ b/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.cpp
@@ -58,7 +58,7 @@ QPlaceContentReplyImpl::QPlaceContentReplyImpl(const QPlaceContentRequest &reque
setRequest(request);
connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(replyError(QNetworkReply::NetworkError)));
connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -81,7 +81,7 @@ void QPlaceContentReplyImpl::replyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.cpp b/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.cpp
index 677efddc..f89a033c 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.cpp
+++ b/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.cpp
@@ -95,7 +95,7 @@ QPlaceDetailsReplyImpl::QPlaceDetailsReplyImpl(QNetworkReply *reply,
return;
}
connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(replyError(QNetworkReply::NetworkError)));
connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -118,7 +118,7 @@ void QPlaceDetailsReplyImpl::replyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp b/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp
index 49574084..ce5c2ac6 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp
+++ b/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp
@@ -64,7 +64,7 @@ QPlaceSearchReplyHere::QPlaceSearchReplyHere(const QPlaceSearchRequest &request,
setRequest(request);
connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(replyError(QNetworkReply::NetworkError)));
connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -87,7 +87,7 @@ void QPlaceSearchReplyHere::replyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.cpp b/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.cpp
index 236af184..c654a4e1 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.cpp
+++ b/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.cpp
@@ -53,7 +53,7 @@ QPlaceSearchSuggestionReplyImpl::QPlaceSearchSuggestionReplyImpl(QNetworkReply *
return;
}
connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(replyError(QNetworkReply::NetworkError)));
connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -77,7 +77,7 @@ void QPlaceSearchSuggestionReplyImpl::replyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
diff --git a/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp b/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp
index 2b302a76..6e1d1270 100644
--- a/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp
@@ -62,7 +62,7 @@ QGeoCodeReplyNokia::QGeoCodeReplyNokia(QNetworkReply *reply, int limit, int offs
qRegisterMetaType<QList<QGeoLocation> >();
connect(reply, SIGNAL(finished()), this, SLOT(networkFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(networkError(QNetworkReply::NetworkError)));
connect(this, &QGeoCodeReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QGeoCodeReply::aborted, [this](){ m_parsing = false; });
@@ -83,7 +83,7 @@ void QGeoCodeReplyNokia::networkFinished()
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QGeoCodeJsonParser *parser = new QGeoCodeJsonParser; // QRunnable, autoDelete = true.
diff --git a/src/plugins/geoservices/nokia/qgeomapreply_nokia.cpp b/src/plugins/geoservices/nokia/qgeomapreply_nokia.cpp
index 1ae32004..20ee9b76 100644
--- a/src/plugins/geoservices/nokia/qgeomapreply_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeomapreply_nokia.cpp
@@ -54,7 +54,7 @@ QGeoMapReplyNokia::QGeoMapReplyNokia(QNetworkReply *reply, const QGeoTileSpec &s
SLOT(networkFinished()));
connect(reply,
- SIGNAL(error(QNetworkReply::NetworkError)),
+ SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this,
SLOT(networkError(QNetworkReply::NetworkError)));
connect(this, &QGeoTiledMapReply::aborted, reply, &QNetworkReply::abort);
@@ -70,7 +70,7 @@ void QGeoMapReplyNokia::networkFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
setMapImageData(reply->readAll());
diff --git a/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp b/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp
index 6aed85cc..ba64d8ae 100644
--- a/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp
@@ -60,7 +60,7 @@ QGeoRouteReplyNokia::QGeoRouteReplyNokia(const QGeoRouteRequest &request,
continue;
}
connect(reply, SIGNAL(finished()), this, SLOT(networkFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(networkError(QNetworkReply::NetworkError)));
connect(this, &QGeoRouteReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -80,8 +80,8 @@ void QGeoRouteReplyNokia::networkFinished()
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError
- && reply->networkError() != QNetworkReply::UnknownContentError) {
+ if (reply->error() != QNetworkReply::NoError
+ && reply->error() != QNetworkReply::UnknownContentError) {
return;
}
diff --git a/src/plugins/geoservices/nokia/qgeotilefetcher_nokia.cpp b/src/plugins/geoservices/nokia/qgeotilefetcher_nokia.cpp
index 2e16a5d8..d07a93ba 100644
--- a/src/plugins/geoservices/nokia/qgeotilefetcher_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeotilefetcher_nokia.cpp
@@ -247,7 +247,7 @@ QString QGeoTileFetcherNokia::applicationId() const
void QGeoTileFetcherNokia::copyrightsFetched()
{
- if (m_engineNokia && m_copyrightsReply->networkError() == QNetworkReply::NoError) {
+ if (m_engineNokia && m_copyrightsReply->error() == QNetworkReply::NoError) {
QMetaObject::invokeMethod(m_engineNokia.data(),
"loadCopyrightsDescriptorsFromJson",
Qt::QueuedConnection,
@@ -259,7 +259,7 @@ void QGeoTileFetcherNokia::copyrightsFetched()
void QGeoTileFetcherNokia::versionFetched()
{
- if (m_engineNokia && m_versionReply->networkError() == QNetworkReply::NoError) {
+ if (m_engineNokia && m_versionReply->error() == QNetworkReply::NoError) {
QMetaObject::invokeMethod(m_engineNokia.data(),
"parseNewVersionInfo",
Qt::QueuedConnection,
@@ -288,7 +288,7 @@ void QGeoTileFetcherNokia::fetchCopyrightsData()
QNetworkRequest netRequest((QUrl(copyrightUrl)));
m_copyrightsReply = m_networkManager->get(netRequest);
- if (m_copyrightsReply->networkError() != QNetworkReply::NoError) {
+ if (m_copyrightsReply->error() != QNetworkReply::NoError) {
qWarning() << __FUNCTION__ << m_copyrightsReply->errorString();
m_copyrightsReply->deleteLater();
return;
@@ -321,7 +321,7 @@ void QGeoTileFetcherNokia::fetchVersionData()
QNetworkRequest netRequest((QUrl(versionUrl)));
m_versionReply = m_networkManager->get(netRequest);
- if (m_versionReply->networkError() != QNetworkReply::NoError) {
+ if (m_versionReply->error() != QNetworkReply::NoError) {
qWarning() << __FUNCTION__ << m_versionReply->errorString();
m_versionReply->deleteLater();
return;
diff --git a/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp b/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp
index acf43a01..c5c05a2e 100644
--- a/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp
+++ b/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp
@@ -637,7 +637,7 @@ QPlaceReply *QPlaceManagerEngineNokiaV2::initializeCategories()
QStringLiteral("/places/v1/categories/places/") + *it);
QNetworkReply *networkReply = sendRequest(requestUrl);
connect(networkReply, SIGNAL(finished()), this, SLOT(categoryReplyFinished()));
- connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(networkReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(categoryReplyError()));
m_categoryRequests.insert(*it, networkReply);
@@ -777,7 +777,7 @@ void QPlaceManagerEngineNokiaV2::categoryReplyFinished()
QString categoryId;
- if (reply->networkError() == QNetworkReply::NoError) {
+ if (reply->error() == QNetworkReply::NoError) {
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
if (!document.isObject()) {
if (m_categoryReply) {
diff --git a/src/plugins/geoservices/osm/qgeocodereplyosm.cpp b/src/plugins/geoservices/osm/qgeocodereplyosm.cpp
index 145a26ca..e309c87f 100644
--- a/src/plugins/geoservices/osm/qgeocodereplyosm.cpp
+++ b/src/plugins/geoservices/osm/qgeocodereplyosm.cpp
@@ -58,7 +58,7 @@ QGeoCodeReplyOsm::QGeoCodeReplyOsm(QNetworkReply *reply, bool includeExtraData,
return;
}
connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(this, &QGeoCodeReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -129,7 +129,7 @@ void QGeoCodeReplyOsm::networkReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QList<QGeoLocation> locations;
diff --git a/src/plugins/geoservices/osm/qgeomapreplyosm.cpp b/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
index b83d9015..1d693455 100644
--- a/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
+++ b/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
@@ -52,7 +52,7 @@ QGeoMapReplyOsm::QGeoMapReplyOsm(QNetworkReply *reply,
return;
}
connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(this, &QGeoTiledMapReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -68,7 +68,7 @@ void QGeoMapReplyOsm::networkReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError) // Already handled in networkReplyError
+ if (reply->error() != QNetworkReply::NoError) // Already handled in networkReplyError
return;
QByteArray a = reply->readAll();
diff --git a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
index 45e6b2c3..255ccfe5 100644
--- a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
+++ b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
@@ -51,7 +51,7 @@ QGeoRouteReplyOsm::QGeoRouteReplyOsm(QNetworkReply *reply, const QGeoRouteReques
return;
}
connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(this, &QGeoRouteReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
@@ -66,7 +66,7 @@ void QGeoRouteReplyOsm::networkReplyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QGeoRoutingManagerEngineOsm *engine = qobject_cast<QGeoRoutingManagerEngineOsm *>(parent());
diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.cpp b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp
index 13b9f47e..dfe3d8e9 100644
--- a/src/plugins/geoservices/osm/qgeotileproviderosm.cpp
+++ b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp
@@ -339,7 +339,7 @@ void TileProvider::resolveProvider()
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork);
QNetworkReply *reply = m_nm->get(request);
connect(reply, SIGNAL(finished()), this, SLOT(onNetworkReplyFinished()) );
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onNetworkReplyError(QNetworkReply::NetworkError)));
+ connect(reply, SIGNAL(errorOccured(QNetworkReply::NetworkError)), this, SLOT(onNetworkReplyError(QNetworkReply::NetworkError)));
}
void TileProvider::handleError(QNetworkReply::NetworkError error)
@@ -383,8 +383,8 @@ void TileProvider::onNetworkReplyFinished()
QObject errorEmitter;
QMetaObject::Connection errorEmitterConnection = connect(&errorEmitter, &QObject::destroyed, [this](){ this->resolutionError(this); });
- if (reply->networkError() != QNetworkReply::NoError) {
- handleError(reply->networkError());
+ if (reply->error() != QNetworkReply::NoError) {
+ handleError(reply->error());
return;
}
m_status = Invalid;
diff --git a/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp b/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp
index 80964d35..d6344989 100644
--- a/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp
+++ b/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp
@@ -354,6 +354,6 @@ void QPlaceManagerEngineOsm::fetchNextCategoryLocale()
m_categoriesReply = m_networkManager->get(QNetworkRequest(requestUrl));
connect(m_categoriesReply, SIGNAL(finished()), this, SLOT(categoryReplyFinished()));
- connect(m_categoriesReply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(m_categoriesReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(categoryReplyError()));
}
diff --git a/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp b/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp
index ba6eb81c..593f476a 100644
--- a/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp
+++ b/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp
@@ -64,7 +64,8 @@ QPlaceSearchReplyOsm::QPlaceSearchReplyOsm(const QPlaceSearchRequest &request,
setRequest(request);
connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
- connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkError(QNetworkReply::NetworkError)));
+ connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
+ this, SLOT(networkError(QNetworkReply::NetworkError)));
connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
@@ -99,7 +100,7 @@ void QPlaceSearchReplyOsm::replyFinished()
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
- if (reply->networkError() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
diff --git a/src/plugins/position/serialnmea/qiopipe.cpp b/src/plugins/position/serialnmea/qiopipe.cpp
index ce908d4d..fab0b56b 100644
--- a/src/plugins/position/serialnmea/qiopipe.cpp
+++ b/src/plugins/position/serialnmea/qiopipe.cpp
@@ -50,7 +50,15 @@ QT_BEGIN_NAMESPACE
QIOPipePrivate::QIOPipePrivate(QIODevice *iodevice, bool proxying)
: m_proxying(proxying), source(iodevice)
{
- const QIOPipe *parentPipe = qobject_cast<QIOPipe *>(iodevice);
+}
+
+QIOPipePrivate::~QIOPipePrivate()
+{
+}
+
+void QIOPipePrivate::initialize()
+{
+ const QIOPipe *parentPipe = qobject_cast<QIOPipe *>(source);
if (parentPipe && parentPipe->d_func()->m_proxying) // with proxying parent,
return; // don't do anything
@@ -60,10 +68,6 @@ QIOPipePrivate::QIOPipePrivate(QIODevice *iodevice, bool proxying)
QObjectPrivate::connect(source, &QIODevice::readyRead, this, &QIOPipePrivate::_q_onReadyRead);
}
-QIOPipePrivate::~QIOPipePrivate()
-{
-}
-
bool QIOPipePrivate::readAvailableData() {
if (!source)
return false;
@@ -130,6 +134,7 @@ void QIOPipePrivate::removeChildPipe(QIOPipe *childPipe)
QIOPipe::QIOPipe(QIODevice *parent, Mode mode)
: QIODevice(*new QIOPipePrivate(parent, mode == ProxyPipe), parent)
{
+ this->d_func()->initialize();
if (!parent->isOpen() && !parent->open(QIODevice::ReadOnly)) {
qWarning() << "QIOPipe: Failed to open " << parent;
return;
diff --git a/src/plugins/position/serialnmea/qiopipe_p.h b/src/plugins/position/serialnmea/qiopipe_p.h
index 25758fcb..472ab102 100644
--- a/src/plugins/position/serialnmea/qiopipe_p.h
+++ b/src/plugins/position/serialnmea/qiopipe_p.h
@@ -95,6 +95,7 @@ public:
explicit QIOPipePrivate(QIODevice *iodevice, bool proxying);
~QIOPipePrivate() override;
+ void initialize();
bool readAvailableData();
void pumpData(const QByteArray &ba);
void pushData(const QByteArray &ba);
diff --git a/src/positioning/qgeopolygon.cpp b/src/positioning/qgeopolygon.cpp
index 301759df..7d8a0ce0 100644
--- a/src/positioning/qgeopolygon.cpp
+++ b/src/positioning/qgeopolygon.cpp
@@ -673,6 +673,7 @@ QGeoShapePrivate *QGeoPolygonPrivateEager::clone() const
void QGeoPolygonPrivateEager::translate(double degreesLatitude, double degreesLongitude)
{
translatePoly(m_path, m_holesList, m_bbox, degreesLatitude, degreesLongitude, m_maxLati, m_minLati);
+ m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
m_clipperDirty = true;
}
diff --git a/src/positioning/qlocationutils_p.h b/src/positioning/qlocationutils_p.h
index e2d739e7..563db200 100644
--- a/src/positioning/qlocationutils_p.h
+++ b/src/positioning/qlocationutils_p.h
@@ -258,6 +258,13 @@ public:
return wrapLong(centerLongitude - leftOffset);
}
+ inline static void split_double(double input, float *hipart, float *lopart)
+ {
+ *hipart = (float) input;
+ double delta = input - ((double) *hipart);
+ *lopart = (float) delta;
+ }
+
static qreal metersPerPixel(qreal zoomLevel, const QGeoCoordinate &coordinate)
{
const qreal metersPerTile = earthMeanCircumference() * std::cos(radians(coordinate.latitude())) / std::pow(2, zoomLevel);
diff --git a/src/positioningquick/qdeclarativepositionsource.cpp b/src/positioningquick/qdeclarativepositionsource.cpp
index d6c62147..cf160541 100644
--- a/src/positioningquick/qdeclarativepositionsource.cpp
+++ b/src/positioningquick/qdeclarativepositionsource.cpp
@@ -280,7 +280,7 @@ void QDeclarativePositionSource::setNmeaSource(const QUrl &nmeaSource)
delete m_nmeaSocket;
m_nmeaSocket = new QTcpSocket();
- connect(m_nmeaSocket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)> (&QAbstractSocket::error),
+ connect(m_nmeaSocket, &QAbstractSocket::errorOccurred,
this, &QDeclarativePositionSource::socketError);
connect(m_nmeaSocket, &QTcpSocket::connected,
this, &QDeclarativePositionSource::socketConnected);
diff --git a/tests/auto/nokia_services/routing/tst_routing.cpp b/tests/auto/nokia_services/routing/tst_routing.cpp
index ff3fd6ac..fdfdfe0a 100644
--- a/tests/auto/nokia_services/routing/tst_routing.cpp
+++ b/tests/auto/nokia_services/routing/tst_routing.cpp
@@ -102,8 +102,8 @@ void MockGeoNetworkReply::setFile(QFile* file)
void MockGeoNetworkReply::complete()
{
- if (networkError() != QNetworkReply::NoError)
- emit error(networkError());
+ if (error() != QNetworkReply::NoError)
+ emit errorOccurred(error());
setFinished(true);
emit finished();
}
diff --git a/tests/manual/mapitems_backends/main.cpp b/tests/manual/mapitems_backends/main.cpp
new file mode 100644
index 00000000..c04944d0
--- /dev/null
+++ b/tests/manual/mapitems_backends/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/mapitems_backends/main.qml b/tests/manual/mapitems_backends/main.qml
new file mode 100644
index 00000000..d28605c9
--- /dev/null
+++ b/tests/manual/mapitems_backends/main.qml
@@ -0,0 +1,552 @@
+/****************************************************************************
+**
+** 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
+
+Window {
+ id: win
+ visible: true
+ width: 1600
+ height: 800
+ title: qsTr("MapItems backends")
+
+
+ property real initialZL: 4
+ property var initialCenter: QtPositioning.coordinate(59.9154, 10.7425) //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"
+ PluginParameter {
+ name: "osm.mapping.prefetching_style"
+ value: "NoPrefetching"
+ }
+ PluginParameter {
+ name: "osm.mapping.cache.memory.cost_strategy"
+ value: "unitary"
+ }
+ PluginParameter {
+ name: "osm.mapping.cache.memory.size"
+ value: 0
+ }
+ PluginParameter {
+ name: "osm.mapping.cache.texture.cost_strategy"
+ value: "unitary"
+ }
+ PluginParameter {
+ name: "osm.mapping.cache.texture.size"
+ value: 70
+ }
+ }
+ 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 = migComponent.createObject(map)
+ o.glPolygons = Qt.binding(function() {return switchPolygons1.checked})
+ o.glPolylines = Qt.binding(function() {return switchPolylines1.currentText})
+ o.glCircles = Qt.binding(function() {return switchCircles1.checked})
+ o.glRectangles = Qt.binding(function() {return switchRectangles1.checked})
+ map.addMapItemGroup(o);
+ }
+ 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)
+ }
+ }
+ C2.Switch {
+ text: qsTr("OGL Polygons")
+ id: switchPolygons1
+ checked: true
+ anchors {
+ top: parent.top
+ right: parent.right
+ topMargin: 12
+ rightMargin: 12
+ }
+ }
+ C2.ComboBox {
+ model: ['Software','OpenGL','Triangulated']
+ id: switchPolylines1
+ anchors {
+ top: switchPolygons1.bottom
+ right: parent.right
+ topMargin: 12
+ rightMargin: 12
+ }
+ }
+ C2.Switch {
+ text: qsTr("OGL Circles")
+ id: switchCircles1
+ anchors {
+ top: switchPolylines1.bottom
+ right: parent.right
+ topMargin: 12
+ rightMargin: 12
+ }
+ }
+ C2.Switch {
+ text: qsTr("OGL Rectangles")
+ id: switchRectangles1
+ anchors {
+ top: switchCircles1.bottom
+ right: parent.right
+ topMargin: 12
+ rightMargin: 12
+ }
+ }
+
+// MapPolygon {
+// id: geoJsonFeature
+// color: "limegreen"
+// border.color: "black"
+// border.width: 15
+// objectName: parent.objectName + "limegreen"
+// backend: polygonBackend()
+// path: [
+// { longitude:17.13, latitude: 51.11},
+// { longitude:30.54, latitude: 50.42},
+// { longitude:26.70, latitude: 58.36},
+// { longitude:17.13, latitude: 51.11}
+// ]
+
+// function polygonBackend()
+// {
+// return (switchPolygons1.checked)
+// ? MapPolygon.OpenGL : MapPolygon.Software
+// }
+// }
+
+ layer {
+ enabled: true
+ samples: 8
+ }
+ }
+ 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
+ }
+ }
+
+ layer {
+ enabled: true
+ samples: 8
+ }
+ }
+ }
+
+ 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 }
+ ]
+ }
+
+ MapPolygon {
+ id: geoJsonFeature
+ color: "limegreen"
+ border.color: "black"
+ border.width: 15
+ objectName: parent.objectName + "limegreen"
+ backend: polygonBackend()
+ path: [
+ { longitude:17.13, latitude: 51.11},
+ { longitude:30.54, latitude: 50.42},
+ { longitude:26.70, latitude: 58.36},
+ { longitude:17.13, latitude: 51.11}
+ ]
+ }
+
+ MapPolygon {
+ id: geoJsonRect
+ color: "yellow"
+ border.color: "black"
+ border.width: 8
+ objectName: parent.objectName + "yellow"
+ backend: polygonBackend()
+ path: [
+ { longitude:4, latitude: 15},
+ { longitude:5, latitude: 15},
+ { longitude:5, latitude: 14},
+ { longitude:4, latitude: 14},
+ { longitude:4, latitude: 15}
+ ]
+
+
+ }
+
+ 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
+ }
+ }
+ }
+
+ LongPolyline {
+ id: longPolyline
+ line.width: sliLineWidth.value
+ line.color: 'firebrick'
+ backend: polylineBackend()
+ }
+
+ MapCircle {
+ center: QtPositioning.coordinate(52, 0)
+ radius: 100*1000
+ 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
+ }
+ }
+ }
+
+ C2.Slider {
+ id: sliLineWidth
+ orientation: Qt.Vertical
+ anchors {
+ left: parent.left
+ top: parent.top
+ bottom: parent.bottom
+ topMargin: 10
+ leftMargin: 10
+ bottomMargin: 10
+ }
+ from: 1
+ to: 20
+ value: 10
+ }
+
+ Text {
+ id: zl
+ text: "" + map.zoomLevel.toFixed(2)
+ anchors.top: parent.top
+ anchors.left: parent.left
+ }
+}
diff --git a/tests/manual/mapitems_backends/mapitems_backends.pro b/tests/manual/mapitems_backends/mapitems_backends.pro
new file mode 100644
index 00000000..a517b750
--- /dev/null
+++ b/tests/manual/mapitems_backends/mapitems_backends.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/mapitems_backends/qml.qrc b/tests/manual/mapitems_backends/qml.qrc
new file mode 100644
index 00000000..3a8a697d
--- /dev/null
+++ b/tests/manual/mapitems_backends/qml.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file alias="LongPolyline.qml">../mappolyline_tester/LongPolyline.qml</file>
+ </qresource>
+</RCC>
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..1e758ace
--- /dev/null
+++ b/tests/manual/mapobjects_tester/main.qml
@@ -0,0 +1,531 @@
+/****************************************************************************
+**
+** 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("MapObjects tester")
+
+
+ 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
+ }
+ }
+ }
+
+ LongPolyline {
+ id: longPoly
+ backend: polylineBackend()
+ Component.onCompleted: longPolyPath = path
+ }
+
+ 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'
+ }
+
+ MapPolylineObject {
+ id: longPolyline
+ line.color: "firebrick"
+ objectName: parent.objectName + "longPolyline"
+ line.width: 10
+ path: longPolyPath
+ }
+
+ MapCircleObject {
+ id: circle1
+ border.color: 'deepskyblue'
+ border.width: 26
+ center: QtPositioning.coordinate(17, 44);
+ radius: 200*1000
+ color: "firebrick"
+ }
+ }
+ }
+
+ property var longPolyPath
+
+ 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..3a8a697d
--- /dev/null
+++ b/tests/manual/mapobjects_tester/qml.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file alias="LongPolyline.qml">../mappolyline_tester/LongPolyline.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/mappolyline_tester/LongPolyline.qml b/tests/manual/mappolyline_tester/LongPolyline.qml
new file mode 100644
index 00000000..a0ca98bf
--- /dev/null
+++ b/tests/manual/mappolyline_tester/LongPolyline.qml
@@ -0,0 +1,92745 @@
+/****************************************************************************
+**
+** 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 QtLocation 5.15
+import QtPositioning 5.6
+
+MapPolyline {
+ id: longPoly
+ objectName: "longPoly"
+ line.color: 'blue'
+ line.width: 7
+
+ path : [ QtPositioning.coordinate(59.948692 , 10.769687),
+QtPositioning.coordinate(59.948856 , 10.769572),
+QtPositioning.coordinate(59.948969 , 10.769486),
+QtPositioning.coordinate(59.949212 , 10.769308),
+QtPositioning.coordinate(59.949312 , 10.76923),
+QtPositioning.coordinate(59.949471 , 10.769121),
+QtPositioning.coordinate(59.949805 , 10.768894),
+QtPositioning.coordinate(59.94999 , 10.768774),
+QtPositioning.coordinate(59.950102 , 10.768712),
+QtPositioning.coordinate(59.95021 , 10.768654),
+QtPositioning.coordinate(59.950315 , 10.7686),
+QtPositioning.coordinate(59.950444 , 10.768547),
+QtPositioning.coordinate(59.95054 , 10.768516),
+QtPositioning.coordinate(59.950611 , 10.768492),
+QtPositioning.coordinate(59.950702 , 10.768467),
+QtPositioning.coordinate(59.950858 , 10.768428),
+QtPositioning.coordinate(59.95088 , 10.768422),
+QtPositioning.coordinate(59.950968 , 10.768394),
+QtPositioning.coordinate(59.95104 , 10.768367),
+QtPositioning.coordinate(59.951114 , 10.76833),
+QtPositioning.coordinate(59.951225 , 10.768258),
+QtPositioning.coordinate(59.951525 , 10.76805),
+QtPositioning.coordinate(59.951879 , 10.76782),
+QtPositioning.coordinate(59.952096 , 10.767775),
+QtPositioning.coordinate(59.952225 , 10.767812),
+QtPositioning.coordinate(59.952392 , 10.767959),
+QtPositioning.coordinate(59.95258 , 10.768169),
+QtPositioning.coordinate(59.952707 , 10.768312),
+QtPositioning.coordinate(59.952795 , 10.768426),
+QtPositioning.coordinate(59.952825 , 10.768463),
+QtPositioning.coordinate(59.952858 , 10.768506),
+QtPositioning.coordinate(59.952919 , 10.768626),
+QtPositioning.coordinate(59.952954 , 10.768708),
+QtPositioning.coordinate(59.952975 , 10.768807),
+QtPositioning.coordinate(59.952987 , 10.768872),
+QtPositioning.coordinate(59.952983 , 10.768979),
+QtPositioning.coordinate(59.952977 , 10.769035),
+QtPositioning.coordinate(59.9529 , 10.769467),
+QtPositioning.coordinate(59.952826 , 10.769706),
+QtPositioning.coordinate(59.952706 , 10.770102),
+QtPositioning.coordinate(59.952328 , 10.771368),
+QtPositioning.coordinate(59.952129 , 10.772053),
+QtPositioning.coordinate(59.951922 , 10.772784),
+QtPositioning.coordinate(59.951584 , 10.774127),
+QtPositioning.coordinate(59.951445 , 10.774647),
+QtPositioning.coordinate(59.95134 , 10.775008),
+QtPositioning.coordinate(59.951244 , 10.775294),
+QtPositioning.coordinate(59.9512 , 10.775415),
+QtPositioning.coordinate(59.951154 , 10.775542),
+QtPositioning.coordinate(59.951043 , 10.775794),
+QtPositioning.coordinate(59.950902 , 10.776073),
+QtPositioning.coordinate(59.950757 , 10.776322),
+QtPositioning.coordinate(59.950589 , 10.776581),
+QtPositioning.coordinate(59.950401 , 10.776812),
+QtPositioning.coordinate(59.950251 , 10.77695),
+QtPositioning.coordinate(59.950096 , 10.777077),
+QtPositioning.coordinate(59.949903 , 10.777201),
+QtPositioning.coordinate(59.949606 , 10.777372),
+QtPositioning.coordinate(59.94935 , 10.777542),
+QtPositioning.coordinate(59.948543 , 10.777985),
+QtPositioning.coordinate(59.94813 , 10.778204),
+QtPositioning.coordinate(59.947857 , 10.778342),
+QtPositioning.coordinate(59.94741 , 10.778507),
+QtPositioning.coordinate(59.946512 , 10.778769),
+QtPositioning.coordinate(59.945988 , 10.778928),
+QtPositioning.coordinate(59.944792 , 10.779457),
+QtPositioning.coordinate(59.944325 , 10.77969),
+QtPositioning.coordinate(59.944038 , 10.779843),
+QtPositioning.coordinate(59.943712 , 10.780015),
+QtPositioning.coordinate(59.943488 , 10.780143),
+QtPositioning.coordinate(59.943185 , 10.780295),
+QtPositioning.coordinate(59.942712 , 10.780567),
+QtPositioning.coordinate(59.942267 , 10.780809),
+QtPositioning.coordinate(59.94191 , 10.780985),
+QtPositioning.coordinate(59.941207 , 10.781311),
+QtPositioning.coordinate(59.94092 , 10.781448),
+QtPositioning.coordinate(59.940396 , 10.781706),
+QtPositioning.coordinate(59.94014 , 10.781835),
+QtPositioning.coordinate(59.939881 , 10.781989),
+QtPositioning.coordinate(59.939574 , 10.782198),
+QtPositioning.coordinate(59.939243 , 10.782455),
+QtPositioning.coordinate(59.938912 , 10.782798),
+QtPositioning.coordinate(59.938751 , 10.782963),
+QtPositioning.coordinate(59.938599 , 10.783133),
+QtPositioning.coordinate(59.938445 , 10.783314),
+QtPositioning.coordinate(59.938258 , 10.783553),
+QtPositioning.coordinate(59.93806 , 10.783824),
+QtPositioning.coordinate(59.937903 , 10.784066),
+QtPositioning.coordinate(59.937658 , 10.784504),
+QtPositioning.coordinate(59.937544 , 10.784717),
+QtPositioning.coordinate(59.937425 , 10.784956),
+QtPositioning.coordinate(59.937283 , 10.785278),
+QtPositioning.coordinate(59.93714 , 10.78563),
+QtPositioning.coordinate(59.937022 , 10.785951),
+QtPositioning.coordinate(59.936838 , 10.786435),
+QtPositioning.coordinate(59.936623 , 10.786982),
+QtPositioning.coordinate(59.93641 , 10.787528),
+QtPositioning.coordinate(59.93613 , 10.788245),
+QtPositioning.coordinate(59.935807 , 10.789117),
+QtPositioning.coordinate(59.935588 , 10.789786),
+QtPositioning.coordinate(59.935413 , 10.790406),
+QtPositioning.coordinate(59.935308 , 10.790819),
+QtPositioning.coordinate(59.934972 , 10.792299),
+QtPositioning.coordinate(59.933858 , 10.797256),
+QtPositioning.coordinate(59.933695 , 10.797927),
+QtPositioning.coordinate(59.933551 , 10.798416),
+QtPositioning.coordinate(59.933263 , 10.799202),
+QtPositioning.coordinate(59.933024 , 10.799743),
+QtPositioning.coordinate(59.932618 , 10.800441),
+QtPositioning.coordinate(59.932231 , 10.800924),
+QtPositioning.coordinate(59.931994 , 10.801197),
+QtPositioning.coordinate(59.931685 , 10.801455),
+QtPositioning.coordinate(59.931258 , 10.801734),
+QtPositioning.coordinate(59.9309 , 10.801911),
+QtPositioning.coordinate(59.930339 , 10.802018),
+QtPositioning.coordinate(59.929564 , 10.802051),
+QtPositioning.coordinate(59.929176 , 10.802038),
+QtPositioning.coordinate(59.928648 , 10.802023),
+QtPositioning.coordinate(59.928325 , 10.802007),
+QtPositioning.coordinate(59.928185 , 10.801999),
+QtPositioning.coordinate(59.928048 , 10.802005),
+QtPositioning.coordinate(59.927901 , 10.802014),
+QtPositioning.coordinate(59.927758 , 10.802029),
+QtPositioning.coordinate(59.927594 , 10.802061),
+QtPositioning.coordinate(59.927458 , 10.802117),
+QtPositioning.coordinate(59.927339 , 10.802156),
+QtPositioning.coordinate(59.927196 , 10.802215),
+QtPositioning.coordinate(59.927068 , 10.802279),
+QtPositioning.coordinate(59.926967 , 10.802344),
+QtPositioning.coordinate(59.926846 , 10.802428),
+QtPositioning.coordinate(59.926777 , 10.802487),
+QtPositioning.coordinate(59.926649 , 10.802575),
+QtPositioning.coordinate(59.926536 , 10.802702),
+QtPositioning.coordinate(59.926439 , 10.802825),
+QtPositioning.coordinate(59.926341 , 10.802964),
+QtPositioning.coordinate(59.926216 , 10.80315),
+QtPositioning.coordinate(59.926084 , 10.803385),
+QtPositioning.coordinate(59.925915 , 10.803694),
+QtPositioning.coordinate(59.925763 , 10.803984),
+QtPositioning.coordinate(59.92532 , 10.804838),
+QtPositioning.coordinate(59.925095 , 10.805264),
+QtPositioning.coordinate(59.924931 , 10.805568),
+QtPositioning.coordinate(59.924833 , 10.805738),
+QtPositioning.coordinate(59.924743 , 10.805907),
+QtPositioning.coordinate(59.924674 , 10.806019),
+QtPositioning.coordinate(59.924546 , 10.806219),
+QtPositioning.coordinate(59.924417 , 10.806414),
+QtPositioning.coordinate(59.924293 , 10.806581),
+QtPositioning.coordinate(59.924155 , 10.806732),
+QtPositioning.coordinate(59.923997 , 10.806891),
+QtPositioning.coordinate(59.923869 , 10.806999),
+QtPositioning.coordinate(59.923729 , 10.807107),
+QtPositioning.coordinate(59.923587 , 10.807205),
+QtPositioning.coordinate(59.923459 , 10.807282),
+QtPositioning.coordinate(59.923342 , 10.807336),
+QtPositioning.coordinate(59.923196 , 10.807396),
+QtPositioning.coordinate(59.92305 , 10.807447),
+QtPositioning.coordinate(59.922906 , 10.807488),
+QtPositioning.coordinate(59.922752 , 10.807527),
+QtPositioning.coordinate(59.922122 , 10.807664),
+QtPositioning.coordinate(59.921682 , 10.807756),
+QtPositioning.coordinate(59.921235 , 10.807849),
+QtPositioning.coordinate(59.920869 , 10.807908),
+QtPositioning.coordinate(59.920291 , 10.808033),
+QtPositioning.coordinate(59.919928 , 10.808108),
+QtPositioning.coordinate(59.919599 , 10.808188),
+QtPositioning.coordinate(59.919349 , 10.808277),
+QtPositioning.coordinate(59.919126 , 10.808378),
+QtPositioning.coordinate(59.918951 , 10.808485),
+QtPositioning.coordinate(59.918782 , 10.808606),
+QtPositioning.coordinate(59.918615 , 10.808759),
+QtPositioning.coordinate(59.918493 , 10.808885),
+QtPositioning.coordinate(59.918395 , 10.809),
+QtPositioning.coordinate(59.918189 , 10.809315),
+QtPositioning.coordinate(59.917989 , 10.809645),
+QtPositioning.coordinate(59.917849 , 10.809919),
+QtPositioning.coordinate(59.917672 , 10.810305),
+QtPositioning.coordinate(59.917487 , 10.81076),
+QtPositioning.coordinate(59.917224 , 10.811371),
+QtPositioning.coordinate(59.917015 , 10.81183),
+QtPositioning.coordinate(59.916871 , 10.812114),
+QtPositioning.coordinate(59.916719 , 10.812373),
+QtPositioning.coordinate(59.916582 , 10.812577),
+QtPositioning.coordinate(59.9164 , 10.812828),
+QtPositioning.coordinate(59.916242 , 10.813016),
+QtPositioning.coordinate(59.916075 , 10.813197),
+QtPositioning.coordinate(59.915867 , 10.813404),
+QtPositioning.coordinate(59.915353 , 10.813914),
+QtPositioning.coordinate(59.914723 , 10.814554),
+QtPositioning.coordinate(59.913963 , 10.815343),
+QtPositioning.coordinate(59.913112 , 10.816257),
+QtPositioning.coordinate(59.912347 , 10.817064),
+QtPositioning.coordinate(59.912051 , 10.817357),
+QtPositioning.coordinate(59.911849 , 10.817527),
+QtPositioning.coordinate(59.911653 , 10.817669),
+QtPositioning.coordinate(59.911362 , 10.817849),
+QtPositioning.coordinate(59.911132 , 10.817969),
+QtPositioning.coordinate(59.910578 , 10.81821),
+QtPositioning.coordinate(59.910248 , 10.818369),
+QtPositioning.coordinate(59.910017 , 10.818512),
+QtPositioning.coordinate(59.90992 , 10.81857),
+QtPositioning.coordinate(59.909803 , 10.818661),
+QtPositioning.coordinate(59.909717 , 10.818723),
+QtPositioning.coordinate(59.909594 , 10.818815),
+QtPositioning.coordinate(59.909541 , 10.818862),
+QtPositioning.coordinate(59.90948 , 10.818915),
+QtPositioning.coordinate(59.909319 , 10.819064),
+QtPositioning.coordinate(59.909154 , 10.819227),
+QtPositioning.coordinate(59.908744 , 10.819655),
+QtPositioning.coordinate(59.908471 , 10.819935),
+QtPositioning.coordinate(59.908378 , 10.820026),
+QtPositioning.coordinate(59.90827 , 10.820123),
+QtPositioning.coordinate(59.908151 , 10.820223),
+QtPositioning.coordinate(59.908023 , 10.820329),
+QtPositioning.coordinate(59.908012 , 10.820338),
+QtPositioning.coordinate(59.907834 , 10.820492),
+QtPositioning.coordinate(59.90773 , 10.820555),
+QtPositioning.coordinate(59.907613 , 10.82061),
+QtPositioning.coordinate(59.907464 , 10.820657),
+QtPositioning.coordinate(59.907259 , 10.820688),
+QtPositioning.coordinate(59.906717 , 10.820711),
+QtPositioning.coordinate(59.905684 , 10.820702),
+QtPositioning.coordinate(59.905113 , 10.820674),
+QtPositioning.coordinate(59.904891 , 10.820658),
+QtPositioning.coordinate(59.904655 , 10.820635),
+QtPositioning.coordinate(59.904372 , 10.820578),
+QtPositioning.coordinate(59.904234 , 10.820534),
+QtPositioning.coordinate(59.904081 , 10.820482),
+QtPositioning.coordinate(59.903945 , 10.820423),
+QtPositioning.coordinate(59.903782 , 10.820344),
+QtPositioning.coordinate(59.903521 , 10.820186),
+QtPositioning.coordinate(59.903252 , 10.819989),
+QtPositioning.coordinate(59.902841 , 10.819631),
+QtPositioning.coordinate(59.902464 , 10.819286),
+QtPositioning.coordinate(59.902117 , 10.81894),
+QtPositioning.coordinate(59.901693 , 10.818496),
+QtPositioning.coordinate(59.901364 , 10.818125),
+QtPositioning.coordinate(59.900922 , 10.8176),
+QtPositioning.coordinate(59.900712 , 10.817345),
+QtPositioning.coordinate(59.900433 , 10.817004),
+QtPositioning.coordinate(59.900226 , 10.816748),
+QtPositioning.coordinate(59.900039 , 10.816497),
+QtPositioning.coordinate(59.899959 , 10.816388),
+QtPositioning.coordinate(59.899797 , 10.816174),
+QtPositioning.coordinate(59.89971 , 10.816055),
+QtPositioning.coordinate(59.899576 , 10.815863),
+QtPositioning.coordinate(59.899404 , 10.815623),
+QtPositioning.coordinate(59.899191 , 10.815316),
+QtPositioning.coordinate(59.898993 , 10.815017),
+QtPositioning.coordinate(59.898814 , 10.814726),
+QtPositioning.coordinate(59.898636 , 10.814427),
+QtPositioning.coordinate(59.898533 , 10.814248),
+QtPositioning.coordinate(59.898362 , 10.813949),
+QtPositioning.coordinate(59.898225 , 10.813687),
+QtPositioning.coordinate(59.898121 , 10.813491),
+QtPositioning.coordinate(59.897983 , 10.813217),
+QtPositioning.coordinate(59.897841 , 10.812935),
+QtPositioning.coordinate(59.897673 , 10.812595),
+QtPositioning.coordinate(59.897385 , 10.811968),
+QtPositioning.coordinate(59.897224 , 10.811611),
+QtPositioning.coordinate(59.897073 , 10.811256),
+QtPositioning.coordinate(59.896933 , 10.810926),
+QtPositioning.coordinate(59.896788 , 10.810577),
+QtPositioning.coordinate(59.896655 , 10.810239),
+QtPositioning.coordinate(59.896536 , 10.80993),
+QtPositioning.coordinate(59.896457 , 10.809716),
+QtPositioning.coordinate(59.896372 , 10.809486),
+QtPositioning.coordinate(59.89629 , 10.809252),
+QtPositioning.coordinate(59.896235 , 10.809079),
+QtPositioning.coordinate(59.896169 , 10.808853),
+QtPositioning.coordinate(59.896104 , 10.808612),
+QtPositioning.coordinate(59.896033 , 10.808308),
+QtPositioning.coordinate(59.895976 , 10.808031),
+QtPositioning.coordinate(59.895931 , 10.807795),
+QtPositioning.coordinate(59.895871 , 10.807489),
+QtPositioning.coordinate(59.895809 , 10.807199),
+QtPositioning.coordinate(59.895749 , 10.806913),
+QtPositioning.coordinate(59.895683 , 10.806651),
+QtPositioning.coordinate(59.895607 , 10.806375),
+QtPositioning.coordinate(59.895541 , 10.806177),
+QtPositioning.coordinate(59.89542 , 10.805874),
+QtPositioning.coordinate(59.895305 , 10.805612),
+QtPositioning.coordinate(59.895186 , 10.805362),
+QtPositioning.coordinate(59.895053 , 10.805118),
+QtPositioning.coordinate(59.894927 , 10.804915),
+QtPositioning.coordinate(59.894771 , 10.804708),
+QtPositioning.coordinate(59.894592 , 10.80449),
+QtPositioning.coordinate(59.894444 , 10.804327),
+QtPositioning.coordinate(59.894281 , 10.804193),
+QtPositioning.coordinate(59.894134 , 10.804097),
+QtPositioning.coordinate(59.893967 , 10.804014),
+QtPositioning.coordinate(59.893742 , 10.803934),
+QtPositioning.coordinate(59.893585 , 10.80391),
+QtPositioning.coordinate(59.893445 , 10.803898),
+QtPositioning.coordinate(59.893316 , 10.8039),
+QtPositioning.coordinate(59.893221 , 10.803904),
+QtPositioning.coordinate(59.892998 , 10.803923),
+QtPositioning.coordinate(59.892784 , 10.803971),
+QtPositioning.coordinate(59.8925 , 10.804036),
+QtPositioning.coordinate(59.891907 , 10.804197),
+QtPositioning.coordinate(59.891476 , 10.804332),
+QtPositioning.coordinate(59.891063 , 10.804493),
+QtPositioning.coordinate(59.890647 , 10.804692),
+QtPositioning.coordinate(59.890147 , 10.804991),
+QtPositioning.coordinate(59.889601 , 10.805398),
+QtPositioning.coordinate(59.889166 , 10.805794),
+QtPositioning.coordinate(59.889009 , 10.805965),
+QtPositioning.coordinate(59.888789 , 10.806185),
+QtPositioning.coordinate(59.88858 , 10.806411),
+QtPositioning.coordinate(59.888178 , 10.806888),
+QtPositioning.coordinate(59.887823 , 10.807361),
+QtPositioning.coordinate(59.887585 , 10.807719),
+QtPositioning.coordinate(59.887256 , 10.808209),
+QtPositioning.coordinate(59.886886 , 10.808809),
+QtPositioning.coordinate(59.886657 , 10.809206),
+QtPositioning.coordinate(59.886315 , 10.809836),
+QtPositioning.coordinate(59.885934 , 10.810554),
+QtPositioning.coordinate(59.885282 , 10.811824),
+QtPositioning.coordinate(59.884794 , 10.812701),
+QtPositioning.coordinate(59.884511 , 10.813176),
+QtPositioning.coordinate(59.884224 , 10.813617),
+QtPositioning.coordinate(59.883942 , 10.813999),
+QtPositioning.coordinate(59.883554 , 10.814465),
+QtPositioning.coordinate(59.883136 , 10.814888),
+QtPositioning.coordinate(59.882815 , 10.815164),
+QtPositioning.coordinate(59.882636 , 10.8153),
+QtPositioning.coordinate(59.882397 , 10.815475),
+QtPositioning.coordinate(59.882113 , 10.815676),
+QtPositioning.coordinate(59.881895 , 10.815834),
+QtPositioning.coordinate(59.881742 , 10.815947),
+QtPositioning.coordinate(59.8815 , 10.81614),
+QtPositioning.coordinate(59.881362 , 10.816257),
+QtPositioning.coordinate(59.881088 , 10.816483),
+QtPositioning.coordinate(59.880864 , 10.816679),
+QtPositioning.coordinate(59.88058 , 10.816942),
+QtPositioning.coordinate(59.880323 , 10.817194),
+QtPositioning.coordinate(59.880161 , 10.817349),
+QtPositioning.coordinate(59.879979 , 10.817531),
+QtPositioning.coordinate(59.879838 , 10.81768),
+QtPositioning.coordinate(59.87965 , 10.817877),
+QtPositioning.coordinate(59.879369 , 10.818187),
+QtPositioning.coordinate(59.879108 , 10.818483),
+QtPositioning.coordinate(59.878895 , 10.818738),
+QtPositioning.coordinate(59.878674 , 10.819014),
+QtPositioning.coordinate(59.87841 , 10.819347),
+QtPositioning.coordinate(59.878268 , 10.819533),
+QtPositioning.coordinate(59.87812 , 10.819728),
+QtPositioning.coordinate(59.87796 , 10.81995),
+QtPositioning.coordinate(59.877785 , 10.820191),
+QtPositioning.coordinate(59.877347 , 10.820819),
+QtPositioning.coordinate(59.877114 , 10.821147),
+QtPositioning.coordinate(59.876885 , 10.82147),
+QtPositioning.coordinate(59.876708 , 10.821718),
+QtPositioning.coordinate(59.876491 , 10.822014),
+QtPositioning.coordinate(59.876351 , 10.822205),
+QtPositioning.coordinate(59.876208 , 10.822389),
+QtPositioning.coordinate(59.876026 , 10.822608),
+QtPositioning.coordinate(59.875858 , 10.822802),
+QtPositioning.coordinate(59.875676 , 10.822994),
+QtPositioning.coordinate(59.875525 , 10.823152),
+QtPositioning.coordinate(59.875361 , 10.823307),
+QtPositioning.coordinate(59.875048 , 10.82359),
+QtPositioning.coordinate(59.874876 , 10.823728),
+QtPositioning.coordinate(59.874682 , 10.823877),
+QtPositioning.coordinate(59.874303 , 10.824161),
+QtPositioning.coordinate(59.873701 , 10.824602),
+QtPositioning.coordinate(59.87347 , 10.82477),
+QtPositioning.coordinate(59.873209 , 10.824979),
+QtPositioning.coordinate(59.872995 , 10.825148),
+QtPositioning.coordinate(59.872808 , 10.825303),
+QtPositioning.coordinate(59.872614 , 10.825474),
+QtPositioning.coordinate(59.872425 , 10.825658),
+QtPositioning.coordinate(59.872237 , 10.825837),
+QtPositioning.coordinate(59.872015 , 10.826078),
+QtPositioning.coordinate(59.871722 , 10.826414),
+QtPositioning.coordinate(59.871378 , 10.826823),
+QtPositioning.coordinate(59.870792 , 10.827554),
+QtPositioning.coordinate(59.870108 , 10.828385),
+QtPositioning.coordinate(59.869781 , 10.828718),
+QtPositioning.coordinate(59.869433 , 10.828987),
+QtPositioning.coordinate(59.869143 , 10.829153),
+QtPositioning.coordinate(59.868921 , 10.82927),
+QtPositioning.coordinate(59.868546 , 10.829423),
+QtPositioning.coordinate(59.867851 , 10.829677),
+QtPositioning.coordinate(59.867147 , 10.829918),
+QtPositioning.coordinate(59.865964 , 10.830281),
+QtPositioning.coordinate(59.865257 , 10.830447),
+QtPositioning.coordinate(59.864563 , 10.83059),
+QtPositioning.coordinate(59.863927 , 10.830644),
+QtPositioning.coordinate(59.863362 , 10.830666),
+QtPositioning.coordinate(59.862687 , 10.830647),
+QtPositioning.coordinate(59.862258 , 10.830643),
+QtPositioning.coordinate(59.861874 , 10.830645),
+QtPositioning.coordinate(59.861505 , 10.830658),
+QtPositioning.coordinate(59.861294 , 10.830671),
+QtPositioning.coordinate(59.861004 , 10.8307),
+QtPositioning.coordinate(59.860539 , 10.830763),
+QtPositioning.coordinate(59.860131 , 10.83083),
+QtPositioning.coordinate(59.859638 , 10.830941),
+QtPositioning.coordinate(59.858868 , 10.831152),
+QtPositioning.coordinate(59.857977 , 10.831451),
+QtPositioning.coordinate(59.857161 , 10.831779),
+QtPositioning.coordinate(59.856614 , 10.832021),
+QtPositioning.coordinate(59.856043 , 10.832296),
+QtPositioning.coordinate(59.855099 , 10.832752),
+QtPositioning.coordinate(59.85411 , 10.833227),
+QtPositioning.coordinate(59.852972 , 10.833772),
+QtPositioning.coordinate(59.852476 , 10.834021),
+QtPositioning.coordinate(59.852143 , 10.834191),
+QtPositioning.coordinate(59.851787 , 10.834391),
+QtPositioning.coordinate(59.851444 , 10.834597),
+QtPositioning.coordinate(59.85132 , 10.834675),
+QtPositioning.coordinate(59.851213 , 10.834738),
+QtPositioning.coordinate(59.85082 , 10.835002),
+QtPositioning.coordinate(59.850612 , 10.835147),
+QtPositioning.coordinate(59.850514 , 10.835212),
+QtPositioning.coordinate(59.850301 , 10.835354),
+QtPositioning.coordinate(59.850001 , 10.835555),
+QtPositioning.coordinate(59.849743 , 10.835728),
+QtPositioning.coordinate(59.849392 , 10.835933),
+QtPositioning.coordinate(59.849096 , 10.836105),
+QtPositioning.coordinate(59.848968 , 10.836169),
+QtPositioning.coordinate(59.848756 , 10.836276),
+QtPositioning.coordinate(59.848521 , 10.836361),
+QtPositioning.coordinate(59.848231 , 10.836446),
+QtPositioning.coordinate(59.847994 , 10.836497),
+QtPositioning.coordinate(59.847791 , 10.836533),
+QtPositioning.coordinate(59.847184 , 10.836631),
+QtPositioning.coordinate(59.846522 , 10.836771),
+QtPositioning.coordinate(59.845901 , 10.836935),
+QtPositioning.coordinate(59.845255 , 10.837136),
+QtPositioning.coordinate(59.845069 , 10.837198),
+QtPositioning.coordinate(59.844446 , 10.837433),
+QtPositioning.coordinate(59.843717 , 10.837729),
+QtPositioning.coordinate(59.843303 , 10.837905),
+QtPositioning.coordinate(59.842886 , 10.838083),
+QtPositioning.coordinate(59.8424 , 10.838301),
+QtPositioning.coordinate(59.841434 , 10.838769),
+QtPositioning.coordinate(59.840731 , 10.83912),
+QtPositioning.coordinate(59.840621 , 10.839173),
+QtPositioning.coordinate(59.840173 , 10.839389),
+QtPositioning.coordinate(59.839978 , 10.839468),
+QtPositioning.coordinate(59.839788 , 10.839525),
+QtPositioning.coordinate(59.839568 , 10.839592),
+QtPositioning.coordinate(59.839372 , 10.839636),
+QtPositioning.coordinate(59.839058 , 10.839682),
+QtPositioning.coordinate(59.838847 , 10.839694),
+QtPositioning.coordinate(59.838662 , 10.839688),
+QtPositioning.coordinate(59.838486 , 10.839682),
+QtPositioning.coordinate(59.838281 , 10.839658),
+QtPositioning.coordinate(59.837885 , 10.839589),
+QtPositioning.coordinate(59.837675 , 10.839552),
+QtPositioning.coordinate(59.837514 , 10.839518),
+QtPositioning.coordinate(59.837338 , 10.839487),
+QtPositioning.coordinate(59.836937 , 10.839424),
+QtPositioning.coordinate(59.836712 , 10.839415),
+QtPositioning.coordinate(59.836535 , 10.839412),
+QtPositioning.coordinate(59.836391 , 10.839412),
+QtPositioning.coordinate(59.836203 , 10.839414),
+QtPositioning.coordinate(59.836038 , 10.839429),
+QtPositioning.coordinate(59.835817 , 10.839452),
+QtPositioning.coordinate(59.835518 , 10.839496),
+QtPositioning.coordinate(59.835092 , 10.839582),
+QtPositioning.coordinate(59.834672 , 10.839706),
+QtPositioning.coordinate(59.83435 , 10.839822),
+QtPositioning.coordinate(59.834025 , 10.839961),
+QtPositioning.coordinate(59.833886 , 10.840025),
+QtPositioning.coordinate(59.833649 , 10.840145),
+QtPositioning.coordinate(59.833424 , 10.840271),
+QtPositioning.coordinate(59.83319 , 10.840403),
+QtPositioning.coordinate(59.832982 , 10.840522),
+QtPositioning.coordinate(59.830037 , 10.842389),
+QtPositioning.coordinate(59.829641 , 10.842615),
+QtPositioning.coordinate(59.829326 , 10.842791),
+QtPositioning.coordinate(59.829003 , 10.842953),
+QtPositioning.coordinate(59.828666 , 10.843122),
+QtPositioning.coordinate(59.828349 , 10.843268),
+QtPositioning.coordinate(59.828095 , 10.843373),
+QtPositioning.coordinate(59.827801 , 10.843499),
+QtPositioning.coordinate(59.827488 , 10.843622),
+QtPositioning.coordinate(59.825037 , 10.844454),
+QtPositioning.coordinate(59.8248 , 10.844534),
+QtPositioning.coordinate(59.824525 , 10.844639),
+QtPositioning.coordinate(59.824256 , 10.844743),
+QtPositioning.coordinate(59.824015 , 10.84485),
+QtPositioning.coordinate(59.823715 , 10.844991),
+QtPositioning.coordinate(59.82344 , 10.84513),
+QtPositioning.coordinate(59.823075 , 10.845329),
+QtPositioning.coordinate(59.822134 , 10.845834),
+QtPositioning.coordinate(59.821383 , 10.846217),
+QtPositioning.coordinate(59.820956 , 10.846432),
+QtPositioning.coordinate(59.820792 , 10.846512),
+QtPositioning.coordinate(59.820572 , 10.846602),
+QtPositioning.coordinate(59.820367 , 10.846669),
+QtPositioning.coordinate(59.820196 , 10.846725),
+QtPositioning.coordinate(59.819989 , 10.846778),
+QtPositioning.coordinate(59.819815 , 10.846815),
+QtPositioning.coordinate(59.819653 , 10.846828),
+QtPositioning.coordinate(59.819497 , 10.846835),
+QtPositioning.coordinate(59.819334 , 10.846842),
+QtPositioning.coordinate(59.819164 , 10.846822),
+QtPositioning.coordinate(59.818983 , 10.846794),
+QtPositioning.coordinate(59.818806 , 10.846746),
+QtPositioning.coordinate(59.818652 , 10.846698),
+QtPositioning.coordinate(59.818497 , 10.846633),
+QtPositioning.coordinate(59.81832 , 10.846541),
+QtPositioning.coordinate(59.818155 , 10.846456),
+QtPositioning.coordinate(59.817943 , 10.846322),
+QtPositioning.coordinate(59.817739 , 10.846161),
+QtPositioning.coordinate(59.817579 , 10.846013),
+QtPositioning.coordinate(59.817424 , 10.845858),
+QtPositioning.coordinate(59.817252 , 10.845667),
+QtPositioning.coordinate(59.817078 , 10.845465),
+QtPositioning.coordinate(59.816897 , 10.845225),
+QtPositioning.coordinate(59.816719 , 10.844955),
+QtPositioning.coordinate(59.816542 , 10.844656),
+QtPositioning.coordinate(59.8164 , 10.844398),
+QtPositioning.coordinate(59.816217 , 10.844044),
+QtPositioning.coordinate(59.815884 , 10.843424),
+QtPositioning.coordinate(59.815384 , 10.842472),
+QtPositioning.coordinate(59.81519 , 10.84211),
+QtPositioning.coordinate(59.815 , 10.841758),
+QtPositioning.coordinate(59.814848 , 10.841506),
+QtPositioning.coordinate(59.814675 , 10.841228),
+QtPositioning.coordinate(59.814486 , 10.840965),
+QtPositioning.coordinate(59.814312 , 10.840747),
+QtPositioning.coordinate(59.814169 , 10.840587),
+QtPositioning.coordinate(59.814012 , 10.840424),
+QtPositioning.coordinate(59.8138 , 10.840231),
+QtPositioning.coordinate(59.813636 , 10.840097),
+QtPositioning.coordinate(59.813453 , 10.839977),
+QtPositioning.coordinate(59.813215 , 10.839836),
+QtPositioning.coordinate(59.812955 , 10.839712),
+QtPositioning.coordinate(59.812737 , 10.839638),
+QtPositioning.coordinate(59.812514 , 10.839584),
+QtPositioning.coordinate(59.812308 , 10.839556),
+QtPositioning.coordinate(59.812093 , 10.839546),
+QtPositioning.coordinate(59.811878 , 10.839552),
+QtPositioning.coordinate(59.811639 , 10.83959),
+QtPositioning.coordinate(59.811406 , 10.839646),
+QtPositioning.coordinate(59.811168 , 10.83972),
+QtPositioning.coordinate(59.810956 , 10.839804),
+QtPositioning.coordinate(59.810726 , 10.839903),
+QtPositioning.coordinate(59.810502 , 10.84001),
+QtPositioning.coordinate(59.810266 , 10.840121),
+QtPositioning.coordinate(59.809985 , 10.840271),
+QtPositioning.coordinate(59.809719 , 10.840414),
+QtPositioning.coordinate(59.80849 , 10.84105),
+QtPositioning.coordinate(59.808177 , 10.841205),
+QtPositioning.coordinate(59.807888 , 10.841343),
+QtPositioning.coordinate(59.807576 , 10.841476),
+QtPositioning.coordinate(59.807252 , 10.841616),
+QtPositioning.coordinate(59.806835 , 10.841781),
+QtPositioning.coordinate(59.806613 , 10.841857),
+QtPositioning.coordinate(59.806346 , 10.84195),
+QtPositioning.coordinate(59.806081 , 10.842036),
+QtPositioning.coordinate(59.805789 , 10.842122),
+QtPositioning.coordinate(59.805511 , 10.842206),
+QtPositioning.coordinate(59.8052 , 10.842282),
+QtPositioning.coordinate(59.8049 , 10.842357),
+QtPositioning.coordinate(59.804627 , 10.842413),
+QtPositioning.coordinate(59.804251 , 10.842485),
+QtPositioning.coordinate(59.80385 , 10.842555),
+QtPositioning.coordinate(59.80341 , 10.842627),
+QtPositioning.coordinate(59.802454 , 10.842761),
+QtPositioning.coordinate(59.801468 , 10.842868),
+QtPositioning.coordinate(59.801026 , 10.842912),
+QtPositioning.coordinate(59.800556 , 10.842947),
+QtPositioning.coordinate(59.800187 , 10.842967),
+QtPositioning.coordinate(59.799859 , 10.842981),
+QtPositioning.coordinate(59.79952 , 10.84298),
+QtPositioning.coordinate(59.799178 , 10.842966),
+QtPositioning.coordinate(59.798838 , 10.842948),
+QtPositioning.coordinate(59.798482 , 10.842915),
+QtPositioning.coordinate(59.798163 , 10.842875),
+QtPositioning.coordinate(59.79785 , 10.842824),
+QtPositioning.coordinate(59.797565 , 10.842773),
+QtPositioning.coordinate(59.797338 , 10.842729),
+QtPositioning.coordinate(59.797009 , 10.842654),
+QtPositioning.coordinate(59.796761 , 10.84259),
+QtPositioning.coordinate(59.796504 , 10.842517),
+QtPositioning.coordinate(59.796268 , 10.842449),
+QtPositioning.coordinate(59.79581 , 10.842298),
+QtPositioning.coordinate(59.795493 , 10.842178),
+QtPositioning.coordinate(59.795211 , 10.842063),
+QtPositioning.coordinate(59.794921 , 10.841941),
+QtPositioning.coordinate(59.794267 , 10.841644),
+QtPositioning.coordinate(59.793921 , 10.841472),
+QtPositioning.coordinate(59.793533 , 10.841283),
+QtPositioning.coordinate(59.792976 , 10.841017),
+QtPositioning.coordinate(59.792609 , 10.840835),
+QtPositioning.coordinate(59.792216 , 10.840646),
+QtPositioning.coordinate(59.791761 , 10.840431),
+QtPositioning.coordinate(59.791291 , 10.840213),
+QtPositioning.coordinate(59.790864 , 10.84003),
+QtPositioning.coordinate(59.790431 , 10.839854),
+QtPositioning.coordinate(59.789927 , 10.839682),
+QtPositioning.coordinate(59.789559 , 10.839564),
+QtPositioning.coordinate(59.788841 , 10.839397),
+QtPositioning.coordinate(59.788583 , 10.839327),
+QtPositioning.coordinate(59.788276 , 10.839256),
+QtPositioning.coordinate(59.787872 , 10.839165),
+QtPositioning.coordinate(59.787574 , 10.839114),
+QtPositioning.coordinate(59.787298 , 10.839079),
+QtPositioning.coordinate(59.787043 , 10.839046),
+QtPositioning.coordinate(59.786784 , 10.83902),
+QtPositioning.coordinate(59.786487 , 10.838999),
+QtPositioning.coordinate(59.786216 , 10.838981),
+QtPositioning.coordinate(59.785883 , 10.83896),
+QtPositioning.coordinate(59.784867 , 10.838944),
+QtPositioning.coordinate(59.784303 , 10.838935),
+QtPositioning.coordinate(59.78369 , 10.83892),
+QtPositioning.coordinate(59.782828 , 10.838906),
+QtPositioning.coordinate(59.782114 , 10.838965),
+QtPositioning.coordinate(59.781277 , 10.839009),
+QtPositioning.coordinate(59.780614 , 10.839074),
+QtPositioning.coordinate(59.779792 , 10.839127),
+QtPositioning.coordinate(59.779478 , 10.839144),
+QtPositioning.coordinate(59.779144 , 10.839152),
+QtPositioning.coordinate(59.77889 , 10.839141),
+QtPositioning.coordinate(59.778586 , 10.839126),
+QtPositioning.coordinate(59.778291 , 10.839077),
+QtPositioning.coordinate(59.778005 , 10.839019),
+QtPositioning.coordinate(59.777785 , 10.838958),
+QtPositioning.coordinate(59.77758 , 10.838898),
+QtPositioning.coordinate(59.777332 , 10.838807),
+QtPositioning.coordinate(59.777072 , 10.838694),
+QtPositioning.coordinate(59.776843 , 10.838578),
+QtPositioning.coordinate(59.776597 , 10.838446),
+QtPositioning.coordinate(59.776303 , 10.838273),
+// ]
+//}
+
+QtPositioning.coordinate(59.776041 , 10.838089),
+QtPositioning.coordinate(59.775846 , 10.837943),
+QtPositioning.coordinate(59.775561 , 10.83771),
+QtPositioning.coordinate(59.775348 , 10.837526),
+QtPositioning.coordinate(59.775136 , 10.837325),
+QtPositioning.coordinate(59.774852 , 10.837025),
+QtPositioning.coordinate(59.774718 , 10.836882),
+QtPositioning.coordinate(59.774483 , 10.836605),
+QtPositioning.coordinate(59.774307 , 10.836379),
+QtPositioning.coordinate(59.774127 , 10.836131),
+QtPositioning.coordinate(59.773988 , 10.835928),
+QtPositioning.coordinate(59.773846 , 10.835717),
+QtPositioning.coordinate(59.773687 , 10.835453),
+QtPositioning.coordinate(59.773567 , 10.835246),
+QtPositioning.coordinate(59.773446 , 10.835024),
+QtPositioning.coordinate(59.773313 , 10.834767),
+QtPositioning.coordinate(59.772471 , 10.833107),
+QtPositioning.coordinate(59.772089 , 10.832339),
+QtPositioning.coordinate(59.771388 , 10.830892),
+QtPositioning.coordinate(59.770914 , 10.829938),
+QtPositioning.coordinate(59.770176 , 10.828595),
+QtPositioning.coordinate(59.769659 , 10.827726),
+QtPositioning.coordinate(59.76954 , 10.827506),
+QtPositioning.coordinate(59.768741 , 10.826321),
+QtPositioning.coordinate(59.768025 , 10.825378),
+QtPositioning.coordinate(59.767289 , 10.824508),
+QtPositioning.coordinate(59.766532 , 10.823729),
+QtPositioning.coordinate(59.76587 , 10.823138),
+QtPositioning.coordinate(59.765075 , 10.822475),
+QtPositioning.coordinate(59.764287 , 10.821681),
+QtPositioning.coordinate(59.763728 , 10.82103),
+QtPositioning.coordinate(59.763066 , 10.820115),
+QtPositioning.coordinate(59.762396 , 10.819023),
+QtPositioning.coordinate(59.761839 , 10.817957),
+QtPositioning.coordinate(59.761036 , 10.816123),
+QtPositioning.coordinate(59.760412 , 10.814342),
+QtPositioning.coordinate(59.759846 , 10.812534),
+QtPositioning.coordinate(59.758922 , 10.809093),
+QtPositioning.coordinate(59.758313 , 10.806477),
+QtPositioning.coordinate(59.757838 , 10.804091),
+QtPositioning.coordinate(59.757484 , 10.802088),
+QtPositioning.coordinate(59.757214 , 10.800324),
+QtPositioning.coordinate(59.756992 , 10.798702),
+QtPositioning.coordinate(59.756742 , 10.796322),
+QtPositioning.coordinate(59.756495 , 10.793773),
+QtPositioning.coordinate(59.756279 , 10.792418),
+QtPositioning.coordinate(59.756091 , 10.79141),
+QtPositioning.coordinate(59.755857 , 10.790458),
+QtPositioning.coordinate(59.755515 , 10.789373),
+QtPositioning.coordinate(59.755145 , 10.788389),
+QtPositioning.coordinate(59.75459 , 10.787201),
+QtPositioning.coordinate(59.753911 , 10.786111),
+QtPositioning.coordinate(59.75333 , 10.785386),
+QtPositioning.coordinate(59.752754 , 10.784823),
+QtPositioning.coordinate(59.752202 , 10.784402),
+QtPositioning.coordinate(59.751873 , 10.784204),
+QtPositioning.coordinate(59.751664 , 10.784097),
+QtPositioning.coordinate(59.751504 , 10.784022),
+QtPositioning.coordinate(59.751304 , 10.783944),
+QtPositioning.coordinate(59.751028 , 10.783821),
+QtPositioning.coordinate(59.750714 , 10.783752),
+QtPositioning.coordinate(59.75033 , 10.78367),
+QtPositioning.coordinate(59.748989 , 10.783415),
+QtPositioning.coordinate(59.747655 , 10.783122),
+QtPositioning.coordinate(59.74693 , 10.782929),
+QtPositioning.coordinate(59.746206 , 10.782727),
+QtPositioning.coordinate(59.744685 , 10.782276),
+QtPositioning.coordinate(59.74425 , 10.78213),
+QtPositioning.coordinate(59.743824 , 10.781956),
+QtPositioning.coordinate(59.743401 , 10.781761),
+QtPositioning.coordinate(59.74311 , 10.781611),
+QtPositioning.coordinate(59.742754 , 10.781398),
+QtPositioning.coordinate(59.74249 , 10.781216),
+QtPositioning.coordinate(59.742172 , 10.780963),
+QtPositioning.coordinate(59.741829 , 10.780644),
+QtPositioning.coordinate(59.741482 , 10.780265),
+QtPositioning.coordinate(59.741152 , 10.779852),
+QtPositioning.coordinate(59.74073 , 10.779237),
+QtPositioning.coordinate(59.740526 , 10.778905),
+QtPositioning.coordinate(59.740163 , 10.778258),
+QtPositioning.coordinate(59.739584 , 10.777213),
+QtPositioning.coordinate(59.73914 , 10.776419),
+QtPositioning.coordinate(59.738999 , 10.776194),
+QtPositioning.coordinate(59.737899 , 10.774618),
+QtPositioning.coordinate(59.736486 , 10.772806),
+QtPositioning.coordinate(59.734326 , 10.770223),
+QtPositioning.coordinate(59.728648 , 10.763414),
+QtPositioning.coordinate(59.722882 , 10.756501),
+QtPositioning.coordinate(59.720443 , 10.753412),
+QtPositioning.coordinate(59.718896 , 10.750987),
+QtPositioning.coordinate(59.717462 , 10.748409),
+QtPositioning.coordinate(59.714967 , 10.74338),
+QtPositioning.coordinate(59.713936 , 10.741336),
+QtPositioning.coordinate(59.713288 , 10.740235),
+QtPositioning.coordinate(59.712707 , 10.739484),
+QtPositioning.coordinate(59.711921 , 10.738707),
+QtPositioning.coordinate(59.71162 , 10.738484),
+QtPositioning.coordinate(59.711272 , 10.738277),
+QtPositioning.coordinate(59.710622 , 10.737963),
+QtPositioning.coordinate(59.710393 , 10.73787),
+QtPositioning.coordinate(59.710151 , 10.737793),
+QtPositioning.coordinate(59.709891 , 10.737717),
+QtPositioning.coordinate(59.709674 , 10.737662),
+QtPositioning.coordinate(59.709431 , 10.737637),
+QtPositioning.coordinate(59.709169 , 10.737621),
+QtPositioning.coordinate(59.70891 , 10.73762),
+QtPositioning.coordinate(59.708672 , 10.737628),
+QtPositioning.coordinate(59.70797 , 10.737651),
+QtPositioning.coordinate(59.707499 , 10.737672),
+QtPositioning.coordinate(59.707164 , 10.737682),
+QtPositioning.coordinate(59.706869 , 10.737689),
+QtPositioning.coordinate(59.706182 , 10.737694),
+QtPositioning.coordinate(59.705622 , 10.737672),
+QtPositioning.coordinate(59.704927 , 10.737634),
+QtPositioning.coordinate(59.704647 , 10.737572),
+QtPositioning.coordinate(59.704267 , 10.737489),
+QtPositioning.coordinate(59.70352 , 10.737222),
+QtPositioning.coordinate(59.70247 , 10.736836),
+QtPositioning.coordinate(59.700965 , 10.736172),
+QtPositioning.coordinate(59.699499 , 10.735486),
+QtPositioning.coordinate(59.698051 , 10.734779),
+QtPositioning.coordinate(59.696866 , 10.734277),
+QtPositioning.coordinate(59.695423 , 10.733635),
+QtPositioning.coordinate(59.695115 , 10.733527),
+QtPositioning.coordinate(59.694808 , 10.733423),
+QtPositioning.coordinate(59.694493 , 10.733339),
+QtPositioning.coordinate(59.694277 , 10.733293),
+QtPositioning.coordinate(59.693959 , 10.733238),
+QtPositioning.coordinate(59.693608 , 10.733211),
+QtPositioning.coordinate(59.693307 , 10.733205),
+QtPositioning.coordinate(59.692987 , 10.733211),
+QtPositioning.coordinate(59.692667 , 10.733244),
+QtPositioning.coordinate(59.692306 , 10.733305),
+QtPositioning.coordinate(59.691904 , 10.733404),
+QtPositioning.coordinate(59.6915 , 10.733531),
+QtPositioning.coordinate(59.691047 , 10.733721),
+QtPositioning.coordinate(59.690659 , 10.733919),
+QtPositioning.coordinate(59.690246 , 10.734164),
+QtPositioning.coordinate(59.689799 , 10.734473),
+QtPositioning.coordinate(59.68939 , 10.734797),
+QtPositioning.coordinate(59.688529 , 10.735462),
+QtPositioning.coordinate(59.687942 , 10.735906),
+QtPositioning.coordinate(59.68743 , 10.736266),
+QtPositioning.coordinate(59.68707 , 10.736486),
+QtPositioning.coordinate(59.686736 , 10.736669),
+QtPositioning.coordinate(59.686328 , 10.736877),
+QtPositioning.coordinate(59.685852 , 10.737094),
+QtPositioning.coordinate(59.68508 , 10.737427),
+QtPositioning.coordinate(59.684441 , 10.737747),
+QtPositioning.coordinate(59.683692 , 10.738225),
+QtPositioning.coordinate(59.683126 , 10.738658),
+QtPositioning.coordinate(59.681637 , 10.739956),
+QtPositioning.coordinate(59.68115 , 10.740317),
+QtPositioning.coordinate(59.680601 , 10.74066),
+QtPositioning.coordinate(59.679978 , 10.740968),
+QtPositioning.coordinate(59.67937 , 10.741184),
+QtPositioning.coordinate(59.678722 , 10.741337),
+QtPositioning.coordinate(59.677873 , 10.741455),
+QtPositioning.coordinate(59.677167 , 10.741584),
+QtPositioning.coordinate(59.676584 , 10.741757),
+QtPositioning.coordinate(59.675511 , 10.742175),
+QtPositioning.coordinate(59.672366 , 10.743603),
+QtPositioning.coordinate(59.671453 , 10.744012),
+QtPositioning.coordinate(59.670853 , 10.744254),
+QtPositioning.coordinate(59.670172 , 10.744493),
+QtPositioning.coordinate(59.669224 , 10.744769),
+QtPositioning.coordinate(59.668216 , 10.744989),
+QtPositioning.coordinate(59.667134 , 10.745137),
+QtPositioning.coordinate(59.665693 , 10.745263),
+QtPositioning.coordinate(59.665282 , 10.745269),
+QtPositioning.coordinate(59.66449 , 10.745311),
+QtPositioning.coordinate(59.664004 , 10.745329),
+QtPositioning.coordinate(59.663722 , 10.745322),
+QtPositioning.coordinate(59.663426 , 10.745293),
+QtPositioning.coordinate(59.662943 , 10.745237),
+QtPositioning.coordinate(59.662478 , 10.745145),
+QtPositioning.coordinate(59.661967 , 10.745005),
+QtPositioning.coordinate(59.661421 , 10.744819),
+QtPositioning.coordinate(59.660845 , 10.744578),
+QtPositioning.coordinate(59.659841 , 10.744045),
+QtPositioning.coordinate(59.659148 , 10.743693),
+QtPositioning.coordinate(59.657001 , 10.742578),
+QtPositioning.coordinate(59.656328 , 10.742249),
+QtPositioning.coordinate(59.655497 , 10.741897),
+QtPositioning.coordinate(59.654655 , 10.741605),
+QtPositioning.coordinate(59.65345 , 10.741256),
+QtPositioning.coordinate(59.652528 , 10.74108),
+QtPositioning.coordinate(59.651341 , 10.740879),
+QtPositioning.coordinate(59.650534 , 10.740756),
+QtPositioning.coordinate(59.648305 , 10.740401),
+QtPositioning.coordinate(59.647356 , 10.740257),
+QtPositioning.coordinate(59.646346 , 10.740096),
+QtPositioning.coordinate(59.644787 , 10.739886),
+QtPositioning.coordinate(59.643438 , 10.739709),
+QtPositioning.coordinate(59.642001 , 10.739492),
+QtPositioning.coordinate(59.6389 , 10.738976),
+QtPositioning.coordinate(59.636627 , 10.738608),
+QtPositioning.coordinate(59.635585 , 10.738448),
+QtPositioning.coordinate(59.634621 , 10.738274),
+QtPositioning.coordinate(59.633977 , 10.738119),
+QtPositioning.coordinate(59.633244 , 10.73791),
+QtPositioning.coordinate(59.632583 , 10.737683),
+QtPositioning.coordinate(59.631881 , 10.737404),
+QtPositioning.coordinate(59.631162 , 10.737084),
+QtPositioning.coordinate(59.630345 , 10.736668),
+QtPositioning.coordinate(59.629544 , 10.736213),
+QtPositioning.coordinate(59.62878 , 10.735766),
+QtPositioning.coordinate(59.627978 , 10.735321),
+QtPositioning.coordinate(59.627188 , 10.734907),
+QtPositioning.coordinate(59.626717 , 10.734679),
+QtPositioning.coordinate(59.626162 , 10.734421),
+QtPositioning.coordinate(59.625692 , 10.734217),
+QtPositioning.coordinate(59.62524 , 10.73403),
+QtPositioning.coordinate(59.624844 , 10.733879),
+QtPositioning.coordinate(59.624466 , 10.733741),
+QtPositioning.coordinate(59.624175 , 10.733633),
+QtPositioning.coordinate(59.623931 , 10.733552),
+QtPositioning.coordinate(59.623552 , 10.733432),
+QtPositioning.coordinate(59.623043 , 10.733274),
+QtPositioning.coordinate(59.622691 , 10.733177),
+QtPositioning.coordinate(59.622365 , 10.733102),
+QtPositioning.coordinate(59.62176 , 10.732949),
+QtPositioning.coordinate(59.620673 , 10.732729),
+QtPositioning.coordinate(59.620025 , 10.732636),
+QtPositioning.coordinate(59.619257 , 10.73254),
+QtPositioning.coordinate(59.617039 , 10.73228),
+QtPositioning.coordinate(59.615695 , 10.732135),
+QtPositioning.coordinate(59.615051 , 10.732081),
+QtPositioning.coordinate(59.614428 , 10.732088),
+QtPositioning.coordinate(59.613824 , 10.732113),
+QtPositioning.coordinate(59.613288 , 10.732179),
+QtPositioning.coordinate(59.612572 , 10.732333),
+QtPositioning.coordinate(59.61182 , 10.732553),
+QtPositioning.coordinate(59.611016 , 10.732889),
+QtPositioning.coordinate(59.610222 , 10.733294),
+QtPositioning.coordinate(59.607872 , 10.734665),
+QtPositioning.coordinate(59.605527 , 10.736078),
+QtPositioning.coordinate(59.604913 , 10.736445),
+QtPositioning.coordinate(59.604441 , 10.736714),
+QtPositioning.coordinate(59.603993 , 10.736965),
+QtPositioning.coordinate(59.603779 , 10.737076),
+QtPositioning.coordinate(59.603524 , 10.737204),
+QtPositioning.coordinate(59.603224 , 10.737351),
+QtPositioning.coordinate(59.602697 , 10.737587),
+QtPositioning.coordinate(59.602291 , 10.737752),
+QtPositioning.coordinate(59.602035 , 10.737853),
+QtPositioning.coordinate(59.601763 , 10.737954),
+QtPositioning.coordinate(59.60135 , 10.738093),
+QtPositioning.coordinate(59.601126 , 10.738165),
+QtPositioning.coordinate(59.600892 , 10.738234),
+QtPositioning.coordinate(59.60043 , 10.738359),
+QtPositioning.coordinate(59.599587 , 10.738534),
+QtPositioning.coordinate(59.599057 , 10.738628),
+QtPositioning.coordinate(59.59832 , 10.738723),
+QtPositioning.coordinate(59.597703 , 10.738781),
+QtPositioning.coordinate(59.596844 , 10.738822),
+QtPositioning.coordinate(59.596069 , 10.73881),
+QtPositioning.coordinate(59.595235 , 10.738775),
+QtPositioning.coordinate(59.594532 , 10.738718),
+QtPositioning.coordinate(59.593712 , 10.738577),
+QtPositioning.coordinate(59.59309 , 10.738435),
+QtPositioning.coordinate(59.592384 , 10.738209),
+QtPositioning.coordinate(59.591689 , 10.737929),
+QtPositioning.coordinate(59.590914 , 10.737549),
+QtPositioning.coordinate(59.590254 , 10.737194),
+QtPositioning.coordinate(59.58843 , 10.73605),
+QtPositioning.coordinate(59.586256 , 10.734667),
+QtPositioning.coordinate(59.584531 , 10.733577),
+QtPositioning.coordinate(59.582972 , 10.7326),
+QtPositioning.coordinate(59.581641 , 10.731724),
+QtPositioning.coordinate(59.581641 , 10.731716),
+QtPositioning.coordinate(59.580821 , 10.73114),
+QtPositioning.coordinate(59.580119 , 10.730608),
+QtPositioning.coordinate(59.579163 , 10.729839),
+QtPositioning.coordinate(59.577343 , 10.728355),
+QtPositioning.coordinate(59.574432 , 10.725955),
+QtPositioning.coordinate(59.573061 , 10.724826),
+QtPositioning.coordinate(59.572136 , 10.724083),
+QtPositioning.coordinate(59.571252 , 10.723428),
+QtPositioning.coordinate(59.570367 , 10.722872),
+QtPositioning.coordinate(59.569607 , 10.722445),
+QtPositioning.coordinate(59.568799 , 10.722065),
+QtPositioning.coordinate(59.567919 , 10.721714),
+QtPositioning.coordinate(59.566937 , 10.72139),
+QtPositioning.coordinate(59.565976 , 10.721158),
+QtPositioning.coordinate(59.564962 , 10.720983),
+QtPositioning.coordinate(59.56378 , 10.720863),
+QtPositioning.coordinate(59.561752 , 10.720817),
+QtPositioning.coordinate(59.560993 , 10.720853),
+QtPositioning.coordinate(59.560027 , 10.720927),
+QtPositioning.coordinate(59.559095 , 10.721029),
+QtPositioning.coordinate(59.55843 , 10.72112),
+QtPositioning.coordinate(59.55702 , 10.721345),
+QtPositioning.coordinate(59.555284 , 10.721667),
+QtPositioning.coordinate(59.551796 , 10.722356),
+QtPositioning.coordinate(59.548534 , 10.723113),
+QtPositioning.coordinate(59.546511 , 10.723637),
+QtPositioning.coordinate(59.545377 , 10.723984),
+QtPositioning.coordinate(59.544084 , 10.724418),
+QtPositioning.coordinate(59.540744 , 10.725734),
+QtPositioning.coordinate(59.538322 , 10.726726),
+QtPositioning.coordinate(59.536953 , 10.727335),
+QtPositioning.coordinate(59.535977 , 10.727742),
+QtPositioning.coordinate(59.535281 , 10.728018),
+QtPositioning.coordinate(59.533682 , 10.728673),
+QtPositioning.coordinate(59.532059 , 10.729205),
+QtPositioning.coordinate(59.531043 , 10.72948),
+QtPositioning.coordinate(59.529767 , 10.729693),
+QtPositioning.coordinate(59.52858 , 10.729755),
+QtPositioning.coordinate(59.527353 , 10.729661),
+QtPositioning.coordinate(59.526474 , 10.729543),
+QtPositioning.coordinate(59.525548 , 10.729392),
+QtPositioning.coordinate(59.524709 , 10.729195),
+QtPositioning.coordinate(59.523805 , 10.728921),
+QtPositioning.coordinate(59.522979 , 10.728609),
+QtPositioning.coordinate(59.522125 , 10.728238),
+QtPositioning.coordinate(59.521299 , 10.727809),
+QtPositioning.coordinate(59.520281 , 10.727225),
+QtPositioning.coordinate(59.517777 , 10.725523),
+QtPositioning.coordinate(59.515247 , 10.723709),
+QtPositioning.coordinate(59.513062 , 10.722178),
+QtPositioning.coordinate(59.512082 , 10.7215),
+QtPositioning.coordinate(59.510986 , 10.720829),
+QtPositioning.coordinate(59.510039 , 10.720362),
+QtPositioning.coordinate(59.509661 , 10.720214),
+QtPositioning.coordinate(59.509265 , 10.720074),
+QtPositioning.coordinate(59.508874 , 10.719964),
+QtPositioning.coordinate(59.508556 , 10.719879),
+QtPositioning.coordinate(59.508198 , 10.719803),
+QtPositioning.coordinate(59.507688 , 10.719721),
+QtPositioning.coordinate(59.507081 , 10.719636),
+QtPositioning.coordinate(59.504765 , 10.719271),
+QtPositioning.coordinate(59.503785 , 10.718965),
+QtPositioning.coordinate(59.503298 , 10.718772),
+QtPositioning.coordinate(59.502594 , 10.718439),
+QtPositioning.coordinate(59.501909 , 10.718021),
+QtPositioning.coordinate(59.501209 , 10.717519),
+QtPositioning.coordinate(59.499508 , 10.716144),
+QtPositioning.coordinate(59.497858 , 10.714788),
+QtPositioning.coordinate(59.497134 , 10.714245),
+QtPositioning.coordinate(59.496366 , 10.713724),
+QtPositioning.coordinate(59.495665 , 10.713325),
+QtPositioning.coordinate(59.494976 , 10.712982),
+QtPositioning.coordinate(59.493395 , 10.71224),
+QtPositioning.coordinate(59.491795 , 10.711527),
+QtPositioning.coordinate(59.490621 , 10.710914),
+QtPositioning.coordinate(59.489732 , 10.710317),
+QtPositioning.coordinate(59.489372 , 10.710048),
+QtPositioning.coordinate(59.489242 , 10.709962),
+QtPositioning.coordinate(59.488955 , 10.709742),
+QtPositioning.coordinate(59.488296 , 10.709214),
+QtPositioning.coordinate(59.485682 , 10.707057),
+QtPositioning.coordinate(59.484391 , 10.705992),
+QtPositioning.coordinate(59.48343 , 10.705216),
+QtPositioning.coordinate(59.483021 , 10.704909),
+QtPositioning.coordinate(59.482567 , 10.704607),
+QtPositioning.coordinate(59.482271 , 10.704428),
+QtPositioning.coordinate(59.481823 , 10.704187),
+QtPositioning.coordinate(59.481387 , 10.703979),
+QtPositioning.coordinate(59.480969 , 10.703804),
+QtPositioning.coordinate(59.480305 , 10.70356),
+QtPositioning.coordinate(59.479807 , 10.7034),
+QtPositioning.coordinate(59.47878 , 10.703104),
+QtPositioning.coordinate(59.470568 , 10.700837),
+QtPositioning.coordinate(59.470542 , 10.700831),
+QtPositioning.coordinate(59.470345 , 10.700776),
+QtPositioning.coordinate(59.470288 , 10.70076),
+QtPositioning.coordinate(59.466285 , 10.699662),
+QtPositioning.coordinate(59.465683 , 10.699486),
+QtPositioning.coordinate(59.46501 , 10.699246),
+QtPositioning.coordinate(59.463547 , 10.698643),
+QtPositioning.coordinate(59.463 , 10.698452),
+QtPositioning.coordinate(59.462445 , 10.698323),
+QtPositioning.coordinate(59.461977 , 10.698267),
+QtPositioning.coordinate(59.461453 , 10.69827),
+QtPositioning.coordinate(59.461073 , 10.69831),
+QtPositioning.coordinate(59.46068 , 10.698392),
+QtPositioning.coordinate(59.46024 , 10.698531),
+QtPositioning.coordinate(59.459939 , 10.698658),
+QtPositioning.coordinate(59.459566 , 10.698842),
+QtPositioning.coordinate(59.457362 , 10.700069),
+QtPositioning.coordinate(59.45696 , 10.70027),
+QtPositioning.coordinate(59.45667 , 10.700395),
+QtPositioning.coordinate(59.456341 , 10.700513),
+QtPositioning.coordinate(59.456049 , 10.700596),
+QtPositioning.coordinate(59.455626 , 10.700682),
+QtPositioning.coordinate(59.455227 , 10.700728),
+QtPositioning.coordinate(59.454798 , 10.700738),
+QtPositioning.coordinate(59.454427 , 10.700713),
+QtPositioning.coordinate(59.454019 , 10.700651),
+QtPositioning.coordinate(59.453493 , 10.700517),
+QtPositioning.coordinate(59.453105 , 10.700377),
+QtPositioning.coordinate(59.452671 , 10.700191),
+QtPositioning.coordinate(59.452095 , 10.699913),
+QtPositioning.coordinate(59.452066 , 10.699899),
+QtPositioning.coordinate(59.451809 , 10.699769),
+QtPositioning.coordinate(59.451795 , 10.699762),
+QtPositioning.coordinate(59.451251 , 10.699492),
+QtPositioning.coordinate(59.450795 , 10.699292),
+QtPositioning.coordinate(59.450392 , 10.69915),
+QtPositioning.coordinate(59.450109 , 10.69908),
+QtPositioning.coordinate(59.449694 , 10.699016),
+QtPositioning.coordinate(59.449309 , 10.698999),
+QtPositioning.coordinate(59.448994 , 10.699016),
+QtPositioning.coordinate(59.448631 , 10.699075),
+QtPositioning.coordinate(59.44836 , 10.699136),
+QtPositioning.coordinate(59.44814 , 10.69921),
+QtPositioning.coordinate(59.447978 , 10.699267),
+QtPositioning.coordinate(59.447812 , 10.699328),
+QtPositioning.coordinate(59.447567 , 10.699445),
+QtPositioning.coordinate(59.447369 , 10.699554),
+QtPositioning.coordinate(59.447185 , 10.699668),
+QtPositioning.coordinate(59.447057 , 10.699752),
+QtPositioning.coordinate(59.446832 , 10.699905),
+QtPositioning.coordinate(59.446642 , 10.700055),
+QtPositioning.coordinate(59.446478 , 10.700188),
+QtPositioning.coordinate(59.446211 , 10.700419),
+QtPositioning.coordinate(59.446027 , 10.700594),
+QtPositioning.coordinate(59.44586 , 10.700747),
+QtPositioning.coordinate(59.445686 , 10.700926),
+QtPositioning.coordinate(59.445594 , 10.701022),
+QtPositioning.coordinate(59.445233 , 10.701401),
+QtPositioning.coordinate(59.445136 , 10.701502),
+QtPositioning.coordinate(59.444553 , 10.702143),
+QtPositioning.coordinate(59.443797 , 10.702982),
+QtPositioning.coordinate(59.443484 , 10.703327),
+QtPositioning.coordinate(59.44315 , 10.703682),
+QtPositioning.coordinate(59.442913 , 10.703915),
+QtPositioning.coordinate(59.442688 , 10.704128),
+QtPositioning.coordinate(59.442516 , 10.70429),
+QtPositioning.coordinate(59.442287 , 10.704484),
+QtPositioning.coordinate(59.44203 , 10.704692),
+QtPositioning.coordinate(59.441785 , 10.704878),
+QtPositioning.coordinate(59.441588 , 10.705014),
+QtPositioning.coordinate(59.441382 , 10.705148),
+QtPositioning.coordinate(59.441168 , 10.705279),
+QtPositioning.coordinate(59.440914 , 10.705418),
+QtPositioning.coordinate(59.440596 , 10.705577),
+QtPositioning.coordinate(59.440385 , 10.705677),
+QtPositioning.coordinate(59.440073 , 10.7058),
+QtPositioning.coordinate(59.439708 , 10.705922),
+QtPositioning.coordinate(59.439162 , 10.706058),
+QtPositioning.coordinate(59.438647 , 10.706135),
+QtPositioning.coordinate(59.438212 , 10.706158),
+QtPositioning.coordinate(59.437728 , 10.706148),
+QtPositioning.coordinate(59.437149 , 10.706088),
+QtPositioning.coordinate(59.436373 , 10.705945),
+QtPositioning.coordinate(59.434111 , 10.705398),
+QtPositioning.coordinate(59.43351 , 10.705283),
+QtPositioning.coordinate(59.433351 , 10.705262),
+QtPositioning.coordinate(59.433306 , 10.705256),
+QtPositioning.coordinate(59.433256 , 10.705252),
+QtPositioning.coordinate(59.432689 , 10.705224),
+QtPositioning.coordinate(59.43228 , 10.705241),
+QtPositioning.coordinate(59.431825 , 10.705293),
+QtPositioning.coordinate(59.431285 , 10.705391),
+QtPositioning.coordinate(59.430735 , 10.705527),
+QtPositioning.coordinate(59.430206 , 10.705681),
+QtPositioning.coordinate(59.428506 , 10.706224),
+QtPositioning.coordinate(59.428268 , 10.706301),
+QtPositioning.coordinate(59.427801 , 10.706429),
+QtPositioning.coordinate(59.426719 , 10.706789),
+QtPositioning.coordinate(59.426055 , 10.707006),
+QtPositioning.coordinate(59.425352 , 10.707179),
+QtPositioning.coordinate(59.424996 , 10.707225),
+QtPositioning.coordinate(59.424806 , 10.707235),
+QtPositioning.coordinate(59.424227 , 10.707222),
+QtPositioning.coordinate(59.423893 , 10.707188),
+QtPositioning.coordinate(59.423314 , 10.707063),
+QtPositioning.coordinate(59.422802 , 10.706886),
+QtPositioning.coordinate(59.422457 , 10.706735),
+QtPositioning.coordinate(59.422001 , 10.706495),
+QtPositioning.coordinate(59.421296 , 10.706027),
+QtPositioning.coordinate(59.42043 , 10.705327),
+QtPositioning.coordinate(59.420178 , 10.705128),
+QtPositioning.coordinate(59.41991 , 10.704918),
+QtPositioning.coordinate(59.417853 , 10.703269),
+QtPositioning.coordinate(59.416819 , 10.702443),
+QtPositioning.coordinate(59.4166 , 10.702279),
+QtPositioning.coordinate(59.414421 , 10.700532),
+QtPositioning.coordinate(59.413832 , 10.700122),
+QtPositioning.coordinate(59.413543 , 10.699951),
+QtPositioning.coordinate(59.413277 , 10.699823),
+QtPositioning.coordinate(59.412988 , 10.699713),
+QtPositioning.coordinate(59.412803 , 10.699662),
+QtPositioning.coordinate(59.41258 , 10.699609),
+QtPositioning.coordinate(59.41217 , 10.699571),
+QtPositioning.coordinate(59.411851 , 10.699591),
+QtPositioning.coordinate(59.411446 , 10.699668),
+QtPositioning.coordinate(59.411113 , 10.699777),
+QtPositioning.coordinate(59.4109 , 10.699864),
+QtPositioning.coordinate(59.410583 , 10.700036),
+QtPositioning.coordinate(59.410368 , 10.700174),
+QtPositioning.coordinate(59.410117 , 10.700366),
+QtPositioning.coordinate(59.40986 , 10.700584),
+QtPositioning.coordinate(59.409505 , 10.700952),
+QtPositioning.coordinate(59.409183 , 10.701345),
+QtPositioning.coordinate(59.408973 , 10.701623),
+QtPositioning.coordinate(59.408854 , 10.701797),
+QtPositioning.coordinate(59.408374 , 10.702611),
+QtPositioning.coordinate(59.408031 , 10.703337),
+QtPositioning.coordinate(59.407856 , 10.703769),
+QtPositioning.coordinate(59.407666 , 10.704276),
+QtPositioning.coordinate(59.407226 , 10.705638),
+QtPositioning.coordinate(59.407098 , 10.706047),
+QtPositioning.coordinate(59.406309 , 10.70859),
+QtPositioning.coordinate(59.405253 , 10.711935),
+QtPositioning.coordinate(59.404799 , 10.713434),
+QtPositioning.coordinate(59.404338 , 10.714872),
+QtPositioning.coordinate(59.402475 , 10.720837),
+QtPositioning.coordinate(59.402127 , 10.721894),
+QtPositioning.coordinate(59.401963 , 10.722354),
+QtPositioning.coordinate(59.401669 , 10.723112),
+QtPositioning.coordinate(59.401412 , 10.723703),
+QtPositioning.coordinate(59.400985 , 10.724571),
+QtPositioning.coordinate(59.400733 , 10.725051),
+QtPositioning.coordinate(59.400551 , 10.725367),
+QtPositioning.coordinate(59.400087 , 10.726099),
+QtPositioning.coordinate(59.393218 , 10.736374),
+QtPositioning.coordinate(59.392733 , 10.737123),
+QtPositioning.coordinate(59.392026 , 10.738271),
+QtPositioning.coordinate(59.391327 , 10.739474),
+QtPositioning.coordinate(59.390544 , 10.740885),
+QtPositioning.coordinate(59.390223 , 10.741485),
+QtPositioning.coordinate(59.389168 , 10.743599),
+QtPositioning.coordinate(59.388476 , 10.745094),
+QtPositioning.coordinate(59.387732 , 10.746796),
+QtPositioning.coordinate(59.387379 , 10.747637),
+QtPositioning.coordinate(59.386823 , 10.749024),
+QtPositioning.coordinate(59.385394 , 10.752642),
+QtPositioning.coordinate(59.385057 , 10.75346),
+QtPositioning.coordinate(59.384881 , 10.753858),
+QtPositioning.coordinate(59.384641 , 10.754373),
+QtPositioning.coordinate(59.38439 , 10.754874),
+QtPositioning.coordinate(59.383894 , 10.755806),
+QtPositioning.coordinate(59.381953 , 10.759547),
+QtPositioning.coordinate(59.381575 , 10.760306),
+QtPositioning.coordinate(59.380941 , 10.761649),
+QtPositioning.coordinate(59.38049 , 10.762664),
+QtPositioning.coordinate(59.380027 , 10.763763),
+QtPositioning.coordinate(59.379599 , 10.764879),
+QtPositioning.coordinate(59.379183 , 10.76603),
+QtPositioning.coordinate(59.378739 , 10.767359),
+QtPositioning.coordinate(59.378503 , 10.768109),
+QtPositioning.coordinate(59.378232 , 10.769026),
+QtPositioning.coordinate(59.377971 , 10.769948),
+QtPositioning.coordinate(59.37772 , 10.770885),
+QtPositioning.coordinate(59.374226 , 10.784406),
+QtPositioning.coordinate(59.373469 , 10.787366),
+QtPositioning.coordinate(59.373125 , 10.788801),
+QtPositioning.coordinate(59.372831 , 10.790088),
+QtPositioning.coordinate(59.372585 , 10.791222),
+QtPositioning.coordinate(59.372216 , 10.793019),
+QtPositioning.coordinate(59.371155 , 10.798628),
+QtPositioning.coordinate(59.370764 , 10.800592),
+QtPositioning.coordinate(59.370452 , 10.802049),
+QtPositioning.coordinate(59.370123 , 10.803492),
+QtPositioning.coordinate(59.369739 , 10.805079),
+QtPositioning.coordinate(59.369377 , 10.806491),
+QtPositioning.coordinate(59.365535 , 10.820654),
+QtPositioning.coordinate(59.365285 , 10.821543),
+QtPositioning.coordinate(59.365105 , 10.822148),
+QtPositioning.coordinate(59.36468 , 10.823488),
+QtPositioning.coordinate(59.364224 , 10.824791),
+QtPositioning.coordinate(59.363971 , 10.825469),
+QtPositioning.coordinate(59.36232 , 10.829771),
+QtPositioning.coordinate(59.362288 , 10.829854),
+QtPositioning.coordinate(59.360509 , 10.834497),
+QtPositioning.coordinate(59.360144 , 10.835503),
+QtPositioning.coordinate(59.359842 , 10.836379),
+QtPositioning.coordinate(59.359456 , 10.837569),
+QtPositioning.coordinate(59.359134 , 10.838628),
+QtPositioning.coordinate(59.358825 , 10.839705),
+QtPositioning.coordinate(59.358783 , 10.83986),
+QtPositioning.coordinate(59.358748 , 10.839988),
+QtPositioning.coordinate(59.358321 , 10.841617),
+QtPositioning.coordinate(59.358102 , 10.842543),
+QtPositioning.coordinate(59.357848 , 10.843673),
+QtPositioning.coordinate(59.35761 , 10.844815),
+QtPositioning.coordinate(59.357387 , 10.845969),
+QtPositioning.coordinate(59.357125 , 10.847468),
+QtPositioning.coordinate(59.356939 , 10.848648),
+QtPositioning.coordinate(59.356746 , 10.850007),
+QtPositioning.coordinate(59.356595 , 10.851205),
+QtPositioning.coordinate(59.356443 , 10.852583),
+QtPositioning.coordinate(59.356327 , 10.853795),
+QtPositioning.coordinate(59.356241 , 10.854839),
+QtPositioning.coordinate(59.356092 , 10.857009),
+QtPositioning.coordinate(59.355365 , 10.868447),
+QtPositioning.coordinate(59.355264 , 10.869835),
+QtPositioning.coordinate(59.355257 , 10.869922),
+QtPositioning.coordinate(59.355216 , 10.87039),
+QtPositioning.coordinate(59.355105 , 10.87156),
+QtPositioning.coordinate(59.355022 , 10.872331),
+QtPositioning.coordinate(59.35491 , 10.873273),
+QtPositioning.coordinate(59.354777 , 10.874289),
+QtPositioning.coordinate(59.354655 , 10.875135),
+QtPositioning.coordinate(59.354497 , 10.876138),
+QtPositioning.coordinate(59.354385 , 10.876807),
+QtPositioning.coordinate(59.354176 , 10.877963),
+QtPositioning.coordinate(59.353917 , 10.879271),
+QtPositioning.coordinate(59.353602 , 10.880723),
+QtPositioning.coordinate(59.353271 , 10.882163),
+QtPositioning.coordinate(59.352291 , 10.886313),
+QtPositioning.coordinate(59.351963 , 10.887763),
+QtPositioning.coordinate(59.351753 , 10.888734),
+QtPositioning.coordinate(59.351383 , 10.89053),
+QtPositioning.coordinate(59.351097 , 10.89201),
+QtPositioning.coordinate(59.350794 , 10.893669),
+QtPositioning.coordinate(59.350536 , 10.89517),
+QtPositioning.coordinate(59.350153 , 10.897597),
+QtPositioning.coordinate(59.349967 , 10.898878),
+QtPositioning.coordinate(59.349737 , 10.90058),
+QtPositioning.coordinate(59.349524 , 10.902289),
+QtPositioning.coordinate(59.348564 , 10.910589),
+QtPositioning.coordinate(59.34842 , 10.911709),
+QtPositioning.coordinate(59.348247 , 10.912886),
+QtPositioning.coordinate(59.348024 , 10.914218),
+QtPositioning.coordinate(59.347857 , 10.915116),
+QtPositioning.coordinate(59.347721 , 10.91579),
+QtPositioning.coordinate(59.347556 , 10.916569),
+QtPositioning.coordinate(59.347349 , 10.917449),
+QtPositioning.coordinate(59.347149 , 10.918256),
+QtPositioning.coordinate(59.34684 , 10.919416),
+QtPositioning.coordinate(59.346536 , 10.920463),
+QtPositioning.coordinate(59.346391 , 10.920931),
+QtPositioning.coordinate(59.346033 , 10.922003),
+QtPositioning.coordinate(59.345796 , 10.922711),
+QtPositioning.coordinate(59.345435 , 10.923713),
+QtPositioning.coordinate(59.345268 , 10.924144),
+QtPositioning.coordinate(59.345025 , 10.924729),
+QtPositioning.coordinate(59.344871 , 10.925025),
+QtPositioning.coordinate(59.344503 , 10.92579),
+QtPositioning.coordinate(59.344216 , 10.92632),
+QtPositioning.coordinate(59.343909 , 10.926848),
+QtPositioning.coordinate(59.343575 , 10.927382),
+QtPositioning.coordinate(59.343215 , 10.927923),
+QtPositioning.coordinate(59.342822 , 10.928475),
+QtPositioning.coordinate(59.342406 , 10.929028),
+QtPositioning.coordinate(59.341982 , 10.929556),
+QtPositioning.coordinate(59.34155 , 10.930062),
+QtPositioning.coordinate(59.341113 , 10.930542),
+QtPositioning.coordinate(59.340666 , 10.931),
+QtPositioning.coordinate(59.340215 , 10.931431),
+QtPositioning.coordinate(59.339758 , 10.93184),
+QtPositioning.coordinate(59.339129 , 10.932358),
+QtPositioning.coordinate(59.338425 , 10.932909),
+QtPositioning.coordinate(59.337715 , 10.933433),
+QtPositioning.coordinate(59.337 , 10.933931),
+QtPositioning.coordinate(59.336281 , 10.934403),
+QtPositioning.coordinate(59.335558 , 10.934848),
+QtPositioning.coordinate(59.33483 , 10.935267),
+QtPositioning.coordinate(59.334098 , 10.93566),
+QtPositioning.coordinate(59.333363 , 10.936024),
+QtPositioning.coordinate(59.332625 , 10.936362),
+QtPositioning.coordinate(59.331883 , 10.936672),
+QtPositioning.coordinate(59.329827 , 10.937467),
+QtPositioning.coordinate(59.329336 , 10.93768),
+QtPositioning.coordinate(59.328788 , 10.937968),
+QtPositioning.coordinate(59.328588 , 10.938084),
+QtPositioning.coordinate(59.328273 , 10.938293),
+QtPositioning.coordinate(59.327985 , 10.938515),
+QtPositioning.coordinate(59.327719 , 10.938748),
+QtPositioning.coordinate(59.32747 , 10.938994),
+QtPositioning.coordinate(59.327229 , 10.939265),
+QtPositioning.coordinate(59.326995 , 10.939559),
+QtPositioning.coordinate(59.326768 , 10.939875),
+QtPositioning.coordinate(59.32655 , 10.940214),
+QtPositioning.coordinate(59.326341 , 10.940573),
+QtPositioning.coordinate(59.326142 , 10.940953),
+QtPositioning.coordinate(59.325953 , 10.941352),
+QtPositioning.coordinate(59.325774 , 10.941769),
+QtPositioning.coordinate(59.325606 , 10.942204),
+QtPositioning.coordinate(59.325449 , 10.942653),
+QtPositioning.coordinate(59.325305 , 10.943119),
+QtPositioning.coordinate(59.325172 , 10.943598),
+QtPositioning.coordinate(59.325052 , 10.944089),
+QtPositioning.coordinate(59.324944 , 10.94459),
+QtPositioning.coordinate(59.32485 , 10.945103),
+QtPositioning.coordinate(59.324769 , 10.945624),
+QtPositioning.coordinate(59.324702 , 10.946152),
+QtPositioning.coordinate(59.324648 , 10.946686),
+QtPositioning.coordinate(59.324607 , 10.947224),
+QtPositioning.coordinate(59.324581 , 10.947767),
+QtPositioning.coordinate(59.32457 , 10.948484),
+QtPositioning.coordinate(59.324557 , 10.948998),
+QtPositioning.coordinate(59.324607 , 10.9501),
+QtPositioning.coordinate(59.324706 , 10.951034),
+QtPositioning.coordinate(59.32502 , 10.953179),
+QtPositioning.coordinate(59.325167 , 10.954337),
+QtPositioning.coordinate(59.325233 , 10.955255),
+QtPositioning.coordinate(59.325255 , 10.955976),
+QtPositioning.coordinate(59.325245 , 10.956872),
+QtPositioning.coordinate(59.325209 , 10.95762),
+QtPositioning.coordinate(59.325158 , 10.958241),
+QtPositioning.coordinate(59.32509 , 10.958861),
+QtPositioning.coordinate(59.324924 , 10.960004),
+QtPositioning.coordinate(59.324823 , 10.96054),
+QtPositioning.coordinate(59.324701 , 10.961141),
+QtPositioning.coordinate(59.324506 , 10.96195),
+QtPositioning.coordinate(59.324141 , 10.96327),
+QtPositioning.coordinate(59.323722 , 10.96441),
+QtPositioning.coordinate(59.323128 , 10.965774),
+QtPositioning.coordinate(59.322432 , 10.967065),
+QtPositioning.coordinate(59.321803 , 10.96799),
+QtPositioning.coordinate(59.321057 , 10.968895),
+QtPositioning.coordinate(59.320007 , 10.970141),
+QtPositioning.coordinate(59.319521 , 10.970735),
+QtPositioning.coordinate(59.319137 , 10.971302),
+QtPositioning.coordinate(59.318831 , 10.971829),
+QtPositioning.coordinate(59.318557 , 10.972382),
+QtPositioning.coordinate(59.318216 , 10.973154),
+QtPositioning.coordinate(59.317903 , 10.974079),
+QtPositioning.coordinate(59.317698 , 10.974844),
+QtPositioning.coordinate(59.317525 , 10.975578),
+QtPositioning.coordinate(59.317405 , 10.976201),
+QtPositioning.coordinate(59.317282 , 10.977045),
+QtPositioning.coordinate(59.317203 , 10.977872),
+QtPositioning.coordinate(59.317108 , 10.979333),
+QtPositioning.coordinate(59.316543 , 10.988854),
+QtPositioning.coordinate(59.316489 , 10.989719),
+QtPositioning.coordinate(59.316394 , 10.99149),
+QtPositioning.coordinate(59.315994 , 10.998384),
+QtPositioning.coordinate(59.31594 , 10.999818),
+QtPositioning.coordinate(59.315915 , 11.000829),
+QtPositioning.coordinate(59.316244 , 11.016018),
+QtPositioning.coordinate(59.316334 , 11.01945),
+QtPositioning.coordinate(59.316378 , 11.02108),
+QtPositioning.coordinate(59.316372 , 11.021887),
+QtPositioning.coordinate(59.316345 , 11.022661),
+QtPositioning.coordinate(59.316306 , 11.023293),
+QtPositioning.coordinate(59.316211 , 11.024096),
+QtPositioning.coordinate(59.315926 , 11.0257),
+QtPositioning.coordinate(59.315665 , 11.026754),
+QtPositioning.coordinate(59.315283 , 11.027862),
+QtPositioning.coordinate(59.314829 , 11.028918),
+QtPositioning.coordinate(59.314028 , 11.030204),
+QtPositioning.coordinate(59.313007 , 11.03132),
+QtPositioning.coordinate(59.311952 , 11.032174),
+QtPositioning.coordinate(59.311415 , 11.032667),
+QtPositioning.coordinate(59.310963 , 11.033161),
+QtPositioning.coordinate(59.310521 , 11.033774),
+QtPositioning.coordinate(59.309825 , 11.035004),
+QtPositioning.coordinate(59.308289 , 11.038031),
+QtPositioning.coordinate(59.306383 , 11.04185),
+QtPositioning.coordinate(59.305827 , 11.042992),
+QtPositioning.coordinate(59.304142 , 11.046803),
+QtPositioning.coordinate(59.302812 , 11.050193),
+QtPositioning.coordinate(59.302037 , 11.052498),
+QtPositioning.coordinate(59.300637 , 11.05665),
+QtPositioning.coordinate(59.299165 , 11.06094),
+QtPositioning.coordinate(59.298588 , 11.062467),
+QtPositioning.coordinate(59.297916 , 11.064071),
+QtPositioning.coordinate(59.297498 , 11.065031),
+QtPositioning.coordinate(59.297061 , 11.065961),
+QtPositioning.coordinate(59.296444 , 11.067179),
+QtPositioning.coordinate(59.295945 , 11.068081),
+QtPositioning.coordinate(59.295342 , 11.069115),
+QtPositioning.coordinate(59.294699 , 11.070133),
+QtPositioning.coordinate(59.293947 , 11.071204),
+QtPositioning.coordinate(59.291779 , 11.073892),
+QtPositioning.coordinate(59.289928 , 11.075581),
+QtPositioning.coordinate(59.28835 , 11.07674),
+QtPositioning.coordinate(59.286579 , 11.077727),
+QtPositioning.coordinate(59.282884 , 11.079399),
+QtPositioning.coordinate(59.281594 , 11.080148),
+QtPositioning.coordinate(59.280182 , 11.081203),
+QtPositioning.coordinate(59.279268 , 11.082042),
+QtPositioning.coordinate(59.278666 , 11.082674),
+QtPositioning.coordinate(59.278068 , 11.083394),
+QtPositioning.coordinate(59.277442 , 11.084243),
+QtPositioning.coordinate(59.277032 , 11.084884),
+QtPositioning.coordinate(59.276841 , 11.085212),
+QtPositioning.coordinate(59.27644 , 11.085972),
+QtPositioning.coordinate(59.276283 , 11.086314),
+QtPositioning.coordinate(59.27598 , 11.086968),
+QtPositioning.coordinate(59.275768 , 11.087494),
+QtPositioning.coordinate(59.275256 , 11.088852),
+QtPositioning.coordinate(59.275039 , 11.089459),
+QtPositioning.coordinate(59.274521 , 11.090778),
+QtPositioning.coordinate(59.274222 , 11.091509),
+QtPositioning.coordinate(59.273976 , 11.09206),
+QtPositioning.coordinate(59.273697 , 11.092584),
+QtPositioning.coordinate(59.273307 , 11.09318),
+QtPositioning.coordinate(59.272937 , 11.093709),
+QtPositioning.coordinate(59.27267 , 11.094051),
+QtPositioning.coordinate(59.272391 , 11.094363),
+QtPositioning.coordinate(59.272111 , 11.094611),
+QtPositioning.coordinate(59.271912 , 11.094796),
+QtPositioning.coordinate(59.271476 , 11.095062),
+QtPositioning.coordinate(59.271096 , 11.095221),
+QtPositioning.coordinate(59.270628 , 11.09536),
+QtPositioning.coordinate(59.270197 , 11.095453),
+QtPositioning.coordinate(59.269483 , 11.095567),
+QtPositioning.coordinate(59.268895 , 11.095658),
+QtPositioning.coordinate(59.267967 , 11.095795),
+QtPositioning.coordinate(59.267103 , 11.095925),
+QtPositioning.coordinate(59.266277 , 11.096068),
+QtPositioning.coordinate(59.265508 , 11.096178),
+QtPositioning.coordinate(59.264716 , 11.096291),
+QtPositioning.coordinate(59.263613 , 11.096454),
+QtPositioning.coordinate(59.262867 , 11.096634),
+QtPositioning.coordinate(59.261939 , 11.096866),
+QtPositioning.coordinate(59.261046 , 11.09722),
+QtPositioning.coordinate(59.260325 , 11.097577),
+QtPositioning.coordinate(59.259827 , 11.097837),
+QtPositioning.coordinate(59.259418 , 11.098069),
+QtPositioning.coordinate(59.258468 , 11.098703),
+QtPositioning.coordinate(59.257972 , 11.099087),
+QtPositioning.coordinate(59.257866 , 11.099165),
+QtPositioning.coordinate(59.257357 , 11.099583),
+QtPositioning.coordinate(59.256602 , 11.100221),
+QtPositioning.coordinate(59.256417 , 11.100394),
+QtPositioning.coordinate(59.256257 , 11.100543),
+QtPositioning.coordinate(59.255655 , 11.101106),
+QtPositioning.coordinate(59.25474 , 11.102116),
+QtPositioning.coordinate(59.253888 , 11.103179),
+QtPositioning.coordinate(59.253734 , 11.103387),
+QtPositioning.coordinate(59.253398 , 11.103844),
+QtPositioning.coordinate(59.252508 , 11.105112),
+QtPositioning.coordinate(59.252273 , 11.105487),
+QtPositioning.coordinate(59.251635 , 11.106507),
+QtPositioning.coordinate(59.250827 , 11.107902),
+QtPositioning.coordinate(59.25012 , 11.109278),
+QtPositioning.coordinate(59.249718 , 11.110076),
+QtPositioning.coordinate(59.248956 , 11.111816),
+QtPositioning.coordinate(59.248469 , 11.113079),
+QtPositioning.coordinate(59.247715 , 11.115033),
+QtPositioning.coordinate(59.246588 , 11.118075),
+QtPositioning.coordinate(59.245851 , 11.120063),
+QtPositioning.coordinate(59.245228 , 11.121701),
+QtPositioning.coordinate(59.244443 , 11.123801),
+QtPositioning.coordinate(59.243698 , 11.125818),
+QtPositioning.coordinate(59.242955 , 11.127773),
+QtPositioning.coordinate(59.242392 , 11.129251),
+QtPositioning.coordinate(59.241967 , 11.130273),
+QtPositioning.coordinate(59.240527 , 11.133303),
+QtPositioning.coordinate(59.238618 , 11.136006),
+QtPositioning.coordinate(59.235773 , 11.139362),
+QtPositioning.coordinate(59.233929 , 11.141508),
+QtPositioning.coordinate(59.232418 , 11.143705),
+QtPositioning.coordinate(59.231154 , 11.145817),
+QtPositioning.coordinate(59.228721 , 11.150323),
+QtPositioning.coordinate(59.226561 , 11.153928),
+QtPositioning.coordinate(59.225649 , 11.155146),
+QtPositioning.coordinate(59.224527 , 11.156476),
+QtPositioning.coordinate(59.224186 , 11.156881),
+QtPositioning.coordinate(59.222094 , 11.158751),
+QtPositioning.coordinate(59.220043 , 11.160271),
+QtPositioning.coordinate(59.218075 , 11.161386),
+QtPositioning.coordinate(59.215826 , 11.162331),
+QtPositioning.coordinate(59.21429 , 11.163135),
+QtPositioning.coordinate(59.213929 , 11.163336),
+QtPositioning.coordinate(59.213619 , 11.163554),
+QtPositioning.coordinate(59.212991 , 11.164077),
+QtPositioning.coordinate(59.212499 , 11.164587),
+QtPositioning.coordinate(59.211907 , 11.16525),
+QtPositioning.coordinate(59.211523 , 11.165771),
+QtPositioning.coordinate(59.211076 , 11.166413),
+QtPositioning.coordinate(59.21064 , 11.167137),
+QtPositioning.coordinate(59.209931 , 11.168526),
+QtPositioning.coordinate(59.208947 , 11.17082),
+QtPositioning.coordinate(59.208094 , 11.172534),
+QtPositioning.coordinate(59.207407 , 11.173706),
+QtPositioning.coordinate(59.207061 , 11.174291),
+QtPositioning.coordinate(59.206748 , 11.174828),
+QtPositioning.coordinate(59.205053 , 11.177251),
+QtPositioning.coordinate(59.204575 , 11.177947),
+QtPositioning.coordinate(59.204309 , 11.17835),
+QtPositioning.coordinate(59.203551 , 11.179634),
+QtPositioning.coordinate(59.202951 , 11.180725),
+QtPositioning.coordinate(59.202274 , 11.182216),
+QtPositioning.coordinate(59.20189 , 11.183166),
+QtPositioning.coordinate(59.201751 , 11.18353),
+QtPositioning.coordinate(59.201114 , 11.185449),
+QtPositioning.coordinate(59.200349 , 11.188134),
+QtPositioning.coordinate(59.200004 , 11.189331),
+QtPositioning.coordinate(59.199481 , 11.191119),
+QtPositioning.coordinate(59.199008 , 11.192584),
+QtPositioning.coordinate(59.198532 , 11.193846),
+QtPositioning.coordinate(59.198036 , 11.194935),
+QtPositioning.coordinate(59.197395 , 11.196065),
+QtPositioning.coordinate(59.19675 , 11.196955),
+QtPositioning.coordinate(59.196061 , 11.197718),
+QtPositioning.coordinate(59.19539 , 11.198312),
+QtPositioning.coordinate(59.194712 , 11.198785),
+QtPositioning.coordinate(59.193939 , 11.199168),
+QtPositioning.coordinate(59.193255 , 11.199358),
+QtPositioning.coordinate(59.192428 , 11.199461),
+QtPositioning.coordinate(59.190949 , 11.199514),
+QtPositioning.coordinate(59.189476 , 11.199582),
+QtPositioning.coordinate(59.188703 , 11.19965),
+QtPositioning.coordinate(59.187682 , 11.199924),
+QtPositioning.coordinate(59.186636 , 11.200362),
+QtPositioning.coordinate(59.185097 , 11.200975),
+QtPositioning.coordinate(59.183766 , 11.201544),
+QtPositioning.coordinate(59.182432 , 11.202271),
+QtPositioning.coordinate(59.18149 , 11.203016),
+QtPositioning.coordinate(59.181177 , 11.203296),
+QtPositioning.coordinate(59.180881 , 11.203581),
+QtPositioning.coordinate(59.18019 , 11.204402),
+QtPositioning.coordinate(59.179556 , 11.205226),
+QtPositioning.coordinate(59.179353 , 11.205494),
+QtPositioning.coordinate(59.179074 , 11.205864),
+QtPositioning.coordinate(59.178862 , 11.20613),
+QtPositioning.coordinate(59.177358 , 11.208164),
+QtPositioning.coordinate(59.176367 , 11.209559),
+QtPositioning.coordinate(59.175287 , 11.210979),
+QtPositioning.coordinate(59.174514 , 11.211891),
+QtPositioning.coordinate(59.17366 , 11.212822),
+QtPositioning.coordinate(59.172839 , 11.21357),
+QtPositioning.coordinate(59.171909 , 11.214338),
+QtPositioning.coordinate(59.170854 , 11.215044),
+QtPositioning.coordinate(59.169013 , 11.216189),
+QtPositioning.coordinate(59.16805 , 11.2168),
+QtPositioning.coordinate(59.166958 , 11.217638),
+QtPositioning.coordinate(59.165944 , 11.218542),
+QtPositioning.coordinate(59.165665 , 11.218871),
+QtPositioning.coordinate(59.165386 , 11.21918),
+QtPositioning.coordinate(59.164851 , 11.21979),
+QtPositioning.coordinate(59.163537 , 11.221281),
+QtPositioning.coordinate(59.161853 , 11.223275),
+QtPositioning.coordinate(59.160381 , 11.224964),
+QtPositioning.coordinate(59.158974 , 11.226654),
+QtPositioning.coordinate(59.157951 , 11.227831),
+QtPositioning.coordinate(59.157202 , 11.228721),
+QtPositioning.coordinate(59.156308 , 11.229855),
+QtPositioning.coordinate(59.155155 , 11.231526),
+QtPositioning.coordinate(59.15376 , 11.233998),
+QtPositioning.coordinate(59.152474 , 11.236771),
+QtPositioning.coordinate(59.151187 , 11.239716),
+QtPositioning.coordinate(59.14995 , 11.242525),
+QtPositioning.coordinate(59.149095 , 11.244402),
+QtPositioning.coordinate(59.1484 , 11.245815),
+QtPositioning.coordinate(59.147577 , 11.247383),
+QtPositioning.coordinate(59.146879 , 11.248627),
+QtPositioning.coordinate(59.14607 , 11.249938),
+QtPositioning.coordinate(59.145565 , 11.25065),
+QtPositioning.coordinate(59.144574 , 11.251918),
+QtPositioning.coordinate(59.143885 , 11.252705),
+QtPositioning.coordinate(59.142957 , 11.253652),
+QtPositioning.coordinate(59.141731 , 11.254744),
+QtPositioning.coordinate(59.141139 , 11.255281),
+QtPositioning.coordinate(59.140416 , 11.256001),
+QtPositioning.coordinate(59.139521 , 11.257048),
+QtPositioning.coordinate(59.138704 , 11.258126),
+QtPositioning.coordinate(59.137547 , 11.259821),
+QtPositioning.coordinate(59.136779 , 11.260893),
+QtPositioning.coordinate(59.136077 , 11.261842),
+QtPositioning.coordinate(59.135542 , 11.262467),
+QtPositioning.coordinate(59.1351 , 11.262976),
+QtPositioning.coordinate(59.134297 , 11.263841),
+QtPositioning.coordinate(59.133314 , 11.264873),
+QtPositioning.coordinate(59.131751 , 11.266472),
+QtPositioning.coordinate(59.131242 , 11.26699),
+QtPositioning.coordinate(59.130728 , 11.26751),
+QtPositioning.coordinate(59.13031 , 11.267931),
+QtPositioning.coordinate(59.129861 , 11.268341),
+QtPositioning.coordinate(59.129291 , 11.268811),
+QtPositioning.coordinate(59.128754 , 11.269194),
+QtPositioning.coordinate(59.128363 , 11.269464),
+QtPositioning.coordinate(59.12789 , 11.269754),
+QtPositioning.coordinate(59.12746 , 11.269977),
+QtPositioning.coordinate(59.12695 , 11.270202),
+QtPositioning.coordinate(59.126159 , 11.270449),
+QtPositioning.coordinate(59.125652 , 11.270561),
+QtPositioning.coordinate(59.124983 , 11.270626),
+QtPositioning.coordinate(59.124508 , 11.27064),
+QtPositioning.coordinate(59.123931 , 11.270615),
+QtPositioning.coordinate(59.123179 , 11.270519),
+QtPositioning.coordinate(59.122472 , 11.270364),
+QtPositioning.coordinate(59.121961 , 11.270201),
+QtPositioning.coordinate(59.121271 , 11.26993),
+QtPositioning.coordinate(59.120669 , 11.269612),
+QtPositioning.coordinate(59.120059 , 11.269259),
+QtPositioning.coordinate(59.11935 , 11.268753),
+QtPositioning.coordinate(59.118666 , 11.268191),
+QtPositioning.coordinate(59.118061 , 11.267615),
+QtPositioning.coordinate(59.117473 , 11.266994),
+QtPositioning.coordinate(59.116796 , 11.266171),
+QtPositioning.coordinate(59.11613 , 11.265315),
+QtPositioning.coordinate(59.112713 , 11.2605),
+QtPositioning.coordinate(59.111314 , 11.258557),
+QtPositioning.coordinate(59.111018 , 11.258153),
+QtPositioning.coordinate(59.110509 , 11.257479),
+QtPositioning.coordinate(59.110094 , 11.257038),
+QtPositioning.coordinate(59.109563 , 11.256474),
+QtPositioning.coordinate(59.108969 , 11.255996),
+QtPositioning.coordinate(59.107957 , 11.255363),
+QtPositioning.coordinate(59.106994 , 11.254974),
+QtPositioning.coordinate(59.106413 , 11.254733),
+QtPositioning.coordinate(59.106146 , 11.254643),
+QtPositioning.coordinate(59.105535 , 11.2543),
+QtPositioning.coordinate(59.104967 , 11.253888),
+QtPositioning.coordinate(59.104393 , 11.253347),
+QtPositioning.coordinate(59.103711 , 11.252655),
+QtPositioning.coordinate(59.102527 , 11.251496),
+QtPositioning.coordinate(59.101964 , 11.251115),
+QtPositioning.coordinate(59.101221 , 11.250756),
+QtPositioning.coordinate(59.1002 , 11.250478),
+QtPositioning.coordinate(59.099473 , 11.250426),
+QtPositioning.coordinate(59.098805 , 11.250504),
+QtPositioning.coordinate(59.0981 , 11.250646),
+QtPositioning.coordinate(59.097247 , 11.25089),
+QtPositioning.coordinate(59.096432 , 11.251195),
+QtPositioning.coordinate(59.09524 , 11.251597),
+QtPositioning.coordinate(59.094518 , 11.251848),
+QtPositioning.coordinate(59.093772 , 11.252026),
+QtPositioning.coordinate(59.093014 , 11.252222),
+QtPositioning.coordinate(59.092473 , 11.252349),
+QtPositioning.coordinate(59.091886 , 11.252418),
+QtPositioning.coordinate(59.091673 , 11.252429),
+QtPositioning.coordinate(59.091319 , 11.25241),
+QtPositioning.coordinate(59.09082 , 11.252326),
+QtPositioning.coordinate(59.090223 , 11.25219),
+QtPositioning.coordinate(59.089792 , 11.252043),
+QtPositioning.coordinate(59.089457 , 11.25193),
+QtPositioning.coordinate(59.088945 , 11.251741),
+QtPositioning.coordinate(59.088354 , 11.25146),
+QtPositioning.coordinate(59.087497 , 11.251007),
+QtPositioning.coordinate(59.086452 , 11.250545),
+QtPositioning.coordinate(59.085338 , 11.250121),
+QtPositioning.coordinate(59.083974 , 11.249712),
+QtPositioning.coordinate(59.082937 , 11.249497),
+QtPositioning.coordinate(59.082398 , 11.249435),
+QtPositioning.coordinate(59.081849 , 11.249373),
+QtPositioning.coordinate(59.079712 , 11.249281),
+QtPositioning.coordinate(59.077995 , 11.249339),
+QtPositioning.coordinate(59.077312 , 11.249296),
+QtPositioning.coordinate(59.076462 , 11.249181),
+QtPositioning.coordinate(59.075661 , 11.248991),
+QtPositioning.coordinate(59.075138 , 11.248842),
+QtPositioning.coordinate(59.074544 , 11.248561),
+QtPositioning.coordinate(59.073752 , 11.248169),
+QtPositioning.coordinate(59.07287 , 11.247713),
+QtPositioning.coordinate(59.072866 , 11.247707),
+QtPositioning.coordinate(59.072179 , 11.247309),
+QtPositioning.coordinate(59.072005 , 11.247209),
+QtPositioning.coordinate(59.071368 , 11.246828),
+QtPositioning.coordinate(59.070626 , 11.246409),
+QtPositioning.coordinate(59.069678 , 11.24598),
+QtPositioning.coordinate(59.069017 , 11.245753),
+QtPositioning.coordinate(59.068429 , 11.245613),
+QtPositioning.coordinate(59.067781 , 11.245534),
+QtPositioning.coordinate(59.067238 , 11.245508),
+QtPositioning.coordinate(59.066478 , 11.245587),
+QtPositioning.coordinate(59.065781 , 11.245735),
+QtPositioning.coordinate(59.064932 , 11.246015),
+QtPositioning.coordinate(59.064356 , 11.246251),
+QtPositioning.coordinate(59.063341 , 11.246802),
+QtPositioning.coordinate(59.062244 , 11.247414),
+QtPositioning.coordinate(59.061498 , 11.247764),
+QtPositioning.coordinate(59.06099 , 11.247904),
+QtPositioning.coordinate(59.060135 , 11.248087),
+QtPositioning.coordinate(59.059313 , 11.24814),
+QtPositioning.coordinate(59.058805 , 11.248183),
+QtPositioning.coordinate(59.058018 , 11.248183),
+QtPositioning.coordinate(59.05733 , 11.24828),
+QtPositioning.coordinate(59.056629 , 11.248481),
+QtPositioning.coordinate(59.056022 , 11.248717),
+QtPositioning.coordinate(59.055518 , 11.24897),
+QtPositioning.coordinate(59.054812 , 11.249364),
+QtPositioning.coordinate(59.054102 , 11.249906),
+QtPositioning.coordinate(59.053432 , 11.250527),
+QtPositioning.coordinate(59.052758 , 11.251218),
+QtPositioning.coordinate(59.052083 , 11.252013),
+QtPositioning.coordinate(59.051464 , 11.252932),
+QtPositioning.coordinate(59.050987 , 11.253532),
+QtPositioning.coordinate(59.050839 , 11.253718),
+QtPositioning.coordinate(59.050172 , 11.254488),
+QtPositioning.coordinate(59.049677 , 11.255065),
+QtPositioning.coordinate(59.049201 , 11.255554),
+QtPositioning.coordinate(59.04867 , 11.256009),
+QtPositioning.coordinate(59.048103 , 11.256429),
+QtPositioning.coordinate(59.047595 , 11.25677),
+QtPositioning.coordinate(59.046948 , 11.257137),
+QtPositioning.coordinate(59.046386 , 11.257408),
+QtPositioning.coordinate(59.045814 , 11.257574),
+QtPositioning.coordinate(59.045338 , 11.257705),
+QtPositioning.coordinate(59.044824 , 11.257745),
+QtPositioning.coordinate(59.044289 , 11.257781),
+QtPositioning.coordinate(59.043766 , 11.25775),
+QtPositioning.coordinate(59.04352 , 11.257714),
+QtPositioning.coordinate(59.043047 , 11.257645),
+QtPositioning.coordinate(59.042477 , 11.257523),
+QtPositioning.coordinate(59.041932 , 11.257318),
+QtPositioning.coordinate(59.041326 , 11.25704),
+QtPositioning.coordinate(59.040599 , 11.256633),
+QtPositioning.coordinate(59.039733 , 11.256002),
+QtPositioning.coordinate(59.038858 , 11.255225),
+QtPositioning.coordinate(59.03805 , 11.254289),
+QtPositioning.coordinate(59.037228 , 11.253203),
+QtPositioning.coordinate(59.036449 , 11.25195),
+QtPositioning.coordinate(59.035604 , 11.250438),
+QtPositioning.coordinate(59.0349 , 11.24917),
+QtPositioning.coordinate(59.034264 , 11.248169),
+QtPositioning.coordinate(59.033695 , 11.247332),
+QtPositioning.coordinate(59.033092 , 11.24658),
+QtPositioning.coordinate(59.032386 , 11.245828),
+QtPositioning.coordinate(59.031579 , 11.245037),
+QtPositioning.coordinate(59.030322 , 11.2439),
+QtPositioning.coordinate(59.029312 , 11.243048),
+QtPositioning.coordinate(59.027582 , 11.241639),
+QtPositioning.coordinate(59.026115 , 11.240563),
+QtPositioning.coordinate(59.0248 , 11.239661),
+QtPositioning.coordinate(59.023818 , 11.23915),
+QtPositioning.coordinate(59.022863 , 11.238784),
+QtPositioning.coordinate(59.02246 , 11.238662),
+QtPositioning.coordinate(59.02201 , 11.238559),
+QtPositioning.coordinate(59.021459 , 11.238504),
+QtPositioning.coordinate(59.02015 , 11.238653),
+QtPositioning.coordinate(59.018565 , 11.238953),
+QtPositioning.coordinate(59.017702 , 11.239143),
+QtPositioning.coordinate(59.016996 , 11.239226),
+QtPositioning.coordinate(59.016508 , 11.23925),
+QtPositioning.coordinate(59.015865 , 11.239262),
+QtPositioning.coordinate(59.015245 , 11.239186),
+QtPositioning.coordinate(59.014726 , 11.239094),
+QtPositioning.coordinate(59.014146 , 11.238938),
+QtPositioning.coordinate(59.013509 , 11.238739),
+QtPositioning.coordinate(59.012921 , 11.238422),
+QtPositioning.coordinate(59.012222 , 11.237989),
+QtPositioning.coordinate(59.011634 , 11.237537),
+QtPositioning.coordinate(59.011008 , 11.236989),
+QtPositioning.coordinate(59.010121 , 11.236112),
+QtPositioning.coordinate(59.009235 , 11.235202),
+QtPositioning.coordinate(59.008535 , 11.234522),
+QtPositioning.coordinate(59.007964 , 11.234031),
+QtPositioning.coordinate(59.007186 , 11.233425),
+QtPositioning.coordinate(59.006643 , 11.233085),
+QtPositioning.coordinate(59.006101 , 11.232778),
+QtPositioning.coordinate(59.00526 , 11.232384),
+QtPositioning.coordinate(59.004728 , 11.232224),
+QtPositioning.coordinate(59.004204 , 11.232066),
+QtPositioning.coordinate(59.003403 , 11.231901),
+QtPositioning.coordinate(59.002737 , 11.231858),
+QtPositioning.coordinate(59.002507 , 11.231843),
+QtPositioning.coordinate(59.000794 , 11.232002),
+QtPositioning.coordinate(59.000649 , 11.232015),
+QtPositioning.coordinate(58.999841 , 11.232089),
+QtPositioning.coordinate(58.999031 , 11.232124),
+QtPositioning.coordinate(58.99792 , 11.232026),
+QtPositioning.coordinate(58.997048 , 11.231904),
+QtPositioning.coordinate(58.996226 , 11.231709),
+QtPositioning.coordinate(58.994959 , 11.231307),
+QtPositioning.coordinate(58.99408 , 11.231137),
+QtPositioning.coordinate(58.993484 , 11.231052),
+QtPositioning.coordinate(58.992429 , 11.231125),
+QtPositioning.coordinate(58.991515 , 11.231319),
+QtPositioning.coordinate(58.990358 , 11.23149),
+QtPositioning.coordinate(58.989304 , 11.231454),
+QtPositioning.coordinate(58.988298 , 11.231296),
+QtPositioning.coordinate(58.987651 , 11.231146),
+QtPositioning.coordinate(58.98695 , 11.231015),
+QtPositioning.coordinate(58.986504 , 11.230988),
+QtPositioning.coordinate(58.985971 , 11.230978),
+QtPositioning.coordinate(58.985498 , 11.231027),
+QtPositioning.coordinate(58.984822 , 11.231132),
+QtPositioning.coordinate(58.983341 , 11.231575),
+QtPositioning.coordinate(58.982261 , 11.231916),
+QtPositioning.coordinate(58.981448 , 11.232105),
+QtPositioning.coordinate(58.980327 , 11.232282),
+QtPositioning.coordinate(58.979567 , 11.232332),
+QtPositioning.coordinate(58.978839 , 11.232343),
+QtPositioning.coordinate(58.977985 , 11.232303),
+QtPositioning.coordinate(58.977803 , 11.232295),
+QtPositioning.coordinate(58.977456 , 11.232278),
+QtPositioning.coordinate(58.977281 , 11.232258),
+QtPositioning.coordinate(58.977087 , 11.232236),
+QtPositioning.coordinate(58.976162 , 11.232128),
+QtPositioning.coordinate(58.974812 , 11.231993),
+QtPositioning.coordinate(58.973358 , 11.231929),
+QtPositioning.coordinate(58.972237 , 11.231963),
+QtPositioning.coordinate(58.971091 , 11.232051),
+QtPositioning.coordinate(58.969653 , 11.232233),
+QtPositioning.coordinate(58.968243 , 11.232485),
+QtPositioning.coordinate(58.967834 , 11.232571),
+QtPositioning.coordinate(58.966729 , 11.232883),
+QtPositioning.coordinate(58.965249 , 11.233358),
+QtPositioning.coordinate(58.964073 , 11.233788),
+QtPositioning.coordinate(58.963036 , 11.234267),
+QtPositioning.coordinate(58.962301 , 11.234681),
+QtPositioning.coordinate(58.961643 , 11.23515),
+QtPositioning.coordinate(58.961057 , 11.235725),
+QtPositioning.coordinate(58.960359 , 11.236499),
+QtPositioning.coordinate(58.959031 , 11.238188),
+QtPositioning.coordinate(58.957911 , 11.239745),
+QtPositioning.coordinate(58.957149 , 11.240914),
+QtPositioning.coordinate(58.956339 , 11.242091),
+QtPositioning.coordinate(58.955531 , 11.243407),
+QtPositioning.coordinate(58.953792 , 11.246406),
+QtPositioning.coordinate(58.952822 , 11.248056),
+QtPositioning.coordinate(58.951946 , 11.249371),
+QtPositioning.coordinate(58.951329 , 11.250249),
+QtPositioning.coordinate(58.950605 , 11.251213),
+QtPositioning.coordinate(58.949141 , 11.253001),
+QtPositioning.coordinate(58.948049 , 11.254163),
+QtPositioning.coordinate(58.947252 , 11.254876),
+QtPositioning.coordinate(58.946733 , 11.255299),
+QtPositioning.coordinate(58.946128 , 11.255734),
+QtPositioning.coordinate(58.945308 , 11.256161),
+QtPositioning.coordinate(58.944628 , 11.256437),
+QtPositioning.coordinate(58.943971 , 11.256668),
+QtPositioning.coordinate(58.943277 , 11.256724),
+QtPositioning.coordinate(58.94236 , 11.256698),
+QtPositioning.coordinate(58.94003 , 11.256398),
+QtPositioning.coordinate(58.938691 , 11.256124),
+QtPositioning.coordinate(58.937954 , 11.255916),
+QtPositioning.coordinate(58.937216 , 11.255702),
+QtPositioning.coordinate(58.935647 , 11.255426),
+QtPositioning.coordinate(58.935099 , 11.255335),
+QtPositioning.coordinate(58.934742 , 11.255276),
+QtPositioning.coordinate(58.933094 , 11.255152),
+QtPositioning.coordinate(58.932403 , 11.255093),
+QtPositioning.coordinate(58.931216 , 11.255086),
+QtPositioning.coordinate(58.929041 , 11.255247),
+QtPositioning.coordinate(58.928745 , 11.255298),
+QtPositioning.coordinate(58.92801 , 11.255398),
+QtPositioning.coordinate(58.926729 , 11.255645),
+QtPositioning.coordinate(58.925342 , 11.256),
+QtPositioning.coordinate(58.924041 , 11.256428),
+QtPositioning.coordinate(58.92241 , 11.257141),
+QtPositioning.coordinate(58.920988 , 11.25787),
+QtPositioning.coordinate(58.919248 , 11.259019),
+QtPositioning.coordinate(58.917411 , 11.260532),
+QtPositioning.coordinate(58.91678 , 11.261101),
+QtPositioning.coordinate(58.915539 , 11.262385),
+QtPositioning.coordinate(58.914297 , 11.263822),
+QtPositioning.coordinate(58.91153 , 11.267037),
+QtPositioning.coordinate(58.910776 , 11.267803),
+QtPositioning.coordinate(58.90981 , 11.268587),
+QtPositioning.coordinate(58.908802 , 11.269288),
+QtPositioning.coordinate(58.907779 , 11.269893),
+QtPositioning.coordinate(58.906721 , 11.270416),
+QtPositioning.coordinate(58.905755 , 11.270719),
+QtPositioning.coordinate(58.904605 , 11.271007),
+QtPositioning.coordinate(58.903454 , 11.271131),
+QtPositioning.coordinate(58.901643 , 11.2712),
+QtPositioning.coordinate(58.899881 , 11.271062),
+QtPositioning.coordinate(58.898383 , 11.270829),
+QtPositioning.coordinate(58.896976 , 11.270485),
+QtPositioning.coordinate(58.895839 , 11.270141),
+QtPositioning.coordinate(58.894788 , 11.269673),
+QtPositioning.coordinate(58.892891 , 11.268601),
+QtPositioning.coordinate(58.891847 , 11.268133),
+QtPositioning.coordinate(58.890831 , 11.267858),
+QtPositioning.coordinate(58.889985 , 11.267803),
+QtPositioning.coordinate(58.889033 , 11.2679),
+QtPositioning.coordinate(58.888095 , 11.268147),
+QtPositioning.coordinate(58.887172 , 11.26856),
+QtPositioning.coordinate(58.886326 , 11.269068),
+QtPositioning.coordinate(58.885431 , 11.269825),
+QtPositioning.coordinate(58.884017 , 11.271351),
+QtPositioning.coordinate(58.883128 , 11.272259),
+QtPositioning.coordinate(58.882213 , 11.27314),
+QtPositioning.coordinate(58.88161 , 11.273612),
+QtPositioning.coordinate(58.881036 , 11.273968),
+QtPositioning.coordinate(58.880502 , 11.274268),
+QtPositioning.coordinate(58.87976 , 11.274611),
+QtPositioning.coordinate(58.879163 , 11.274821),
+QtPositioning.coordinate(58.878177 , 11.275121),
+QtPositioning.coordinate(58.877587 , 11.275233),
+QtPositioning.coordinate(58.877037 , 11.27534),
+QtPositioning.coordinate(58.876481 , 11.275434),
+QtPositioning.coordinate(58.875852 , 11.275499),
+QtPositioning.coordinate(58.875286 , 11.275537),
+QtPositioning.coordinate(58.874708 , 11.27555),
+QtPositioning.coordinate(58.873975 , 11.275482),
+QtPositioning.coordinate(58.873569 , 11.275447),
+QtPositioning.coordinate(58.873136 , 11.275374),
+QtPositioning.coordinate(58.871827 , 11.275037),
+QtPositioning.coordinate(58.870776 , 11.274725),
+QtPositioning.coordinate(58.870268 , 11.274547),
+QtPositioning.coordinate(58.869115 , 11.274123),
+QtPositioning.coordinate(58.868325 , 11.273863),
+QtPositioning.coordinate(58.867585 , 11.273668),
+QtPositioning.coordinate(58.866723 , 11.27359),
+QtPositioning.coordinate(58.865814 , 11.273571),
+QtPositioning.coordinate(58.864989 , 11.273662),
+QtPositioning.coordinate(58.863992 , 11.273911),
+QtPositioning.coordinate(58.863079 , 11.274257),
+QtPositioning.coordinate(58.862117 , 11.27473),
+QtPositioning.coordinate(58.861029 , 11.275457),
+QtPositioning.coordinate(58.858496 , 11.277445),
+QtPositioning.coordinate(58.857435 , 11.278259),
+QtPositioning.coordinate(58.856272 , 11.27908),
+QtPositioning.coordinate(58.854956 , 11.279906),
+QtPositioning.coordinate(58.853038 , 11.281062),
+QtPositioning.coordinate(58.851609 , 11.281807),
+QtPositioning.coordinate(58.850625 , 11.28227),
+QtPositioning.coordinate(58.849669 , 11.282699),
+QtPositioning.coordinate(58.848707 , 11.283053),
+QtPositioning.coordinate(58.847714 , 11.283199),
+QtPositioning.coordinate(58.846775 , 11.283207),
+QtPositioning.coordinate(58.845662 , 11.283006),
+QtPositioning.coordinate(58.845187 , 11.282868),
+QtPositioning.coordinate(58.844876 , 11.282745),
+QtPositioning.coordinate(58.844708 , 11.282674),
+QtPositioning.coordinate(58.843643 , 11.282098),
+QtPositioning.coordinate(58.842511 , 11.281285),
+QtPositioning.coordinate(58.841642 , 11.28048),
+QtPositioning.coordinate(58.840626 , 11.279274),
+QtPositioning.coordinate(58.839458 , 11.278043),
+QtPositioning.coordinate(58.838602 , 11.277236),
+QtPositioning.coordinate(58.838329 , 11.277037),
+QtPositioning.coordinate(58.838236 , 11.27697),
+QtPositioning.coordinate(58.83781 , 11.276716),
+QtPositioning.coordinate(58.837228 , 11.276408),
+QtPositioning.coordinate(58.836661 , 11.276192),
+QtPositioning.coordinate(58.836165 , 11.276054),
+QtPositioning.coordinate(58.83562 , 11.275959),
+QtPositioning.coordinate(58.834622 , 11.275897),
+QtPositioning.coordinate(58.833548 , 11.27612),
+QtPositioning.coordinate(58.832265 , 11.276598),
+QtPositioning.coordinate(58.830992 , 11.277333),
+QtPositioning.coordinate(58.82906 , 11.27876),
+QtPositioning.coordinate(58.82711 , 11.280353),
+QtPositioning.coordinate(58.826052 , 11.281123),
+QtPositioning.coordinate(58.824936 , 11.281783),
+QtPositioning.coordinate(58.823757 , 11.282287),
+QtPositioning.coordinate(58.822293 , 11.282764),
+QtPositioning.coordinate(58.820833 , 11.28292),
+QtPositioning.coordinate(58.819516 , 11.282955),
+QtPositioning.coordinate(58.818263 , 11.282735),
+QtPositioning.coordinate(58.816109 , 11.282199),
+QtPositioning.coordinate(58.814876 , 11.282011),
+QtPositioning.coordinate(58.814412 , 11.28199),
+QtPositioning.coordinate(58.813721 , 11.282028),
+QtPositioning.coordinate(58.812758 , 11.282123),
+QtPositioning.coordinate(58.810585 , 11.282658),
+QtPositioning.coordinate(58.809247 , 11.28302),
+QtPositioning.coordinate(58.807768 , 11.283149),
+QtPositioning.coordinate(58.806604 , 11.282983),
+QtPositioning.coordinate(58.805114 , 11.282656),
+QtPositioning.coordinate(58.803409 , 11.281801),
+QtPositioning.coordinate(58.801725 , 11.280591),
+QtPositioning.coordinate(58.800404 , 11.279505),
+QtPositioning.coordinate(58.799145 , 11.278628),
+QtPositioning.coordinate(58.797617 , 11.277965),
+QtPositioning.coordinate(58.796279 , 11.277608),
+QtPositioning.coordinate(58.795033 , 11.277616),
+QtPositioning.coordinate(58.79323 , 11.278059),
+QtPositioning.coordinate(58.791691 , 11.278619),
+QtPositioning.coordinate(58.790295 , 11.278866),
+QtPositioning.coordinate(58.787618 , 11.278356),
+QtPositioning.coordinate(58.785574 , 11.27748),
+QtPositioning.coordinate(58.784623 , 11.276869),
+QtPositioning.coordinate(58.782128 , 11.275188),
+QtPositioning.coordinate(58.780368 , 11.274158),
+QtPositioning.coordinate(58.778678 , 11.273549),
+QtPositioning.coordinate(58.777655 , 11.273265),
+QtPositioning.coordinate(58.776006 , 11.273063),
+QtPositioning.coordinate(58.775025 , 11.273087),
+QtPositioning.coordinate(58.773793 , 11.273272),
+QtPositioning.coordinate(58.772333 , 11.273911),
+QtPositioning.coordinate(58.77074 , 11.275006),
+QtPositioning.coordinate(58.769348 , 11.275924),
+QtPositioning.coordinate(58.767892 , 11.276633),
+QtPositioning.coordinate(58.767207 , 11.276867),
+QtPositioning.coordinate(58.765448 , 11.277151),
+QtPositioning.coordinate(58.764188 , 11.277291),
+QtPositioning.coordinate(58.76274 , 11.277607),
+QtPositioning.coordinate(58.761419 , 11.278043),
+QtPositioning.coordinate(58.760094 , 11.27857),
+QtPositioning.coordinate(58.757591 , 11.280136),
+QtPositioning.coordinate(58.755743 , 11.281776),
+QtPositioning.coordinate(58.75429 , 11.283559),
+QtPositioning.coordinate(58.753119 , 11.285253),
+QtPositioning.coordinate(58.752278 , 11.286887),
+QtPositioning.coordinate(58.751938 , 11.287562),
+QtPositioning.coordinate(58.750514 , 11.290249),
+QtPositioning.coordinate(58.749065 , 11.292674),
+QtPositioning.coordinate(58.747765 , 11.294642),
+QtPositioning.coordinate(58.746352 , 11.296584),
+QtPositioning.coordinate(58.744955 , 11.298285),
+QtPositioning.coordinate(58.743378 , 11.299991),
+QtPositioning.coordinate(58.741954 , 11.301344),
+QtPositioning.coordinate(58.740475 , 11.302614),
+QtPositioning.coordinate(58.738802 , 11.303805),
+QtPositioning.coordinate(58.737882 , 11.30463),
+QtPositioning.coordinate(58.737198 , 11.305392),
+QtPositioning.coordinate(58.736515 , 11.306371),
+QtPositioning.coordinate(58.736 , 11.307303),
+QtPositioning.coordinate(58.735466 , 11.308592),
+QtPositioning.coordinate(58.735102 , 11.309725),
+QtPositioning.coordinate(58.734738 , 11.311017),
+QtPositioning.coordinate(58.734356 , 11.312766),
+QtPositioning.coordinate(58.734087 , 11.314644),
+QtPositioning.coordinate(58.733917 , 11.316773),
+QtPositioning.coordinate(58.733876 , 11.318182),
+QtPositioning.coordinate(58.733862 , 11.31874),
+QtPositioning.coordinate(58.733775 , 11.321462),
+QtPositioning.coordinate(58.733673 , 11.323198),
+QtPositioning.coordinate(58.733505 , 11.324576),
+QtPositioning.coordinate(58.733057 , 11.327248),
+QtPositioning.coordinate(58.732523 , 11.329271),
+QtPositioning.coordinate(58.731862 , 11.331764),
+QtPositioning.coordinate(58.731266 , 11.333857),
+QtPositioning.coordinate(58.730713 , 11.335561),
+QtPositioning.coordinate(58.730108 , 11.337226),
+QtPositioning.coordinate(58.729361 , 11.339237),
+QtPositioning.coordinate(58.728419 , 11.341522),
+QtPositioning.coordinate(58.727386 , 11.343894),
+QtPositioning.coordinate(58.726326 , 11.346092),
+QtPositioning.coordinate(58.725252 , 11.348027),
+QtPositioning.coordinate(58.724391 , 11.349505),
+QtPositioning.coordinate(58.723939 , 11.350192),
+QtPositioning.coordinate(58.723429 , 11.350778),
+QtPositioning.coordinate(58.722788 , 11.351464),
+QtPositioning.coordinate(58.722045 , 11.352103),
+QtPositioning.coordinate(58.721456 , 11.352574),
+QtPositioning.coordinate(58.720617 , 11.353077),
+QtPositioning.coordinate(58.719929 , 11.3533),
+QtPositioning.coordinate(58.719437 , 11.353435),
+QtPositioning.coordinate(58.718487 , 11.35362),
+QtPositioning.coordinate(58.717523 , 11.353676),
+QtPositioning.coordinate(58.716286 , 11.353854),
+QtPositioning.coordinate(58.715563 , 11.354063),
+QtPositioning.coordinate(58.715222 , 11.354198),
+QtPositioning.coordinate(58.714271 , 11.354686),
+QtPositioning.coordinate(58.713591 , 11.355193),
+QtPositioning.coordinate(58.713287 , 11.355452),
+QtPositioning.coordinate(58.713002 , 11.355722),
+QtPositioning.coordinate(58.712577 , 11.356136),
+QtPositioning.coordinate(58.712202 , 11.356596),
+QtPositioning.coordinate(58.711789 , 11.35718),
+QtPositioning.coordinate(58.711398 , 11.357825),
+QtPositioning.coordinate(58.710945 , 11.35865),
+QtPositioning.coordinate(58.710746 , 11.359041),
+QtPositioning.coordinate(58.71054 , 11.359482),
+QtPositioning.coordinate(58.710181 , 11.360366),
+QtPositioning.coordinate(58.709958 , 11.360962),
+QtPositioning.coordinate(58.709776 , 11.361497),
+QtPositioning.coordinate(58.70963 , 11.361973),
+QtPositioning.coordinate(58.709484 , 11.362472),
+QtPositioning.coordinate(58.709327 , 11.363075),
+QtPositioning.coordinate(58.709191 , 11.3637),
+QtPositioning.coordinate(58.709094 , 11.364145),
+QtPositioning.coordinate(58.708998 , 11.364634),
+QtPositioning.coordinate(58.708826 , 11.365733),
+QtPositioning.coordinate(58.70873 , 11.366557),
+QtPositioning.coordinate(58.708652 , 11.367379),
+QtPositioning.coordinate(58.708492 , 11.369371),
+QtPositioning.coordinate(58.708422 , 11.370448),
+QtPositioning.coordinate(58.708353 , 11.371061),
+QtPositioning.coordinate(58.708232 , 11.371991),
+QtPositioning.coordinate(58.708141 , 11.372817),
+QtPositioning.coordinate(58.708089 , 11.373318),
+QtPositioning.coordinate(58.708008 , 11.373839),
+QtPositioning.coordinate(58.707917 , 11.374347),
+QtPositioning.coordinate(58.707732 , 11.375219),
+QtPositioning.coordinate(58.70752 , 11.376112),
+QtPositioning.coordinate(58.707327 , 11.376865),
+QtPositioning.coordinate(58.706959 , 11.378129),
+QtPositioning.coordinate(58.706453 , 11.379468),
+QtPositioning.coordinate(58.705968 , 11.380721),
+QtPositioning.coordinate(58.705163 , 11.382576),
+QtPositioning.coordinate(58.704586 , 11.383712),
+QtPositioning.coordinate(58.703989 , 11.384784),
+QtPositioning.coordinate(58.703059 , 11.386283),
+QtPositioning.coordinate(58.701915 , 11.387823),
+QtPositioning.coordinate(58.701115 , 11.388764),
+QtPositioning.coordinate(58.700471 , 11.389464),
+QtPositioning.coordinate(58.698984 , 11.390818),
+QtPositioning.coordinate(58.697628 , 11.391965),
+QtPositioning.coordinate(58.696203 , 11.393297),
+QtPositioning.coordinate(58.694963 , 11.394702),
+QtPositioning.coordinate(58.693987 , 11.396071),
+QtPositioning.coordinate(58.693246 , 11.397196),
+QtPositioning.coordinate(58.69253 , 11.39857),
+QtPositioning.coordinate(58.691331 , 11.401475),
+QtPositioning.coordinate(58.690666 , 11.402966),
+QtPositioning.coordinate(58.689933 , 11.404354),
+QtPositioning.coordinate(58.689191 , 11.405503),
+QtPositioning.coordinate(58.688495 , 11.406454),
+QtPositioning.coordinate(58.687897 , 11.407156),
+QtPositioning.coordinate(58.687201 , 11.407832),
+QtPositioning.coordinate(58.686581 , 11.408361),
+QtPositioning.coordinate(58.685645 , 11.408986),
+QtPositioning.coordinate(58.684599 , 11.409506),
+QtPositioning.coordinate(58.68325 , 11.409882),
+QtPositioning.coordinate(58.682504 , 11.409947),
+QtPositioning.coordinate(58.681829 , 11.409899),
+QtPositioning.coordinate(58.681618 , 11.409867),
+QtPositioning.coordinate(58.680708 , 11.409694),
+QtPositioning.coordinate(58.678656 , 11.409118),
+QtPositioning.coordinate(58.677797 , 11.408985),
+QtPositioning.coordinate(58.676774 , 11.409074),
+QtPositioning.coordinate(58.675836 , 11.409324),
+QtPositioning.coordinate(58.674646 , 11.409953),
+QtPositioning.coordinate(58.673345 , 11.410946),
+QtPositioning.coordinate(58.672012 , 11.41186),
+QtPositioning.coordinate(58.671807 , 11.411953),
+QtPositioning.coordinate(58.670951 , 11.412274),
+QtPositioning.coordinate(58.670375 , 11.412422),
+QtPositioning.coordinate(58.669751 , 11.412536),
+QtPositioning.coordinate(58.668393 , 11.412652),
+QtPositioning.coordinate(58.667443 , 11.41292),
+QtPositioning.coordinate(58.666139 , 11.413523),
+QtPositioning.coordinate(58.664935 , 11.414514),
+QtPositioning.coordinate(58.663992 , 11.4156),
+QtPositioning.coordinate(58.662674 , 11.417501),
+QtPositioning.coordinate(58.66174 , 11.418892),
+QtPositioning.coordinate(58.655557 , 11.428418),
+QtPositioning.coordinate(58.654226 , 11.430142),
+QtPositioning.coordinate(58.6529 , 11.431712),
+QtPositioning.coordinate(58.651631 , 11.432978),
+QtPositioning.coordinate(58.650112 , 11.434011),
+QtPositioning.coordinate(58.648367 , 11.434595),
+QtPositioning.coordinate(58.643048 , 11.434859),
+QtPositioning.coordinate(58.640458 , 11.434999),
+QtPositioning.coordinate(58.639298 , 11.435139),
+QtPositioning.coordinate(58.638124 , 11.435386),
+QtPositioning.coordinate(58.636769 , 11.436056),
+QtPositioning.coordinate(58.634982 , 11.437622),
+QtPositioning.coordinate(58.629732 , 11.444757),
+QtPositioning.coordinate(58.629305 , 11.445285),
+QtPositioning.coordinate(58.628925 , 11.445654),
+QtPositioning.coordinate(58.628563 , 11.445955),
+QtPositioning.coordinate(58.628165 , 11.446271),
+QtPositioning.coordinate(58.627659 , 11.446598),
+QtPositioning.coordinate(58.626529 , 11.447134),
+QtPositioning.coordinate(58.625363 , 11.447377),
+QtPositioning.coordinate(58.623083 , 11.447824),
+QtPositioning.coordinate(58.622263 , 11.448238),
+QtPositioning.coordinate(58.621726 , 11.448601),
+QtPositioning.coordinate(58.621143 , 11.44909),
+QtPositioning.coordinate(58.620508 , 11.449732),
+QtPositioning.coordinate(58.61989 , 11.450478),
+QtPositioning.coordinate(58.618668 , 11.451871),
+QtPositioning.coordinate(58.618199 , 11.452391),
+QtPositioning.coordinate(58.617497 , 11.453152),
+QtPositioning.coordinate(58.617033 , 11.453516),
+QtPositioning.coordinate(58.616811 , 11.45369),
+QtPositioning.coordinate(58.616104 , 11.454133),
+QtPositioning.coordinate(58.615104 , 11.454445),
+QtPositioning.coordinate(58.614094 , 11.454759),
+QtPositioning.coordinate(58.609238 , 11.455258),
+QtPositioning.coordinate(58.605454 , 11.455564),
+QtPositioning.coordinate(58.60178 , 11.455851),
+QtPositioning.coordinate(58.596657 , 11.456268),
+QtPositioning.coordinate(58.594894 , 11.456076),
+QtPositioning.coordinate(58.593235 , 11.45537),
+QtPositioning.coordinate(58.591686 , 11.454486),
+QtPositioning.coordinate(58.590382 , 11.453956),
+QtPositioning.coordinate(58.588285 , 11.453555),
+QtPositioning.coordinate(58.587443 , 11.453209),
+QtPositioning.coordinate(58.586514 , 11.45272),
+QtPositioning.coordinate(58.585738 , 11.452242),
+QtPositioning.coordinate(58.584688 , 11.451596),
+QtPositioning.coordinate(58.583622 , 11.45121),
+QtPositioning.coordinate(58.582512 , 11.450969),
+QtPositioning.coordinate(58.581582 , 11.450915),
+QtPositioning.coordinate(58.580505 , 11.451048),
+QtPositioning.coordinate(58.579342 , 11.451396),
+QtPositioning.coordinate(58.578253 , 11.452002),
+QtPositioning.coordinate(58.577049 , 11.452787),
+QtPositioning.coordinate(58.575977 , 11.453634),
+QtPositioning.coordinate(58.574016 , 11.455464),
+QtPositioning.coordinate(58.573809 , 11.455657),
+QtPositioning.coordinate(58.573562 , 11.455895),
+QtPositioning.coordinate(58.573312 , 11.456177),
+QtPositioning.coordinate(58.570904 , 11.459052),
+QtPositioning.coordinate(58.569929 , 11.46046),
+QtPositioning.coordinate(58.568836 , 11.462263),
+QtPositioning.coordinate(58.568114 , 11.46354),
+QtPositioning.coordinate(58.567333 , 11.465298),
+QtPositioning.coordinate(58.56679 , 11.467021),
+QtPositioning.coordinate(58.565914 , 11.470424),
+QtPositioning.coordinate(58.565383 , 11.472739),
+QtPositioning.coordinate(58.565166 , 11.473725),
+QtPositioning.coordinate(58.564825 , 11.475076),
+QtPositioning.coordinate(58.564483 , 11.476193),
+QtPositioning.coordinate(58.564122 , 11.477423),
+QtPositioning.coordinate(58.563715 , 11.478566),
+QtPositioning.coordinate(58.563453 , 11.479284),
+QtPositioning.coordinate(58.561917 , 11.482847),
+QtPositioning.coordinate(58.560705 , 11.485517),
+QtPositioning.coordinate(58.559197 , 11.488317),
+QtPositioning.coordinate(58.556972 , 11.49278),
+QtPositioning.coordinate(58.554116 , 11.499419),
+QtPositioning.coordinate(58.553947 , 11.499813),
+QtPositioning.coordinate(58.553717 , 11.500346),
+QtPositioning.coordinate(58.553516 , 11.500813),
+QtPositioning.coordinate(58.552328 , 11.503398),
+QtPositioning.coordinate(58.550993 , 11.506162),
+QtPositioning.coordinate(58.549471 , 11.509135),
+QtPositioning.coordinate(58.547657 , 11.512381),
+QtPositioning.coordinate(58.544668 , 11.517553),
+QtPositioning.coordinate(58.542076 , 11.522933),
+QtPositioning.coordinate(58.541276 , 11.524382),
+QtPositioning.coordinate(58.540083 , 11.526179),
+QtPositioning.coordinate(58.538677 , 11.527758),
+QtPositioning.coordinate(58.537322 , 11.529434),
+QtPositioning.coordinate(58.533613 , 11.534629),
+QtPositioning.coordinate(58.530306 , 11.53927),
+QtPositioning.coordinate(58.527481 , 11.543158),
+QtPositioning.coordinate(58.526055 , 11.544733),
+QtPositioning.coordinate(58.521189 , 11.548141),
+QtPositioning.coordinate(58.519301 , 11.549413),
+QtPositioning.coordinate(58.515817 , 11.551805),
+QtPositioning.coordinate(58.514346 , 11.552944),
+QtPositioning.coordinate(58.512754 , 11.554385),
+QtPositioning.coordinate(58.511355 , 11.555658),
+QtPositioning.coordinate(58.509331 , 11.55782),
+QtPositioning.coordinate(58.503816 , 11.563853),
+QtPositioning.coordinate(58.498791 , 11.569333),
+QtPositioning.coordinate(58.497272 , 11.570855),
+QtPositioning.coordinate(58.496229 , 11.571837),
+QtPositioning.coordinate(58.495415 , 11.572478),
+QtPositioning.coordinate(58.494729 , 11.573065),
+QtPositioning.coordinate(58.493494 , 11.574108),
+QtPositioning.coordinate(58.492749 , 11.574946),
+QtPositioning.coordinate(58.49161 , 11.576471),
+QtPositioning.coordinate(58.49048 , 11.578348),
+QtPositioning.coordinate(58.489701 , 11.579957),
+QtPositioning.coordinate(58.489053 , 11.581582),
+QtPositioning.coordinate(58.488525 , 11.583206),
+QtPositioning.coordinate(58.48811 , 11.584719),
+QtPositioning.coordinate(58.487888 , 11.585708),
+QtPositioning.coordinate(58.487713 , 11.586646),
+QtPositioning.coordinate(58.487533 , 11.587843),
+QtPositioning.coordinate(58.487391 , 11.589085),
+QtPositioning.coordinate(58.487329 , 11.589871),
+QtPositioning.coordinate(58.487249 , 11.591082),
+QtPositioning.coordinate(58.487248 , 11.591882),
+QtPositioning.coordinate(58.487259 , 11.592934),
+QtPositioning.coordinate(58.487304 , 11.594019),
+QtPositioning.coordinate(58.487522 , 11.59618),
+QtPositioning.coordinate(58.48789 , 11.598435),
+QtPositioning.coordinate(58.488314 , 11.600389),
+QtPositioning.coordinate(58.488984 , 11.603497),
+QtPositioning.coordinate(58.489377 , 11.605602),
+QtPositioning.coordinate(58.489664 , 11.607731),
+QtPositioning.coordinate(58.489908 , 11.610179),
+QtPositioning.coordinate(58.490015 , 11.61221),
+QtPositioning.coordinate(58.490034 , 11.613591),
+QtPositioning.coordinate(58.490022 , 11.614313),
+QtPositioning.coordinate(58.489958 , 11.616037),
+QtPositioning.coordinate(58.489754 , 11.618102),
+QtPositioning.coordinate(58.489601 , 11.61912),
+QtPositioning.coordinate(58.489429 , 11.620061),
+QtPositioning.coordinate(58.489128 , 11.621426),
+QtPositioning.coordinate(58.489045 , 11.621757),
+QtPositioning.coordinate(58.488713 , 11.622948),
+QtPositioning.coordinate(58.488287 , 11.624164),
+QtPositioning.coordinate(58.487782 , 11.6254),
+QtPositioning.coordinate(58.487466 , 11.626118),
+QtPositioning.coordinate(58.487014 , 11.627027),
+QtPositioning.coordinate(58.486408 , 11.628092),
+QtPositioning.coordinate(58.485961 , 11.628799),
+QtPositioning.coordinate(58.485518 , 11.629349),
+QtPositioning.coordinate(58.485008 , 11.629933),
+QtPositioning.coordinate(58.484472 , 11.630476),
+QtPositioning.coordinate(58.483947 , 11.63096),
+QtPositioning.coordinate(58.483417 , 11.631381),
+QtPositioning.coordinate(58.482835 , 11.631802),
+QtPositioning.coordinate(58.480403 , 11.633215),
+QtPositioning.coordinate(58.479911 , 11.63354),
+QtPositioning.coordinate(58.479269 , 11.634018),
+QtPositioning.coordinate(58.478756 , 11.63446),
+QtPositioning.coordinate(58.478224 , 11.635012),
+QtPositioning.coordinate(58.477665 , 11.635687),
+QtPositioning.coordinate(58.477139 , 11.636436),
+QtPositioning.coordinate(58.476633 , 11.637221),
+QtPositioning.coordinate(58.47594 , 11.638558),
+QtPositioning.coordinate(58.475459 , 11.639613),
+QtPositioning.coordinate(58.475022 , 11.640779),
+QtPositioning.coordinate(58.474163 , 11.64327),
+QtPositioning.coordinate(58.473887 , 11.644043),
+QtPositioning.coordinate(58.473547 , 11.644865),
+QtPositioning.coordinate(58.473143 , 11.645699),
+QtPositioning.coordinate(58.472713 , 11.646521),
+QtPositioning.coordinate(58.472334 , 11.647184),
+QtPositioning.coordinate(58.471904 , 11.647859),
+QtPositioning.coordinate(58.471507 , 11.648448),
+QtPositioning.coordinate(58.471096 , 11.648975),
+QtPositioning.coordinate(58.470576 , 11.64954),
+QtPositioning.coordinate(58.470153 , 11.649957),
+QtPositioning.coordinate(58.469633 , 11.650399),
+QtPositioning.coordinate(58.469242 , 11.650742),
+QtPositioning.coordinate(58.468773 , 11.651073),
+QtPositioning.coordinate(58.468196 , 11.651454),
+QtPositioning.coordinate(58.462761 , 11.654491),
+QtPositioning.coordinate(58.46215 , 11.65491),
+QtPositioning.coordinate(58.461723 , 11.655204),
+QtPositioning.coordinate(58.461176 , 11.655657),
+QtPositioning.coordinate(58.460752 , 11.656046),
+QtPositioning.coordinate(58.460506 , 11.656283),
+QtPositioning.coordinate(58.460382 , 11.656411),
+QtPositioning.coordinate(58.459358 , 11.6577),
+QtPositioning.coordinate(58.459056 , 11.658159),
+QtPositioning.coordinate(58.458662 , 11.658867),
+QtPositioning.coordinate(58.457961 , 11.660207),
+QtPositioning.coordinate(58.456867 , 11.662611),
+QtPositioning.coordinate(58.456421 , 11.663519),
+QtPositioning.coordinate(58.456098 , 11.664067),
+QtPositioning.coordinate(58.455732 , 11.664681),
+QtPositioning.coordinate(58.455257 , 11.665454),
+QtPositioning.coordinate(58.454872 , 11.665981),
+QtPositioning.coordinate(58.454365 , 11.66657),
+QtPositioning.coordinate(58.453794 , 11.667147),
+QtPositioning.coordinate(58.453338 , 11.667539),
+QtPositioning.coordinate(58.451714 , 11.668607),
+QtPositioning.coordinate(58.451303 , 11.668877),
+QtPositioning.coordinate(58.450962 , 11.669159),
+QtPositioning.coordinate(58.450584 , 11.669478),
+QtPositioning.coordinate(58.450224 , 11.669871),
+QtPositioning.coordinate(58.449845 , 11.6703),
+QtPositioning.coordinate(58.449428 , 11.670865),
+QtPositioning.coordinate(58.448998 , 11.671527),
+QtPositioning.coordinate(58.448581 , 11.672226),
+QtPositioning.coordinate(58.448215 , 11.67295),
+QtPositioning.coordinate(58.447855 , 11.673736),
+QtPositioning.coordinate(58.447489 , 11.674668),
+QtPositioning.coordinate(58.447136 , 11.675772),
+QtPositioning.coordinate(58.446802 , 11.676975),
+QtPositioning.coordinate(58.44652 , 11.678214),
+QtPositioning.coordinate(58.446346 , 11.679134),
+QtPositioning.coordinate(58.44616 , 11.680562),
+QtPositioning.coordinate(58.446001 , 11.682128),
+QtPositioning.coordinate(58.445204 , 11.690524),
+QtPositioning.coordinate(58.445089 , 11.691528),
+QtPositioning.coordinate(58.444908 , 11.692827),
+QtPositioning.coordinate(58.444773 , 11.693834),
+QtPositioning.coordinate(58.444613 , 11.694803),
+QtPositioning.coordinate(58.444409 , 11.695793),
+QtPositioning.coordinate(58.44433 , 11.696132),
+QtPositioning.coordinate(58.444193 , 11.696651),
+QtPositioning.coordinate(58.44392 , 11.697542),
+QtPositioning.coordinate(58.443661 , 11.69828),
+QtPositioning.coordinate(58.443323 , 11.699117),
+QtPositioning.coordinate(58.442928 , 11.699955),
+QtPositioning.coordinate(58.442648 , 11.700486),
+QtPositioning.coordinate(58.442291 , 11.701095),
+QtPositioning.coordinate(58.442163 , 11.701316),
+QtPositioning.coordinate(58.441701 , 11.701956),
+QtPositioning.coordinate(58.440964 , 11.70285),
+QtPositioning.coordinate(58.438788 , 11.705453),
+QtPositioning.coordinate(58.43815 , 11.706234),
+QtPositioning.coordinate(58.437409 , 11.707201),
+QtPositioning.coordinate(58.435359 , 11.710116),
+QtPositioning.coordinate(58.434703 , 11.711017),
+QtPositioning.coordinate(58.433939 , 11.711993),
+QtPositioning.coordinate(58.433188 , 11.71279),
+QtPositioning.coordinate(58.432455 , 11.713527),
+QtPositioning.coordinate(58.431659 , 11.714312),
+QtPositioning.coordinate(58.430792 , 11.715171),
+QtPositioning.coordinate(58.429931 , 11.715981),
+QtPositioning.coordinate(58.428588 , 11.717158),
+QtPositioning.coordinate(58.427581 , 11.717944),
+QtPositioning.coordinate(58.426289 , 11.719047),
+QtPositioning.coordinate(58.42573 , 11.719576),
+QtPositioning.coordinate(58.425201 , 11.720112),
+QtPositioning.coordinate(58.424663 , 11.720668),
+QtPositioning.coordinate(58.423706 , 11.721704),
+QtPositioning.coordinate(58.423102 , 11.72244),
+QtPositioning.coordinate(58.420069 , 11.726091),
+QtPositioning.coordinate(58.419607 , 11.726646),
+QtPositioning.coordinate(58.419004 , 11.727379),
+QtPositioning.coordinate(58.417683 , 11.728728),
+QtPositioning.coordinate(58.416584 , 11.729693),
+QtPositioning.coordinate(58.415654 , 11.730306),
+QtPositioning.coordinate(58.414599 , 11.730911),
+QtPositioning.coordinate(58.413021 , 11.731715),
+QtPositioning.coordinate(58.412427 , 11.732075),
+QtPositioning.coordinate(58.411761 , 11.732551),
+QtPositioning.coordinate(58.411296 , 11.732896),
+QtPositioning.coordinate(58.410761 , 11.733378),
+QtPositioning.coordinate(58.410013 , 11.73414),
+QtPositioning.coordinate(58.40914 , 11.735141),
+QtPositioning.coordinate(58.408286 , 11.735999),
+QtPositioning.coordinate(58.407563 , 11.736615),
+QtPositioning.coordinate(58.406697 , 11.737295),
+QtPositioning.coordinate(58.405837 , 11.737989),
+QtPositioning.coordinate(58.405156 , 11.738622),
+QtPositioning.coordinate(58.404577 , 11.739218),
+QtPositioning.coordinate(58.403925 , 11.74002),
+QtPositioning.coordinate(58.403388 , 11.740751),
+QtPositioning.coordinate(58.402784 , 11.741638),
+QtPositioning.coordinate(58.402301 , 11.74245),
+QtPositioning.coordinate(58.401776 , 11.743403),
+QtPositioning.coordinate(58.400482 , 11.745683),
+QtPositioning.coordinate(58.399119 , 11.748152),
+QtPositioning.coordinate(58.397858 , 11.750179),
+QtPositioning.coordinate(58.397085 , 11.751311),
+QtPositioning.coordinate(58.396309 , 11.75241),
+QtPositioning.coordinate(58.395313 , 11.753688),
+QtPositioning.coordinate(58.394459 , 11.754781),
+QtPositioning.coordinate(58.393499 , 11.756019),
+QtPositioning.coordinate(58.392416 , 11.757495),
+QtPositioning.coordinate(58.391511 , 11.758901),
+QtPositioning.coordinate(58.389888 , 11.761673),
+QtPositioning.coordinate(58.389368 , 11.762536),
+QtPositioning.coordinate(58.388799 , 11.763422),
+QtPositioning.coordinate(58.388164 , 11.764248),
+QtPositioning.coordinate(58.38741 , 11.765061),
+QtPositioning.coordinate(58.386406 , 11.765985),
+QtPositioning.coordinate(58.385523 , 11.766807),
+QtPositioning.coordinate(58.38468 , 11.767715),
+QtPositioning.coordinate(58.383997 , 11.768651),
+QtPositioning.coordinate(58.38329 , 11.769787),
+QtPositioning.coordinate(58.382125 , 11.771752),
+QtPositioning.coordinate(58.381539 , 11.772648),
+QtPositioning.coordinate(58.380926 , 11.773493),
+QtPositioning.coordinate(58.380011 , 11.774612),
+QtPositioning.coordinate(58.379822 , 11.774817),
+QtPositioning.coordinate(58.378292 , 11.776404),
+QtPositioning.coordinate(58.377777 , 11.777058),
+QtPositioning.coordinate(58.377174 , 11.777833),
+QtPositioning.coordinate(58.376102 , 11.77947),
+QtPositioning.coordinate(58.375616 , 11.780383),
+QtPositioning.coordinate(58.375114 , 11.781337),
+QtPositioning.coordinate(58.374594 , 11.782433),
+QtPositioning.coordinate(58.374084 , 11.783669),
+QtPositioning.coordinate(58.372887 , 11.786758),
+QtPositioning.coordinate(58.372363 , 11.787958),
+QtPositioning.coordinate(58.371748 , 11.789232),
+QtPositioning.coordinate(58.371193 , 11.790243),
+QtPositioning.coordinate(58.370452 , 11.791426),
+QtPositioning.coordinate(58.369233 , 11.793125),
+QtPositioning.coordinate(58.366745 , 11.796242),
+QtPositioning.coordinate(58.365492 , 11.798129),
+QtPositioning.coordinate(58.364511 , 11.799919),
+QtPositioning.coordinate(58.363331 , 11.802594),
+QtPositioning.coordinate(58.362085 , 11.805398),
+QtPositioning.coordinate(58.360885 , 11.807678),
+QtPositioning.coordinate(58.359489 , 11.810078),
+QtPositioning.coordinate(58.357424 , 11.813096),
+QtPositioning.coordinate(58.356352 , 11.814456),
+QtPositioning.coordinate(58.355105 , 11.815925),
+QtPositioning.coordinate(58.354605 , 11.816469),
+QtPositioning.coordinate(58.354405 , 11.81667),
+QtPositioning.coordinate(58.353829 , 11.817238),
+QtPositioning.coordinate(58.353275 , 11.817742),
+QtPositioning.coordinate(58.352912 , 11.818053),
+QtPositioning.coordinate(58.352139 , 11.81866),
+QtPositioning.coordinate(58.351509 , 11.819121),
+QtPositioning.coordinate(58.351152 , 11.819345),
+QtPositioning.coordinate(58.35045 , 11.81979),
+QtPositioning.coordinate(58.349239 , 11.820449),
+QtPositioning.coordinate(58.344821 , 11.822429),
+QtPositioning.coordinate(58.343855 , 11.822869),
+QtPositioning.coordinate(58.342171 , 11.823787),
+QtPositioning.coordinate(58.340845 , 11.824612),
+QtPositioning.coordinate(58.339161 , 11.825761),
+QtPositioning.coordinate(58.337767 , 11.826895),
+QtPositioning.coordinate(58.336413 , 11.828027),
+QtPositioning.coordinate(58.334675 , 11.829637),
+QtPositioning.coordinate(58.332996 , 11.831411),
+QtPositioning.coordinate(58.331939 , 11.83265),
+QtPositioning.coordinate(58.330895 , 11.834006),
+QtPositioning.coordinate(58.329792 , 11.835679),
+QtPositioning.coordinate(58.328433 , 11.838049),
+QtPositioning.coordinate(58.327837 , 11.839253),
+QtPositioning.coordinate(58.32714 , 11.840698),
+QtPositioning.coordinate(58.324517 , 11.846237),
+QtPositioning.coordinate(58.323493 , 11.848449),
+QtPositioning.coordinate(58.322885 , 11.849721),
+QtPositioning.coordinate(58.32207 , 11.851204),
+QtPositioning.coordinate(58.321402 , 11.852277),
+QtPositioning.coordinate(58.320595 , 11.853449),
+QtPositioning.coordinate(58.319776 , 11.854492),
+QtPositioning.coordinate(58.319018 , 11.855339),
+QtPositioning.coordinate(58.318025 , 11.856265),
+QtPositioning.coordinate(58.317219 , 11.856887),
+QtPositioning.coordinate(58.316009 , 11.857669),
+QtPositioning.coordinate(58.314751 , 11.858264),
+QtPositioning.coordinate(58.313701 , 11.858599),
+QtPositioning.coordinate(58.313129 , 11.85875),
+QtPositioning.coordinate(58.312538 , 11.858837),
+QtPositioning.coordinate(58.311817 , 11.85888),
+QtPositioning.coordinate(58.311224 , 11.858881),
+QtPositioning.coordinate(58.310044 , 11.858866),
+QtPositioning.coordinate(58.308332 , 11.858867),
+QtPositioning.coordinate(58.306613 , 11.858956),
+QtPositioning.coordinate(58.304954 , 11.85916),
+QtPositioning.coordinate(58.3032 , 11.859526),
+QtPositioning.coordinate(58.301646 , 11.859932),
+QtPositioning.coordinate(58.300257 , 11.860411),
+QtPositioning.coordinate(58.298881 , 11.860983),
+QtPositioning.coordinate(58.297741 , 11.861551),
+QtPositioning.coordinate(58.296329 , 11.862583),
+QtPositioning.coordinate(58.295347 , 11.863426),
+QtPositioning.coordinate(58.294532 , 11.864331),
+QtPositioning.coordinate(58.294112 , 11.86483),
+QtPositioning.coordinate(58.29339 , 11.865689),
+QtPositioning.coordinate(58.292363 , 11.867205),
+QtPositioning.coordinate(58.291477 , 11.86871),
+QtPositioning.coordinate(58.290261 , 11.870718),
+QtPositioning.coordinate(58.289651 , 11.871703),
+QtPositioning.coordinate(58.289016 , 11.87264),
+QtPositioning.coordinate(58.288342 , 11.873475),
+QtPositioning.coordinate(58.287638 , 11.874297),
+QtPositioning.coordinate(58.286767 , 11.875215),
+QtPositioning.coordinate(58.286242 , 11.875769),
+QtPositioning.coordinate(58.28398 , 11.878091),
+QtPositioning.coordinate(58.282384 , 11.879742),
+QtPositioning.coordinate(58.28206 , 11.880077),
+QtPositioning.coordinate(58.280733 , 11.88145),
+QtPositioning.coordinate(58.277447 , 11.884821),
+QtPositioning.coordinate(58.275278 , 11.887004),
+QtPositioning.coordinate(58.273158 , 11.889008),
+QtPositioning.coordinate(58.270966 , 11.890904),
+QtPositioning.coordinate(58.268814 , 11.892651),
+QtPositioning.coordinate(58.266236 , 11.894518),
+QtPositioning.coordinate(58.264897 , 11.895442),
+QtPositioning.coordinate(58.263483 , 11.896352),
+QtPositioning.coordinate(58.262548 , 11.896914),
+QtPositioning.coordinate(58.262051 , 11.897211),
+QtPositioning.coordinate(58.261172 , 11.897742),
+QtPositioning.coordinate(58.258357 , 11.899408),
+QtPositioning.coordinate(58.257252 , 11.900066),
+QtPositioning.coordinate(58.255928 , 11.900971),
+QtPositioning.coordinate(58.25437 , 11.902133),
+QtPositioning.coordinate(58.253087 , 11.903041),
+QtPositioning.coordinate(58.249615 , 11.905192),
+QtPositioning.coordinate(58.246376 , 11.907302),
+QtPositioning.coordinate(58.24466 , 11.908367),
+QtPositioning.coordinate(58.243822 , 11.908808),
+QtPositioning.coordinate(58.24293 , 11.909212),
+QtPositioning.coordinate(58.242265 , 11.909457),
+QtPositioning.coordinate(58.241479 , 11.909673),
+QtPositioning.coordinate(58.240561 , 11.909884),
+QtPositioning.coordinate(58.239433 , 11.91009),
+QtPositioning.coordinate(58.238319 , 11.910337),
+QtPositioning.coordinate(58.236931 , 11.910743),
+QtPositioning.coordinate(58.235709 , 11.91126),
+QtPositioning.coordinate(58.234806 , 11.911701),
+QtPositioning.coordinate(58.234509 , 11.911846),
+QtPositioning.coordinate(58.2336 , 11.912391),
+QtPositioning.coordinate(58.232658 , 11.913007),
+QtPositioning.coordinate(58.231777 , 11.913613),
+QtPositioning.coordinate(58.230528 , 11.914494),
+QtPositioning.coordinate(58.228809 , 11.915501),
+QtPositioning.coordinate(58.228657 , 11.915579),
+QtPositioning.coordinate(58.2286 , 11.915604),
+QtPositioning.coordinate(58.227293 , 11.916202),
+QtPositioning.coordinate(58.226538 , 11.916472),
+QtPositioning.coordinate(58.226409 , 11.916517),
+QtPositioning.coordinate(58.225316 , 11.916852),
+QtPositioning.coordinate(58.223724 , 11.917164),
+QtPositioning.coordinate(58.222894 , 11.917256),
+QtPositioning.coordinate(58.22206 , 11.917282),
+QtPositioning.coordinate(58.220535 , 11.917258),
+QtPositioning.coordinate(58.219307 , 11.917063),
+QtPositioning.coordinate(58.217871 , 11.91663),
+QtPositioning.coordinate(58.217134 , 11.916338),
+QtPositioning.coordinate(58.216322 , 11.915962),
+QtPositioning.coordinate(58.21369 , 11.914551),
+QtPositioning.coordinate(58.21111 , 11.91315),
+QtPositioning.coordinate(58.210408 , 11.91281),
+QtPositioning.coordinate(58.209214 , 11.912183),
+QtPositioning.coordinate(58.208416 , 11.91177),
+QtPositioning.coordinate(58.208022 , 11.911567),
+QtPositioning.coordinate(58.20741 , 11.911222),
+QtPositioning.coordinate(58.205241 , 11.910095),
+QtPositioning.coordinate(58.203208 , 11.90902),
+QtPositioning.coordinate(58.202188 , 11.908551),
+QtPositioning.coordinate(58.201157 , 11.908166),
+QtPositioning.coordinate(58.199856 , 11.907808),
+QtPositioning.coordinate(58.19859 , 11.907582),
+QtPositioning.coordinate(58.196982 , 11.907526),
+QtPositioning.coordinate(58.195955 , 11.907606),
+QtPositioning.coordinate(58.194984 , 11.907759),
+QtPositioning.coordinate(58.194004 , 11.907998),
+QtPositioning.coordinate(58.19259 , 11.908431),
+QtPositioning.coordinate(58.191248 , 11.908759),
+QtPositioning.coordinate(58.189802 , 11.908947),
+QtPositioning.coordinate(58.188538 , 11.908947),
+QtPositioning.coordinate(58.187306 , 11.90884),
+QtPositioning.coordinate(58.186154 , 11.908691),
+QtPositioning.coordinate(58.184821 , 11.908343),
+QtPositioning.coordinate(58.183369 , 11.907856),
+QtPositioning.coordinate(58.182041 , 11.907272),
+QtPositioning.coordinate(58.180688 , 11.906526),
+QtPositioning.coordinate(58.179345 , 11.905645),
+QtPositioning.coordinate(58.178052 , 11.904648),
+QtPositioning.coordinate(58.177266 , 11.903983),
+QtPositioning.coordinate(58.175942 , 11.902738),
+QtPositioning.coordinate(58.174677 , 11.901439),
+QtPositioning.coordinate(58.173511 , 11.900158),
+QtPositioning.coordinate(58.17248 , 11.898894),
+QtPositioning.coordinate(58.17148 , 11.897484),
+QtPositioning.coordinate(58.17029 , 11.895696),
+QtPositioning.coordinate(58.169182 , 11.894115),
+QtPositioning.coordinate(58.168252 , 11.892967),
+QtPositioning.coordinate(58.167296 , 11.891877),
+QtPositioning.coordinate(58.166339 , 11.890942),
+QtPositioning.coordinate(58.165368 , 11.890076),
+QtPositioning.coordinate(58.164419 , 11.889342),
+QtPositioning.coordinate(58.163612 , 11.888759),
+QtPositioning.coordinate(58.162337 , 11.888085),
+QtPositioning.coordinate(58.160989 , 11.887559),
+QtPositioning.coordinate(58.160098 , 11.887319),
+QtPositioning.coordinate(58.159105 , 11.887151),
+QtPositioning.coordinate(58.15816 , 11.887084),
+QtPositioning.coordinate(58.157317 , 11.887096),
+QtPositioning.coordinate(58.155754 , 11.887158),
+QtPositioning.coordinate(58.154771 , 11.887071),
+QtPositioning.coordinate(58.153349 , 11.886777),
+QtPositioning.coordinate(58.152047 , 11.886293),
+QtPositioning.coordinate(58.150762 , 11.885592),
+QtPositioning.coordinate(58.149641 , 11.884973),
+QtPositioning.coordinate(58.148174 , 11.884381),
+QtPositioning.coordinate(58.146916 , 11.884048),
+QtPositioning.coordinate(58.145535 , 11.883899),
+QtPositioning.coordinate(58.144566 , 11.883885),
+QtPositioning.coordinate(58.143822 , 11.883978),
+QtPositioning.coordinate(58.142109 , 11.884319),
+QtPositioning.coordinate(58.138767 , 11.884991),
+QtPositioning.coordinate(58.135878 , 11.885551),
+QtPositioning.coordinate(58.13422 , 11.885714),
+QtPositioning.coordinate(58.132607 , 11.885715),
+QtPositioning.coordinate(58.131084 , 11.885541),
+QtPositioning.coordinate(58.129532 , 11.885193),
+QtPositioning.coordinate(58.128159 , 11.884732),
+QtPositioning.coordinate(58.126833 , 11.884136),
+QtPositioning.coordinate(58.126034 , 11.88373),
+QtPositioning.coordinate(58.12519 , 11.883242),
+QtPositioning.coordinate(58.1238 , 11.882419),
+QtPositioning.coordinate(58.122249 , 11.881585),
+QtPositioning.coordinate(58.120808 , 11.880934),
+QtPositioning.coordinate(58.119386 , 11.880431),
+QtPositioning.coordinate(58.117844 , 11.879975),
+QtPositioning.coordinate(58.115924 , 11.879592),
+QtPositioning.coordinate(58.113996 , 11.879342),
+QtPositioning.coordinate(58.112277 , 11.879063),
+QtPositioning.coordinate(58.111374 , 11.878942),
+QtPositioning.coordinate(58.110451 , 11.878892),
+QtPositioning.coordinate(58.108871 , 11.87896),
+QtPositioning.coordinate(58.108307 , 11.879006),
+QtPositioning.coordinate(58.107704 , 11.879068),
+QtPositioning.coordinate(58.106768 , 11.879207),
+QtPositioning.coordinate(58.105487 , 11.879632),
+QtPositioning.coordinate(58.104778 , 11.879937),
+QtPositioning.coordinate(58.103542 , 11.880568),
+QtPositioning.coordinate(58.102051 , 11.88136),
+QtPositioning.coordinate(58.100718 , 11.88184),
+QtPositioning.coordinate(58.099323 , 11.882165),
+QtPositioning.coordinate(58.097876 , 11.88226),
+QtPositioning.coordinate(58.096481 , 11.88218),
+QtPositioning.coordinate(58.094838 , 11.882003),
+QtPositioning.coordinate(58.093319 , 11.881906),
+QtPositioning.coordinate(58.091858 , 11.881982),
+QtPositioning.coordinate(58.09037 , 11.882189),
+QtPositioning.coordinate(58.08846 , 11.882622),
+QtPositioning.coordinate(58.086603 , 11.883224),
+QtPositioning.coordinate(58.085102 , 11.88379),
+QtPositioning.coordinate(58.083494 , 11.884456),
+QtPositioning.coordinate(58.082178 , 11.885067),
+QtPositioning.coordinate(58.080996 , 11.885709),
+QtPositioning.coordinate(58.079334 , 11.886637),
+QtPositioning.coordinate(58.07764 , 11.887712),
+QtPositioning.coordinate(58.075803 , 11.888915),
+QtPositioning.coordinate(58.074879 , 11.889466),
+QtPositioning.coordinate(58.073798 , 11.889979),
+QtPositioning.coordinate(58.072567 , 11.890378),
+QtPositioning.coordinate(58.071102 , 11.890594),
+QtPositioning.coordinate(58.069702 , 11.890563),
+QtPositioning.coordinate(58.068541 , 11.890335),
+QtPositioning.coordinate(58.06731 , 11.889927),
+QtPositioning.coordinate(58.066165 , 11.889351),
+QtPositioning.coordinate(58.064972 , 11.888574),
+QtPositioning.coordinate(58.064141 , 11.887855),
+QtPositioning.coordinate(58.063106 , 11.886877),
+QtPositioning.coordinate(58.062225 , 11.88582),
+QtPositioning.coordinate(58.061292 , 11.884715),
+QtPositioning.coordinate(58.060933 , 11.884215),
+QtPositioning.coordinate(58.060047 , 11.88295),
+QtPositioning.coordinate(58.058694 , 11.880907),
+QtPositioning.coordinate(58.056778 , 11.877799),
+QtPositioning.coordinate(58.055486 , 11.875327),
+QtPositioning.coordinate(58.054729 , 11.873857),
+QtPositioning.coordinate(58.053615 , 11.871677),
+QtPositioning.coordinate(58.052679 , 11.869766),
+QtPositioning.coordinate(58.051607 , 11.867422),
+QtPositioning.coordinate(58.050615 , 11.865108),
+QtPositioning.coordinate(58.049328 , 11.861914),
+QtPositioning.coordinate(58.048127 , 11.858695),
+QtPositioning.coordinate(58.047111 , 11.856013),
+QtPositioning.coordinate(58.046173 , 11.853676),
+QtPositioning.coordinate(58.045204 , 11.851721),
+QtPositioning.coordinate(58.044196 , 11.850172),
+QtPositioning.coordinate(58.043016 , 11.848669),
+QtPositioning.coordinate(58.041834 , 11.847527),
+QtPositioning.coordinate(58.040774 , 11.84671),
+QtPositioning.coordinate(58.039852 , 11.846143),
+QtPositioning.coordinate(58.038614 , 11.845671),
+QtPositioning.coordinate(58.037422 , 11.845446),
+QtPositioning.coordinate(58.036591 , 11.845399),
+QtPositioning.coordinate(58.035685 , 11.845484),
+QtPositioning.coordinate(58.034744 , 11.845661),
+QtPositioning.coordinate(58.033376 , 11.846043),
+QtPositioning.coordinate(58.031959 , 11.846381),
+QtPositioning.coordinate(58.030377 , 11.846531),
+QtPositioning.coordinate(58.029727 , 11.846566),
+QtPositioning.coordinate(58.029357 , 11.846551),
+QtPositioning.coordinate(58.028918 , 11.846535),
+QtPositioning.coordinate(58.02862 , 11.846517),
+QtPositioning.coordinate(58.027876 , 11.846443),
+QtPositioning.coordinate(58.026928 , 11.846293),
+QtPositioning.coordinate(58.025896 , 11.846056),
+QtPositioning.coordinate(58.025483 , 11.845928),
+QtPositioning.coordinate(58.023472 , 11.84522),
+QtPositioning.coordinate(58.022296 , 11.844813),
+QtPositioning.coordinate(58.021322 , 11.844512),
+QtPositioning.coordinate(58.020833 , 11.844386),
+QtPositioning.coordinate(58.020201 , 11.844211),
+QtPositioning.coordinate(58.019492 , 11.844034),
+QtPositioning.coordinate(58.018136 , 11.843783),
+QtPositioning.coordinate(58.016756 , 11.843547),
+QtPositioning.coordinate(58.015043 , 11.843335),
+QtPositioning.coordinate(58.013186 , 11.84321),
+QtPositioning.coordinate(58.011374 , 11.843193),
+QtPositioning.coordinate(58.009769 , 11.843256),
+QtPositioning.coordinate(58.008139 , 11.843446),
+QtPositioning.coordinate(58.006569 , 11.843774),
+QtPositioning.coordinate(58.005141 , 11.844145),
+QtPositioning.coordinate(58.004034 , 11.84431),
+QtPositioning.coordinate(58.002742 , 11.844355),
+QtPositioning.coordinate(58.00142 , 11.844223),
+QtPositioning.coordinate(58.000089 , 11.843934),
+QtPositioning.coordinate(57.997423 , 11.842938),
+QtPositioning.coordinate(57.995863 , 11.842483),
+QtPositioning.coordinate(57.994398 , 11.842242),
+QtPositioning.coordinate(57.99309 , 11.842116),
+QtPositioning.coordinate(57.99174 , 11.842126),
+QtPositioning.coordinate(57.990426 , 11.842177),
+QtPositioning.coordinate(57.988957 , 11.84217),
+QtPositioning.coordinate(57.987398 , 11.842088),
+QtPositioning.coordinate(57.985756 , 11.841932),
+QtPositioning.coordinate(57.982298 , 11.841398),
+QtPositioning.coordinate(57.980391 , 11.841017),
+QtPositioning.coordinate(57.978455 , 11.840595),
+QtPositioning.coordinate(57.978161 , 11.840531),
+QtPositioning.coordinate(57.977625 , 11.840388),
+QtPositioning.coordinate(57.975 , 11.83974),
+QtPositioning.coordinate(57.973539 , 11.839529),
+QtPositioning.coordinate(57.972031 , 11.839552),
+QtPositioning.coordinate(57.970426 , 11.839799),
+QtPositioning.coordinate(57.969017 , 11.840266),
+QtPositioning.coordinate(57.968248 , 11.840566),
+QtPositioning.coordinate(57.967499 , 11.840947),
+QtPositioning.coordinate(57.966016 , 11.841883),
+QtPositioning.coordinate(57.964214 , 11.843026),
+QtPositioning.coordinate(57.962696 , 11.844064),
+QtPositioning.coordinate(57.960223 , 11.845977),
+QtPositioning.coordinate(57.958176 , 11.847533),
+QtPositioning.coordinate(57.955776 , 11.849103),
+QtPositioning.coordinate(57.954117 , 11.850057),
+QtPositioning.coordinate(57.952381 , 11.850948),
+QtPositioning.coordinate(57.951042 , 11.851561),
+QtPositioning.coordinate(57.948837 , 11.852987),
+QtPositioning.coordinate(57.947914 , 11.853649),
+QtPositioning.coordinate(57.946826 , 11.8546),
+QtPositioning.coordinate(57.945756 , 11.85564),
+QtPositioning.coordinate(57.945599 , 11.855792),
+QtPositioning.coordinate(57.945347 , 11.856038),
+QtPositioning.coordinate(57.944716 , 11.856713),
+QtPositioning.coordinate(57.943998 , 11.857517),
+QtPositioning.coordinate(57.943155 , 11.858556),
+QtPositioning.coordinate(57.94217 , 11.859931),
+QtPositioning.coordinate(57.941723 , 11.860506),
+QtPositioning.coordinate(57.941204 , 11.861242),
+QtPositioning.coordinate(57.940633 , 11.862064),
+QtPositioning.coordinate(57.939079 , 11.864304),
+QtPositioning.coordinate(57.937748 , 11.866037),
+QtPositioning.coordinate(57.93639 , 11.867756),
+QtPositioning.coordinate(57.934882 , 11.869354),
+QtPositioning.coordinate(57.933445 , 11.870865),
+QtPositioning.coordinate(57.931664 , 11.872475),
+QtPositioning.coordinate(57.929908 , 11.873942),
+QtPositioning.coordinate(57.927914 , 11.875394),
+QtPositioning.coordinate(57.925853 , 11.876819),
+QtPositioning.coordinate(57.923586 , 11.878476),
+QtPositioning.coordinate(57.922371 , 11.879434),
+QtPositioning.coordinate(57.921406 , 11.880231),
+QtPositioning.coordinate(57.919866 , 11.881685),
+QtPositioning.coordinate(57.918029 , 11.8837),
+QtPositioning.coordinate(57.916324 , 11.885865),
+QtPositioning.coordinate(57.914742 , 11.888149),
+QtPositioning.coordinate(57.912426 , 11.892079),
+QtPositioning.coordinate(57.910213 , 11.895875),
+QtPositioning.coordinate(57.909169 , 11.897654),
+QtPositioning.coordinate(57.908131 , 11.899696),
+QtPositioning.coordinate(57.907265 , 11.901674),
+QtPositioning.coordinate(57.90641 , 11.903989),
+QtPositioning.coordinate(57.905499 , 11.906588),
+QtPositioning.coordinate(57.904662 , 11.908927),
+QtPositioning.coordinate(57.903788 , 11.911302),
+QtPositioning.coordinate(57.902833 , 11.913772),
+QtPositioning.coordinate(57.902061 , 11.91569),
+QtPositioning.coordinate(57.901117 , 11.917884),
+QtPositioning.coordinate(57.900137 , 11.920034),
+QtPositioning.coordinate(57.899091 , 11.922285),
+QtPositioning.coordinate(57.897772 , 11.924923),
+QtPositioning.coordinate(57.896341 , 11.927642),
+QtPositioning.coordinate(57.895076 , 11.929916),
+QtPositioning.coordinate(57.893759 , 11.93216),
+QtPositioning.coordinate(57.892387 , 11.934393),
+QtPositioning.coordinate(57.891028 , 11.936489),
+QtPositioning.coordinate(57.889632 , 11.938502),
+QtPositioning.coordinate(57.88815 , 11.940555),
+QtPositioning.coordinate(57.886332 , 11.942887),
+QtPositioning.coordinate(57.885437 , 11.943986),
+QtPositioning.coordinate(57.884366 , 11.945447),
+QtPositioning.coordinate(57.883602 , 11.946567),
+QtPositioning.coordinate(57.882897 , 11.947724),
+QtPositioning.coordinate(57.882202 , 11.949008),
+QtPositioning.coordinate(57.88149 , 11.950369),
+QtPositioning.coordinate(57.880958 , 11.951515),
+QtPositioning.coordinate(57.880782 , 11.951895),
+QtPositioning.coordinate(57.880116 , 11.953407),
+QtPositioning.coordinate(57.878842 , 11.956571),
+QtPositioning.coordinate(57.878208 , 11.958116),
+QtPositioning.coordinate(57.877318 , 11.960014),
+QtPositioning.coordinate(57.877048 , 11.960556),
+QtPositioning.coordinate(57.876486 , 11.961642),
+QtPositioning.coordinate(57.875914 , 11.962559),
+QtPositioning.coordinate(57.875252 , 11.963549),
+QtPositioning.coordinate(57.874527 , 11.964509),
+QtPositioning.coordinate(57.873834 , 11.965309),
+QtPositioning.coordinate(57.873062 , 11.966004),
+QtPositioning.coordinate(57.872411 , 11.96655),
+QtPositioning.coordinate(57.872216 , 11.966695),
+QtPositioning.coordinate(57.87095 , 11.967543),
+QtPositioning.coordinate(57.870023 , 11.968169),
+QtPositioning.coordinate(57.869335 , 11.968626),
+QtPositioning.coordinate(57.867993 , 11.969672),
+QtPositioning.coordinate(57.867461 , 11.970137),
+QtPositioning.coordinate(57.866725 , 11.970894),
+QtPositioning.coordinate(57.866011 , 11.971672),
+QtPositioning.coordinate(57.864909 , 11.972895),
+QtPositioning.coordinate(57.864285 , 11.973664),
+QtPositioning.coordinate(57.863911 , 11.974186),
+QtPositioning.coordinate(57.863592 , 11.97465),
+QtPositioning.coordinate(57.863261 , 11.97519),
+QtPositioning.coordinate(57.862876 , 11.975858),
+QtPositioning.coordinate(57.862493 , 11.976575),
+QtPositioning.coordinate(57.862179 , 11.977244),
+QtPositioning.coordinate(57.861805 , 11.978085),
+QtPositioning.coordinate(57.861442 , 11.978966),
+QtPositioning.coordinate(57.861019 , 11.980181),
+QtPositioning.coordinate(57.860795 , 11.980885),
+QtPositioning.coordinate(57.860686 , 11.981231),
+QtPositioning.coordinate(57.86033 , 11.982417),
+QtPositioning.coordinate(57.859604 , 11.98476),
+QtPositioning.coordinate(57.85919 , 11.985962),
+QtPositioning.coordinate(57.858506 , 11.987659),
+QtPositioning.coordinate(57.858036 , 11.988753),
+QtPositioning.coordinate(57.857504 , 11.989864),
+QtPositioning.coordinate(57.857161 , 11.990503),
+QtPositioning.coordinate(57.85657 , 11.991634),
+QtPositioning.coordinate(57.855791 , 11.993022),
+QtPositioning.coordinate(57.854947 , 11.994398),
+QtPositioning.coordinate(57.85428 , 11.995438),
+QtPositioning.coordinate(57.853453 , 11.996666),
+QtPositioning.coordinate(57.852582 , 11.997866),
+QtPositioning.coordinate(57.851654 , 11.999041),
+QtPositioning.coordinate(57.850765 , 12.00005),
+QtPositioning.coordinate(57.850371 , 12.000436),
+QtPositioning.coordinate(57.849857 , 12.000928),
+QtPositioning.coordinate(57.848795 , 12.001816),
+QtPositioning.coordinate(57.848196 , 12.002267),
+QtPositioning.coordinate(57.847314 , 12.002814),
+QtPositioning.coordinate(57.846676 , 12.003188),
+QtPositioning.coordinate(57.845715 , 12.003674),
+QtPositioning.coordinate(57.845344 , 12.003863),
+QtPositioning.coordinate(57.844459 , 12.004311),
+QtPositioning.coordinate(57.843688 , 12.004704),
+QtPositioning.coordinate(57.842766 , 12.005049),
+QtPositioning.coordinate(57.842014 , 12.005283),
+QtPositioning.coordinate(57.841198 , 12.0055),
+QtPositioning.coordinate(57.840055 , 12.005715),
+QtPositioning.coordinate(57.8394 , 12.005801),
+QtPositioning.coordinate(57.838146 , 12.005882),
+QtPositioning.coordinate(57.836843 , 12.005815),
+QtPositioning.coordinate(57.835513 , 12.005624),
+QtPositioning.coordinate(57.832929 , 12.005174),
+QtPositioning.coordinate(57.82988 , 12.004643),
+QtPositioning.coordinate(57.828402 , 12.004371),
+QtPositioning.coordinate(57.827057 , 12.004191),
+QtPositioning.coordinate(57.826435 , 12.004109),
+QtPositioning.coordinate(57.825244 , 12.004029),
+QtPositioning.coordinate(57.824219 , 12.004006),
+QtPositioning.coordinate(57.823058 , 12.004041),
+QtPositioning.coordinate(57.822319 , 12.004088),
+QtPositioning.coordinate(57.821188 , 12.004197),
+QtPositioning.coordinate(57.820094 , 12.004368),
+QtPositioning.coordinate(57.819257 , 12.004525),
+QtPositioning.coordinate(57.815996 , 12.005165),
+QtPositioning.coordinate(57.81179 , 12.006016),
+QtPositioning.coordinate(57.809267 , 12.006527),
+QtPositioning.coordinate(57.805948 , 12.007154),
+QtPositioning.coordinate(57.80425 , 12.007545),
+QtPositioning.coordinate(57.803743 , 12.007618),
+QtPositioning.coordinate(57.802775 , 12.007685),
+QtPositioning.coordinate(57.802007 , 12.007609),
+QtPositioning.coordinate(57.801282 , 12.007555),
+QtPositioning.coordinate(57.800649 , 12.007447),
+QtPositioning.coordinate(57.800051 , 12.007303),
+QtPositioning.coordinate(57.799386 , 12.007071),
+QtPositioning.coordinate(57.798764 , 12.006831),
+QtPositioning.coordinate(57.798019 , 12.006558),
+QtPositioning.coordinate(57.797396 , 12.006214),
+QtPositioning.coordinate(57.796777 , 12.005824),
+QtPositioning.coordinate(57.796007 , 12.005284),
+QtPositioning.coordinate(57.794061 , 12.003845),
+QtPositioning.coordinate(57.793262 , 12.003263),
+QtPositioning.coordinate(57.792437 , 12.002687),
+QtPositioning.coordinate(57.791863 , 12.002305),
+QtPositioning.coordinate(57.791289 , 12.001962),
+QtPositioning.coordinate(57.790425 , 12.001465),
+QtPositioning.coordinate(57.789367 , 12.001006),
+QtPositioning.coordinate(57.788428 , 12.00062),
+QtPositioning.coordinate(57.787501 , 12.00033),
+QtPositioning.coordinate(57.786694 , 12.000087),
+QtPositioning.coordinate(57.784801 , 11.999701),
+QtPositioning.coordinate(57.782813 , 11.999344),
+QtPositioning.coordinate(57.778369 , 11.998436),
+QtPositioning.coordinate(57.777055 , 11.9981),
+QtPositioning.coordinate(57.776384 , 11.997907),
+QtPositioning.coordinate(57.772347 , 11.996453),
+QtPositioning.coordinate(57.766969 , 11.994528),
+QtPositioning.coordinate(57.762466 , 11.992907),
+QtPositioning.coordinate(57.761331 , 11.992495),
+QtPositioning.coordinate(57.760634 , 11.992306),
+QtPositioning.coordinate(57.759916 , 11.992083),
+QtPositioning.coordinate(57.758846 , 11.991836),
+QtPositioning.coordinate(57.757737 , 11.991619),
+QtPositioning.coordinate(57.756987 , 11.991524),
+QtPositioning.coordinate(57.756553 , 11.991467),
+QtPositioning.coordinate(57.755912 , 11.991408),
+QtPositioning.coordinate(57.755625 , 11.99138),
+QtPositioning.coordinate(57.755392 , 11.991374),
+QtPositioning.coordinate(57.754973 , 11.991363),
+QtPositioning.coordinate(57.754163 , 11.991383),
+QtPositioning.coordinate(57.752846 , 11.991394),
+QtPositioning.coordinate(57.752345 , 11.991385),
+QtPositioning.coordinate(57.75199 , 11.991343),
+QtPositioning.coordinate(57.751732 , 11.991313),
+QtPositioning.coordinate(57.751302 , 11.99123),
+QtPositioning.coordinate(57.750428 , 11.991048),
+QtPositioning.coordinate(57.749452 , 11.990768),
+QtPositioning.coordinate(57.74849 , 11.990419),
+QtPositioning.coordinate(57.746355 , 11.989668),
+QtPositioning.coordinate(57.745332 , 11.989296),
+QtPositioning.coordinate(57.744906 , 11.98912),
+QtPositioning.coordinate(57.744018 , 11.988751),
+QtPositioning.coordinate(57.743103 , 11.988436),
+QtPositioning.coordinate(57.742762 , 11.988318),
+QtPositioning.coordinate(57.735451 , 11.985735),
+QtPositioning.coordinate(57.734749 , 11.985428),
+QtPositioning.coordinate(57.734183 , 11.985183),
+QtPositioning.coordinate(57.733664 , 11.984947),
+QtPositioning.coordinate(57.733209 , 11.984749),
+QtPositioning.coordinate(57.732682 , 11.984522),
+QtPositioning.coordinate(57.731448 , 11.983822),
+QtPositioning.coordinate(57.730979 , 11.98349),
+QtPositioning.coordinate(57.730466 , 11.983171),
+QtPositioning.coordinate(57.729863 , 11.982829),
+QtPositioning.coordinate(57.729654 , 11.98269),
+QtPositioning.coordinate(57.728657 , 11.981914),
+QtPositioning.coordinate(57.728482 , 11.981827),
+QtPositioning.coordinate(57.728115 , 11.981781),
+QtPositioning.coordinate(57.727967 , 11.981748),
+QtPositioning.coordinate(57.727817 , 11.981678),
+QtPositioning.coordinate(57.727076 , 11.981274),
+QtPositioning.coordinate(57.72646 , 11.980952),
+QtPositioning.coordinate(57.726245 , 11.980887),
+QtPositioning.coordinate(57.726044 , 11.980871),
+QtPositioning.coordinate(57.725825 , 11.980897),
+QtPositioning.coordinate(57.725654 , 11.980943),
+QtPositioning.coordinate(57.725494 , 11.981032),
+QtPositioning.coordinate(57.725324 , 11.981177),
+QtPositioning.coordinate(57.725196 , 11.981329),
+QtPositioning.coordinate(57.725125 , 11.98142),
+QtPositioning.coordinate(57.725017 , 11.981581),
+QtPositioning.coordinate(57.724881 , 11.981811),
+QtPositioning.coordinate(57.724732 , 11.982087),
+QtPositioning.coordinate(57.724555 , 11.982425),
+QtPositioning.coordinate(57.724402 , 11.982722),
+QtPositioning.coordinate(57.724341 , 11.982839),
+QtPositioning.coordinate(57.724264 , 11.982987),
+QtPositioning.coordinate(57.724183 , 11.98314),
+QtPositioning.coordinate(57.7241 , 11.983301),
+QtPositioning.coordinate(57.723977 , 11.983541),
+QtPositioning.coordinate(57.723872 , 11.983711),
+QtPositioning.coordinate(57.723791 , 11.983841),
+QtPositioning.coordinate(57.721922 , 11.986754),
+QtPositioning.coordinate(57.72037 , 11.989192),
+QtPositioning.coordinate(57.720071 , 11.98964),
+QtPositioning.coordinate(57.719818 , 11.990012),
+QtPositioning.coordinate(57.719712 , 11.990162),
+QtPositioning.coordinate(57.719607 , 11.99031),
+QtPositioning.coordinate(57.719504 , 11.99045),
+QtPositioning.coordinate(57.719416 , 11.990564),
+QtPositioning.coordinate(57.719274 , 11.990763),
+QtPositioning.coordinate(57.719106 , 11.990982),
+QtPositioning.coordinate(57.718835 , 11.991287),
+QtPositioning.coordinate(57.718589 , 11.991547),
+QtPositioning.coordinate(57.718354 , 11.991774),
+QtPositioning.coordinate(57.718087 , 11.992006),
+QtPositioning.coordinate(57.717913 , 11.99217),
+QtPositioning.coordinate(57.717681 , 11.992385),
+QtPositioning.coordinate(57.717276 , 11.992672),
+QtPositioning.coordinate(57.716734 , 11.993011),
+QtPositioning.coordinate(57.716212 , 11.993287),
+QtPositioning.coordinate(57.715666 , 11.993497),
+QtPositioning.coordinate(57.715162 , 11.993683),
+QtPositioning.coordinate(57.714806 , 11.993795),
+QtPositioning.coordinate(57.714437 , 11.99391),
+QtPositioning.coordinate(57.714034 , 11.99401),
+QtPositioning.coordinate(57.713741 , 11.994088),
+QtPositioning.coordinate(57.713545 , 11.994164),
+QtPositioning.coordinate(57.713463 , 11.99423),
+QtPositioning.coordinate(57.713209 , 11.994356),
+QtPositioning.coordinate(57.71302 , 11.994499),
+QtPositioning.coordinate(57.71281 , 11.994707),
+QtPositioning.coordinate(57.712544 , 11.995119),
+QtPositioning.coordinate(57.712308 , 11.995582),
+QtPositioning.coordinate(57.71221 , 11.995786),
+QtPositioning.coordinate(57.712024 , 11.996091),
+QtPositioning.coordinate(57.711924 , 11.996281),
+QtPositioning.coordinate(57.711795 , 11.996386),
+QtPositioning.coordinate(57.711636 , 11.996571),
+QtPositioning.coordinate(57.71143 , 11.996709),
+QtPositioning.coordinate(57.711195 , 11.996841),
+QtPositioning.coordinate(57.710937 , 11.996903),
+QtPositioning.coordinate(57.710702 , 11.996929),
+QtPositioning.coordinate(57.710252 , 11.996837),
+QtPositioning.coordinate(57.7096 , 11.996632),
+QtPositioning.coordinate(57.709366 , 11.996552),
+QtPositioning.coordinate(57.70881 , 11.996363),
+QtPositioning.coordinate(57.70749 , 11.995938),
+QtPositioning.coordinate(57.707064 , 11.995817),
+QtPositioning.coordinate(57.70626 , 11.995624),
+QtPositioning.coordinate(57.705693 , 11.995455),
+QtPositioning.coordinate(57.703956 , 11.994978),
+QtPositioning.coordinate(57.703557 , 11.994894),
+QtPositioning.coordinate(57.70285 , 11.994739),
+QtPositioning.coordinate(57.702351 , 11.994735),
+QtPositioning.coordinate(57.700739 , 11.994955),
+QtPositioning.coordinate(57.699385 , 11.99512),
+QtPositioning.coordinate(57.698429 , 11.995268),
+QtPositioning.coordinate(57.697882 , 11.995418),
+QtPositioning.coordinate(57.697325 , 11.995651),
+QtPositioning.coordinate(57.696378 , 11.996237),
+QtPositioning.coordinate(57.695685 , 11.996507),
+QtPositioning.coordinate(57.695521 , 11.996574),
+QtPositioning.coordinate(57.695311 , 11.996653),
+QtPositioning.coordinate(57.695091 , 11.996729),
+QtPositioning.coordinate(57.694853 , 11.996807),
+QtPositioning.coordinate(57.694594 , 11.996894),
+QtPositioning.coordinate(57.694378 , 11.996983),
+QtPositioning.coordinate(57.694175 , 11.997062),
+QtPositioning.coordinate(57.694008 , 11.997132),
+QtPositioning.coordinate(57.693806 , 11.997225),
+QtPositioning.coordinate(57.693597 , 11.997319),
+QtPositioning.coordinate(57.693384 , 11.997411),
+QtPositioning.coordinate(57.693136 , 11.997525),
+QtPositioning.coordinate(57.692934 , 11.997622),
+QtPositioning.coordinate(57.6927 , 11.997726),
+QtPositioning.coordinate(57.692439 , 11.997852),
+QtPositioning.coordinate(57.692303 , 11.997913),
+QtPositioning.coordinate(57.692126 , 11.99802),
+QtPositioning.coordinate(57.691926 , 11.998111),
+QtPositioning.coordinate(57.691729 , 11.998204),
+QtPositioning.coordinate(57.691587 , 11.998276),
+QtPositioning.coordinate(57.691478 , 11.998341),
+QtPositioning.coordinate(57.691331 , 11.998429),
+QtPositioning.coordinate(57.691211 , 11.998512),
+QtPositioning.coordinate(57.691116 , 11.998575),
+QtPositioning.coordinate(57.691047 , 11.998626),
+QtPositioning.coordinate(57.690985 , 11.998674),
+QtPositioning.coordinate(57.690901 , 11.998747),
+QtPositioning.coordinate(57.69082 , 11.998817),
+QtPositioning.coordinate(57.690723 , 11.998906),
+QtPositioning.coordinate(57.69063 , 11.999),
+QtPositioning.coordinate(57.690548 , 11.99908),
+QtPositioning.coordinate(57.690458 , 11.999169),
+QtPositioning.coordinate(57.69035 , 11.999273),
+QtPositioning.coordinate(57.690237 , 11.999393),
+QtPositioning.coordinate(57.690134 , 11.999504),
+QtPositioning.coordinate(57.690014 , 11.999628),
+QtPositioning.coordinate(57.689882 , 11.999762),
+QtPositioning.coordinate(57.689738 , 11.99991),
+QtPositioning.coordinate(57.689597 , 12.00005),
+QtPositioning.coordinate(57.689484 , 12.000163),
+QtPositioning.coordinate(57.689134 , 12.000461),
+QtPositioning.coordinate(57.688974 , 12.000593),
+QtPositioning.coordinate(57.688835 , 12.000709),
+QtPositioning.coordinate(57.688686 , 12.000835),
+QtPositioning.coordinate(57.688527 , 12.00097),
+QtPositioning.coordinate(57.688408 , 12.001067),
+QtPositioning.coordinate(57.688282 , 12.001167),
+QtPositioning.coordinate(57.688108 , 12.001307),
+QtPositioning.coordinate(57.687989 , 12.001408),
+QtPositioning.coordinate(57.687888 , 12.001492),
+QtPositioning.coordinate(57.687725 , 12.001626),
+QtPositioning.coordinate(57.687457 , 12.001847),
+QtPositioning.coordinate(57.687148 , 12.002102),
+QtPositioning.coordinate(57.686846 , 12.00235),
+QtPositioning.coordinate(57.686504 , 12.002632),
+QtPositioning.coordinate(57.686168 , 12.002909),
+QtPositioning.coordinate(57.685889 , 12.003139),
+QtPositioning.coordinate(57.685596 , 12.003381),
+QtPositioning.coordinate(57.685337 , 12.003595),
+QtPositioning.coordinate(57.685075 , 12.003802),
+QtPositioning.coordinate(57.68462 , 12.004185),
+QtPositioning.coordinate(57.684421 , 12.004347),
+QtPositioning.coordinate(57.684231 , 12.004504),
+QtPositioning.coordinate(57.684046 , 12.004657),
+QtPositioning.coordinate(57.683849 , 12.004821),
+QtPositioning.coordinate(57.68365 , 12.004983),
+QtPositioning.coordinate(57.683449 , 12.005154),
+QtPositioning.coordinate(57.683279 , 12.005288),
+QtPositioning.coordinate(57.683099 , 12.005437),
+QtPositioning.coordinate(57.682925 , 12.005576),
+QtPositioning.coordinate(57.682768 , 12.005707),
+QtPositioning.coordinate(57.682576 , 12.005853),
+QtPositioning.coordinate(57.682388 , 12.005993),
+QtPositioning.coordinate(57.682253 , 12.006099),
+QtPositioning.coordinate(57.682123 , 12.006194),
+QtPositioning.coordinate(57.682009 , 12.006284),
+QtPositioning.coordinate(57.681871 , 12.006383),
+QtPositioning.coordinate(57.681724 , 12.006492),
+QtPositioning.coordinate(57.681516 , 12.00665),
+QtPositioning.coordinate(57.681307 , 12.006798),
+QtPositioning.coordinate(57.68112 , 12.006932),
+QtPositioning.coordinate(57.68091 , 12.007082),
+QtPositioning.coordinate(57.680794 , 12.007161),
+QtPositioning.coordinate(57.680578 , 12.007307),
+QtPositioning.coordinate(57.680383 , 12.007452),
+QtPositioning.coordinate(57.680189 , 12.007581),
+QtPositioning.coordinate(57.679992 , 12.007718),
+QtPositioning.coordinate(57.679493 , 12.007976),
+QtPositioning.coordinate(57.678927 , 12.008216),
+QtPositioning.coordinate(57.678717 , 12.008306),
+QtPositioning.coordinate(57.678523 , 12.008386),
+QtPositioning.coordinate(57.678305 , 12.008479),
+QtPositioning.coordinate(57.67816 , 12.008541),
+QtPositioning.coordinate(57.678048 , 12.0086),
+QtPositioning.coordinate(57.677913 , 12.008671),
+QtPositioning.coordinate(57.677734 , 12.008769),
+QtPositioning.coordinate(57.677435 , 12.008958),
+QtPositioning.coordinate(57.677075 , 12.009188),
+QtPositioning.coordinate(57.676132 , 12.009845),
+QtPositioning.coordinate(57.675737 , 12.010125),
+QtPositioning.coordinate(57.67545 , 12.010329),
+QtPositioning.coordinate(57.67514 , 12.010537),
+QtPositioning.coordinate(57.674716 , 12.010822),
+QtPositioning.coordinate(57.674168 , 12.01119),
+QtPositioning.coordinate(57.673842 , 12.011389),
+QtPositioning.coordinate(57.673575 , 12.011557),
+QtPositioning.coordinate(57.672584 , 12.01213),
+QtPositioning.coordinate(57.672373 , 12.012248),
+QtPositioning.coordinate(57.672147 , 12.012365),
+QtPositioning.coordinate(57.671823 , 12.012526),
+QtPositioning.coordinate(57.671624 , 12.012628),
+QtPositioning.coordinate(57.671356 , 12.012755),
+QtPositioning.coordinate(57.671081 , 12.012876),
+QtPositioning.coordinate(57.670785 , 12.013012),
+QtPositioning.coordinate(57.670585 , 12.013107),
+QtPositioning.coordinate(57.670295 , 12.013238),
+QtPositioning.coordinate(57.669964 , 12.013383),
+QtPositioning.coordinate(57.66975 , 12.013477),
+QtPositioning.coordinate(57.669516 , 12.013587),
+QtPositioning.coordinate(57.669307 , 12.013675),
+QtPositioning.coordinate(57.669127 , 12.01376),
+QtPositioning.coordinate(57.668924 , 12.01385),
+QtPositioning.coordinate(57.668714 , 12.013942),
+QtPositioning.coordinate(57.668518 , 12.014027),
+QtPositioning.coordinate(57.668266 , 12.014141),
+QtPositioning.coordinate(57.667944 , 12.014279),
+QtPositioning.coordinate(57.667642 , 12.014409),
+QtPositioning.coordinate(57.667408 , 12.014509),
+QtPositioning.coordinate(57.666145 , 12.0148),
+QtPositioning.coordinate(57.664867 , 12.01523),
+QtPositioning.coordinate(57.663239 , 12.015889),
+QtPositioning.coordinate(57.66135 , 12.016526),
+QtPositioning.coordinate(57.659767 , 12.016938),
+QtPositioning.coordinate(57.658275 , 12.017315),
+QtPositioning.coordinate(57.657559 , 12.01751),
+QtPositioning.coordinate(57.657307 , 12.017586),
+QtPositioning.coordinate(57.657127 , 12.01764),
+QtPositioning.coordinate(57.657045 , 12.017664),
+QtPositioning.coordinate(57.656615 , 12.017817),
+QtPositioning.coordinate(57.656304 , 12.01793),
+QtPositioning.coordinate(57.655949 , 12.018059),
+QtPositioning.coordinate(57.6557 , 12.018149),
+QtPositioning.coordinate(57.65518 , 12.018358),
+QtPositioning.coordinate(57.654884 , 12.018469),
+QtPositioning.coordinate(57.654618 , 12.018571),
+QtPositioning.coordinate(57.654335 , 12.018689),
+QtPositioning.coordinate(57.654128 , 12.018774),
+QtPositioning.coordinate(57.653974 , 12.018847),
+QtPositioning.coordinate(57.653726 , 12.018954),
+QtPositioning.coordinate(57.653481 , 12.019064),
+QtPositioning.coordinate(57.653124 , 12.019233),
+QtPositioning.coordinate(57.652943 , 12.019316),
+QtPositioning.coordinate(57.652641 , 12.019465),
+QtPositioning.coordinate(57.652387 , 12.019593),
+QtPositioning.coordinate(57.652178 , 12.019698),
+QtPositioning.coordinate(57.652004 , 12.019779),
+QtPositioning.coordinate(57.65169 , 12.019954),
+QtPositioning.coordinate(57.651428 , 12.020088),
+QtPositioning.coordinate(57.650738 , 12.020461),
+QtPositioning.coordinate(57.650598 , 12.020542),
+QtPositioning.coordinate(57.650419 , 12.020639),
+QtPositioning.coordinate(57.647087 , 12.022479),
+QtPositioning.coordinate(57.646527 , 12.022793),
+QtPositioning.coordinate(57.645375 , 12.023469),
+QtPositioning.coordinate(57.644799 , 12.023874),
+QtPositioning.coordinate(57.644353 , 12.02424),
+QtPositioning.coordinate(57.643329 , 12.02513),
+QtPositioning.coordinate(57.640705 , 12.027634),
+QtPositioning.coordinate(57.639095 , 12.02926),
+QtPositioning.coordinate(57.635201 , 12.032529),
+QtPositioning.coordinate(57.63278 , 12.034105),
+QtPositioning.coordinate(57.630329 , 12.034976),
+QtPositioning.coordinate(57.628781 , 12.035283),
+QtPositioning.coordinate(57.627228 , 12.035456),
+QtPositioning.coordinate(57.626075 , 12.035561),
+QtPositioning.coordinate(57.624409 , 12.035837),
+QtPositioning.coordinate(57.623605 , 12.035946),
+QtPositioning.coordinate(57.623163 , 12.036066),
+QtPositioning.coordinate(57.622663 , 12.036219),
+QtPositioning.coordinate(57.622189 , 12.03645),
+QtPositioning.coordinate(57.621652 , 12.036769),
+QtPositioning.coordinate(57.620935 , 12.037368),
+QtPositioning.coordinate(57.620137 , 12.038192),
+QtPositioning.coordinate(57.618931 , 12.039576),
+QtPositioning.coordinate(57.618321 , 12.040277),
+QtPositioning.coordinate(57.617526 , 12.041112),
+QtPositioning.coordinate(57.61668 , 12.041924),
+QtPositioning.coordinate(57.616238 , 12.042311),
+QtPositioning.coordinate(57.6158 , 12.042665),
+QtPositioning.coordinate(57.615521 , 12.042889),
+QtPositioning.coordinate(57.615124 , 12.043168),
+QtPositioning.coordinate(57.614636 , 12.04349),
+QtPositioning.coordinate(57.614142 , 12.043758),
+QtPositioning.coordinate(57.613525 , 12.044056),
+QtPositioning.coordinate(57.612769 , 12.044404),
+QtPositioning.coordinate(57.611972 , 12.044783),
+QtPositioning.coordinate(57.611123 , 12.045161),
+QtPositioning.coordinate(57.610104 , 12.045628),
+QtPositioning.coordinate(57.609412 , 12.046028),
+QtPositioning.coordinate(57.608905 , 12.046343),
+QtPositioning.coordinate(57.608356 , 12.046728),
+QtPositioning.coordinate(57.607788 , 12.047158),
+QtPositioning.coordinate(57.607236 , 12.047622),
+QtPositioning.coordinate(57.606481 , 12.048329),
+QtPositioning.coordinate(57.605819 , 12.048996),
+QtPositioning.coordinate(57.604893 , 12.050111),
+QtPositioning.coordinate(57.604436 , 12.050693),
+QtPositioning.coordinate(57.603979 , 12.051326),
+QtPositioning.coordinate(57.60355 , 12.051939),
+QtPositioning.coordinate(57.603128 , 12.052597),
+QtPositioning.coordinate(57.602283 , 12.053921),
+QtPositioning.coordinate(57.601854 , 12.054592),
+QtPositioning.coordinate(57.601374 , 12.05524),
+QtPositioning.coordinate(57.600965 , 12.055724),
+QtPositioning.coordinate(57.600574 , 12.056132),
+QtPositioning.coordinate(57.600182 , 12.056468),
+QtPositioning.coordinate(57.599697 , 12.056828),
+QtPositioning.coordinate(57.599194 , 12.057144),
+QtPositioning.coordinate(57.598109 , 12.057647),
+QtPositioning.coordinate(57.597557 , 12.057939),
+QtPositioning.coordinate(57.596938 , 12.058344),
+QtPositioning.coordinate(57.59468 , 12.059968),
+QtPositioning.coordinate(57.593376 , 12.060904),
+QtPositioning.coordinate(57.592076 , 12.06182),
+QtPositioning.coordinate(57.591152 , 12.062454),
+QtPositioning.coordinate(57.591003 , 12.062559),
+QtPositioning.coordinate(57.590583 , 12.062853),
+QtPositioning.coordinate(57.590144 , 12.063098),
+QtPositioning.coordinate(57.589431 , 12.063433),
+QtPositioning.coordinate(57.588808 , 12.063653),
+QtPositioning.coordinate(57.588156 , 12.063827),
+QtPositioning.coordinate(57.587536 , 12.063905),
+QtPositioning.coordinate(57.587071 , 12.063933),
+QtPositioning.coordinate(57.586551 , 12.063915),
+QtPositioning.coordinate(57.585918 , 12.063842),
+QtPositioning.coordinate(57.585283 , 12.06371),
+QtPositioning.coordinate(57.584014 , 12.063289),
+QtPositioning.coordinate(57.581473 , 12.062379),
+QtPositioning.coordinate(57.578762 , 12.061308),
+QtPositioning.coordinate(57.575562 , 12.059923),
+QtPositioning.coordinate(57.574082 , 12.059239),
+QtPositioning.coordinate(57.5726 , 12.058517),
+QtPositioning.coordinate(57.571369 , 12.057873),
+QtPositioning.coordinate(57.56976 , 12.056904),
+QtPositioning.coordinate(57.567033 , 12.055019),
+QtPositioning.coordinate(57.56548 , 12.053994),
+QtPositioning.coordinate(57.563083 , 12.052946),
+QtPositioning.coordinate(57.560914 , 12.052586),
+QtPositioning.coordinate(57.559409 , 12.052637),
+QtPositioning.coordinate(57.557383 , 12.052716),
+QtPositioning.coordinate(57.555098 , 12.052887),
+QtPositioning.coordinate(57.553129 , 12.053016),
+QtPositioning.coordinate(57.551246 , 12.053059),
+QtPositioning.coordinate(57.550657 , 12.053047),
+QtPositioning.coordinate(57.549438 , 12.052993),
+QtPositioning.coordinate(57.548436 , 12.052947),
+QtPositioning.coordinate(57.547654 , 12.052867),
+QtPositioning.coordinate(57.545678 , 12.052684),
+QtPositioning.coordinate(57.539017 , 12.051586),
+QtPositioning.coordinate(57.532816 , 12.049998),
+QtPositioning.coordinate(57.532511 , 12.049912),
+QtPositioning.coordinate(57.531857 , 12.04974),
+QtPositioning.coordinate(57.528945 , 12.049114),
+QtPositioning.coordinate(57.52791 , 12.048977),
+QtPositioning.coordinate(57.527746 , 12.048956),
+QtPositioning.coordinate(57.526813 , 12.048909),
+QtPositioning.coordinate(57.525536 , 12.048954),
+QtPositioning.coordinate(57.523867 , 12.049182),
+QtPositioning.coordinate(57.519825 , 12.049981),
+QtPositioning.coordinate(57.517856 , 12.050453),
+QtPositioning.coordinate(57.516751 , 12.050713),
+QtPositioning.coordinate(57.516427 , 12.050789),
+QtPositioning.coordinate(57.51486 , 12.051182),
+QtPositioning.coordinate(57.512461 , 12.051667),
+QtPositioning.coordinate(57.511255 , 12.051888),
+QtPositioning.coordinate(57.50991 , 12.052079),
+QtPositioning.coordinate(57.509522 , 12.052144),
+QtPositioning.coordinate(57.508489 , 12.052281),
+QtPositioning.coordinate(57.508221 , 12.052324),
+QtPositioning.coordinate(57.505303 , 12.05265),
+QtPositioning.coordinate(57.50332 , 12.05259),
+QtPositioning.coordinate(57.501356 , 12.052272),
+QtPositioning.coordinate(57.49845 , 12.051285),
+QtPositioning.coordinate(57.495282 , 12.049637),
+QtPositioning.coordinate(57.49117 , 12.047207),
+QtPositioning.coordinate(57.485809 , 12.044398),
+QtPositioning.coordinate(57.483818 ,