summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-02-01 20:43:47 +0100
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-02-01 20:43:47 +0100
commit87d7387c51f564f44602a8d2841d49df2d789e41 (patch)
tree69a4e65f94ecb2dffc9466a3b2e2760185ce6363 /src
parent25b42f4165d23b64faa02adf6c71d6c5f6d985bb (diff)
parent55d4490ee62d5c1105a6733b717f2ef7340af492 (diff)
downloadqtlocation-87d7387c51f564f44602a8d2841d49df2d789e41.tar.gz
Merge dev into 5.9
Change-Id: Ib755265554410a62e14ee3e23fd09d9f4385519b
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/3rdparty.pro14
-rw-r--r--src/3rdparty/clip2tri/clip2tri.cpp99
-rw-r--r--src/3rdparty/clip2tri/clip2tri.h33
-rw-r--r--src/3rdparty/clip2tri/clip2tri.pro3
m---------src/3rdparty/mapbox-gl-native0
-rw-r--r--src/imports/location/location.cpp64
-rw-r--r--src/imports/location/location.pro63
-rw-r--r--src/imports/location/qdeclarativegeomapcopyrightsnotice.cpp168
-rw-r--r--src/location/declarativemaps/declarativemaps.pri64
-rw-r--r--src/location/declarativemaps/error_messages.cpp (renamed from src/imports/location/error_messages.cpp)0
-rw-r--r--src/location/declarativemaps/error_messages.h (renamed from src/imports/location/error_messages.h)0
-rw-r--r--src/location/declarativemaps/locationvaluetypehelper.cpp (renamed from src/imports/location/locationvaluetypehelper.cpp)0
-rw-r--r--src/location/declarativemaps/locationvaluetypehelper_p.h (renamed from src/imports/location/locationvaluetypehelper_p.h)0
-rw-r--r--src/location/declarativemaps/mapitemviewdelegateincubator.cpp (renamed from src/imports/location/mapitemviewdelegateincubator.cpp)2
-rw-r--r--src/location/declarativemaps/mapitemviewdelegateincubator_p.h (renamed from src/imports/location/mapitemviewdelegateincubator.h)16
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem.cpp (renamed from src/imports/location/qdeclarativecirclemapitem.cpp)419
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem_p.h (renamed from src/imports/location/qdeclarativecirclemapitem_p.h)18
-rw-r--r--src/location/declarativemaps/qdeclarativegeocodemodel.cpp (renamed from src/imports/location/qdeclarativegeocodemodel.cpp)0
-rw-r--r--src/location/declarativemaps/qdeclarativegeocodemodel_p.h (renamed from src/imports/location/qdeclarativegeocodemodel_p.h)8
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaneuver.cpp (renamed from src/imports/location/qdeclarativegeomaneuver.cpp)0
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaneuver_p.h (renamed from src/imports/location/qdeclarativegeomaneuver_p.h)6
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap.cpp (renamed from src/imports/location/qdeclarativegeomap.cpp)556
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap_p.h (renamed from src/imports/location/qdeclarativegeomap_p.h)62
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp306
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h (renamed from src/imports/location/qdeclarativegeomapcopyrightsnotice_p.h)29
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitembase.cpp (renamed from src/imports/location/qdeclarativegeomapitembase.cpp)59
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitembase_p.h (renamed from src/imports/location/qdeclarativegeomapitembase_p.h)41
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp150
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h69
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemview.cpp (renamed from src/imports/location/qdeclarativegeomapitemview.cpp)3
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemview_p.h (renamed from src/imports/location/qdeclarativegeomapitemview_p.h)6
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h (renamed from src/imports/location/qdeclarativegeomapitemview_p_p.h)0
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapparameter.cpp (renamed from src/imports/location/qdeclarativegeomapparameter.cpp)2
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapparameter_p.h (renamed from src/imports/location/qdeclarativegeomapparameter_p.h)3
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapquickitem.cpp (renamed from src/imports/location/qdeclarativegeomapquickitem.cpp)25
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapquickitem_p.h (renamed from src/imports/location/qdeclarativegeomapquickitem_p.h)13
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaptype.cpp (renamed from src/imports/location/qdeclarativegeomaptype.cpp)0
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaptype_p.h (renamed from src/imports/location/qdeclarativegeomaptype_p.h)4
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroute.cpp (renamed from src/imports/location/qdeclarativegeoroute.cpp)1
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroute_p.h (renamed from src/imports/location/qdeclarativegeoroute_p.h)5
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutemodel.cpp (renamed from src/imports/location/qdeclarativegeoroutemodel.cpp)0
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutemodel_p.h (renamed from src/imports/location/qdeclarativegeoroutemodel_p.h)7
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutesegment.cpp (renamed from src/imports/location/qdeclarativegeoroutesegment.cpp)0
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutesegment_p.h (renamed from src/imports/location/qdeclarativegeoroutesegment_p.h)5
-rw-r--r--src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp (renamed from src/imports/location/qdeclarativegeoserviceprovider.cpp)3
-rw-r--r--src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h (renamed from src/imports/location/qdeclarativegeoserviceprovider_p.h)10
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem.cpp (renamed from src/imports/location/qdeclarativepolygonmapitem.cpp)340
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem_p.h (renamed from src/imports/location/qdeclarativepolygonmapitem_p.h)18
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem.cpp (renamed from src/imports/location/qdeclarativepolylinemapitem.cpp)474
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem_p.h (renamed from src/imports/location/qdeclarativepolylinemapitem_p.h)37
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem.cpp (renamed from src/imports/location/qdeclarativerectanglemapitem.cpp)221
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem_p.h (renamed from src/imports/location/qdeclarativerectanglemapitem_p.h)30
-rw-r--r--src/location/declarativemaps/qdeclarativeroutemapitem.cpp (renamed from src/imports/location/qdeclarativeroutemapitem.cpp)4
-rw-r--r--src/location/declarativemaps/qdeclarativeroutemapitem_p.h (renamed from src/imports/location/qdeclarativeroutemapitem_p.h)9
-rw-r--r--src/location/declarativemaps/qgeomapitemgeometry.cpp (renamed from src/imports/location/qgeomapitemgeometry.cpp)2
-rw-r--r--src/location/declarativemaps/qgeomapitemgeometry_p.h (renamed from src/imports/location/qgeomapitemgeometry_p.h)4
-rw-r--r--src/location/declarativemaps/qquickgeomapgesturearea.cpp (renamed from src/imports/location/qquickgeomapgesturearea.cpp)668
-rw-r--r--src/location/declarativemaps/qquickgeomapgesturearea_p.h (renamed from src/imports/location/qquickgeomapgesturearea_p.h)92
-rw-r--r--src/location/declarativeplaces/declarativeplaces.pri (renamed from src/imports/location/declarativeplaces/declarativeplaces.pri)11
-rw-r--r--src/location/declarativeplaces/qdeclarativecategory.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativecategory.cpp)4
-rw-r--r--src/location/declarativeplaces/qdeclarativecategory_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativecategory_p.h)7
-rw-r--r--src/location/declarativeplaces/qdeclarativecontactdetail.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativecontactdetail.cpp)4
-rw-r--r--src/location/declarativeplaces/qdeclarativecontactdetail_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativecontactdetail_p.h)6
-rw-r--r--src/location/declarativeplaces/qdeclarativeperiod_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativeperiod_p.h)0
-rw-r--r--src/location/declarativeplaces/qdeclarativeplace.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativeplace.cpp)4
-rw-r--r--src/location/declarativeplaces/qdeclarativeplace_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativeplace_p.h)19
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceattribute.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativeplaceattribute.cpp)4
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceattribute_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativeplaceattribute_p.h)5
-rw-r--r--src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp)2
-rw-r--r--src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativeplacecontentmodel.h)14
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp)2
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceeditorialmodel_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativeplaceeditorialmodel.h)16
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceicon.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativeplaceicon.cpp)4
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceicon_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativeplaceicon_p.h)7
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp)0
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h)5
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceuser.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativeplaceuser.cpp)3
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceuser_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativeplaceuser_p.h)3
-rw-r--r--src/location/declarativeplaces/qdeclarativeratings.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativeratings.cpp)3
-rw-r--r--src/location/declarativeplaces/qdeclarativeratings_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativeratings_p.h)5
-rw-r--r--src/location/declarativeplaces/qdeclarativereviewmodel.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativereviewmodel.cpp)0
-rw-r--r--src/location/declarativeplaces/qdeclarativereviewmodel_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativereviewmodel_p.h)5
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativesearchmodelbase.cpp)6
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchmodelbase_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativesearchmodelbase.h)17
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativesearchresultmodel.cpp)5
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativesearchresultmodel_p.h)11
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp)4
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h)5
-rw-r--r--src/location/declarativeplaces/qdeclarativesupplier.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativesupplier.cpp)4
-rw-r--r--src/location/declarativeplaces/qdeclarativesupplier_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativesupplier_p.h)7
-rw-r--r--src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp (renamed from src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp)4
-rw-r--r--src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h (renamed from src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h)7
-rw-r--r--src/location/doc/images/api-mapitemgroup.pngbin0 -> 26089 bytes
-rw-r--r--src/location/doc/src/plugins/mapboxgl.qdoc98
-rw-r--r--src/location/doc/src/plugins/osm.qdoc3
-rw-r--r--src/location/location.pro15
-rw-r--r--src/location/maps/qgeocameracapabilities.cpp61
-rw-r--r--src/location/maps/qgeocameracapabilities_p.h6
-rw-r--r--src/location/maps/qgeocameradata.cpp16
-rw-r--r--src/location/maps/qgeocameradata_p.h3
-rw-r--r--src/location/maps/qgeocameratiles.cpp188
-rw-r--r--src/location/maps/qgeomap.cpp53
-rw-r--r--src/location/maps/qgeomap_p.h25
-rw-r--r--src/location/maps/qgeomap_p_p.h7
-rw-r--r--src/location/maps/qgeoprojection.cpp255
-rw-r--r--src/location/maps/qgeoprojection_p.h72
-rw-r--r--src/location/maps/qgeotiledmapscene.cpp143
-rw-r--r--src/plugins/geoservices/esri/geotiledmap_esri.cpp7
-rw-r--r--src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp7
-rw-r--r--src/plugins/geoservices/geoservices.pro14
-rw-r--r--src/plugins/geoservices/mapbox/qgeotiledmappingmanagerenginemapbox.cpp6
-rw-r--r--src/plugins/geoservices/mapboxgl/mapboxgl.pro30
-rw-r--r--src/plugins/geoservices/mapboxgl/mapboxgl_plugin.json11
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp377
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h68
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp151
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h65
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.cpp80
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.h70
-rw-r--r--src/plugins/geoservices/mapboxgl/qsgmapboxglnode.cpp110
-rw-r--r--src/plugins/geoservices/mapboxgl/qsgmapboxglnode.h68
-rw-r--r--src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp7
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmaposm.cpp11
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp6
-rw-r--r--src/positioning/positioning.pro12
-rw-r--r--src/positioning/qclipperutils.cpp100
-rw-r--r--src/positioning/qclipperutils_p.h86
-rw-r--r--src/positioning/qgeocircle.cpp8
-rw-r--r--src/positioning/qgeopath.cpp2
-rw-r--r--src/positioning/qlocationutils_p.h68
-rw-r--r--src/positioning/qwebmercator.cpp24
-rw-r--r--src/positioning/qwebmercator_p.h1
-rw-r--r--src/src.pro2
133 files changed, 5059 insertions, 1715 deletions
diff --git a/src/3rdparty/3rdparty.pro b/src/3rdparty/3rdparty.pro
index 72996c7b..15f63a5f 100644
--- a/src/3rdparty/3rdparty.pro
+++ b/src/3rdparty/3rdparty.pro
@@ -2,3 +2,17 @@ TEMPLATE = subdirs
SUBDIRS += poly2tri
SUBDIRS += clipper
SUBDIRS += clip2tri
+
+linux|android: {
+ equals(QT_GCC_MAJOR_VERSION, 4): greaterThan(QT_GCC_MINOR_VERSION, 8) {
+ SUBDIRS += mapbox-gl-native
+ }
+
+ greaterThan(QT_GCC_MAJOR_VERSION, 4) {
+ SUBDIRS += mapbox-gl-native
+ }
+}
+
+ios|macos: {
+ SUBDIRS += mapbox-gl-native
+}
diff --git a/src/3rdparty/clip2tri/clip2tri.cpp b/src/3rdparty/clip2tri/clip2tri.cpp
index 16b1b86b..2f502667 100644
--- a/src/3rdparty/clip2tri/clip2tri.cpp
+++ b/src/3rdparty/clip2tri/clip2tri.cpp
@@ -27,10 +27,12 @@
*/
#include "clip2tri.h"
-#include "../poly2tri/poly2tri.h"
+#include <poly2tri.h>
#include <cstdio>
+static const double clipperScaleFactor = 1073741822.0;
+static const double clipperScaleFactorInv = 1.0 / 1073741822.0;
using namespace p2t;
@@ -41,9 +43,6 @@ namespace c2t
static const F32 CLIPPER_SCALE_FACT = 1000.0f;
static const F32 CLIPPER_SCALE_FACT_INVERSE = 0.001f;
-static const F64 CLIPPER_SCALE_FACT_D = double(1<<31);
-static const F64 CLIPPER_SCALE_FACT_INVERSE_D = 1.0 / double(1<<31);
-
/////////////////////////////////
Point::Point()
@@ -61,7 +60,7 @@ Point::Point(const Point& pt)
/////////////////////////////////
-clip2tri::clip2tri()
+clip2tri::clip2tri() : openSubject(false)
{
// Do nothing!
}
@@ -85,79 +84,95 @@ void clip2tri::triangulate(const vector<vector<Point> > &inputPolygons, vector<P
triangulateComplex(outputTriangles, bounds, solution);
}
-IntPoint clip2tri::intPoint(double x, double y)
-{
- return IntPoint(S64(x * CLIPPER_SCALE_FACT_D), S64(y * CLIPPER_SCALE_FACT_D));
-}
-
-PointD clip2tri::pointD(IntPoint p)
-{
- return PointD(F64(p.X) * CLIPPER_SCALE_FACT_INVERSE_D, F64(p.Y) * CLIPPER_SCALE_FACT_INVERSE_D);
-}
-
-void clip2tri::addClipPolygon(const std::vector<IntPoint> &path)
+void clip2tri::addClipPolygon(const Path &path)
{
try // prevent any exception to spill into Qt
{
- if (path.front() != path.back())
- return; // Clip polygons must be closed.
clipper.AddPath(path, ptClip, true);
}
- catch(...)
+ catch(ClipperLib::clipperException &e)
{
- printf("addClipPolygon: clipper.AddPath, something went wrong\n");
+ printf("addClipPolygon: %s\n", e.what());
}
}
-void clip2tri::addSubjectPath(const std::vector<IntPoint> &path, bool closed)
+void clip2tri::addSubjectPath(const Path &path, bool closed)
{
try // prevent any exception to spill into Qt
{
- if (path.front() != path.back() && closed)
- return; // Clip polygons must be closed.
clipper.AddPath(path, ptSubject, closed);
}
- catch(...)
+ catch(ClipperLib::clipperException &e)
{
- printf("addSubjectPath: clipper.AddPath, something went wrong\n");
+ printf("addSubjectPath: %s\n", e.what());
+ return;
}
+ if (!closed)
+ openSubject = true;
}
void clip2tri::clearClipper()
{
// clear doesn't throw
clipper.Clear();
+ openSubject = false;
}
-Paths clip2tri::executeUnion(PolyFillType subjFillType, PolyFillType clipFillType)
+static ClipperLib::ClipType operation(const clip2tri::Operation &op)
{
- Paths solution;
- try // prevent any exception to spill into Qt
- {
- clipper.Execute(ctUnion, solution, subjFillType, subjFillType);
+ switch (op) {
+ case clip2tri::Intersection:
+ return ClipperLib::ctIntersection;
+ case clip2tri::Union:
+ return ClipperLib::ctUnion;
+ case clip2tri::Difference:
+ return ClipperLib::ctDifference;
+ case clip2tri::Xor:
+ return ClipperLib::ctXor;
}
- catch(...)
- {
- printf("executeUnion: clipper.Execute, something went wrong\n");
+ return ctIntersection;
+}
+
+static std::string operationName(const clip2tri::Operation &op)
+{
+ switch (op) {
+ case clip2tri::Intersection:
+ return std::string("Intersection");
+ case clip2tri::Union:
+ return std::string("Union");
+ case clip2tri::Difference:
+ return std::string("Difference");
+ case clip2tri::Xor:
+ return std::string("Xor");
}
- return solution;
+ return std::string("Intersection");
}
-Paths clip2tri::executeIntersection(PolyFillType subjFillType, PolyFillType clipFillType)
+Paths clip2tri::execute(const clip2tri::Operation op, const PolyFillType subjFillType, const PolyFillType clipFillType)
{
Paths solution;
- try // prevent any exception to spill into Qt
+ try // prevent any exception from spilling into Qt
{
- clipper.Execute(ctIntersection, solution, subjFillType, subjFillType);
+ if (!openSubject) {
+ clipper.Execute(operation(op), solution, subjFillType, clipFillType);
+ } else {
+ PolyTree res;
+ clipper.Execute(operation(op), res, subjFillType, clipFillType);
+ PolyNode *n = res.GetFirst();
+ if (n) {
+ solution.push_back(n->Contour);
+ while ((n = n->GetNext()))
+ solution.push_back(n->Contour);
+ }
+ }
}
- catch(...)
+ catch(ClipperLib::clipperException &e)
{
- printf("executeIntersection: clipper.Execute, something went wrong\n");
+ printf("executing %s: %s\n", operationName(op).c_str(), e.what());
}
return solution;
}
-
Path clip2tri::upscaleClipperPoints(const vector<Point> &inputPolygon)
{
Path outputPolygon;
@@ -222,9 +237,9 @@ bool clip2tri::mergePolysToPolyTree(const vector<vector<Point> > &inputPolygons,
{
clipper.AddPaths(input, ptSubject, true);
}
- catch(...)
+ catch(ClipperLib::clipperException &e)
{
- printf("clipper.AddPaths, something went wrong\n");
+ printf("mergePolysToPolyTree: %s\n", e.what());
}
return clipper.Execute(ctUnion, solution, pftNonZero, pftNonZero);
diff --git a/src/3rdparty/clip2tri/clip2tri.h b/src/3rdparty/clip2tri/clip2tri.h
index a94bb6a1..37b563bb 100644
--- a/src/3rdparty/clip2tri/clip2tri.h
+++ b/src/3rdparty/clip2tri/clip2tri.h
@@ -30,7 +30,7 @@
#define CLIP2TRI_H_
#include <vector>
-#include "../clipper/clipper.h"
+#include <clipper.h>
using namespace std;
using namespace ClipperLib;
@@ -57,18 +57,6 @@ struct Point
Point(T in_x, U in_y) { x = static_cast<F32>(in_x); y = static_cast<F32>(in_y); }
};
-struct PointD
-{
- F64 x;
- F64 y;
-
- PointD();
- PointD(const PointD &pt);
-
- template<class T, class U>
- PointD(T in_x, U in_y) { x = static_cast<F64>(in_x); y = static_cast<F64>(in_y); }
-};
-
class clip2tri
{
private:
@@ -85,29 +73,26 @@ private:
const PolyTree &polyTree, bool ignoreFills = true, bool ignoreHoles = false);
public:
+ enum Operation { Union, Intersection, Difference, Xor };
clip2tri();
virtual ~clip2tri();
void triangulate(const vector<vector<Point> > &inputPolygons, vector<Point> &outputTriangles,
const vector<Point> &boundingPolygon);
- inline static IntPoint intPoint(double x, double y);
- inline static PointD pointD(IntPoint p);
-
- // Clip polygons MUST be closed. Meaning path[0] == path[path.size()-1]
- void addClipPolygon(const std::vector<IntPoint> &path);
+ // Clip polygons are intended as closed, even if the first and last vertex aren't the same.
+ void addClipPolygon(const Path &path);
// Closed means the path has to be effectively closed. Meaning path[0] == path[path.size()-1]
- void addSubjectPath(const std::vector<IntPoint> &path, bool closed);
+ void addSubjectPath(const Path &path, bool closed);
void clearClipper();
- Paths executeUnion(PolyFillType subjFillType = pftEvenOdd,
- PolyFillType clipFillType = pftEvenOdd);
-
- Paths executeIntersection(PolyFillType subjFillType = pftEvenOdd,
- PolyFillType clipFillType = pftEvenOdd);
+ Paths execute(const Operation op,
+ const PolyFillType subjFillType = pftNonZero,
+ const PolyFillType clipFillType = pftNonZero);
Clipper clipper;
+ bool openSubject;
};
} /* namespace c2t */
diff --git a/src/3rdparty/clip2tri/clip2tri.pro b/src/3rdparty/clip2tri/clip2tri.pro
index 50901c06..4ae7a799 100644
--- a/src/3rdparty/clip2tri/clip2tri.pro
+++ b/src/3rdparty/clip2tri/clip2tri.pro
@@ -2,6 +2,9 @@ TARGET = clip2tri
CONFIG += staticlib exceptions
+INCLUDEPATH += ../poly2tri
+INCLUDEPATH += ../clipper
+
load(qt_helper_lib)
# workaround for QTBUG-31586
diff --git a/src/3rdparty/mapbox-gl-native b/src/3rdparty/mapbox-gl-native
new file mode 160000
+Subproject 9810dbd7a2959ac114ede3b3c0d452b862f6954
diff --git a/src/imports/location/location.cpp b/src/imports/location/location.cpp
index f9b3545f..4536b371 100644
--- a/src/imports/location/location.cpp
+++ b/src/imports/location/location.cpp
@@ -34,37 +34,40 @@
**
****************************************************************************/
-#include "qdeclarativegeoserviceprovider_p.h"
-#include "qdeclarativegeomap_p.h"
-
-#include "qdeclarativegeoroute_p.h"
-#include "qdeclarativegeoroutemodel_p.h"
-#include "qdeclarativegeocodemodel_p.h"
-#include "qdeclarativegeomaneuver_p.h"
-#include "qdeclarativegeomapquickitem_p.h"
-#include "qdeclarativegeomapitemview_p.h"
-#include "qdeclarativegeomaptype_p.h"
-#include "qdeclarativerectanglemapitem_p.h"
-#include "qdeclarativecirclemapitem_p.h"
-#include "qdeclarativeroutemapitem_p.h"
-#include "qdeclarativepolylinemapitem_p.h"
-#include "qdeclarativepolygonmapitem_p.h"
-#include "qdeclarativegeomapparameter_p.h"
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+
+#include <QtLocation/private/qdeclarativegeoroute_p.h>
+#include <QtLocation/private/qdeclarativegeoroutemodel_p.h>
+#include <QtLocation/private/qdeclarativegeocodemodel_p.h>
+#include <QtLocation/private/qdeclarativegeomaneuver_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qdeclarativegeomapquickitem_p.h>
+#include <QtLocation/private/qdeclarativegeomapitemview_p.h>
+#include <QtLocation/private/qdeclarativegeomaptype_p.h>
+#include <QtLocation/private/qdeclarativerectanglemapitem_p.h>
+#include <QtLocation/private/qdeclarativecirclemapitem_p.h>
+#include <QtLocation/private/qdeclarativeroutemapitem_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
+#include <QtLocation/private/qdeclarativegeomapparameter_p.h>
+#include <QtLocation/private/qdeclarativegeomapcopyrightsnotice_p.h>
+#include <QtLocation/private/qdeclarativegeomapitemgroup_p.h>
//Place includes
-#include "qdeclarativecategory_p.h"
-#include "qdeclarativeplace_p.h"
-#include "qdeclarativeplaceattribute_p.h"
-#include "qdeclarativeplaceicon_p.h"
-#include "qdeclarativeratings_p.h"
-#include "qdeclarativesupplier_p.h"
-#include "qdeclarativeplaceuser_p.h"
-#include "qdeclarativecontactdetail_p.h"
-
-#include "qdeclarativesupportedcategoriesmodel_p.h"
-#include "qdeclarativesearchresultmodel_p.h"
-#include "qdeclarativesearchsuggestionmodel_p.h"
-#include "error_messages.h"
+#include <QtLocation/private/qdeclarativecategory_p.h>
+#include <QtLocation/private/qdeclarativeplace_p.h>
+#include <QtLocation/private/qdeclarativeplaceattribute_p.h>
+#include <QtLocation/private/qdeclarativeplaceicon_p.h>
+#include <QtLocation/private/qdeclarativeratings_p.h>
+#include <QtLocation/private/qdeclarativesupplier_p.h>
+#include <QtLocation/private/qdeclarativeplaceuser_p.h>
+#include <QtLocation/private/qdeclarativecontactdetail_p.h>
+
+#include <QtLocation/private/qdeclarativesupportedcategoriesmodel_p.h>
+#include <QtLocation/private/qdeclarativesearchresultmodel_p.h>
+#include <QtLocation/private/qdeclarativesearchsuggestionmodel_p.h>
+#include <QtLocation/error_messages.h>
#include <QtQml/qqmlextensionplugin.h>
@@ -170,7 +173,8 @@ public:
// Register the 5.9 types
minor = 9;
qmlRegisterType<QDeclarativeGeoMapParameter>(uri, major, minor, "MapParameter");
-
+ qmlRegisterType<QDeclarativeGeoMapCopyrightNotice>(uri, major, minor, "MapCopyrightNotice");
+ qmlRegisterType<QDeclarativeGeoMapItemGroup>(uri, major, minor, "MapItemGroup");
//registrations below are version independent
qRegisterMetaType<QPlaceCategory>();
diff --git a/src/imports/location/location.pro b/src/imports/location/location.pro
index e733a768..dec1149b 100644
--- a/src/imports/location/location.pro
+++ b/src/imports/location/location.pro
@@ -1,71 +1,10 @@
QT += quick-private network positioning-private location-private qml-private core-private gui-private
-INCLUDEPATH += ../../location
-INCLUDEPATH += ../../location/maps
-INCLUDEPATH += ../../positioning
-INCLUDEPATH += ../positioning
-INCLUDEPATH *= $$PWD
-
-HEADERS += \
- qdeclarativegeomapitemview_p.h \
- qdeclarativegeoserviceprovider_p.h \
- qdeclarativegeocodemodel_p.h \
- qdeclarativegeoroutemodel_p.h \
- qdeclarativegeoroute_p.h \
- qdeclarativegeoroutesegment_p.h \
- qdeclarativegeomaneuver_p.h \
- qdeclarativegeomap_p.h \
- qdeclarativegeomaptype_p.h \
- qdeclarativegeomapitembase_p.h \
- qdeclarativegeomapquickitem_p.h \
- qdeclarativecirclemapitem_p.h \
- qdeclarativerectanglemapitem_p.h \
- qdeclarativepolygonmapitem_p.h \
- qdeclarativepolylinemapitem_p.h \
- qdeclarativeroutemapitem_p.h \
- qgeomapitemgeometry_p.h \
- qdeclarativegeomapcopyrightsnotice_p.h \
- error_messages.h \
- locationvaluetypehelper_p.h\
- qquickgeomapgesturearea_p.h\
- ../positioning/qquickgeocoordinateanimation_p.h \
- mapitemviewdelegateincubator.h \
- qdeclarativegeomapitemview_p_p.h \
- qdeclarativegeomapparameter_p.h
-
SOURCES += \
- location.cpp \
- qdeclarativegeomapitemview.cpp \
- qdeclarativegeoserviceprovider.cpp \
- qdeclarativegeocodemodel.cpp \
- qdeclarativegeoroutemodel.cpp \
- qdeclarativegeoroute.cpp \
- qdeclarativegeoroutesegment.cpp \
- qdeclarativegeomaneuver.cpp \
- qdeclarativegeomap.cpp \
- qdeclarativegeomaptype.cpp \
- qdeclarativegeomapitembase.cpp \
- qdeclarativegeomapquickitem.cpp \
- qdeclarativecirclemapitem.cpp \
- qdeclarativerectanglemapitem.cpp \
- qdeclarativepolygonmapitem.cpp \
- qdeclarativepolylinemapitem.cpp \
- qdeclarativeroutemapitem.cpp \
- qgeomapitemgeometry.cpp \
- qdeclarativegeomapcopyrightsnotice.cpp \
- error_messages.cpp \
- locationvaluetypehelper.cpp \
- qquickgeomapgesturearea.cpp \
- ../positioning/qquickgeocoordinateanimation.cpp \
- mapitemviewdelegateincubator.cpp \
- qdeclarativegeomapparameter.cpp
-
-include(declarativeplaces/declarativeplaces.pri)
+ location.cpp
load(qml_plugin)
-LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lpoly2tri$$qtPlatformTargetSuffix() -lclip2tri$$qtPlatformTargetSuffix()
-
OTHER_FILES += \
plugin.json \
qmldir
diff --git a/src/imports/location/qdeclarativegeomapcopyrightsnotice.cpp b/src/imports/location/qdeclarativegeomapcopyrightsnotice.cpp
deleted file mode 100644
index 7b5a5765..00000000
--- a/src/imports/location/qdeclarativegeomapcopyrightsnotice.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com>
-** Copyright (C) 2015 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 "qdeclarativegeomapcopyrightsnotice_p.h"
-
-#include <QtGui/QTextDocument>
-#include <QtGui/QAbstractTextDocumentLayout>
-#include <QtGui/QPainter>
-#include <QtQuick/private/qquickanchors_p.h>
-#include <QtQuick/private/qquickanchors_p_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QDeclarativeGeoMapCopyrightNotice::QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent)
-: QQuickPaintedItem(parent), m_copyrightsHtml(0), m_copyrightsVisible(true)
-{
- QQuickAnchors *anchors = property("anchors").value<QQuickAnchors *>();
- if (anchors) {
- anchors->setLeft(QQuickAnchorLine(parent, QQuickAnchors::LeftAnchor));
- anchors->setBottom(QQuickAnchorLine(parent, QQuickAnchors::BottomAnchor));
- }
-}
-
-QDeclarativeGeoMapCopyrightNotice::~QDeclarativeGeoMapCopyrightNotice()
-{
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapCopyrightNotice::paint(QPainter *painter)
-{
- painter->drawImage(0, 0, m_copyrightsImage);
-}
-
-void QDeclarativeGeoMapCopyrightNotice::mousePressEvent(QMouseEvent *event)
-{
- if (m_copyrightsHtml) {
- m_activeAnchor = m_copyrightsHtml->documentLayout()->anchorAt(event->pos());
- if (!m_activeAnchor.isEmpty())
- return;
- }
-
- QQuickPaintedItem::mousePressEvent(event);
-}
-
-void QDeclarativeGeoMapCopyrightNotice::mouseReleaseEvent(QMouseEvent *event)
-{
- if (m_copyrightsHtml) {
- QString anchor = m_copyrightsHtml->documentLayout()->anchorAt(event->pos());
- if (anchor == m_activeAnchor && !anchor.isEmpty()) {
- emit linkActivated(anchor);
- m_activeAnchor.clear();
- }
- }
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapCopyrightNotice::setCopyrightsVisible(bool visible)
-{
- m_copyrightsVisible = visible;
-
- setVisible(!m_copyrightsImage.isNull() && visible);
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapCopyrightNotice::setCopyrightsZ(int copyrightsZ)
-{
- setZ(copyrightsZ);
- update();
-}
-
-/*!
- \internal
-*/
-void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QImage &copyrightsImage)
-{
- delete m_copyrightsHtml;
- m_copyrightsHtml = 0;
-
- m_copyrightsImage = copyrightsImage;
-
- setWidth(m_copyrightsImage.width());
- setHeight(m_copyrightsImage.height());
-
- setKeepMouseGrab(false);
- setAcceptedMouseButtons(Qt::NoButton);
- setVisible(m_copyrightsVisible);
-
- update();
-}
-
-void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QString &copyrightsHtml)
-{
- if (copyrightsHtml.isEmpty() || !m_copyrightsVisible) {
- m_copyrightsImage = QImage();
- setVisible(false);
- return;
- } else {
- setVisible(true);
- }
-
- if (!m_copyrightsHtml)
- m_copyrightsHtml = new QTextDocument(this);
-
- m_copyrightsHtml->setHtml(copyrightsHtml);
-
- m_copyrightsImage = QImage(m_copyrightsHtml->size().toSize(),
- QImage::Format_ARGB32_Premultiplied);
- m_copyrightsImage.fill(qPremultiply(qRgba(255, 255, 255, 128)));
-
- QPainter painter(&m_copyrightsImage);
- //m_copyrightsHtml->drawContents(&painter); // <- this uses the default application palette, that might have, f.ex., white text
- QAbstractTextDocumentLayout::PaintContext ctx;
- ctx.palette.setColor(QPalette::Text, QColor(QStringLiteral("black")));
- ctx.palette.setColor(QPalette::Link, QColor(QStringLiteral("blue")));
- m_copyrightsHtml->documentLayout()->draw(&painter, ctx);
-
- setWidth(m_copyrightsImage.width());
- setHeight(m_copyrightsImage.height());
-
- setContentsSize(m_copyrightsImage.size());
-
- setKeepMouseGrab(true);
- setAcceptedMouseButtons(Qt::LeftButton);
-
- update();
-}
-
-QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/declarativemaps.pri b/src/location/declarativemaps/declarativemaps.pri
new file mode 100644
index 00000000..e1054001
--- /dev/null
+++ b/src/location/declarativemaps/declarativemaps.pri
@@ -0,0 +1,64 @@
+QT += quick-private network positioning-private qml-private core-private gui-private
+
+INCLUDEPATH += declarativemaps
+
+PUBLIC_HEADERS += \
+ declarativemaps/error_messages.h
+
+PRIVATE_HEADERS += \
+ declarativemaps/qdeclarativegeomapitemview_p.h \
+ declarativemaps/qdeclarativegeomapitemview_p_p.h \
+ declarativemaps/qdeclarativegeoserviceprovider_p.h \
+ declarativemaps/qdeclarativegeocodemodel_p.h \
+ declarativemaps/qdeclarativegeoroutemodel_p.h \
+ declarativemaps/qdeclarativegeoroute_p.h \
+ declarativemaps/qdeclarativegeoroutesegment_p.h \
+ declarativemaps/qdeclarativegeomaneuver_p.h \
+ declarativemaps/qdeclarativegeomap_p.h \
+ declarativemaps/qdeclarativegeomaptype_p.h \
+ declarativemaps/qdeclarativegeomapitembase_p.h \
+ declarativemaps/qdeclarativegeomapquickitem_p.h \
+ declarativemaps/qdeclarativecirclemapitem_p.h \
+ declarativemaps/qdeclarativerectanglemapitem_p.h \
+ declarativemaps/qdeclarativepolygonmapitem_p.h \
+ declarativemaps/qdeclarativepolylinemapitem_p.h \
+ declarativemaps/qdeclarativeroutemapitem_p.h \
+ declarativemaps/qdeclarativegeomapparameter_p.h \
+ declarativemaps/qgeomapitemgeometry_p.h \
+ declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h \
+ declarativemaps/locationvaluetypehelper_p.h \
+ declarativemaps/qquickgeomapgesturearea_p.h \
+ declarativemaps/qdeclarativegeomapitemgroup_p.h \
+ declarativemaps/mapitemviewdelegateincubator_p.h \
+ ../imports/positioning/qquickgeocoordinateanimation_p.h
+
+SOURCES += \
+ declarativemaps/qdeclarativegeomapitemview.cpp \
+ declarativemaps/qdeclarativegeoserviceprovider.cpp \
+ declarativemaps/qdeclarativegeocodemodel.cpp \
+ declarativemaps/qdeclarativegeoroutemodel.cpp \
+ declarativemaps/qdeclarativegeoroute.cpp \
+ declarativemaps/qdeclarativegeoroutesegment.cpp \
+ declarativemaps/qdeclarativegeomaneuver.cpp \
+ declarativemaps/qdeclarativegeomap.cpp \
+ declarativemaps/qdeclarativegeomaptype.cpp \
+ declarativemaps/qdeclarativegeomapitembase.cpp \
+ declarativemaps/qdeclarativegeomapquickitem.cpp \
+ declarativemaps/qdeclarativecirclemapitem.cpp \
+ declarativemaps/qdeclarativerectanglemapitem.cpp \
+ declarativemaps/qdeclarativepolygonmapitem.cpp \
+ declarativemaps/qdeclarativepolylinemapitem.cpp \
+ declarativemaps/qdeclarativeroutemapitem.cpp \
+ declarativemaps/qdeclarativegeomapparameter.cpp \
+ declarativemaps/qgeomapitemgeometry.cpp \
+ declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp \
+ declarativemaps/error_messages.cpp \
+ declarativemaps/locationvaluetypehelper.cpp \
+ declarativemaps/qquickgeomapgesturearea.cpp \
+ declarativemaps/qdeclarativegeomapitemgroup.cpp \
+ ../imports/positioning/qquickgeocoordinateanimation.cpp \
+ declarativemaps/mapitemviewdelegateincubator.cpp
+
+LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lpoly2tri$$qtPlatformTargetSuffix() -lclip2tri$$qtPlatformTargetSuffix()
+
+
diff --git a/src/imports/location/error_messages.cpp b/src/location/declarativemaps/error_messages.cpp
index a2557f79..a2557f79 100644
--- a/src/imports/location/error_messages.cpp
+++ b/src/location/declarativemaps/error_messages.cpp
diff --git a/src/imports/location/error_messages.h b/src/location/declarativemaps/error_messages.h
index 81c43b34..81c43b34 100644
--- a/src/imports/location/error_messages.h
+++ b/src/location/declarativemaps/error_messages.h
diff --git a/src/imports/location/locationvaluetypehelper.cpp b/src/location/declarativemaps/locationvaluetypehelper.cpp
index 4f39e0b4..4f39e0b4 100644
--- a/src/imports/location/locationvaluetypehelper.cpp
+++ b/src/location/declarativemaps/locationvaluetypehelper.cpp
diff --git a/src/imports/location/locationvaluetypehelper_p.h b/src/location/declarativemaps/locationvaluetypehelper_p.h
index 50038e88..50038e88 100644
--- a/src/imports/location/locationvaluetypehelper_p.h
+++ b/src/location/declarativemaps/locationvaluetypehelper_p.h
diff --git a/src/imports/location/mapitemviewdelegateincubator.cpp b/src/location/declarativemaps/mapitemviewdelegateincubator.cpp
index 06dee7ba..c8500e4b 100644
--- a/src/imports/location/mapitemviewdelegateincubator.cpp
+++ b/src/location/declarativemaps/mapitemviewdelegateincubator.cpp
@@ -35,7 +35,7 @@
**
****************************************************************************/
-#include "mapitemviewdelegateincubator.h"
+#include "mapitemviewdelegateincubator_p.h"
#include "qdeclarativegeomapitemview_p.h"
#include "qdeclarativegeomapitemview_p_p.h"
diff --git a/src/imports/location/mapitemviewdelegateincubator.h b/src/location/declarativemaps/mapitemviewdelegateincubator_p.h
index 94c73252..f03ae405 100644
--- a/src/imports/location/mapitemviewdelegateincubator.h
+++ b/src/location/declarativemaps/mapitemviewdelegateincubator_p.h
@@ -37,14 +37,26 @@
#ifndef MAPITEMVIEWDELEGATEINCUBATOR_H
#define MAPITEMVIEWDELEGATEINCUBATOR_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 <QtQml/QQmlIncubator>
-#include "qdeclarativegeomapitemview_p_p.h"
QT_BEGIN_NAMESPACE
class QDeclarativeGeoMapItemView;
+class QDeclarativeGeoMapItemViewItemData;
-class MapItemViewDelegateIncubator : public QQmlIncubator
+class Q_LOCATION_PRIVATE_EXPORT MapItemViewDelegateIncubator : public QQmlIncubator
{
public:
MapItemViewDelegateIncubator(QDeclarativeGeoMapItemView *view, QDeclarativeGeoMapItemViewItemData *itemData, bool batched = true);
diff --git a/src/imports/location/qdeclarativecirclemapitem.cpp b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
index e107091c..4cba1ab6 100644
--- a/src/imports/location/qdeclarativecirclemapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
@@ -37,20 +37,27 @@
#include "qdeclarativecirclemapitem_p.h"
#include "qdeclarativepolygonmapitem_p.h"
#include "qgeocameracapabilities_p.h"
+
#include "qwebmercator_p.h"
+#include <QtLocation/private/qgeomap_p.h>
#include <cmath>
+#include <algorithm>
#include <QtCore/QScopedValueRollback>
#include <QPen>
#include <QPainter>
+#include <QtGui/private/qtriangulator_p.h>
#include "qdoublevector2d_p.h"
#include "qlocationutils_p.h"
+#include "qgeocircle.h"
/* poly2tri triangulator includes */
-#include "../../3rdparty/poly2tri/common/shapes.h"
-#include "../../3rdparty/poly2tri/sweep/cdt.h"
+#include <common/shapes.h>
+#include <sweep/cdt.h>
+
+#include <QtPositioning/private/qclipperutils_p.h>
QT_BEGIN_NAMESPACE
@@ -122,9 +129,10 @@ QT_BEGIN_NAMESPACE
\image api-mapcircle.png
*/
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
+#ifdef M_PI
+#undef M_PI
#endif
+#define M_PI 3.14159265358979323846264338327950288
static const int CircleSamples = 128;
@@ -140,115 +148,124 @@ QGeoMapCircleGeometry::QGeoMapCircleGeometry()
/*!
\internal
*/
-void QGeoMapCircleGeometry::updateScreenPointsInvert(const QGeoMap &map)
+void QGeoMapCircleGeometry::updateScreenPointsInvert(const QList<QGeoCoordinate> &circlePath, const QGeoMap &map)
{
- if (!screenDirty_)
- return;
-
- if (map.viewportWidth() == 0 || map.viewportHeight() == 0) {
- clear();
- return;
- }
-
- QPointF origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false).toPointF();
-
- QPainterPath ppi = srcPath_;
-
+ // Not checking for !screenDirty anymore, as everything is now recalculated.
clear();
-
- // a circle requires at least 3 points;
- if (ppi.elementCount() < 3)
+ if (map.viewportWidth() == 0 || map.viewportHeight() == 0 || circlePath.size() < 3) // a circle requires at least 3 points;
return;
- // translate the path into top-left-centric coordinates
- QRectF bb = ppi.boundingRect();
- ppi.translate(-bb.left(), -bb.top());
- firstPointOffset_ = -1 * bb.topLeft();
-
- ppi.closeSubpath();
-
- // calculate actual width of map on screen in pixels
- QGeoCoordinate mapCenter(0, map.cameraData().center().longitude());
- QDoubleVector2D midPoint = map.geoProjection().coordinateToItemPosition(mapCenter, false);
- QDoubleVector2D midPointPlusOne = QDoubleVector2D(midPoint.x() + 1.0, midPoint.y());
- QGeoCoordinate coord1 = map.geoProjection().itemPositionToCoordinate(midPointPlusOne, false);
- double geoDistance = coord1.longitude() - map.cameraData().center().longitude();
- if ( geoDistance < 0 )
- geoDistance += 360.0;
- double mapWidth = 360.0 / geoDistance;
-
- qreal leftOffset = origin.x() - (map.viewportWidth()/2.0 - mapWidth/2.0) - firstPointOffset_.x();
- qreal topOffset = origin.y() - (midPoint.y() - mapWidth/2.0) - firstPointOffset_.y();
- QPainterPath ppiBorder;
- ppiBorder.moveTo(QPointF(-leftOffset, -topOffset));
- ppiBorder.lineTo(QPointF(mapWidth - leftOffset, -topOffset));
- ppiBorder.lineTo(QPointF(mapWidth - leftOffset, mapWidth - topOffset));
- ppiBorder.lineTo(QPointF(-leftOffset, mapWidth - topOffset));
-
- screenOutline_ = ppiBorder;
-
- std::vector<p2t::Point*> borderPts;
- borderPts.reserve(4);
-
- std::vector<p2t::Point*> curPts;
- curPts.reserve(ppi.elementCount());
- for (int i = 0; i < ppi.elementCount(); ++i) {
- const QPainterPath::Element e = ppi.elementAt(i);
- if (e.isMoveTo() || i == ppi.elementCount() - 1
- || (qAbs(e.x - curPts.front()->x) < 0.1
- && qAbs(e.y - curPts.front()->y) < 0.1)) {
- if (curPts.size() > 2) {
- for (int j = 0; j < 4; ++j) {
- const QPainterPath::Element e2 = ppiBorder.elementAt(j);
- borderPts.push_back(new p2t::Point(e2.x, e2.y));
+ /*
+ * No special case for no tilting as these items are very rare, and usually at most one per map.
+ *
+ * Approach:
+ * 1) subtract the circle from a rectangle filling the whole map, *in wrapped mercator space*
+ * 2) clip the resulting geometries against the visible region, *in wrapped mercator space*
+ * 3) create a QPainterPath with each of the resulting polygons projected to screen
+ * 4) use qTriangulate() to triangulate the painter path
+ */
+
+ // 1)
+ double topLati = QLocationUtils::mercatorMaxLatitude();
+ double bottomLati = -(QLocationUtils::mercatorMaxLatitude());
+ double leftLongi = QLocationUtils::mapLeftLongitude(map.cameraData().center().longitude());
+ double rightLongi = QLocationUtils::mapRightLongitude(map.cameraData().center().longitude());
+
+ srcOrigin_ = QGeoCoordinate(topLati,leftLongi);
+ QDoubleVector2D tl = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(topLati,leftLongi));
+ QDoubleVector2D tr = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(topLati,rightLongi));
+ QDoubleVector2D br = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(bottomLati,rightLongi));
+ QDoubleVector2D bl = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(bottomLati,leftLongi));
+
+ QList<QDoubleVector2D> fill;
+ fill << tl << tr << br << bl;
+
+ QList<QDoubleVector2D> hole;
+ for (const QGeoCoordinate &c: circlePath)
+ hole << map.geoProjection().geoToWrappedMapProjection(c);
+
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(fill), true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(hole));
+ Paths difference = clipper.execute(c2t::clip2tri::Difference, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
+
+ // 2)
+ QDoubleVector2D lb = map.geoProjection().geoToWrappedMapProjection(srcOrigin_);
+ QList<QList<QDoubleVector2D> > clippedPaths;
+ const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion();
+ if (visibleRegion.size()) {
+ clipper.clearClipper();
+ for (const Path &p: difference)
+ clipper.addSubjectPath(p, true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(visibleRegion));
+ Paths res = clipper.execute(c2t::clip2tri::Intersection, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
+ clippedPaths = QClipperUtils::pathsToQList(res);
+
+ // 2.1) update srcOrigin_ with the point with minimum X/Y
+ lb = QDoubleVector2D(qInf(), qInf());
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ for (const QDoubleVector2D &p: path) {
+ if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) {
+ lb = p;
}
- p2t::CDT *cdt = new p2t::CDT(borderPts);
- cdt->AddHole(curPts);
- cdt->Triangulate();
- std::vector<p2t::Triangle*> tris = cdt->GetTriangles();
- screenVertices_.reserve(screenVertices_.size() + int(tris.size()));
- for (size_t i = 0; i < tris.size(); ++i) {
- p2t::Triangle *t = tris.at(i);
- for (int j = 0; j < 3; ++j) {
- p2t::Point *p = t->GetPoint(j);
- screenVertices_ << QPointF(p->x, p->y);
- }
- }
- delete cdt;
}
- curPts.clear();
- curPts.reserve(ppi.elementCount() - i);
- curPts.push_back(new p2t::Point(e.x, e.y));
- } else if (e.isLineTo()) {
- curPts.push_back(new p2t::Point(e.x, e.y));
- } else {
- qWarning("Unhandled element type in circle painterpath");
}
- }
+ if (qIsInf(lb.x()))
+ return;
- if (curPts.size() > 0) {
- qDeleteAll(curPts.begin(), curPts.end());
- curPts.clear();
+ // Prevent the conversion to and from clipper from introducing negative offsets which
+ // in turn will make the geometry wrap around.
+ lb.setX(qMax(tl.x(), lb.x()));
+ srcOrigin_ = map.geoProjection().mapProjectionToGeo(map.geoProjection().unwrapMapProjection(lb));
+ } else {
+ clippedPaths = QClipperUtils::pathsToQList(difference);
}
- if (borderPts.size() > 0) {
- qDeleteAll(borderPts.begin(), borderPts.end());
- borderPts.clear();
+ //3)
+ QDoubleVector2D origin = map.geoProjection().wrappedMapProjectionToItemPosition(lb);
+
+ QPainterPath ppi;
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ QDoubleVector2D lastAddedPoint;
+ for (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D point = map.geoProjection().wrappedMapProjectionToItemPosition(path.at(i));
+ //point = point - origin; // Do this using ppi.translate()
+
+ if (i == 0) {
+ ppi.moveTo(point.toPointF());
+ lastAddedPoint = point;
+ } else {
+ if ((point - lastAddedPoint).manhattanLength() > 3 ||
+ i == path.size() - 1) {
+ ppi.lineTo(point.toPointF());
+ lastAddedPoint = point;
+ }
+ }
+ }
+ ppi.closeSubpath();
}
+ ppi.translate(-1 * origin.toPointF());
- screenBounds_ = ppiBorder.boundingRect();
+ QTriangleSet ts = qTriangulate(ppi);
+ qreal *vx = ts.vertices.data();
-}
+ screenIndices_.reserve(ts.indices.size());
+ screenVertices_.reserve(ts.vertices.size());
-static const qreal qgeocoordinate_EARTH_MEAN_RADIUS = 6371.0072;
+ if (ts.indices.type() == QVertexIndexVector::UnsignedInt) {
+ const quint32 *ix = reinterpret_cast<const quint32 *>(ts.indices.data());
+ for (int i = 0; i < (ts.indices.size()/3*3); ++i)
+ screenIndices_ << ix[i];
+ } else {
+ const quint16 *ix = reinterpret_cast<const quint16 *>(ts.indices.data());
+ for (int i = 0; i < (ts.indices.size()/3*3); ++i)
+ screenIndices_ << ix[i];
+ }
+ for (int i = 0; i < (ts.vertices.size()/2*2); i += 2)
+ screenVertices_ << QPointF(vx[i], vx[i + 1]);
-inline static qreal qgeocoordinate_degToRad(qreal deg)
-{
- return deg * M_PI / 180;
-}
-inline static qreal qgeocoordinate_radToDeg(qreal rad)
-{
- return rad * 180 / M_PI;
+ screenBounds_ = ppi.boundingRect();
+ sourceBounds_ = screenBounds_;
}
static bool crossEarthPole(const QGeoCoordinate &center, qreal distance)
@@ -267,8 +284,7 @@ static bool crossEarthPole(const QGeoCoordinate &center, qreal distance)
static void calculatePeripheralPoints(QList<QGeoCoordinate> &path,
const QGeoCoordinate &center,
qreal distance,
- int steps,
- QGeoCoordinate &leftBound )
+ int steps)
{
// Calculate points based on great-circle distance
// Calculation is the same as GeoCoordinate's atDistanceAndAzimuth function
@@ -277,42 +293,30 @@ static void calculatePeripheralPoints(QList<QGeoCoordinate> &path,
// pre-calculations
steps = qMax(steps, 3);
qreal centerLon = center.longitude();
- qreal minLon = centerLon;
- qreal latRad = qgeocoordinate_degToRad(center.latitude());
- qreal lonRad = qgeocoordinate_degToRad(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 / (qgeocoordinate_EARTH_MEAN_RADIUS * 1000.0));
+ 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 = qgeocoordinate_radToDeg(resultLatRad);
- qreal lon2 = QLocationUtils::wrapLong(qgeocoordinate_radToDeg(resultLonRad));
+ 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);
}
QDeclarativeCircleMapItem::QDeclarativeCircleMapItem(QQuickItem *parent)
-: QDeclarativeGeoMapItemBase(parent), color_(Qt::transparent), radius_(0), dirtyMaterial_(true),
+: QDeclarativeGeoMapItemBase(parent), color_(Qt::transparent), dirtyMaterial_(true),
updatingGeometry_(false)
{
setFlag(ItemHasContents, true);
@@ -320,6 +324,10 @@ QDeclarativeCircleMapItem::QDeclarativeCircleMapItem(QQuickItem *parent)
this, SLOT(markSourceDirtyAndUpdate()));
QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
this, SLOT(markSourceDirtyAndUpdate()));
+ QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(markGeoMaterialDirty()));
+ QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(markGeoMaterialDirty()));
// assume that circles are not self-intersecting
// to speed up processing
@@ -373,17 +381,18 @@ void QDeclarativeCircleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *ma
*/
void QDeclarativeCircleMapItem::setCenter(const QGeoCoordinate &center)
{
- if (center_ == center)
+ if (circle_.center() == center)
return;
- center_ = center;
+ circle_.setCenter(center);
+ markGeoGeometryDirty();
markSourceDirtyAndUpdate();
- emit centerChanged(center_);
+ emit centerChanged(center);
}
QGeoCoordinate QDeclarativeCircleMapItem::center()
{
- return center_;
+ return circle_.center();
}
/*!
@@ -398,6 +407,7 @@ void QDeclarativeCircleMapItem::setColor(const QColor &color)
return;
color_ = color;
dirtyMaterial_ = true;
+ geoMaterialDirty_ = true;
update();
emit colorChanged(color_);
}
@@ -416,17 +426,18 @@ QColor QDeclarativeCircleMapItem::color() const
*/
void QDeclarativeCircleMapItem::setRadius(qreal radius)
{
- if (radius_ == radius)
+ if (circle_.radius() == radius)
return;
- radius_ = radius;
+ circle_.setRadius(radius);
+ markGeoGeometryDirty();
markSourceDirtyAndUpdate();
emit radiusChanged(radius);
}
qreal QDeclarativeCircleMapItem::radius() const
{
- return radius_;
+ return circle_.radius();
}
/*!
@@ -468,7 +479,7 @@ QSGNode *QDeclarativeCircleMapItem::updateMapItemPaintNode(QSGNode *oldNode, Upd
*/
void QDeclarativeCircleMapItem::updatePolish()
{
- if (!map() || !center().isValid() || qIsNaN(radius_) || radius_ <= 0.0)
+ if (!map() || !circle_.isValid())
return;
QScopedValueRollback<bool> rollback(updatingGeometry_);
@@ -476,37 +487,65 @@ void QDeclarativeCircleMapItem::updatePolish()
if (geometry_.isSourceDirty()) {
circlePath_.clear();
- calculatePeripheralPoints(circlePath_, center_, radius_, CircleSamples, geoLeftBound_);
+ calculatePeripheralPoints(circlePath_, circle_.center(), circle_.radius(), CircleSamples);
}
+ QList<QGeoCoordinate> originalCirclePath = circlePath_;
+
int pathCount = circlePath_.size();
- bool preserve = preserveCircleGeometry(circlePath_, center_, radius_);
- geometry_.setPreserveGeometry(preserve, geoLeftBound_);
- geometry_.updateSourcePoints(*map(), circlePath_);
- if (crossEarthPole(center_, radius_) && circlePath_.size() == pathCount)
- geometry_.updateScreenPointsInvert(*map()); // invert fill area for really huge circles
- else geometry_.updateScreenPoints(*map());
+ bool preserve = preserveCircleGeometry(circlePath_, circle_.center(), circle_.radius());
+ geometry_.setPreserveGeometry(true, circle_.boundingGeoRectangle().topLeft()); // to set the geoLeftBound_
+ geometry_.setPreserveGeometry(preserve, circle_.boundingGeoRectangle().topLeft());
+
+ 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());
+ }
+
+ borderGeometry_.clear();
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
if (border_.color() != Qt::transparent && border_.width() > 0) {
QList<QGeoCoordinate> closedPath = circlePath_;
closedPath << closedPath.first();
- borderGeometry_.setPreserveGeometry(preserve, geoLeftBound_);
- borderGeometry_.updateSourcePoints(*map(), closedPath, geoLeftBound_);
- borderGeometry_.updateScreenPoints(*map(), border_.width());
- QList<QGeoMapItemGeometry *> geoms;
- geoms << &geometry_ << &borderGeometry_;
- QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ if (invertedCircle) {
+ closedPath = originalCirclePath;
+ closedPath << closedPath.first();
+ std::reverse(closedPath.begin(), closedPath.end());
+ }
+
+ borderGeometry_.setPreserveGeometry(true, circle_.boundingGeoRectangle().topLeft()); // to set the geoLeftBound_
+ borderGeometry_.setPreserveGeometry(preserve, circle_.boundingGeoRectangle().topLeft());
- setWidth(combined.width());
- setHeight(combined.height());
- } else {
- borderGeometry_.clear();
- setWidth(geometry_.screenBoundingBox().width());
- setHeight(geometry_.screenBoundingBox().height());
+ // 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 = map()->geoProjection().geoToWrappedMapProjection(geometryOrigin);
+ borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
+ borderGeometry_.updateScreenPoints(*map(), border_.width());
+ geoms << &borderGeometry_;
+ } else {
+ borderGeometry_.clear();
+ }
}
- setPositionOnMap(circlePath_.at(0), geometry_.firstPointOffset());
+ QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ setWidth(combined.width());
+ setHeight(combined.height());
+
+ setPositionOnMap(geometry_.origin(), geometry_.firstPointOffset());
}
/*!
@@ -517,36 +556,7 @@ void QDeclarativeCircleMapItem::afterViewportChanged(const QGeoMapViewportChange
if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
return;
- // if the scene is tilted, we must regenerate our geometry every frame
- if (map()->cameraCapabilities().supportsTilting()
- && (event.cameraData.tilt() > 0.1
- || event.cameraData.tilt() < -0.1)) {
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- }
-
- // if the scene is rolled, we must regen too
- if (map()->cameraCapabilities().supportsRolling()
- && (event.cameraData.roll() > 0.1
- || event.cameraData.roll() < -0.1)) {
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- }
-
- // otherwise, only regen on rotate, resize and zoom
- if (event.bearingChanged || event.mapSizeChanged || event.zoomLevelChanged) {
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- }
-
- if (event.centerChanged && crossEarthPole(center_, radius_)) {
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- }
-
- geometry_.markScreenDirty();
- borderGeometry_.markScreenDirty();
- polishAndUpdate();
+ markSourceDirtyAndUpdate();
}
/*!
@@ -557,6 +567,16 @@ bool QDeclarativeCircleMapItem::contains(const QPointF &point) const
return (geometry_.contains(point) || borderGeometry_.contains(point));
}
+const QGeoShape &QDeclarativeCircleMapItem::geoShape() const
+{
+ return circle_;
+}
+
+QGeoMap::ItemType QDeclarativeCircleMapItem::itemType() const
+{
+ return QGeoMap::MapCircle;
+}
+
/*!
\internal
*/
@@ -588,8 +608,23 @@ bool QDeclarativeCircleMapItem::preserveCircleGeometry (QList<QGeoCoordinate> &p
}
-
-// A workaround for circle path to be drawn correctly using a polygon geometry
+/*
+ * A workaround for circle path to be drawn correctly using a polygon geometry
+ * This method generates a polygon like
+ * _____________
+ * | |
+ * \ /
+ * | |
+ * / \
+ * | |
+ * -------------
+ *
+ * or a polygon like
+ *
+ * ______________
+ * | ____ |
+ * \__/ \__/
+ */
void QDeclarativeCircleMapItem::updateCirclePathForRendering(QList<QGeoCoordinate> &path,
const QGeoCoordinate &center,
qreal distance)
@@ -599,24 +634,24 @@ void QDeclarativeCircleMapItem::updateCirclePathForRendering(QList<QGeoCoordinat
qreal distanceToSouthPole = center.distanceTo(QGeoCoordinate(-poleLat, 0));
bool crossNorthPole = distanceToNorthPole < distance;
bool crossSouthPole = distanceToSouthPole < distance;
- if (!crossNorthPole && !crossSouthPole)
- return;
+
QList<int> wrapPathIndex;
- // calculate actual width of map on screen in pixels
- QDoubleVector2D midPoint = map()->geoProjection().coordinateToItemPosition(map()->cameraData().center(), false);
- QDoubleVector2D midPointPlusOne(midPoint.x() + 1.0, midPoint.y());
- QGeoCoordinate coord1 = map()->geoProjection().itemPositionToCoordinate(midPointPlusOne, false);
- qreal geoDistance = coord1.longitude() - map()->cameraData().center().longitude();
- if ( geoDistance < 0 )
- geoDistance += 360;
- qreal mapWidth = 360.0 / geoDistance;
- mapWidth = qMin(static_cast<int>(mapWidth), map()->viewportWidth());
- QDoubleVector2D prev = map()->geoProjection().coordinateToItemPosition(path.at(0), false);
+ QDoubleVector2D prev = map()->geoProjection().wrapMapProjection(map()->geoProjection().geoToMapProjection(path.at(0)));
+
+ for (int i = 1; i <= path.count(); ++i) {
+ int index = i % path.count();
+ QDoubleVector2D point = map()->geoProjection().wrapMapProjection(map()->geoProjection().geoToMapProjection(path.at(index)));
+ double diff = qAbs(point.x() - prev.x());
+ if (diff > 0.5) {
+ continue;
+ }
+ }
+
// find the points in path where wrapping occurs
for (int i = 1; i <= path.count(); ++i) {
int index = i % path.count();
- QDoubleVector2D point = map()->geoProjection().coordinateToItemPosition(path.at(index), false);
- if ( (qAbs(point.x() - prev.x())) >= mapWidth/2.0 ) {
+ QDoubleVector2D point = map()->geoProjection().wrapMapProjection(map()->geoProjection().geoToMapProjection(path.at(index)));
+ if ( (qAbs(point.x() - prev.x())) >= 0.5 ) {
wrapPathIndex << index;
if (wrapPathIndex.size() == 2 || !(crossNorthPole && crossSouthPole))
break;
diff --git a/src/imports/location/qdeclarativecirclemapitem_p.h b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h
index c91d1606..bcbd67d8 100644
--- a/src/imports/location/qdeclarativecirclemapitem_p.h
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h
@@ -48,11 +48,13 @@
// We mean it.
//
-#include "qdeclarativegeomapitembase_p.h"
-#include "qdeclarativepolylinemapitem_p.h"
-#include "qdeclarativepolygonmapitem_p.h"
+#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 <QSGGeometryNode>
#include <QSGFlatColorMaterial>
+#include <QtPositioning/QGeoCircle>
QT_BEGIN_NAMESPACE
@@ -61,10 +63,10 @@ class QGeoMapCircleGeometry : public QGeoMapPolygonGeometry
public:
QGeoMapCircleGeometry();
- void updateScreenPointsInvert(const QGeoMap &map);
+ void updateScreenPointsInvert(const QList<QGeoCoordinate> &circlePath, const QGeoMap &map);
};
-class QDeclarativeCircleMapItem : public QDeclarativeGeoMapItemBase
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeCircleMapItem : public QDeclarativeGeoMapItemBase
{
Q_OBJECT
Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged)
@@ -91,6 +93,8 @@ public:
QDeclarativeMapLineProperties *border();
bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+ QGeoMap::ItemType itemType() const Q_DECL_OVERRIDE;
Q_SIGNALS:
void centerChanged(const QGeoCoordinate &center);
@@ -112,11 +116,9 @@ private:
qreal distance);
private:
- QGeoCoordinate center_;
+ QGeoCircle circle_;
QDeclarativeMapLineProperties border_;
QColor color_;
- qreal radius_;
- QGeoCoordinate geoLeftBound_;
QList<QGeoCoordinate> circlePath_;
bool dirtyMaterial_;
QGeoMapCircleGeometry geometry_;
diff --git a/src/imports/location/qdeclarativegeocodemodel.cpp b/src/location/declarativemaps/qdeclarativegeocodemodel.cpp
index e92949ee..e92949ee 100644
--- a/src/imports/location/qdeclarativegeocodemodel.cpp
+++ b/src/location/declarativemaps/qdeclarativegeocodemodel.cpp
diff --git a/src/imports/location/qdeclarativegeocodemodel_p.h b/src/location/declarativemaps/qdeclarativegeocodemodel_p.h
index 2fbe9937..6c8f533b 100644
--- a/src/imports/location/qdeclarativegeocodemodel_p.h
+++ b/src/location/declarativemaps/qdeclarativegeocodemodel_p.h
@@ -48,9 +48,10 @@
// We mean it.
//
-#include "qdeclarativegeoserviceprovider_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
-#include <qgeocodereply.h>
+#include <QtLocation/qgeocodereply.h>
#include <QtPositioning/private/qdeclarativegeoaddress_p.h>
#include <QtPositioning/private/qdeclarativegeolocation_p.h>
@@ -59,13 +60,14 @@
#include <QAbstractListModel>
#include <QPointer>
+
QT_BEGIN_NAMESPACE
class QGeoServiceProvider;
class QGeoCodingManager;
class QDeclarativeGeoLocation;
-class QDeclarativeGeocodeModel : public QAbstractListModel, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeocodeModel : public QAbstractListModel, public QQmlParserStatus
{
Q_OBJECT
Q_ENUMS(Status)
diff --git a/src/imports/location/qdeclarativegeomaneuver.cpp b/src/location/declarativemaps/qdeclarativegeomaneuver.cpp
index 72c38865..72c38865 100644
--- a/src/imports/location/qdeclarativegeomaneuver.cpp
+++ b/src/location/declarativemaps/qdeclarativegeomaneuver.cpp
diff --git a/src/imports/location/qdeclarativegeomaneuver_p.h b/src/location/declarativemaps/qdeclarativegeomaneuver_p.h
index b189d83f..0e957a1f 100644
--- a/src/imports/location/qdeclarativegeomaneuver_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomaneuver_p.h
@@ -48,15 +48,17 @@
// We mean it.
//
-#include <qgeomaneuver.h>
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/qgeomaneuver.h>
#include <QtPositioning/QGeoCoordinate>
#include <QObject>
+
QT_BEGIN_NAMESPACE
-class QDeclarativeGeoManeuver : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoManeuver : public QObject
{
Q_OBJECT
Q_ENUMS(Direction)
diff --git a/src/imports/location/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp
index d19f6929..b7ec31ca 100644
--- a/src/imports/location/qdeclarativegeomap.cpp
+++ b/src/location/declarativemaps/qdeclarativegeomap.cpp
@@ -174,8 +174,7 @@ QDeclarativeGeoMap::QDeclarativeGeoMap(QQuickItem *parent)
m_pendingFitViewport(false),
m_copyrightsVisible(true),
m_maximumViewportLatitude(0.0),
- m_initialized(false),
- m_validRegion(false)
+ m_initialized(false)
{
setAcceptHoverEvents(false);
setAcceptedMouseButtons(Qt::LeftButton);
@@ -193,6 +192,12 @@ QDeclarativeGeoMap::QDeclarativeGeoMap(QQuickItem *parent)
QDeclarativeGeoMap::~QDeclarativeGeoMap()
{
+ // Removing map parameters and map items from m_map
+ if (m_map) {
+ m_map->clearParameters();
+ m_map->clearMapItems();
+ }
+
if (!m_mapViews.isEmpty())
qDeleteAll(m_mapViews);
// remove any map items associations
@@ -202,6 +207,18 @@ QDeclarativeGeoMap::~QDeclarativeGeoMap()
}
m_mapItems.clear();
+ for (auto g: qAsConst(m_mapItemGroups)) {
+ if (!g)
+ continue;
+ const QList<QQuickItem *> quickKids = g->childItems();
+ for (auto c: quickKids) {
+ QDeclarativeGeoMapItemBase *itemBase = qobject_cast<QDeclarativeGeoMapItemBase *>(c);
+ if (itemBase)
+ itemBase->setMap(0,0);
+ }
+ }
+ m_mapItemGroups.clear();
+
delete m_copyrights.data();
m_copyrights.clear();
}
@@ -239,10 +256,17 @@ void QDeclarativeGeoMap::onMapChildrenChanged()
// create a new one and set its parent, re-assign it to the weak pointer, then connect the copyrights-change signal
m_copyrights = new QDeclarativeGeoMapCopyrightNotice(this);
copyrights = m_copyrights.data();
+
connect(m_map, SIGNAL(copyrightsChanged(QImage)),
copyrights, SLOT(copyrightsChanged(QImage)));
+ connect(m_map, SIGNAL(copyrightsChanged(QImage)),
+ this, SIGNAL(copyrightsChanged(QImage)));
+
connect(m_map, SIGNAL(copyrightsChanged(QString)),
copyrights, SLOT(copyrightsChanged(QString)));
+ connect(m_map, SIGNAL(copyrightsChanged(QString)),
+ this, SIGNAL(copyrightsChanged(QString)));
+
connect(copyrights, SIGNAL(linkActivated(QString)),
this, SIGNAL(copyrightLinkActivated(QString)));
@@ -308,14 +332,49 @@ void QDeclarativeGeoMap::setError(QGeoServiceProvider::Error error, const QStrin
void QDeclarativeGeoMap::initialize()
{
- // try to keep center change signal in the end
+ // try to keep change signals in the end
bool centerHasChanged = false;
+ bool bearingHasChanged = false;
+ bool tiltHasChanged = false;
+ bool fovHasChanged = false;
+ bool minTiltHasChanged = false;
+ bool maxTiltHasChanged = false;
+ bool minFovHasChanged = false;
+ bool maxFovHasChanged = false;
+
+ QGeoCoordinate center = m_cameraData.center();
setMinimumZoomLevel(m_map->minimumZoom());
- // set latitude bundary check
- m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData.zoomLevel());
- QGeoCoordinate center = m_cameraData.center();
+ double bearing = m_cameraData.bearing();
+ double tilt = m_cameraData.tilt();
+ double fov = m_cameraData.fieldOfView(); // Must be 45.0
+ if (m_map->cameraCapabilities().minimumFieldOfView() != 1)
+ minFovHasChanged = true;
+ if (m_map->cameraCapabilities().maximumFieldOfView() != 179)
+ maxFovHasChanged = true;
+ if (m_map->cameraCapabilities().minimumTilt() != 0)
+ minTiltHasChanged = true;
+ if (m_map->cameraCapabilities().maximumTilt() != 89)
+ maxTiltHasChanged = true;
+ if (!m_map->cameraCapabilities().supportsBearing() && bearing != 0.0) {
+ m_cameraData.setBearing(0);
+ bearingHasChanged = true;
+ }
+ if (!m_map->cameraCapabilities().supportsTilting() && tilt != 0.0) {
+ m_cameraData.setTilt(0);
+ tiltHasChanged = true;
+ }
+
+ m_cameraData.setFieldOfView(qBound(m_map->cameraCapabilities().minimumFieldOfView(),
+ fov,
+ m_map->cameraCapabilities().maximumFieldOfView()));
+ if (fov != m_cameraData.fieldOfView())
+ fovHasChanged = true;
+
+ // set latitude boundary check
+ m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData);
+
center.setLatitude(qBound(-m_maximumViewportLatitude, center.latitude(), m_maximumViewportLatitude));
if (center != m_cameraData.center()) {
@@ -329,6 +388,27 @@ void QDeclarativeGeoMap::initialize()
if (centerHasChanged)
emit centerChanged(m_cameraData.center());
+
+ if (bearingHasChanged)
+ emit bearingChanged(m_cameraData.bearing());
+
+ if (tiltHasChanged)
+ emit tiltChanged(m_cameraData.tilt());
+
+ if (fovHasChanged)
+ emit fieldOfViewChanged(m_cameraData.fieldOfView());
+
+ if (minTiltHasChanged)
+ emit minimumTiltChanged(m_map->cameraCapabilities().minimumTilt());
+
+ if (maxTiltHasChanged)
+ emit maximumTiltChanged(m_map->cameraCapabilities().maximumTilt());
+
+ if (minFovHasChanged)
+ emit minimumFieldOfViewChanged(m_map->cameraCapabilities().minimumFieldOfView());
+
+ if (maxFovHasChanged)
+ emit maximumFieldOfViewChanged(m_map->cameraCapabilities().maximumFieldOfView());
}
/*!
@@ -438,6 +518,8 @@ QQuickGeoMapGestureArea *QDeclarativeGeoMap::gesture()
/*!
\internal
+
+ This may happen before mappingManagerInitialized()
*/
void QDeclarativeGeoMap::populateMap()
{
@@ -457,6 +539,13 @@ void QDeclarativeGeoMap::populateMap()
QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(kids.at(i));
if (mapItem) {
addMapItem(mapItem);
+ continue;
+ }
+ // Allow to add to the map Map items contained inside a parent QQuickItem, but only those at one level of nesting.
+ QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast<QDeclarativeGeoMapItemGroup *>(kids.at(i));
+ if (itemGroup) {
+ addMapItemGroup(itemGroup);
+ continue;
}
}
}
@@ -565,9 +654,8 @@ void QDeclarativeGeoMap::mappingManagerInitialized()
//The zoom level limits are only restricted by the plugins values, if the user has set a more
//strict zoom level limit before initialization nothing is done here.
//minimum zoom level might be changed to limit gray bundaries
-
- if (m_gestureArea->maximumZoomLevel() < 0
- || m_mappingManager->cameraCapabilities().maximumZoomLevelAt256() < m_gestureArea->maximumZoomLevel())
+ //This code assumes that plugins' maximum zoom level will never exceed 30.0
+ if (m_mappingManager->cameraCapabilities().maximumZoomLevelAt256() < m_gestureArea->maximumZoomLevel())
setMaximumZoomLevel(m_mappingManager->cameraCapabilities().maximumZoomLevelAt256());
if (m_mappingManager->cameraCapabilities().minimumZoomLevelAt256() > m_gestureArea->minimumZoomLevel())
@@ -583,10 +671,17 @@ void QDeclarativeGeoMap::mappingManagerInitialized()
}
m_copyrights = new QDeclarativeGeoMapCopyrightNotice(this);
+
connect(m_map, SIGNAL(copyrightsChanged(QImage)),
m_copyrights.data(), SLOT(copyrightsChanged(QImage)));
+ connect(m_map, SIGNAL(copyrightsChanged(QImage)),
+ this, SIGNAL(copyrightsChanged(QImage)));
+
connect(m_map, SIGNAL(copyrightsChanged(QString)),
m_copyrights.data(), SLOT(copyrightsChanged(QString)));
+ connect(m_map, SIGNAL(copyrightsChanged(QString)),
+ this, SIGNAL(copyrightsChanged(QString)));
+
connect(m_copyrights.data(), SIGNAL(linkActivated(QString)),
this, SIGNAL(copyrightLinkActivated(QString)));
connect(m_map, &QGeoMap::sgNodeChanged, this, &QQuickItem::update);
@@ -606,8 +701,21 @@ void QDeclarativeGeoMap::mappingManagerInitialized()
// Any map items that were added before the plugin was ready
// need to have setMap called again
foreach (const QPointer<QDeclarativeGeoMapItemBase> &item, m_mapItems) {
- if (item)
- item.data()->setMap(this, m_map);
+ if (item) {
+ item->setMap(this, m_map);
+ m_map->addMapItem(item.data()); // m_map filters out what is not supported.
+ }
+ }
+
+ // Any map item groups that were added before the plugin was ready
+ // need to have setMap called again on their children map items
+ for (auto g: qAsConst(m_mapItemGroups)) {
+ const QList<QQuickItem *> quickKids = g->childItems();
+ for (auto c: quickKids) {
+ QDeclarativeGeoMapItemBase *itemBase = qobject_cast<QDeclarativeGeoMapItemBase *>(c);
+ if (itemBase)
+ itemBase->setMap(this, m_map);
+ }
}
// All map parameters that were added before the plugin was ready
@@ -638,7 +746,6 @@ void QDeclarativeGeoMap::setMinimumZoomLevel(qreal minimumZoomLevel)
qreal oldMinimumZoomLevel = this->minimumZoomLevel();
if (m_map) {
-
minimumZoomLevel = qBound(qreal(m_map->cameraCapabilities().minimumZoomLevelAt256()), minimumZoomLevel, maximumZoomLevel());
double minimumViewportZoomLevel = m_map->minimumZoom();
if (minimumZoomLevel < minimumViewportZoomLevel)
@@ -666,17 +773,12 @@ void QDeclarativeGeoMap::setMinimumZoomLevel(qreal minimumZoomLevel)
defined by the plugin used, to prevent the map from being smaller than the
viewport in either dimension.
- If a plugin supporting mapping is not set, -1.0 is returned.
+ If a plugin supporting mapping is not set, 0.0 is returned.
*/
qreal QDeclarativeGeoMap::minimumZoomLevel() const
{
- if (m_gestureArea->minimumZoomLevel() != -1)
- return m_gestureArea->minimumZoomLevel();
- else if (m_map)
- return m_map->cameraCapabilities().minimumZoomLevelAt256();
- else
- return -1.0;
+ return m_gestureArea->minimumZoomLevel();
}
/*!
@@ -708,17 +810,12 @@ void QDeclarativeGeoMap::setMaximumZoomLevel(qreal maximumZoomLevel)
This property holds the maximum valid zoom level for the map.
The maximum zoom level is defined by the \l plugin used.
- If a plugin supporting mapping is not set, -1.0 is returned.
+ If a plugin supporting mapping is not set, 30.0 is returned.
*/
qreal QDeclarativeGeoMap::maximumZoomLevel() const
{
- if (m_gestureArea->maximumZoomLevel() != -1)
- return m_gestureArea->maximumZoomLevel();
- else if (m_map)
- return m_map->cameraCapabilities().minimumZoomLevelAt256();
- else
- return -1.0;
+ return m_gestureArea->maximumZoomLevel();
}
/*!
@@ -734,12 +831,12 @@ void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel)
if (m_cameraData.zoomLevel() == zoomLevel || zoomLevel < 0)
return;
- //small optiomatization to avoid double setCameraData
+ //small optimization to avoid double setCameraData
bool centerHasChanged = false;
if (m_initialized) {
m_cameraData.setZoomLevel(qBound(minimumZoomLevel(), zoomLevel, maximumZoomLevel()));
- m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData.zoomLevel());
+ m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData);
QGeoCoordinate coord = m_cameraData.center();
coord.setLatitude(qBound(-m_maximumViewportLatitude, coord.latitude(), m_maximumViewportLatitude));
if (coord != m_cameraData.center()) {
@@ -751,8 +848,6 @@ void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel)
m_cameraData.setZoomLevel(zoomLevel);
}
- m_validRegion = false;
-
if (centerHasChanged)
emit centerChanged(m_cameraData.center());
emit zoomLevelChanged(m_cameraData.zoomLevel());
@@ -764,6 +859,187 @@ qreal QDeclarativeGeoMap::zoomLevel() const
}
/*!
+ \qmlproperty real QtLocation::Map::bearing
+
+ This property holds the bearing for the map.
+ The default value is 0.
+ If the Plugin used for the Map supports bearing, the valid range for this value is between 0 and 360.
+ If the Plugin used for the Map does not support bearing, changing this property will have no effect.
+
+ \since Qt Location 5.9
+*/
+void QDeclarativeGeoMap::setBearing(qreal bearing)
+{
+ bearing = std::fmod(bearing, qreal(360.0));
+ if (bearing < 0.0)
+ bearing += 360.0;
+ if (m_map && !m_map->cameraCapabilities().supportsBearing())
+ bearing = 0.0;
+ if (m_cameraData.bearing() == bearing || bearing < 0.0)
+ return;
+
+ m_cameraData.setBearing(bearing);
+ if (m_map)
+ m_map->setCameraData(m_cameraData);
+ emit bearingChanged(bearing);
+}
+
+qreal QDeclarativeGeoMap::bearing() const
+{
+ return m_cameraData.bearing();
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::tilt
+
+ This property holds the tilt for the map.
+ The default value is 0.
+ If the Plugin used for the Map supports tilt, the valid range for this value is
+ [ plugin.minimumTilt, plugin.maximumTilt ].
+ If the Plugin used for the Map does not support tilting, changing this property will have no effect.
+
+ \since Qt Location 5.9
+*/
+void QDeclarativeGeoMap::setTilt(qreal tilt)
+{
+ tilt = qBound(minimumTilt(), tilt, maximumTilt());
+ if (m_cameraData.tilt() == tilt)
+ return;
+
+ m_cameraData.setTilt(tilt);
+ if (m_map)
+ m_map->setCameraData(m_cameraData);
+ emit tiltChanged(tilt);
+}
+
+qreal QDeclarativeGeoMap::tilt() const
+{
+ return m_cameraData.tilt();
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::fieldOfView
+
+ This property holds the field of view of the camera used to look at the map, in degrees.
+ If the plugin property of the map is not set, or the plugin does not support mapping, the value is 45 degrees.
+
+ Note that changing this value implicitly changes also the distance between the camera and the map,
+ so that, at a tilting angle of 0 degrees, the resulting image is identical for any value used for this property.
+
+ For more information about this parameter, consult the Wikipedia articles about \l {https://en.wikipedia.org/wiki/Field_of_view} {Field of view} and
+ \l {https://en.wikipedia.org/wiki/Angle_of_view} {Angle of view}.
+
+ \since Qt Location 5.9
+*/
+void QDeclarativeGeoMap::setFieldOfView(qreal fieldOfView)
+{
+ fieldOfView = qBound(minimumFieldOfView(), fieldOfView, maximumFieldOfView());
+ if (m_cameraData.fieldOfView() == fieldOfView)
+ return;
+
+ m_cameraData.setFieldOfView(fieldOfView);
+ if (m_map)
+ m_map->setCameraData(m_cameraData);
+ emit fieldOfViewChanged(fieldOfView);
+}
+
+qreal QDeclarativeGeoMap::fieldOfView() const
+{
+ return m_cameraData.fieldOfView();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::minimumFieldOfView
+ This property holds the minimum field of view that the map supports.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is 1.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::minimumFieldOfView() const
+{
+ if (!m_map)
+ return 1;
+ return m_map->cameraCapabilities().minimumFieldOfView();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::maximumFieldOfView
+ This property holds the maximum field of view that the map supports.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is 179.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::maximumFieldOfView() const
+{
+ if (!m_map)
+ return 179;
+ return m_map->cameraCapabilities().maximumFieldOfView();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::bearingSupported
+
+ This property indicates if the Map supports bearing.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is false.
+
+ \since Qt Location 5.9
+*/
+bool QDeclarativeGeoMap::isBearingSupported() const
+{
+ if (!m_map)
+ return false;
+ return m_map->cameraCapabilities().supportsBearing();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::tiltingSupported
+
+ This property indicates if the Map supports tilting.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is false.
+
+ \since Qt Location 5.9
+*/
+bool QDeclarativeGeoMap::isTiltingSupported() const
+{
+ if (!m_map)
+ return false;
+ return m_map->cameraCapabilities().supportsTilting();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::minimumTilt
+
+ This property holds the minimum tilt that the map supports.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is 0.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::minimumTilt() const
+{
+ if (!m_map || !m_map->cameraCapabilities().supportsTilting())
+ return 0.0;
+ return m_map->cameraCapabilities().minimumTilt();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::maximumTilt
+
+ This property holds the maximum tilt that the map supports.
+ If the plugin property of the map is not set, this property is 89.
+ If the plugin is set and it does not support mapping, this property is 0.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::maximumTilt() const
+{
+ if (!m_map)
+ return 89.0;
+ else if (!m_map->cameraCapabilities().supportsTilting())
+ return 0.0;
+ return m_map->cameraCapabilities().maximumTilt();
+}
+
+/*!
\qmlproperty coordinate QtLocation::Map::center
This property holds the coordinate which occupies the center of the
@@ -788,7 +1064,6 @@ void QDeclarativeGeoMap::setCenter(const QGeoCoordinate &center)
m_cameraData.setCenter(center);
}
- m_validRegion = false;
emit centerChanged(m_cameraData.center());
}
@@ -818,12 +1093,15 @@ QGeoCoordinate QDeclarativeGeoMap::center() const
*/
void QDeclarativeGeoMap::setVisibleRegion(const QGeoShape &shape)
{
- if (shape == m_region && m_validRegion)
+ if (shape.boundingGeoRectangle() == visibleRegion())
return;
- m_region = shape;
- if (!shape.isValid()) {
+ m_visibleRegion = shape.boundingGeoRectangle();
+ if (!m_visibleRegion.isValid()
+ || (m_visibleRegion.bottomRight().latitude() >= 85.0) // rect entirely outside web mercator
+ || (m_visibleRegion.topLeft().latitude() <= -85.0)) {
// shape invalidated -> nothing to fit anymore
+ m_visibleRegion = QGeoRectangle();
m_pendingFitViewport = false;
return;
}
@@ -839,7 +1117,7 @@ void QDeclarativeGeoMap::setVisibleRegion(const QGeoShape &shape)
QGeoShape QDeclarativeGeoMap::visibleRegion() const
{
if (!m_map || !width() || !height())
- return m_region;
+ return m_visibleRegion;
QGeoCoordinate tl = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(0, 0));
QGeoCoordinate br = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(width(), height()));
@@ -898,87 +1176,18 @@ QColor QDeclarativeGeoMap::color() const
return m_color;
}
+// TODO: offer the possibility to specify the margins.
void QDeclarativeGeoMap::fitViewportToGeoShape()
{
- int margins = 10;
- if (!m_map || width() <= margins || height() <= margins)
- return;
-
- QGeoCoordinate topLeft;
- QGeoCoordinate bottomRight;
-
- switch (m_region.type()) {
- case QGeoShape::RectangleType:
- {
- QGeoRectangle rect = m_region;
- topLeft = rect.topLeft();
- bottomRight = rect.bottomRight();
- if (bottomRight.longitude() < topLeft.longitude())
- bottomRight.setLongitude(bottomRight.longitude() + 360.0);
-
- break;
- }
- case QGeoShape::CircleType:
- {
- const double pi = M_PI;
- QGeoCircle circle = m_region;
- QGeoCoordinate centerCoordinate = circle.center();
-
- // calculate geo bounding box of the circle
- // circle tangential points with meridians and the north pole create
- // spherical triangle, we use spherical law of sines
- // sin(lon_delta_in_rad)/sin(r_in_rad) =
- // sin(alpha_in_rad)/sin(pi/2 - lat_in_rad), where:
- // * lon_delta_in_rad - delta of longitudes of circle center
- // and tangential points
- // * r_in_rad - angular radius of the circle
- // * lat_in_rad - latitude of circle center
- // * alpha_in_rad - angle between meridian and radius to the circle =>
- // this is tangential point => sin(alpha) = 1
- // * lat_delta_in_rad - delta of latitudes of circle center and
- // latitude of points where great circle (going through circle
- // center) crosses circle and the pole
-
- double r_in_rad = circle.radius() / EARTH_MEAN_RADIUS; // angular r
- double lat_delta_in_deg = r_in_rad * 180 / pi;
- double lon_delta_in_deg = std::asin(std::sin(r_in_rad) /
- std::cos(centerCoordinate.latitude() * pi / 180)) * 180 / pi;
-
- topLeft.setLatitude(centerCoordinate.latitude() + lat_delta_in_deg);
- topLeft.setLongitude(centerCoordinate.longitude() - lon_delta_in_deg);
- bottomRight.setLatitude(centerCoordinate.latitude()
- - lat_delta_in_deg);
- bottomRight.setLongitude(centerCoordinate.longitude()
- + lon_delta_in_deg);
-
- // adjust if circle reaches poles => cross all meridians and
- // fit into Mercator projection bounds
- if (topLeft.latitude() > 90 || bottomRight.latitude() < -90) {
- topLeft.setLatitude(qMin(topLeft.latitude(), 85.05113));
- topLeft.setLongitude(-180.0);
- bottomRight.setLatitude(qMax(bottomRight.latitude(),
- -85.05113));
- bottomRight.setLongitude(180.0);
- }
- break;
- }
- case QGeoShape::UnknownType:
- //Fallthrough to default
- default:
+ const int margins = 10;
+ if (!m_map || !m_visibleRegion.isValid() || width() <= margins || height() <= margins)
return;
- }
- QDoubleVector2D topLeftPoint = m_map->geoProjection().geoToMapProjection(topLeft);
- QDoubleVector2D bottomRightPoint = m_map->geoProjection().geoToMapProjection(bottomRight);
+ QDoubleVector2D topLeftPoint = m_map->geoProjection().geoToMapProjection(m_visibleRegion.topLeft());
+ QDoubleVector2D bottomRightPoint = m_map->geoProjection().geoToMapProjection(m_visibleRegion.bottomRight());
if (bottomRightPoint.x() < topLeftPoint.x()) // crossing the dateline
bottomRightPoint.setX(bottomRightPoint.x() + 1.0);
-
- double bboxWidth = bottomRightPoint.x() - topLeftPoint.x();
- double bboxHeight = bottomRightPoint.y() - topLeftPoint.y();
- bboxWidth *= m_map->mapWidth();
- bboxHeight *= m_map->mapHeight();
-
// find center of the bounding box
QDoubleVector2D center = (topLeftPoint + bottomRightPoint) * 0.5;
center.setX(center.x() > 1.0 ? center.x() - 1.0 : center.x());
@@ -988,16 +1197,17 @@ void QDeclarativeGeoMap::fitViewportToGeoShape()
setCenter(centerCoordinate);
// if the shape is empty we just change center position, not zoom
- if (bboxHeight == 0 && bboxWidth == 0)
+ double bboxWidth = (bottomRightPoint.x() - topLeftPoint.x()) * m_map->mapWidth();
+ double bboxHeight = (bottomRightPoint.y() - topLeftPoint.y()) * m_map->mapHeight();
+
+ if (bboxHeight == 0.0 && bboxWidth == 0.0)
return;
double zoomRatio = qMax(bboxWidth / (width() - margins),
bboxHeight / (height() - margins));
- // fixme: use log2 with c++11
zoomRatio = std::log(zoomRatio) / std::log(2.0);
double newZoom = qMax<double>(minimumZoomLevel(), zoomLevel() - zoomRatio);
setZoomLevel(newZoom);
- m_validRegion = true;
}
@@ -1228,10 +1438,14 @@ void QDeclarativeGeoMap::addMapItem(QDeclarativeGeoMapItemBase *item)
{
if (!item || item->quickMap())
return;
- item->setParentItem(this);
- if (m_map)
- item->setMap(this, m_map);
+ // If the item comes from a MapItemGroup, do not reparent it.
+ if (!qobject_cast<QDeclarativeGeoMapItemGroup *>(item->parentItem()))
+ item->setParentItem(this);
m_mapItems.append(item);
+ if (m_map) {
+ item->setMap(this, m_map);
+ m_map->addMapItem(item);
+ }
emit mapItemsChanged();
}
@@ -1358,11 +1572,13 @@ void QDeclarativeGeoMap::removeMapItem(QDeclarativeGeoMapItemBase *ptr)
{
if (!ptr || !m_map)
return;
+ m_map->removeMapItem(ptr);
QPointer<QDeclarativeGeoMapItemBase> item(ptr);
if (!m_mapItems.contains(item))
return;
- item.data()->setParentItem(0);
- item.data()->setMap(0, 0);
+ if (item->parentItem() == this)
+ item->setParentItem(0);
+ item->setMap(0, 0);
// these can be optimized for perf, as we already check the 'contains' above
m_mapItems.removeOne(item);
emit mapItemsChanged();
@@ -1371,25 +1587,86 @@ void QDeclarativeGeoMap::removeMapItem(QDeclarativeGeoMapItemBase *ptr)
/*!
\qmlmethod void QtLocation::Map::clearMapItems()
- Removes all items from the map.
+ Removes all items and item groups from the map.
- \sa mapItems, addMapItem, removeMapItem
+ \sa mapItems, addMapItem, removeMapItem, addMapItemGroup, removeMapItemGroup
*/
void QDeclarativeGeoMap::clearMapItems()
{
+ m_map->clearMapItems();
if (m_mapItems.isEmpty())
return;
- for (int i = 0; i < m_mapItems.count(); ++i) {
- if (m_mapItems.at(i)) {
- m_mapItems.at(i).data()->setParentItem(0);
- m_mapItems.at(i).data()->setMap(0, 0);
+ for (auto i : qAsConst(m_mapItems)) {
+ if (i) {
+ i->setMap(0, 0);
+ if (i->parentItem() == this)
+ i->setParentItem(0);
}
}
m_mapItems.clear();
+ m_mapItemGroups.clear();
emit mapItemsChanged();
}
/*!
+ \qmlmethod void QtLocation::Map::addMapItemGroup(MapItemGroup itemGroup)
+
+ Adds the map items contained in the given \a itemGroup to the Map
+ (for example MapQuickItem, MapCircle). These items will be reparented, and the map
+ will be their new parent. Property bindings defined using \e{parent.} inside a MapItemGroup
+ will therefore not work.
+
+ \sa MapItemGroup, removeMapItemGroup
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::addMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup)
+{
+ if (!itemGroup)
+ return;
+
+ QPointer<QDeclarativeGeoMapItemGroup> g(itemGroup);
+ if (m_mapItemGroups.contains(g))
+ return;
+
+ m_mapItemGroups.append(g);
+ const QList<QQuickItem *> quickKids = g->childItems();
+ for (auto c: quickKids) {
+ QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(c);
+ if (mapItem)
+ addMapItem(mapItem);
+ }
+ itemGroup->setParentItem(this);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::removeMapItemGroup(MapItemGroup itemGroup)
+
+ Removes \a itemGroup and the items contained therein from the Map.
+
+ \sa MapItemGroup, addMapItemGroup
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::removeMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup)
+{
+ if (!itemGroup)
+ return;
+
+ QPointer<QDeclarativeGeoMapItemGroup> g(itemGroup);
+ if (!m_mapItemGroups.removeOne(g))
+ return;
+
+ const QList<QQuickItem *> quickKids = itemGroup->childItems();
+ for (auto c: quickKids) {
+ QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(c);
+ if (mapItem)
+ removeMapItem(mapItem);
+ }
+ itemGroup->setParentItem(0);
+}
+
+/*!
\qmlproperty MapType QtLocation::Map::activeMapType
\brief Access to the currently active \l{MapType}{map type}.
@@ -1433,7 +1710,7 @@ void QDeclarativeGeoMap::geometryChanged(const QRectF &newGeometry, const QRectF
setMinimumZoomLevel(m_map->minimumZoom());
// Update the center latitudinal threshold
- double maximumCenterLatitudeAtZoom = m_map->maximumCenterLatitudeAtZoom(m_cameraData.zoomLevel());
+ double maximumCenterLatitudeAtZoom = m_map->maximumCenterLatitudeAtZoom(m_cameraData);
if (maximumCenterLatitudeAtZoom != m_maximumViewportLatitude) {
m_maximumViewportLatitude = maximumCenterLatitudeAtZoom;
QGeoCoordinate coord = m_cameraData.center();
@@ -1467,18 +1744,33 @@ void QDeclarativeGeoMap::geometryChanged(const QRectF &newGeometry, const QRectF
Fits the current viewport to the boundary of all map items. The camera is positioned
in the center of the map items, and at the largest integral zoom level possible which
- allows all map items to be visible on screen
+ allows all map items to be visible on screen.
+ \sa fitViewportToVisibleMapItems
*/
void QDeclarativeGeoMap::fitViewportToMapItems()
{
- fitViewportToMapItemsRefine(true);
+ fitViewportToMapItemsRefine(true, false);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::fitViewportToVisibleMapItems()
+
+ Fits the current viewport to the boundary of all \b visible map items.
+ The camera is positioned in the center of the map items, and at the largest integral
+ zoom level possible which allows all map items to be visible on screen.
+
+ \sa fitViewportToMapItems
+*/
+void QDeclarativeGeoMap::fitViewportToVisibleMapItems()
+{
+ fitViewportToMapItemsRefine(true, true);
}
/*!
\internal
*/
-void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine)
+void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine, bool onlyVisible)
{
if (!m_map)
return;
@@ -1502,7 +1794,7 @@ void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine)
if (!m_mapItems.at(i))
continue;
QDeclarativeGeoMapItemBase *item = m_mapItems.at(i).data();
- if (!item)
+ if (!item || (onlyVisible && (!item->isVisible() || item->mapItemOpacity() <= 0.0)))
continue;
// skip quick items in the first pass and refine the fit later
@@ -1516,6 +1808,10 @@ void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine)
}
// Force map items to update immediately. Needed to ensure correct item size and positions
// when recursively calling this function.
+ // TODO: See if we really need updatePolish on delegated items, in particular
+ // in relation to
+ // a) fitViewportToMapItems
+ // b) presence of MouseArea
if (item->isPolishScheduled())
item->updatePolish();
@@ -1540,7 +1836,7 @@ void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine)
if (itemCount == 0) {
if (haveQuickItem)
- fitViewportToMapItemsRefine(false);
+ fitViewportToMapItemsRefine(false, onlyVisible);
return;
}
double bboxWidth = maxX - minX;
@@ -1570,7 +1866,7 @@ void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine)
// as map quick items retain the same screen size after the camera zooms in/out
// we refine the viewport again to achieve better results
if (refine)
- fitViewportToMapItemsRefine(false);
+ fitViewportToMapItemsRefine(false, onlyVisible);
}
bool QDeclarativeGeoMap::sendMouseEvent(QMouseEvent *event)
diff --git a/src/imports/location/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h
index e0940f97..d7aee60f 100644
--- a/src/imports/location/qdeclarativegeomap_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomap_p.h
@@ -48,15 +48,18 @@
// We mean it.
//
-#include "qgeoserviceprovider.h"
-#include "qdeclarativegeomapitemview_p.h"
-#include "qquickgeomapgesturearea_p.h"
-#include "qgeocameradata_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitemview_p.h>
+#include <QtLocation/private/qquickgeomapgesturearea_p.h>
+#include <QtLocation/private/qdeclarativegeomapitemgroup_p.h>
+#include <QtLocation/qgeoserviceprovider.h>
+#include <QtLocation/private/qgeocameradata_p.h>
#include <QtQuick/QQuickItem>
#include <QtCore/QPointer>
#include <QtCore/QSet>
#include <QtGui/QColor>
#include <QtPositioning/qgeoshape.h>
+#include <QtLocation/private/qgeomap_p.h>
QT_BEGIN_NAMESPACE
@@ -65,7 +68,7 @@ class QDeclarativeGeoMapType;
class QDeclarativeGeoMapCopyrightNotice;
class QDeclarativeGeoMapParameter;
-class QDeclarativeGeoMap : public QQuickItem
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMap : public QQuickItem
{
Q_OBJECT
Q_ENUMS(QGeoServiceProvider::Error)
@@ -74,6 +77,17 @@ class QDeclarativeGeoMap : public QQuickItem
Q_PROPERTY(qreal minimumZoomLevel READ minimumZoomLevel WRITE setMinimumZoomLevel NOTIFY minimumZoomLevelChanged)
Q_PROPERTY(qreal maximumZoomLevel READ maximumZoomLevel WRITE setMaximumZoomLevel NOTIFY maximumZoomLevelChanged)
Q_PROPERTY(qreal zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged)
+
+ Q_PROPERTY(bool bearingSupported READ isBearingSupported NOTIFY bearingSupportChanged)
+ Q_PROPERTY(bool tiltingSupported READ isTiltingSupported NOTIFY tiltingSupportChanged)
+ Q_PROPERTY(qreal minimumTilt READ minimumTilt NOTIFY minimumTiltChanged)
+ Q_PROPERTY(qreal maximumTilt READ maximumTilt NOTIFY maximumTiltChanged)
+ Q_PROPERTY(qreal bearing READ bearing WRITE setBearing NOTIFY bearingChanged)
+ Q_PROPERTY(qreal tilt READ tilt WRITE setTilt NOTIFY tiltChanged)
+ Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged)
+ Q_PROPERTY(qreal minimumFieldOfView READ minimumFieldOfView NOTIFY minimumFieldOfViewChanged)
+ Q_PROPERTY(qreal maximumFieldOfView READ maximumFieldOfView NOTIFY minimumFieldOfViewChanged)
+
Q_PROPERTY(QDeclarativeGeoMapType *activeMapType READ activeMapType WRITE setActiveMapType NOTIFY activeMapTypeChanged)
Q_PROPERTY(QQmlListProperty<QDeclarativeGeoMapType> supportedMapTypes READ supportedMapTypes NOTIFY supportedMapTypesChanged)
Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged)
@@ -106,6 +120,22 @@ public:
void setZoomLevel(qreal zoomLevel);
qreal zoomLevel() const;
+ void setBearing(qreal bearing);
+ qreal bearing() const;
+
+ void setTilt(qreal tilt);
+ qreal tilt() const;
+
+ void setFieldOfView(qreal fieldOfView);
+ qreal fieldOfView() const;
+ qreal minimumFieldOfView() const;
+ qreal maximumFieldOfView() const;
+
+ bool isBearingSupported() const;
+ bool isTiltingSupported() const;
+ qreal minimumTilt() const;
+ qreal maximumTilt() const;
+
void setCenter(const QGeoCoordinate &center);
QGeoCoordinate center() const;
@@ -123,6 +153,9 @@ public:
Q_INVOKABLE void removeMapItem(QDeclarativeGeoMapItemBase *item);
Q_INVOKABLE void addMapItem(QDeclarativeGeoMapItemBase *item);
+ Q_INVOKABLE void addMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup);
+ Q_INVOKABLE void removeMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup);
+
Q_INVOKABLE void clearMapItems();
QList<QObject *> mapItems();
@@ -137,6 +170,7 @@ public:
QQuickGeoMapGestureArea *gesture();
Q_INVOKABLE void fitViewportToMapItems();
+ Q_INVOKABLE void fitViewportToVisibleMapItems();
Q_INVOKABLE void pan(int dx, int dy);
Q_INVOKABLE void prefetchData(); // optional hint for prefetch
Q_INVOKABLE void clearData();
@@ -157,6 +191,17 @@ Q_SIGNALS:
void copyrightLinkActivated(const QString &link);
void copyrightsVisibleChanged(bool visible);
void colorChanged(const QColor &color);
+ void bearingChanged(qreal bearing);
+ void tiltChanged(qreal tilt);
+ void fieldOfViewChanged(qreal fieldOfView);
+ void bearingSupportChanged(bool bearingSupport);
+ void tiltingSupportChanged(bool tiltingSupport);
+ void minimumTiltChanged(qreal minimumTilt);
+ void maximumTiltChanged(qreal maximumTilt);
+ void minimumFieldOfViewChanged(qreal minimumFieldOfView);
+ void maximumFieldOfViewChanged(qreal maximumFieldOfView);
+ void copyrightsChanged(const QImage &copyrightsImage);
+ void copyrightsChanged(const QString &copyrightsHtml);
protected:
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE ;
@@ -187,7 +232,7 @@ private:
void setupMapView(QDeclarativeGeoMapItemView *view);
void populateMap();
void populateParameters();
- void fitViewportToMapItemsRefine(bool refine);
+ void fitViewportToMapItemsRefine(bool refine, bool onlyVisible);
void fitViewportToGeoShape();
bool isInteractive();
@@ -201,9 +246,10 @@ private:
QGeoMap *m_map;
QPointer<QDeclarativeGeoMapCopyrightNotice> m_copyrights;
QList<QPointer<QDeclarativeGeoMapItemBase> > m_mapItems;
+ QList<QPointer<QDeclarativeGeoMapItemGroup> > m_mapItemGroups;
QString m_errorString;
QGeoServiceProvider::Error m_error;
- QGeoShape m_region;
+ QGeoRectangle m_visibleRegion;
QColor m_color;
QGeoCameraData m_cameraData;
bool m_componentCompleted;
@@ -211,12 +257,12 @@ private:
bool m_copyrightsVisible;
double m_maximumViewportLatitude;
bool m_initialized;
- bool m_validRegion;
QSet<QDeclarativeGeoMapParameter *> m_mapParameters;
friend class QDeclarativeGeoMapItem;
friend class QDeclarativeGeoMapItemView;
friend class QQuickGeoMapGestureArea;
+ friend class QDeclarativeGeoMapCopyrightNotice;
Q_DISABLE_COPY(QDeclarativeGeoMap)
};
diff --git a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp
new file mode 100644
index 00000000..d7fa9f3d
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com>
+** Copyright (C) 2015 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 "qdeclarativegeomapcopyrightsnotice_p.h"
+
+#include <QtGui/QTextDocument>
+#include <QtGui/QAbstractTextDocumentLayout>
+#include <QtGui/QPainter>
+#include <QtQuick/private/qquickanchors_p.h>
+#include <QtQuick/private/qquickanchors_p_p.h>
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapCopyrightNotice
+ \instantiates QDeclarativeGeoMapCopyrightNotice
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.9
+
+ \brief The MapCopyrightNotice item displays the current valid
+ copyright notice for a Map element.
+
+ This object can be used to place an additional copyright notices
+ programmatically.
+
+ Note that declaring a MapCopyrightNotice inside a QtLocation::Map element
+ is not possible, like for any other QQuickItem.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+*/
+
+/*!
+ \qmlproperty Map QtLocation::MapCopyrightNotice::mapSource
+
+ This property holds the current map source providing the copyright data shown
+ in this notice.
+ In order to let the MapCopyrightNotice display a copyright, this property must
+ be set, as it is the only data source for this element.
+*/
+
+/*!
+ \qmlproperty color QtLocation::MapCopyrightNotice::backgroundColor
+
+ This property holds the current background color of the copyright notice.
+*/
+
+/*!
+ \qmlproperty string QtLocation::MapCopyrightNotice::styleSheet
+
+ This property holds the current css2.1 style sheet used to style the copyright notice, if in HTML form.
+
+ Example:
+ \code
+ MapCopyrightNotice {
+ mapSource: myMap
+ styleSheet: "body { color : green; font-family: \"Lucida\"; font-size: 8px} a{ font-size: 8px; color:#A62900}"
+ }
+ \endcode
+*/
+
+QDeclarativeGeoMapCopyrightNotice::QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent)
+: QQuickPaintedItem(parent), m_copyrightsHtml(0), m_copyrightsVisible(true), m_mapSource(0),
+ m_backgroundColor(255, 255, 255, 128)
+{
+ // If this item is constructed inside the map, automatically anchor it where it always used to be.
+ if (qobject_cast<QDeclarativeGeoMap *>(parent))
+ anchorToBottomLeft();
+}
+
+QDeclarativeGeoMapCopyrightNotice::~QDeclarativeGeoMapCopyrightNotice()
+{
+}
+
+void QDeclarativeGeoMapCopyrightNotice::anchorToBottomLeft()
+{
+ if (!parent())
+ return;
+ QQuickAnchors *anchors = property("anchors").value<QQuickAnchors *>();
+ if (anchors) {
+ anchors->setLeft(QQuickAnchorLine(qobject_cast<QQuickItem *>(parent()), QQuickAnchors::LeftAnchor));
+ anchors->setBottom(QQuickAnchorLine(qobject_cast<QQuickItem *>(parent()), QQuickAnchors::BottomAnchor));
+ }
+}
+
+void QDeclarativeGeoMapCopyrightNotice::setMapSource(QDeclarativeGeoMap *mapSource)
+{
+ if (m_mapSource == mapSource)
+ return;
+
+ if (m_mapSource) {
+ // disconnect this object from current map source
+ m_mapSource->disconnect(this);
+ m_copyrightsHtml->clear();
+ m_copyrightsImage = QImage();
+ m_mapSource = Q_NULLPTR;
+ }
+
+ if (mapSource) {
+ m_mapSource = mapSource;
+ // First update the copyright. Only Image will do here, no need to store HTML right away.
+ if (!mapSource->m_copyrights->m_copyrightsImage.isNull())
+ m_copyrightsImage = mapSource->m_copyrights->m_copyrightsImage;
+
+ connect(m_mapSource, SIGNAL(copyrightsChanged(QImage)),
+ this, SLOT(copyrightsChanged(QImage)));
+ connect(m_mapSource, SIGNAL(copyrightsChanged(QString)),
+ this, SLOT(copyrightsChanged(QString)));
+ connect(this, SIGNAL(linkActivated(QString)),
+ m_mapSource, SIGNAL(copyrightLinkActivated(QString)));
+ }
+
+ update();
+ emit mapSourceChanged();
+}
+
+QDeclarativeGeoMap *QDeclarativeGeoMapCopyrightNotice::mapSource()
+{
+ return m_mapSource;
+}
+
+QColor QDeclarativeGeoMapCopyrightNotice::backgroundColor() const
+{
+ return m_backgroundColor;
+}
+
+QString QDeclarativeGeoMapCopyrightNotice::styleSheet() const
+{
+ return m_styleSheet;
+}
+
+void QDeclarativeGeoMapCopyrightNotice::setBackgroundColor(const QColor &color)
+{
+ m_backgroundColor = color;
+ rasterizeHtmlAndUpdate();
+ emit backgroundColorChanged(m_backgroundColor);
+}
+
+void QDeclarativeGeoMapCopyrightNotice::setStyleSheet(const QString &styleSheet)
+{
+ if (styleSheet == m_styleSheet)
+ return;
+
+ m_styleSheet = styleSheet;
+ if (!m_html.isEmpty() && m_copyrightsHtml) {
+ delete m_copyrightsHtml;
+ createCopyright();
+ m_copyrightsHtml->setHtml(m_html);
+ }
+ rasterizeHtmlAndUpdate();
+ emit styleSheetChanged(m_styleSheet);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::paint(QPainter *painter)
+{
+ painter->drawImage(0, 0, m_copyrightsImage);
+}
+
+void QDeclarativeGeoMapCopyrightNotice::mousePressEvent(QMouseEvent *event)
+{
+ if (m_copyrightsHtml) {
+ m_activeAnchor = m_copyrightsHtml->documentLayout()->anchorAt(event->pos());
+ if (!m_activeAnchor.isEmpty())
+ return;
+ }
+
+ QQuickPaintedItem::mousePressEvent(event);
+}
+
+void QDeclarativeGeoMapCopyrightNotice::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (m_copyrightsHtml) {
+ QString anchor = m_copyrightsHtml->documentLayout()->anchorAt(event->pos());
+ if (anchor == m_activeAnchor && !anchor.isEmpty()) {
+ emit linkActivated(anchor);
+ m_activeAnchor.clear();
+ }
+ }
+}
+
+void QDeclarativeGeoMapCopyrightNotice::rasterizeHtmlAndUpdate()
+{
+ if (!m_copyrightsHtml || m_copyrightsHtml->isEmpty())
+ return;
+
+ m_copyrightsImage = QImage(m_copyrightsHtml->size().toSize(),
+ QImage::Format_ARGB32_Premultiplied);
+
+ m_copyrightsImage.fill(qPremultiply(m_backgroundColor.rgba()));
+ QPainter painter(&m_copyrightsImage);
+ QAbstractTextDocumentLayout::PaintContext ctx;
+ ctx.palette.setColor(QPalette::Text, QStringLiteral("black"));
+ m_copyrightsHtml->documentLayout()->draw(&painter, ctx);
+
+ setImplicitSize(m_copyrightsImage.width(), m_copyrightsImage.height());
+ setContentsSize(m_copyrightsImage.size());
+
+ setKeepMouseGrab(true);
+ setAcceptedMouseButtons(Qt::LeftButton);
+
+ update();
+}
+
+void QDeclarativeGeoMapCopyrightNotice::createCopyright()
+{
+ m_copyrightsHtml = new QTextDocument(this);
+ if (!m_styleSheet.isEmpty())
+ m_copyrightsHtml->setDefaultStyleSheet(m_styleSheet);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::setCopyrightsVisible(bool visible)
+{
+ m_copyrightsVisible = visible;
+
+ setVisible(!m_copyrightsImage.isNull() && visible);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::setCopyrightsZ(int copyrightsZ)
+{
+ setZ(copyrightsZ);
+ update();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QImage &copyrightsImage)
+{
+ delete m_copyrightsHtml;
+ m_copyrightsHtml = 0;
+
+ m_copyrightsImage = copyrightsImage;
+
+ setImplicitSize(m_copyrightsImage.width(), m_copyrightsImage.height());
+
+ setKeepMouseGrab(false);
+ setAcceptedMouseButtons(Qt::NoButton);
+ setVisible(m_copyrightsVisible);
+
+ update();
+}
+
+void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QString &copyrightsHtml)
+{
+ if (copyrightsHtml.isEmpty()) {
+ setVisible(false);
+ return;
+ } else if (!m_copyrightsVisible) {
+ setVisible(false);
+ } else {
+ setVisible(true);
+ }
+
+ m_html = copyrightsHtml;
+ if (!m_copyrightsHtml)
+ createCopyright();
+
+ m_copyrightsHtml->setHtml(copyrightsHtml);
+ rasterizeHtmlAndUpdate();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/qdeclarativegeomapcopyrightsnotice_p.h b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h
index 771ced6c..4501fdf7 100644
--- a/src/imports/location/qdeclarativegeomapcopyrightsnotice_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h
@@ -49,24 +49,39 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
+
#include <QtGui/QImage>
#include <QtQuick/QQuickPaintedItem>
QT_BEGIN_NAMESPACE
class QTextDocument;
+class QDeclarativeGeoMap;
-class QDeclarativeGeoMapCopyrightNotice : public QQuickPaintedItem
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapCopyrightNotice : public QQuickPaintedItem
{
Q_OBJECT
+ Q_PROPERTY(QDeclarativeGeoMap *mapSource READ mapSource WRITE setMapSource NOTIFY mapSourceChanged)
+ Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor NOTIFY backgroundColorChanged)
+ Q_PROPERTY(QString styleSheet READ styleSheet WRITE setStyleSheet NOTIFY styleSheetChanged)
public:
- explicit QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent);
+ QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent = Q_NULLPTR);
~QDeclarativeGeoMapCopyrightNotice();
void setCopyrightsZ(int copyrightsZ);
void setCopyrightsVisible(bool visible);
+ void anchorToBottomLeft();
+
+ void setMapSource(QDeclarativeGeoMap *mapSource);
+ QDeclarativeGeoMap *mapSource();
+
+ QColor backgroundColor() const;
+ QString styleSheet() const;
+ void setBackgroundColor(const QColor &color);
+ void setStyleSheet(const QString &styleSheet);
public Q_SLOTS:
void copyrightsChanged(const QImage &copyrightsImage);
@@ -74,17 +89,27 @@ public Q_SLOTS:
signals:
void linkActivated(const QString &link);
+ void mapSourceChanged();
+ void backgroundColorChanged(const QColor &color);
+ void styleSheetChanged(const QString &styleSheet);
protected:
void paint(QPainter *painter) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+ void rasterizeHtmlAndUpdate();
private:
+ void createCopyright();
+
QTextDocument *m_copyrightsHtml;
+ QString m_html;
QImage m_copyrightsImage;
QString m_activeAnchor;
bool m_copyrightsVisible;
+ QDeclarativeGeoMap *m_mapSource;
+ QColor m_backgroundColor;
+ QString m_styleSheet;
};
QT_END_NAMESPACE
diff --git a/src/imports/location/qdeclarativegeomapitembase.cpp b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
index 84bf757d..49438a32 100644
--- a/src/imports/location/qdeclarativegeomapitembase.cpp
+++ b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
@@ -36,6 +36,7 @@
#include "qdeclarativegeomapitembase_p.h"
#include "qgeocameradata_p.h"
+#include <QtLocation/private/qgeomap_p.h>
#include <QtQml/QQmlInfo>
#include <QtQuick/QSGOpacityNode>
#include <QtQuick/private/qquickmousearea_p.h>
@@ -76,11 +77,18 @@ QGeoMapViewportChangeEvent &QGeoMapViewportChangeEvent::operator=(const QGeoMapV
}
QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent)
-: QQuickItem(parent), map_(0), quickMap_(0)
+: QQuickItem(parent), map_(0), quickMap_(0), geoGeometryDirty_(true), geoMaterialDirty_(true), parentGroup_(0)
{
setFiltersChildMouseEvents(true);
connect(this, SIGNAL(childrenChanged()),
this, SLOT(afterChildrenChanged()));
+ // Changing opacity on a mapItemGroup should affect also the opacity on the children.
+ // This must be notified to plugins, if they are to render the item.
+ connect(this, &QQuickItem::opacityChanged, this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
+ parentGroup_ = qobject_cast<QDeclarativeGeoMapItemGroup *>(parent);
+ if (parentGroup_)
+ connect(qobject_cast<QDeclarativeGeoMapItemGroup *>(parent), &QQuickItem::opacityChanged,
+ this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
}
QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase()
@@ -177,20 +185,27 @@ void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate &coordina
if (!map_ || !quickMap_)
return;
- QPointF topLeft = map_->geoProjection().coordinateToItemPosition(coordinate, false).toPointF() - offset;
+ QDoubleVector2D wrappedProjection = map_->geoProjection().geoToWrappedMapProjection(coordinate);
+ if (!map_->geoProjection().isProjectable(wrappedProjection))
+ return;
+
+ QDoubleVector2D pos = map_->geoProjection().wrappedMapProjectionToItemPosition(wrappedProjection);
+ QPointF topLeft = pos.toPointF() - offset;
setPosition(topLeft);
}
+static const double opacityRampMin = 1.5;
+static const double opacityRampMax = 2.5;
/*!
\internal
*/
float QDeclarativeGeoMapItemBase::zoomLevelOpacity() const
{
- if (quickMap_->zoomLevel() > 3.0)
+ if (quickMap_->zoomLevel() > opacityRampMax)
return 1.0;
- else if (quickMap_->zoomLevel() > 2.0)
- return quickMap_->zoomLevel() - 2.0;
+ else if (quickMap_->zoomLevel() > opacityRampMin)
+ return quickMap_->zoomLevel() - opacityRampMin;
else
return 0.0;
}
@@ -213,8 +228,10 @@ bool QDeclarativeGeoMapItemBase::childMouseEventFilter(QQuickItem *item, QEvent
*/
QSGNode *QDeclarativeGeoMapItemBase::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *pd)
{
- if (!map_ || !quickMap_) {
- delete oldNode;
+ if (!map_ || !quickMap_ || map_->supportedMapItemTypes() & itemType()) {
+ if (oldNode)
+ delete oldNode;
+ oldNode = 0;
return 0;
}
@@ -246,6 +263,33 @@ QSGNode *QDeclarativeGeoMapItemBase::updateMapItemPaintNode(QSGNode *oldNode, Up
return 0;
}
+qreal QDeclarativeGeoMapItemBase::mapItemOpacity() const
+{
+ if (parentGroup_)
+ return parentGroup_->opacity() * opacity();
+ return opacity();
+}
+
+bool QDeclarativeGeoMapItemBase::isDirty() const
+{
+ return geoGeometryDirty_ || geoMaterialDirty_;
+}
+
+bool QDeclarativeGeoMapItemBase::isGeoMaterialDirty() const
+{
+ return geoMaterialDirty_;
+}
+
+bool QDeclarativeGeoMapItemBase::isGeoGeometryDirty() const
+{
+ return geoGeometryDirty_;
+}
+
+void QDeclarativeGeoMapItemBase::markClean()
+{
+ geoGeometryDirty_ = geoMaterialDirty_ = false;
+}
+
bool QDeclarativeGeoMapItemBase::isPolishScheduled() const
{
return QQuickItemPrivate::get(this)->polishScheduled;
@@ -257,7 +301,6 @@ void QDeclarativeGeoMapItemBase::polishAndUpdate()
update();
}
-
#include "moc_qdeclarativegeomapitembase_p.cpp"
QT_END_NAMESPACE
diff --git a/src/imports/location/qdeclarativegeomapitembase_p.h b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h
index c7793fbd..3755cfa1 100644
--- a/src/imports/location/qdeclarativegeomapitembase_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h
@@ -48,13 +48,18 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
+
#include <QtQuick/QQuickItem>
+#include <QtPositioning/QGeoShape>
-#include "qdeclarativegeomap_p.h"
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qgeomap_p.h>
QT_BEGIN_NAMESPACE
-class QGeoMapViewportChangeEvent
+class Q_LOCATION_PRIVATE_EXPORT QGeoMapViewportChangeEvent
{
public:
explicit QGeoMapViewportChangeEvent();
@@ -72,9 +77,11 @@ public:
bool rollChanged;
};
-class QDeclarativeGeoMapItemBase : public QQuickItem
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemBase : public QQuickItem
{
Q_OBJECT
+
+ Q_PROPERTY(QGeoShape geoShape READ geoShape STORED false )
public:
explicit QDeclarativeGeoMapItemBase(QQuickItem *parent = 0);
virtual ~QDeclarativeGeoMapItemBase();
@@ -84,14 +91,35 @@ public:
QDeclarativeGeoMap *quickMap() { return quickMap_; }
QGeoMap *map() { return map_; }
+ virtual const QGeoShape &geoShape() const = 0;
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual QGeoMap::ItemType itemType() const = 0;
+ qreal mapItemOpacity() const;
+ // Data-related bool. Used by QGeoMaps that render the item directly.
+ bool isDirty() const;
+ bool isGeoMaterialDirty() const;
+ bool isGeoGeometryDirty() const;
+ void markClean();
+
+Q_SIGNALS:
+ void mapItemOpacityChanged();
+
protected Q_SLOTS:
virtual void afterChildrenChanged();
virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) = 0;
void polishAndUpdate();
+ inline void markGeoMaterialDirty()
+ {
+ geoMaterialDirty_ = true;
+ }
+
+ inline void markGeoGeometryDirty()
+ {
+ geoGeometryDirty_ = true;
+ }
protected:
float zoomLevelOpacity() const;
@@ -101,6 +129,11 @@ protected:
private Q_SLOTS:
void baseCameraDataChanged(const QGeoCameraData &camera);
+protected:
+ // For consumption by QGeoMaps that are capable of drawing items
+ bool geoGeometryDirty_;
+ bool geoMaterialDirty_;
+
private:
QGeoMap *map_;
QDeclarativeGeoMap *quickMap_;
@@ -108,6 +141,8 @@ private:
QSizeF lastSize_;
QGeoCameraData lastCameraData_;
+ QDeclarativeGeoMapItemGroup *parentGroup_;
+
friend class QDeclarativeGeoMap;
};
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp b/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp
new file mode 100644
index 00000000..a60d7aec
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 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 "qdeclarativegeomapitemgroup_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapItemGroup
+ \instantiates QDeclarativeGeoMapItemGroup
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.9
+
+ \brief The MapItemGroup type is a container for map items.
+
+ Its purpose is to enable code modularization by allowing the usage
+ of qml files containing map elements related to each other, and
+ the associated bindings.
+
+ \note The release of this API with Qt 5.9 is a Technology Preview.
+
+ \section2 Example Usage
+
+ The following snippet shows how to use a MapItemGroup to create a MapCircle, centered at
+ the coordinate (63, -18) with a radius of 100km, filled in red, surrounded by an ondulated green border,
+ both contained in a semitransparent blue circle with a MouseArea that moves the whole group.
+ This group is defined in a separate file named PolygonGroup.qml:
+
+ \code
+ import QtQuick 2.4
+ import QtPositioning 5.6
+ import QtLocation 5.9
+
+ MapItemGroup {
+ id: itemGroup
+ property alias position: mainCircle.center
+ property var radius: 100 * 1000
+ property var borderHeightPct : 0.3
+
+ MapCircle {
+ id: mainCircle
+ center : QtPositioning.coordinate(40, 0)
+ radius: itemGroup.radius * (1.0 + borderHeightPct)
+ opacity: 0.05
+ visible: true
+ color: 'blue'
+
+ MouseArea{
+ anchors.fill: parent
+ drag.target: parent
+ id: maItemGroup
+ }
+ }
+
+ MapCircle {
+ id: groupCircle
+ center: itemGroup.position
+ radius: itemGroup.radius
+ color: 'crimson'
+
+ onCenterChanged: {
+ groupPolyline.populateBorder();
+ }
+ }
+
+ MapPolyline {
+ id: groupPolyline
+ line.color: 'green'
+ line.width: 3
+
+ function populateBorder() {
+ groupPolyline.path = [] // clearing the path
+ var waveLength = 8.0;
+ var waveAmplitude = groupCircle.radius * borderHeightPct;
+ for (var i=0; i <= 360; i++) {
+ var wavePhase = (i/360.0 * 2.0 * Math.PI )* waveLength
+ var waveHeight = (Math.cos(wavePhase) + 1.0) / 2.0
+ groupPolyline.addCoordinate(groupCircle.center.atDistanceAndAzimuth(groupCircle.radius + waveAmplitude * waveHeight , i))
+ }
+ }
+
+ Component.onCompleted: {
+ populateBorder()
+ }
+ }
+ }
+ \endcode
+
+ PolygonGroup.qml is now a reusable component that can then be used in a Map as:
+
+ \code
+ Map {
+ id: map
+ PolygonGroup {
+ id: polygonGroup
+ position: QtPositioning.coordinate(63,-18)
+ }
+ }
+ \endcode
+
+ \image api-mapitemgroup.png
+*/
+
+QDeclarativeGeoMapItemGroup::QDeclarativeGeoMapItemGroup(QQuickItem *parent): QQuickItem(parent)
+{
+
+}
+
+QDeclarativeGeoMapItemGroup::~QDeclarativeGeoMapItemGroup()
+{
+
+}
+
+#include "moc_qdeclarativegeomapitemgroup_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h b/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h
new file mode 100644
index 00000000..1b008d71
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 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 QDECLARATIVEGEOMAPITEMGROUP_P_H
+#define QDECLARATIVEGEOMAPITEMGROUP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtQuick/QQuickItem>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemGroup : public QQuickItem
+{
+ Q_OBJECT
+public:
+ explicit QDeclarativeGeoMapItemGroup(QQuickItem *parent = 0);
+ virtual ~QDeclarativeGeoMapItemGroup();
+
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapItemGroup)
+
+#endif // QDECLARATIVEGEOMAPITEMGROUP_P_H
diff --git a/src/imports/location/qdeclarativegeomapitemview.cpp b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp
index 0a9128f3..cb1a4348 100644
--- a/src/imports/location/qdeclarativegeomapitemview.cpp
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp
@@ -37,9 +37,10 @@
****************************************************************************/
#include "qdeclarativegeomapitemview_p.h"
+#include "qdeclarativegeomapitemview_p_p.h"
#include "qdeclarativegeomap_p.h"
#include "qdeclarativegeomapitembase_p.h"
-#include "mapitemviewdelegateincubator.h"
+#include "mapitemviewdelegateincubator_p.h"
#include <QtCore/QAbstractItemModel>
#include <QtQml/QQmlContext>
diff --git a/src/imports/location/qdeclarativegeomapitemview_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h
index fefc63ba..bd696d6e 100644
--- a/src/imports/location/qdeclarativegeomapitemview_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h
@@ -50,11 +50,12 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
+
#include <QtCore/QModelIndex>
#include <QtQml/QQmlParserStatus>
#include <QtQml/QQmlIncubator>
#include <QtQml/qqml.h>
-#include "qdeclarativegeomapitemview_p_p.h"
QT_BEGIN_NAMESPACE
@@ -66,8 +67,9 @@ class QDeclarativeGeoMapItemBase;
class QQmlOpenMetaObject;
class QQmlOpenMetaObjectType;
class MapItemViewDelegateIncubator;
+class QDeclarativeGeoMapItemViewItemData;
-class QDeclarativeGeoMapItemView : public QObject, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemView : public QObject, public QQmlParserStatus
{
Q_OBJECT
diff --git a/src/imports/location/qdeclarativegeomapitemview_p_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h
index 3ad3ceb4..3ad3ceb4 100644
--- a/src/imports/location/qdeclarativegeomapitemview_p_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h
diff --git a/src/imports/location/qdeclarativegeomapparameter.cpp b/src/location/declarativemaps/qdeclarativegeomapparameter.cpp
index 88d609f4..a0e05436 100644
--- a/src/imports/location/qdeclarativegeomapparameter.cpp
+++ b/src/location/declarativemaps/qdeclarativegeomapparameter.cpp
@@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlproperty georectangle QtLocation::MapParameter::type
+ \qmlproperty string QtLocation::MapParameter::type
Set-once property which holds a string defining the type of the MapParameter
*/
diff --git a/src/imports/location/qdeclarativegeomapparameter_p.h b/src/location/declarativemaps/qdeclarativegeomapparameter_p.h
index 31ea5b04..0f54e1b7 100644
--- a/src/imports/location/qdeclarativegeomapparameter_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomapparameter_p.h
@@ -48,13 +48,14 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
#include <QtLocation/private/qgeomapparameter_p.h>
#include <QQmlParserStatus>
#include <qqml.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeGeoMapParameter : public QGeoMapParameter, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapParameter : public QGeoMapParameter, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
diff --git a/src/imports/location/qdeclarativegeomapquickitem.cpp b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp
index 78fd4f8f..c5c336b5 100644
--- a/src/imports/location/qdeclarativegeomapquickitem.cpp
+++ b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp
@@ -39,8 +39,9 @@
#include <QtCore/QScopedValueRollback>
#include <QtQml/qqmlinfo.h>
#include <QtQuick/QSGOpacityNode>
-#include "qdoublevector2d_p.h"
+#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
+#include <QtLocation/private/qgeomap_p.h>
#include <QDebug>
#include <cmath>
@@ -145,7 +146,10 @@ void QDeclarativeGeoMapQuickItem::setCoordinate(const QGeoCoordinate &coordinate
return;
coordinate_ = coordinate;
-
+ geoshape_.setTopLeft(coordinate_);
+ geoshape_.setBottomRight(coordinate_);
+ // TODO: Handle zoomLevel != 0.0
+ markGeoGeometryDirty();
polishAndUpdate();
emit coordinateChanged();
}
@@ -200,7 +204,7 @@ void QDeclarativeGeoMapQuickItem::setSourceItem(QQuickItem *sourceItem)
if (sourceItem_.data() == sourceItem)
return;
sourceItem_ = sourceItem;
-
+ markGeoGeometryDirty(); // This is equivalent to geometry
polishAndUpdate();
emit sourceItemChanged();
}
@@ -246,6 +250,7 @@ void QDeclarativeGeoMapQuickItem::setAnchorPoint(const QPointF &anchorPoint)
if (anchorPoint == anchorPoint_)
return;
anchorPoint_ = anchorPoint;
+ markGeoGeometryDirty(); // This is equivalent to geometry
polishAndUpdate();
emit anchorPointChanged();
}
@@ -278,6 +283,8 @@ void QDeclarativeGeoMapQuickItem::setZoomLevel(qreal zoomLevel)
if (zoomLevel == zoomLevel_)
return;
zoomLevel_ = zoomLevel;
+ markGeoGeometryDirty(); // This is equivalent to geometry
+ // TODO: update geoshape_!
polishAndUpdate();
emit zoomLevelChanged();
}
@@ -287,6 +294,18 @@ qreal QDeclarativeGeoMapQuickItem::zoomLevel() const
return zoomLevel_;
}
+const QGeoShape &QDeclarativeGeoMapQuickItem::geoShape() const
+{
+ // TODO: return a QGeoRectangle representing the bounding geo rectangle of the quick item
+ // when zoomLevel_ is != 0.0
+ return geoshape_;
+}
+
+QGeoMap::ItemType QDeclarativeGeoMapQuickItem::itemType() const
+{
+ return QGeoMap::MapQuickItem;
+}
+
/*!
\internal
*/
diff --git a/src/imports/location/qdeclarativegeomapquickitem_p.h b/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h
index 0410f060..23de8861 100644
--- a/src/imports/location/qdeclarativegeomapquickitem_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h
@@ -48,15 +48,18 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
+
#include <QtQuick/QQuickItem>
#include <QtQuick/QSGNode>
-#include "qdeclarativegeomap_p.h"
-#include "qdeclarativegeomapitembase_p.h"
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtPositioning/qgeoshape.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeGeoMapQuickItem : public QDeclarativeGeoMapItemBase
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapQuickItem : public QDeclarativeGeoMapItemBase
{
Q_OBJECT
Q_PROPERTY(QGeoCoordinate coordinate READ coordinate WRITE setCoordinate NOTIFY coordinateChanged)
@@ -82,6 +85,9 @@ public:
void setZoomLevel(qreal zoomLevel);
qreal zoomLevel() const;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+ QGeoMap::ItemType itemType() const Q_DECL_OVERRIDE;
+
Q_SIGNALS:
void coordinateChanged();
void sourceItemChanged();
@@ -99,6 +105,7 @@ protected Q_SLOTS:
private:
qreal scaleFactor();
QGeoCoordinate coordinate_;
+ QGeoRectangle geoshape_;
QPointer<QQuickItem> sourceItem_;
QQuickItem *opacityContainer_;
QPointF anchorPoint_;
diff --git a/src/imports/location/qdeclarativegeomaptype.cpp b/src/location/declarativemaps/qdeclarativegeomaptype.cpp
index 0b90ec3a..0b90ec3a 100644
--- a/src/imports/location/qdeclarativegeomaptype.cpp
+++ b/src/location/declarativemaps/qdeclarativegeomaptype.cpp
diff --git a/src/imports/location/qdeclarativegeomaptype_p.h b/src/location/declarativemaps/qdeclarativegeomaptype_p.h
index 980c594a..7b449aa0 100644
--- a/src/imports/location/qdeclarativegeomaptype_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomaptype_p.h
@@ -48,13 +48,15 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
+
#include <QtCore/QObject>
#include <QtQml/qqml.h>
#include <QtLocation/private/qgeomaptype_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeGeoMapType : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapType : public QObject
{
Q_OBJECT
Q_ENUMS(MapStyle)
diff --git a/src/imports/location/qdeclarativegeoroute.cpp b/src/location/declarativemaps/qdeclarativegeoroute.cpp
index 44c59ce2..fd6378da 100644
--- a/src/imports/location/qdeclarativegeoroute.cpp
+++ b/src/location/declarativemaps/qdeclarativegeoroute.cpp
@@ -36,6 +36,7 @@
#include "qdeclarativegeoroute_p.h"
#include "locationvaluetypehelper_p.h"
+#include <QtLocation/private/qgeomap_p.h>
#include <QtQml/QQmlEngine>
#include <QtQml/qqmlinfo.h>
diff --git a/src/imports/location/qdeclarativegeoroute_p.h b/src/location/declarativemaps/qdeclarativegeoroute_p.h
index 9bb46087..e4501770 100644
--- a/src/imports/location/qdeclarativegeoroute_p.h
+++ b/src/location/declarativemaps/qdeclarativegeoroute_p.h
@@ -48,7 +48,8 @@
// We mean it.
//
-#include "qdeclarativegeoroutesegment_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoroutesegment_p.h>
#include <QtCore/QObject>
#include <QtQml/QQmlListProperty>
@@ -56,7 +57,7 @@
QT_BEGIN_NAMESPACE
-class QDeclarativeGeoRoute : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRoute : public QObject
{
Q_OBJECT
diff --git a/src/imports/location/qdeclarativegeoroutemodel.cpp b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
index 90796412..90796412 100644
--- a/src/imports/location/qdeclarativegeoroutemodel.cpp
+++ b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
diff --git a/src/imports/location/qdeclarativegeoroutemodel_p.h b/src/location/declarativemaps/qdeclarativegeoroutemodel_p.h
index 30fc1ecc..3dfd2ce6 100644
--- a/src/imports/location/qdeclarativegeoroutemodel_p.h
+++ b/src/location/declarativemaps/qdeclarativegeoroutemodel_p.h
@@ -48,7 +48,8 @@
// We mean it.
//
-#include "qdeclarativegeoserviceprovider_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
#include <QtPositioning/QGeoCoordinate>
#include <QtPositioning/QGeoRectangle>
@@ -70,7 +71,7 @@ class QGeoRoutingManager;
class QDeclarativeGeoRoute;
class QDeclarativeGeoRouteQuery;
-class QDeclarativeGeoRouteModel : public QAbstractListModel, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRouteModel : public QAbstractListModel, public QQmlParserStatus
{
Q_OBJECT
Q_ENUMS(Status)
@@ -184,7 +185,7 @@ private:
RouteError error_;
};
-class QDeclarativeGeoRouteQuery : public QObject, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRouteQuery : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_ENUMS(TravelMode)
diff --git a/src/imports/location/qdeclarativegeoroutesegment.cpp b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp
index acfe2441..acfe2441 100644
--- a/src/imports/location/qdeclarativegeoroutesegment.cpp
+++ b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp
diff --git a/src/imports/location/qdeclarativegeoroutesegment_p.h b/src/location/declarativemaps/qdeclarativegeoroutesegment_p.h
index e6cf5aa5..c3203ef0 100644
--- a/src/imports/location/qdeclarativegeoroutesegment_p.h
+++ b/src/location/declarativemaps/qdeclarativegeoroutesegment_p.h
@@ -48,7 +48,8 @@
// We mean it.
//
-#include "qdeclarativegeomaneuver_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomaneuver_p.h>
#include <QtCore/QObject>
#include <QtQml/qjsvalue.h>
@@ -56,7 +57,7 @@
QT_BEGIN_NAMESPACE
-class QDeclarativeGeoRouteSegment : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRouteSegment : public QObject
{
Q_OBJECT
diff --git a/src/imports/location/qdeclarativegeoserviceprovider.cpp b/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp
index 8ed6a7bf..994b4913 100644
--- a/src/imports/location/qdeclarativegeoserviceprovider.cpp
+++ b/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp
@@ -35,7 +35,6 @@
****************************************************************************/
#include "qdeclarativegeoserviceprovider_p.h"
-
#include <QtQml/QQmlInfo>
QT_BEGIN_NAMESPACE
@@ -421,7 +420,7 @@ void QDeclarativeGeoServiceProvider::setPreferred(const QStringList &val)
/*!
\qmlproperty bool Plugin::isAttached
- This property indicates if the Plugin is attached to another Plugin.
+ This property indicates if the Plugin item is attached to a geoservice provider plugin.
*/
bool QDeclarativeGeoServiceProvider::isAttached() const
{
diff --git a/src/imports/location/qdeclarativegeoserviceprovider_p.h b/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h
index f7a2ee83..bcf67124 100644
--- a/src/imports/location/qdeclarativegeoserviceprovider_p.h
+++ b/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h
@@ -48,6 +48,8 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
+
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
@@ -59,7 +61,7 @@
QT_BEGIN_NAMESPACE
-class QDeclarativeGeoServiceProviderParameter : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProviderParameter : public QObject
{
Q_OBJECT
@@ -87,7 +89,7 @@ private:
class QDeclarativeGeoServiceProviderRequirements;
-class QDeclarativeGeoServiceProvider : public QObject, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProvider : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_ENUMS(RoutingFeature)
@@ -108,7 +110,7 @@ class QDeclarativeGeoServiceProvider : public QObject, public QQmlParserStatus
Q_INTERFACES(QQmlParserStatus)
public:
- explicit QDeclarativeGeoServiceProvider(QObject *parent = 0);
+ explicit QDeclarativeGeoServiceProvider(QObject *parent = Q_NULLPTR);
~QDeclarativeGeoServiceProvider();
enum RoutingFeature {
@@ -223,7 +225,7 @@ private:
Q_DISABLE_COPY(QDeclarativeGeoServiceProvider)
};
-class QDeclarativeGeoServiceProviderRequirements : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProviderRequirements : public QObject
{
Q_OBJECT
Q_PROPERTY(QDeclarativeGeoServiceProvider::MappingFeatures mapping
diff --git a/src/imports/location/qdeclarativepolygonmapitem.cpp b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
index 0e11db79..8f5442d6 100644
--- a/src/imports/location/qdeclarativepolygonmapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
@@ -39,6 +39,7 @@
#include "qlocationutils_p.h"
#include "error_messages.h"
#include "locationvaluetypehelper_p.h"
+#include <QtLocation/private/qgeomap_p.h>
#include <QtCore/QScopedValueRollback>
#include <QtGui/private/qtriangulator_p.h>
@@ -48,10 +49,11 @@
#include <QPainterPath>
#include <qnumeric.h>
-#include "qdoublevector2d_p.h"
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QtPositioning/private/qclipperutils_p.h>
/* poly2tri triangulator includes */
-#include "../../3rdparty/clip2tri/clip2tri.h"
+#include <clip2tri.h>
QT_BEGIN_NAMESPACE
@@ -131,11 +133,6 @@ QT_BEGIN_NAMESPACE
\image api-mappolygon.png
*/
-struct Vertex
-{
- QVector2D position;
-};
-
QGeoMapPolygonGeometry::QGeoMapPolygonGeometry()
: assumeSimple_(false)
{
@@ -150,49 +147,97 @@ void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map,
if (!sourceDirty_)
return;
- // build the actual path
- QDoubleVector2D origin;
- QDoubleVector2D lastPoint;
srcPath_ = QPainterPath();
+ // build the actual path
+ // The approach is the same as described in QGeoMapPolylineGeometry::updateSourcePoints
+ srcOrigin_ = geoLeftBound_;
double unwrapBelowX = 0;
- if (preserveGeometry_ )
- unwrapBelowX = map.geoProjection().coordinateToItemPosition(geoLeftBound_, false).x();
-
+ QDoubleVector2D leftBoundWrapped = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(geoLeftBound_));
+ if (preserveGeometry_)
+ unwrapBelowX = leftBoundWrapped.x();
+
+ QList<QDoubleVector2D> wrappedPath;
+ wrappedPath.reserve(path.size());
+ QDoubleVector2D wrappedLeftBound(qInf(), qInf());
+ // 1)
for (int i = 0; i < path.size(); ++i) {
const QGeoCoordinate &coord = path.at(i);
-
if (!coord.isValid())
continue;
- QDoubleVector2D point = map.geoProjection().coordinateToItemPosition(coord, false);
+ QDoubleVector2D wrappedProjection = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(coord));
// We can get NaN if the map isn't set up correctly, or the projection
// is faulty -- probably best thing to do is abort
- if (!qIsFinite(point.x()) || !qIsFinite(point.y()))
+ if (!qIsFinite(wrappedProjection.x()) || !qIsFinite(wrappedProjection.y()))
return;
+ const bool isPointLessThanUnwrapBelowX = (wrappedProjection.x() < leftBoundWrapped.x());
// unwrap x to preserve geometry if moved to border of map
- if (preserveGeometry_ && point.x() < unwrapBelowX
- && !qFuzzyCompare(point.x(), unwrapBelowX)
- && !qFuzzyCompare(geoLeftBound_.longitude(), coord.longitude()))
- point.setX(unwrapBelowX + geoDistanceToScreenWidth(map, geoLeftBound_, coord));
-
- if (i == 0) {
- origin = point;
- srcOrigin_ = coord;
- srcPath_.moveTo(point.toPointF() - origin.toPointF());
- lastPoint = point;
- } else {
- const QDoubleVector2D diff = (point - lastPoint);
- if (diff.x() * diff.x() + diff.y() * diff.y() >= 3.0) {
- srcPath_.lineTo(point.toPointF() - origin.toPointF());
- lastPoint = point;
- }
+ if (preserveGeometry_ && isPointLessThanUnwrapBelowX) {
+ double distance = wrappedProjection.x() - unwrapBelowX;
+ if (distance < 0.0)
+ distance += 1.0;
+ wrappedProjection.setX(unwrapBelowX + distance);
+ }
+ if (wrappedProjection.x() < wrappedLeftBound.x() || (wrappedProjection.x() == wrappedLeftBound.x() && wrappedProjection.y() < wrappedLeftBound.y())) {
+ wrappedLeftBound = wrappedProjection;
}
+ wrappedPath.append(wrappedProjection);
+ }
+
+ // 2)
+ QList<QList<QDoubleVector2D> > clippedPaths;
+ const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion();
+ if (visibleRegion.size()) {
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(wrappedPath), true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(visibleRegion));
+ Paths res = clipper.execute(c2t::clip2tri::Intersection, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
+ clippedPaths = QClipperUtils::pathsToQList(res);
+
+ // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X
+ QDoubleVector2D lb(qInf(), qInf());
+ for (const QList<QDoubleVector2D> &path: clippedPaths)
+ for (const QDoubleVector2D &p: path)
+ if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y()))
+ // y-minimization needed to find the same point on polygon and border
+ lb = p;
+
+ if (qIsInf(lb.x())) // e.g., when the polygon is clipped entirely
+ return;
+
+ // 2.2) Prevent the conversion to and from clipper from introducing negative offsets which
+ // in turn will make the geometry wrap around.
+ lb.setX(qMax(wrappedLeftBound.x(), lb.x()));
+ leftBoundWrapped = lb;
+ srcOrigin_ = map.geoProjection().mapProjectionToGeo(map.geoProjection().unwrapMapProjection(lb));
+ } else {
+ clippedPaths.append(wrappedPath);
}
- srcPath_.closeSubpath();
+ // 3)
+ QDoubleVector2D origin = map.geoProjection().wrappedMapProjectionToItemPosition(leftBoundWrapped);
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ QDoubleVector2D lastAddedPoint;
+ for (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D point = map.geoProjection().wrappedMapProjectionToItemPosition(path.at(i));
+ point = point - origin; // (0,0) if point == geoLeftBound_
+
+ if (i == 0) {
+ srcPath_.moveTo(point.toPointF());
+ lastAddedPoint = point;
+ } else {
+ if ((point - lastAddedPoint).manhattanLength() > 3 ||
+ i == path.size() - 1) {
+ srcPath_.lineTo(point.toPointF());
+ lastAddedPoint = point;
+ }
+ }
+ }
+ srcPath_.closeSubpath();
+ }
if (!assumeSimple_)
srcPath_ = srcPath_.simplified();
@@ -223,11 +268,8 @@ void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map)
QPainterPath vpPath;
vpPath.addRect(viewport);
- QPainterPath ppi;
- if (clipToViewport_)
- ppi = srcPath_.intersected(vpPath); // get the clipped version of the path
- else ppi = srcPath_;
-
+ // The geometry has already been clipped against the visible region projection in wrapped mercator space.
+ QPainterPath ppi = srcPath_;
clear();
// a polygon requires at least 3 points;
@@ -268,35 +310,6 @@ void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map)
screenOutline_ = ppi;
-#if 1
- std::vector<std::vector<c2t::Point>> clipperPoints;
- clipperPoints.push_back(std::vector<c2t::Point>());
- std::vector<c2t::Point> &curPts = clipperPoints.front();
- curPts.reserve(ppi.elementCount());
- for (int i = 0; i < ppi.elementCount(); ++i) {
- const QPainterPath::Element e = ppi.elementAt(i);
- if (e.isMoveTo() || i == ppi.elementCount() - 1
- || (qAbs(e.x - curPts.front().x) < 0.1
- && qAbs(e.y - curPts.front().y) < 0.1)) {
- if (curPts.size() > 2) {
- c2t::clip2tri *cdt = new c2t::clip2tri();
- std::vector<c2t::Point> outputTriangles;
- cdt->triangulate(clipperPoints, outputTriangles, std::vector<c2t::Point>());
- for (size_t i = 0; i < outputTriangles.size(); ++i) {
- screenVertices_ << QPointF(outputTriangles[i].x, outputTriangles[i].y);
- }
- delete cdt;
- }
- curPts.clear();
- curPts.reserve(ppi.elementCount() - i);
- curPts.push_back( c2t::Point(e.x, e.y));
- } else if (e.isLineTo()) {
- curPts.push_back( c2t::Point(e.x, e.y));
- } else {
- qWarning("Unhandled element type in polygon painterpath");
- }
- }
-#else // Old qTriangulate()-based code.
QTriangleSet ts = qTriangulate(ppi);
qreal *vx = ts.vertices.data();
@@ -314,7 +327,6 @@ void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map)
}
for (int i = 0; i < (ts.vertices.size()/2*2); i += 2)
screenVertices_ << QPointF(vx[i], vx[i + 1]);
-#endif
screenBounds_ = ppi.boundingRect();
}
@@ -328,6 +340,10 @@ QDeclarativePolygonMapItem::QDeclarativePolygonMapItem(QQuickItem *parent)
this, SLOT(handleBorderUpdated()));
QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
this, SLOT(handleBorderUpdated()));
+ QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(markGeoMaterialDirty()));
+ QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(markGeoMaterialDirty()));
}
/*!
@@ -385,14 +401,14 @@ void QDeclarativePolygonMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *m
*/
QJSValue QDeclarativePolygonMapItem::path() const
{
- QQmlContext *context = QQmlEngine::contextForObject(parent());
+ QQmlContext *context = QQmlEngine::contextForObject(this);
QQmlEngine *engine = context->engine();
QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
QV4::Scope scope(v4);
- QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(path_.length()));
- for (int i = 0; i < path_.length(); ++i) {
- const QGeoCoordinate &c = path_.at(i);
+ QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(geopath_.path().length()));
+ for (int i = 0; i < geopath_.path().length(); ++i) {
+ const QGeoCoordinate &c = geopath_.coordinateAt(i);
QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
pathArray->putIndexed(i, cv);
@@ -420,16 +436,16 @@ void QDeclarativePolygonMapItem::setPath(const QJSValue &value)
pathList.append(c);
}
- if (path_ == pathList)
+ // Equivalent to QDeclarativePolylineMapItem::setPathFromGeoList
+ if (geopath_.path() == pathList)
return;
- path_ = pathList;
- geoLeftBound_ = QDeclarativePolylineMapItem::getLeftBound(path_, deltaXs_, minX_);
- geometry_.setPreserveGeometry(true, geoLeftBound_);
- borderGeometry_.setPreserveGeometry(true, geoLeftBound_);
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- polishAndUpdate();
+ geopath_.setPath(pathList);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markGeoGeometryDirty();
+ markSourceDirtyAndUpdate();
emit pathChanged();
}
@@ -443,13 +459,12 @@ void QDeclarativePolygonMapItem::setPath(const QJSValue &value)
void QDeclarativePolygonMapItem::addCoordinate(const QGeoCoordinate &coordinate)
{
- path_.append(coordinate);
- geoLeftBound_ = QDeclarativePolylineMapItem::getLeftBound(path_, deltaXs_, minX_, geoLeftBound_);
- geometry_.setPreserveGeometry(true, geoLeftBound_);
- borderGeometry_.setPreserveGeometry(true, geoLeftBound_);
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- polishAndUpdate();
+ geopath_.addCoordinate(coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markGeoGeometryDirty();
+ markSourceDirtyAndUpdate();
emit pathChanged();
}
@@ -465,17 +480,15 @@ void QDeclarativePolygonMapItem::addCoordinate(const QGeoCoordinate &coordinate)
*/
void QDeclarativePolygonMapItem::removeCoordinate(const QGeoCoordinate &coordinate)
{
- int index = path_.lastIndexOf(coordinate);
- if (index == -1)
+ int length = geopath_.path().length();
+ geopath_.removeCoordinate(coordinate);
+ if (geopath_.path().length() == length)
return;
- path_.removeAt(index);
- geoLeftBound_ = QDeclarativePolylineMapItem::getLeftBound(path_, deltaXs_, minX_);
- geometry_.setPreserveGeometry(true, geoLeftBound_);
- borderGeometry_.setPreserveGeometry(true, geoLeftBound_);
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- polishAndUpdate();
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markGeoGeometryDirty();
+ markSourceDirtyAndUpdate();
emit pathChanged();
}
@@ -499,6 +512,7 @@ void QDeclarativePolygonMapItem::setColor(const QColor &color)
color_ = color;
dirtyMaterial_ = true;
+ geoMaterialDirty_ = true;
update();
emit colorChanged(color_);
}
@@ -531,31 +545,55 @@ QSGNode *QDeclarativePolygonMapItem::updateMapItemPaintNode(QSGNode *oldNode, Up
*/
void QDeclarativePolygonMapItem::updatePolish()
{
- if (!map() || path_.count() == 0)
+ if (!map() || geopath_.path().length() == 0)
return;
QScopedValueRollback<bool> rollback(updatingGeometry_);
updatingGeometry_ = true;
- geometry_.updateSourcePoints(*map(), path_);
+ geometry_.updateSourcePoints(*map(), geopath_.path());
geometry_.updateScreenPoints(*map());
- QList<QGeoCoordinate> closedPath = path_;
- closedPath << closedPath.first();
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
borderGeometry_.clear();
- borderGeometry_.updateSourcePoints(*map(), closedPath, geoLeftBound_);
- if (border_.color() != Qt::transparent && border_.width() > 0)
- borderGeometry_.updateScreenPoints(*map(), border_.width());
+ if (border_.color() != Qt::transparent && border_.width() > 0) {
+ QList<QGeoCoordinate> closedPath = geopath_.path();
+ closedPath << closedPath.first();
- QList<QGeoMapItemGeometry *> geoms;
- geoms << &geometry_ << &borderGeometry_;
- QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ 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 = map()->geoProjection().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());
setHeight(combined.height());
- setPositionOnMap(path_.at(0), -1 * geometry_.sourceBoundingBox().topLeft());
+ setPositionOnMap(geometry_.origin(), -1 * geometry_.sourceBoundingBox().topLeft());
+}
+
+void QDeclarativePolygonMapItem::markSourceDirtyAndUpdate()
+{
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
}
/*!
@@ -566,31 +604,10 @@ void QDeclarativePolygonMapItem::afterViewportChanged(const QGeoMapViewportChang
if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
return;
- // if the scene is tilted, we must regenerate our geometry every frame
- if (map()->cameraCapabilities().supportsTilting()
- && (event.cameraData.tilt() > 0.1
- || event.cameraData.tilt() < -0.1)) {
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- }
-
- // if the scene is rolled, we must regen too
- if (map()->cameraCapabilities().supportsRolling()
- && (event.cameraData.roll() > 0.1
- || event.cameraData.roll() < -0.1)) {
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- }
-
- // otherwise, only regen on rotate, resize and zoom
- if (event.bearingChanged || event.mapSizeChanged || event.zoomLevelChanged) {
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- }
geometry_.setPreserveGeometry(true, geometry_.geoLeftBound());
borderGeometry_.setPreserveGeometry(true, borderGeometry_.geoLeftBound());
- geometry_.markScreenDirty();
- borderGeometry_.markScreenDirty();
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
polishAndUpdate();
}
@@ -602,6 +619,16 @@ bool QDeclarativePolygonMapItem::contains(const QPointF &point) const
return (geometry_.contains(point) || borderGeometry_.contains(point));
}
+const QGeoShape &QDeclarativePolygonMapItem::geoShape() const
+{
+ return geopath_;
+}
+
+QGeoMap::ItemType QDeclarativePolygonMapItem::itemType() const
+{
+ return QGeoMap::MapPolygon;
+}
+
/*!
\internal
*/
@@ -611,44 +638,22 @@ void QDeclarativePolygonMapItem::geometryChanged(const QRectF &newGeometry, cons
QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
return;
}
+ // TODO: change the algorithm to preserve the distances and size!
+ QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false);
+ QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false);
+ if (!newCenter.isValid() || !oldCenter.isValid())
+ return;
+ double offsetLongi = newCenter.longitude() - oldCenter.longitude();
+ double offsetLati = newCenter.latitude() - oldCenter.latitude();
+ if (offsetLati == 0.0 && offsetLongi == 0.0)
+ return;
- QDoubleVector2D newPoint = QDoubleVector2D(x(),y()) + QDoubleVector2D(geometry_.firstPointOffset());
- QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(newPoint, false);
- if (newCoordinate.isValid()) {
- double firstLongitude = path_.at(0).longitude();
- double firstLatitude = path_.at(0).latitude();
- double minMaxLatitude = firstLatitude;
- // prevent dragging over valid min and max latitudes
- for (int i = 0; i < path_.count(); ++i) {
- double newLatitude = path_.at(i).latitude()
- + newCoordinate.latitude() - firstLatitude;
- if (!QLocationUtils::isValidLat(newLatitude)) {
- if (qAbs(newLatitude) > qAbs(minMaxLatitude)) {
- minMaxLatitude = newLatitude;
- }
- }
- }
- // calculate offset needed to re-position the item within map border
- double offsetLatitude = minMaxLatitude - QLocationUtils::clipLat(minMaxLatitude);
- for (int i = 0; i < path_.count(); ++i) {
- QGeoCoordinate coord = path_.at(i);
- // handle dateline crossing
- coord.setLongitude(QLocationUtils::wrapLong(coord.longitude()
- + newCoordinate.longitude() - firstLongitude));
- coord.setLatitude(coord.latitude()
- + newCoordinate.latitude() - firstLatitude - offsetLatitude);
-
- path_.replace(i, coord);
- }
- geoLeftBound_.setLongitude(QLocationUtils::wrapLong(geoLeftBound_.longitude()
- + newCoordinate.longitude() - firstLongitude));
- geometry_.setPreserveGeometry(true, geoLeftBound_);
- borderGeometry_.setPreserveGeometry(true, geoLeftBound_);
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- polishAndUpdate();
- emit pathChanged();
- }
+ geopath_.translate(offsetLati, offsetLongi);
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markGeoGeometryDirty();
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
// Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
// call to this function.
@@ -715,4 +720,5 @@ void MapPolygonNode::update(const QColor &fillColor, const QColor &borderColor,
markDirty(DirtyMaterial);
}
}
+
QT_END_NAMESPACE
diff --git a/src/imports/location/qdeclarativepolygonmapitem_p.h b/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h
index 19ac5081..9a46bb2c 100644
--- a/src/imports/location/qdeclarativepolygonmapitem_p.h
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h
@@ -48,9 +48,10 @@
// We mean it.
//
-#include "qdeclarativegeomapitembase_p.h"
-#include "qdeclarativepolylinemapitem_p.h"
-#include "qgeomapitemgeometry_p.h"
+#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 <QSGGeometryNode>
#include <QSGFlatColorMaterial>
@@ -76,7 +77,7 @@ protected:
bool assumeSimple_;
};
-class QDeclarativePolygonMapItem : public QDeclarativeGeoMapItemBase
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItem : public QDeclarativeGeoMapItemBase
{
Q_OBJECT
@@ -104,6 +105,8 @@ public:
QDeclarativeMapLineProperties *border();
bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+ QGeoMap::ItemType itemType() const Q_DECL_OVERRIDE;
Q_SIGNALS:
void pathChanged();
@@ -114,23 +117,20 @@ protected:
void updatePolish() Q_DECL_OVERRIDE;
protected Q_SLOTS:
+ void markSourceDirtyAndUpdate();
void handleBorderUpdated();
virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
private:
void pathPropertyChanged();
+ QGeoPath geopath_;
QDeclarativeMapLineProperties border_;
- QList<QGeoCoordinate> path_;
- QGeoCoordinate geoLeftBound_;
QColor color_;
bool dirtyMaterial_;
QGeoMapPolygonGeometry geometry_;
QGeoMapPolylineGeometry borderGeometry_;
bool updatingGeometry_;
- // for the left bound calculation
- QVector<double> deltaXs_; // longitude deltas from path_[0]
- double minX_; // minimum value inside deltaXs_
};
//////////////////////////////////////////////////////////////////////
diff --git a/src/imports/location/qdeclarativepolylinemapitem.cpp b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
index 5fe0535d..cd30e556 100644
--- a/src/imports/location/qdeclarativepolylinemapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
@@ -40,6 +40,7 @@
#include "error_messages.h"
#include "locationvaluetypehelper_p.h"
#include "qdoublevector2d_p.h"
+#include <QtLocation/private/qgeomap_p.h>
#include <QtCore/QScopedValueRollback>
#include <QtQml/QQmlInfo>
@@ -53,6 +54,8 @@
#include <QtGui/private/qtriangulatingstroker_p.h>
#include <QtGui/private/qtriangulator_p.h>
+#include <QtPositioning/private/qclipperutils_p.h>
+
QT_BEGIN_NAMESPACE
/*!
@@ -176,91 +179,127 @@ QGeoMapPolylineGeometry::QGeoMapPolylineGeometry()
{
}
-/*!
- \internal
-*/
-void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map,
- const QList<QGeoCoordinate> &path,
- const QGeoCoordinate geoLeftBound)
+QList<QList<QDoubleVector2D> > QGeoMapPolylineGeometry::clipPath(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ QDoubleVector2D &leftBoundWrapped)
{
- bool foundValid = false;
- double minX = -1.0;
- double minY = -1.0;
- double maxX = -1.0;
- double maxY = -1.0;
-
- if (!sourceDirty_)
- return;
-
- geoLeftBound_ = geoLeftBound;
-
- // clear the old data and reserve enough memory
- srcPoints_.clear();
- srcPoints_.reserve(path.size() * 2);
- srcPointTypes_.clear();
- srcPointTypes_.reserve(path.size());
+ /*
+ * Approach:
+ * 1) project coordinates to wrapped web mercator, and do unwrapBelowX
+ * 2) if the scene is tilted, clip the geometry against the visible region (this may generate multiple polygons)
+ * 2.1) recalculate the origin and geoLeftBound to prevent these parameters from ending in unprojectable areas
+ * 2.2) ensure the left bound does not wrap around due to QGeoCoordinate <-> clipper conversions
+ */
- QDoubleVector2D origin, lastAddedPoint;
+ srcOrigin_ = geoLeftBound_;
- const double mapWidthHalf = map.viewportWidth()/2.0;
double unwrapBelowX = 0;
+ leftBoundWrapped = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(geoLeftBound_));
if (preserveGeometry_)
- unwrapBelowX = map.geoProjection().coordinateToItemPosition(geoLeftBound_, false).x();
+ unwrapBelowX = leftBoundWrapped.x();
+ QList<QDoubleVector2D> wrappedPath;
+ wrappedPath.reserve(path.size());
+ QDoubleVector2D wrappedLeftBound(qInf(), qInf());
+ // 1)
for (int i = 0; i < path.size(); ++i) {
const QGeoCoordinate &coord = path.at(i);
-
if (!coord.isValid())
continue;
- QDoubleVector2D point = map.geoProjection().coordinateToItemPosition(coord, false);
+ QDoubleVector2D wrappedProjection = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(coord));
// We can get NaN if the map isn't set up correctly, or the projection
// is faulty -- probably best thing to do is abort
- if (!qIsFinite(point.x()) || !qIsFinite(point.y()))
- return;
-
- bool isPointLessThanUnwrapBelowX = (point.x() < unwrapBelowX);
- bool isCoordNotLeftBound = !qFuzzyCompare(geoLeftBound_.longitude(), coord.longitude());
- bool isPointNotUnwrapBelowX = !qFuzzyCompare(point.x(), unwrapBelowX);
- bool isPointNotMapWidthHalf = !qFuzzyCompare(mapWidthHalf, point.x());
+ if (!qIsFinite(wrappedProjection.x()) || !qIsFinite(wrappedProjection.y()))
+ return QList<QList<QDoubleVector2D> >();
+ const bool isPointLessThanUnwrapBelowX = (wrappedProjection.x() < leftBoundWrapped.x());
// unwrap x to preserve geometry if moved to border of map
- if (preserveGeometry_ && isPointLessThanUnwrapBelowX
- && isCoordNotLeftBound
- && isPointNotUnwrapBelowX
- && isPointNotMapWidthHalf) {
- double distance = geoDistanceToScreenWidth(map, geoLeftBound_, coord);
- point.setX(unwrapBelowX + distance);
+ if (preserveGeometry_ && isPointLessThanUnwrapBelowX) {
+ double distance = wrappedProjection.x() - unwrapBelowX;
+ if (distance < 0.0)
+ distance += 1.0;
+ wrappedProjection.setX(unwrapBelowX + distance);
+ }
+ if (wrappedProjection.x() < wrappedLeftBound.x() || (wrappedProjection.x() == wrappedLeftBound.x() && wrappedProjection.y() < wrappedLeftBound.y())) {
+ wrappedLeftBound = wrappedProjection;
}
+ wrappedPath.append(wrappedProjection);
+ }
- if (!foundValid) {
- foundValid = true;
- srcOrigin_ = coord; // TODO: Make this consistent with the left bound
- origin = point;
- point = QDoubleVector2D(0,0);
+ // 2)
+ QList<QList<QDoubleVector2D> > clippedPaths;
+ const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion();
+ if (visibleRegion.size()) {
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(wrappedPath), false);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(visibleRegion));
+ Paths res = clipper.execute(c2t::clip2tri::Intersection);
+ clippedPaths = QClipperUtils::pathsToQList(res);
+
+ // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X
+ QDoubleVector2D lb(qInf(), qInf());
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ for (const QDoubleVector2D &p: path) {
+ if (p == leftBoundWrapped) {
+ lb = p;
+ break;
+ } else if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) {
+ // y-minimization needed to find the same point on polygon and border
+ lb = p;
+ }
+ }
+ }
+ if (qIsInf(lb.x()))
+ return QList<QList<QDoubleVector2D> >();
- minX = point.x();
- maxX = minX;
- minY = point.y();
- maxY = minY;
+ // 2.2) Prevent the conversion to and from clipper from introducing negative offsets which
+ // in turn will make the geometry wrap around.
+ lb.setX(qMax(wrappedLeftBound.x(), lb.x()));
+ leftBoundWrapped = lb;
+ } else {
+ clippedPaths.append(wrappedPath);
+ }
- srcPoints_ << point.x() << point.y();
- srcPointTypes_ << QPainterPath::MoveToElement;
- lastAddedPoint = point;
- } else {
- point -= origin;
+ return clippedPaths;
+}
+
+void QGeoMapPolylineGeometry::pathToScreen(const QGeoMap &map,
+ const QList<QList<QDoubleVector2D> > &clippedPaths,
+ const QDoubleVector2D &leftBoundWrapped)
+{
+ // 3) project the resulting geometry to screen position and calculate screen bounds
+ double minX = qInf();
+ double minY = qInf();
+ double maxX = -qInf();
+ double maxY = -qInf();
+
+ srcOrigin_ = map.geoProjection().mapProjectionToGeo(map.geoProjection().unwrapMapProjection(leftBoundWrapped));
+ QDoubleVector2D origin = map.geoProjection().wrappedMapProjectionToItemPosition(leftBoundWrapped);
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ QDoubleVector2D lastAddedPoint;
+ for (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D point = map.geoProjection().wrappedMapProjectionToItemPosition(path.at(i));
+
+ point = point - origin; // (0,0) if point == geoLeftBound_
minX = qMin(point.x(), minX);
minY = qMin(point.y(), minY);
maxX = qMax(point.x(), maxX);
maxY = qMax(point.y(), maxY);
- if ((point - lastAddedPoint).manhattanLength() > 3 ||
- i == path.size() - 1) {
+ if (i == 0) {
srcPoints_ << point.x() << point.y();
- srcPointTypes_ << QPainterPath::LineToElement;
+ srcPointTypes_ << QPainterPath::MoveToElement;
lastAddedPoint = point;
+ } else {
+ if ((point - lastAddedPoint).manhattanLength() > 3 ||
+ i == path.size() - 1) {
+ srcPoints_ << point.x() << point.y();
+ srcPointTypes_ << QPainterPath::LineToElement;
+ lastAddedPoint = point;
+ }
}
}
}
@@ -268,7 +307,41 @@ void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map,
sourceBounds_ = QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
}
+/*!
+ \internal
+*/
+void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ const QGeoCoordinate geoLeftBound)
+{
+ if (!sourceDirty_)
+ return;
+
+ geoLeftBound_ = geoLeftBound;
+
+ // clear the old data and reserve enough memory
+ srcPoints_.clear();
+ srcPoints_.reserve(path.size() * 2);
+ srcPointTypes_.clear();
+ srcPointTypes_.reserve(path.size());
+
+ /*
+ * Approach:
+ * 1) project coordinates to wrapped web mercator, and do unwrapBelowX
+ * 2) if the scene is tilted, clip the geometry against the visible region (this may generate multiple polygons)
+ * 3) project the resulting geometry to screen position and calculate screen bounds
+ */
+
+ QDoubleVector2D leftBoundWrapped;
+ // 1, 2)
+ const QList<QList<QDoubleVector2D> > &clippedPaths = clipPath(map, path, leftBoundWrapped);
+
+ // 3)
+ pathToScreen(map, clippedPaths, leftBoundWrapped);
+}
+
////////////////////////////////////////////////////////////////////////////
+#if 0 // Old polyline to viewport clipping code. Retaining it for now.
/* Polyline clip */
enum ClipPointType {
@@ -381,7 +454,7 @@ static void clipPathToRect(const QVector<qreal> &points,
lastY = points[i * 2 + 1];
}
}
-
+#endif
/*!
\internal
*/
@@ -393,7 +466,7 @@ void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
QPointF origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false).toPointF();
- if (!qIsFinite(origin.x()) || !qIsFinite(origin.y())) {
+ if (!qIsFinite(origin.x()) || !qIsFinite(origin.y()) || srcPointTypes_.size() < 2) { // the line might have been clipped away.
clear();
return;
}
@@ -404,19 +477,13 @@ void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
viewport.adjust(-strokeWidth, -strokeWidth, strokeWidth, strokeWidth);
viewport.translate(-1 * origin);
- // Perform clipping to the viewport limits
- QVector<qreal> points;
- QVector<QPainterPath::ElementType> types;
-
- if (clipToViewport_) {
- clipPathToRect(srcPoints_, srcPointTypes_, viewport, points, types);
- } else {
- points = srcPoints_;
- types = srcPointTypes_;
- }
+ // The geometry has already been clipped against the visible region projection in wrapped mercator space.
+ QVector<qreal> points = srcPoints_;
+ QVector<QPainterPath::ElementType> types = srcPointTypes_;
QVectorPath vp(points.data(), types.size(), types.data());
QTriangulatingStroker ts;
+ // viewport is not used in the call below.
ts.process(vp, QPen(QBrush(Qt::black), strokeWidth), viewport, QPainter::Qt4CompatiblePainting);
clear();
@@ -460,13 +527,17 @@ void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
}
QDeclarativePolylineMapItem::QDeclarativePolylineMapItem(QQuickItem *parent)
-: QDeclarativeGeoMapItemBase(parent), dirtyMaterial_(true), updatingGeometry_(false)
+: QDeclarativeGeoMapItemBase(parent), line_(this), dirtyMaterial_(true), updatingGeometry_(false)
{
setFlag(ItemHasContents, true);
QObject::connect(&line_, SIGNAL(colorChanged(QColor)),
this, SLOT(updateAfterLinePropertiesChanged()));
QObject::connect(&line_, SIGNAL(widthChanged(qreal)),
this, SLOT(updateAfterLinePropertiesChanged()));
+ QObject::connect(&line_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(markGeoMaterialDirty()));
+ QObject::connect(&line_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(markGeoMaterialDirty()));
}
QDeclarativePolylineMapItem::~QDeclarativePolylineMapItem()
@@ -505,15 +576,13 @@ void QDeclarativePolylineMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *
QJSValue QDeclarativePolylineMapItem::path() const
{
QQmlContext *context = QQmlEngine::contextForObject(this);
- if (!context)
- return QJSValue();
QQmlEngine *engine = context->engine();
QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
QV4::Scope scope(v4);
- QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(path_.length()));
- for (int i = 0; i < path_.length(); ++i) {
- const QGeoCoordinate &c = path_.at(i);
+ QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(geopath_.path().length()));
+ for (int i = 0; i < geopath_.path().length(); ++i) {
+ const QGeoCoordinate &c = geopath_.coordinateAt(i);
QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
pathArray->putIndexed(i, cv);
@@ -549,14 +618,13 @@ void QDeclarativePolylineMapItem::setPath(const QJSValue &value)
*/
void QDeclarativePolylineMapItem::setPathFromGeoList(const QList<QGeoCoordinate> &path)
{
- if (path_ == path)
+ if (geopath_.path() == path)
return;
- path_ = path;
- geoLeftBound_ = getLeftBound(path_, deltaXs_, minX_);
- geometry_.setPreserveGeometry(true, geoLeftBound_);
- geometry_.markSourceDirty();
- polishAndUpdate();
+ geopath_.setPath(path);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
emit pathChanged();
}
@@ -571,7 +639,7 @@ void QDeclarativePolylineMapItem::setPathFromGeoList(const QList<QGeoCoordinate>
*/
int QDeclarativePolylineMapItem::pathLength() const
{
- return path_.size();
+ return geopath_.path().length();
}
/*!
@@ -583,11 +651,11 @@ int QDeclarativePolylineMapItem::pathLength() const
*/
void QDeclarativePolylineMapItem::addCoordinate(const QGeoCoordinate &coordinate)
{
- path_.append(coordinate);
- geoLeftBound_ = getLeftBound(path_, deltaXs_, minX_, geoLeftBound_);
- geometry_.setPreserveGeometry(true, geoLeftBound_);
- geometry_.markSourceDirty();
- polishAndUpdate();
+ geopath_.addCoordinate(coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markGeoGeometryDirty();
+ markSourceDirtyAndUpdate();
emit pathChanged();
}
@@ -602,14 +670,13 @@ void QDeclarativePolylineMapItem::addCoordinate(const QGeoCoordinate &coordinate
*/
void QDeclarativePolylineMapItem::insertCoordinate(int index, const QGeoCoordinate &coordinate)
{
- if (index < 0 || index > path_.size())
+ if (index < 0 || index > geopath_.path().length())
return;
- path_.insert(index, coordinate);
- geoLeftBound_ = getLeftBound(path_, deltaXs_, minX_);
- geometry_.setPreserveGeometry(true, geoLeftBound_);
- geometry_.markSourceDirty();
- polishAndUpdate();
+ geopath_.insertCoordinate(index, coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
emit pathChanged();
}
@@ -625,14 +692,14 @@ void QDeclarativePolylineMapItem::insertCoordinate(int index, const QGeoCoordina
*/
void QDeclarativePolylineMapItem::replaceCoordinate(int index, const QGeoCoordinate &coordinate)
{
- if (index < 0 || index >= path_.size())
+ if (index < 0 || index >= geopath_.path().length())
return;
- path_[index] = coordinate;
- geoLeftBound_ = getLeftBound(path_, deltaXs_, minX_);
- geometry_.setPreserveGeometry(true, geoLeftBound_);
- geometry_.markSourceDirty();
- polishAndUpdate();
+ geopath_.replaceCoordinate(index, coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markGeoGeometryDirty();
+ markSourceDirtyAndUpdate();
emit pathChanged();
}
@@ -647,10 +714,10 @@ void QDeclarativePolylineMapItem::replaceCoordinate(int index, const QGeoCoordin
*/
QGeoCoordinate QDeclarativePolylineMapItem::coordinateAt(int index) const
{
- if (index < 0 || index >= path_.size())
+ if (index < 0 || index >= geopath_.path().length())
return QGeoCoordinate();
- return path_.at(index);
+ return geopath_.coordinateAt(index);
}
/*!
@@ -662,7 +729,7 @@ QGeoCoordinate QDeclarativePolylineMapItem::coordinateAt(int index) const
*/
bool QDeclarativePolylineMapItem::containsCoordinate(const QGeoCoordinate &coordinate)
{
- return path_.indexOf(coordinate) > -1;
+ return geopath_.containsCoordinate(coordinate);
}
/*!
@@ -677,8 +744,13 @@ bool QDeclarativePolylineMapItem::containsCoordinate(const QGeoCoordinate &coord
*/
void QDeclarativePolylineMapItem::removeCoordinate(const QGeoCoordinate &coordinate)
{
- int index = path_.lastIndexOf(coordinate);
- removeCoordinate(index);
+ int length = geopath_.path().length();
+ geopath_.removeCoordinate(coordinate);
+ if (geopath_.path().length() == length)
+ return;
+ markGeoGeometryDirty();
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
}
/*!
@@ -694,14 +766,14 @@ void QDeclarativePolylineMapItem::removeCoordinate(const QGeoCoordinate &coordin
*/
void QDeclarativePolylineMapItem::removeCoordinate(int index)
{
- if (index < 0 || index >= path_.size())
+ if (index < 0 || index >= geopath_.path().length())
return;
- path_.removeAt(index);
- geoLeftBound_ = getLeftBound(path_, deltaXs_, minX_);
- geometry_.setPreserveGeometry(true, geoLeftBound_);
- geometry_.markSourceDirty();
- polishAndUpdate();
+ geopath_.removeCoordinate(index);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markGeoGeometryDirty();
+ markSourceDirtyAndUpdate();
emit pathChanged();
}
@@ -724,96 +796,6 @@ QDeclarativeMapLineProperties *QDeclarativePolylineMapItem::line()
return &line_;
}
-QGeoCoordinate QDeclarativePolylineMapItem::computeLeftBound(const QList<QGeoCoordinate> &path,
- QVector<double> &deltaXs,
- double &minX)
-{
- if (path.isEmpty()) {
- minX = qInf();
- return QGeoCoordinate();
- }
- deltaXs.resize(path.size());
-
- deltaXs[0] = minX = 0.0;
- int minId = 0;
-
- for (int i = 1; i < path.size(); i++) {
- const QGeoCoordinate &geoFrom = path.at(i-1);
- const QGeoCoordinate &geoTo = path.at(i);
- double longiFrom = geoFrom.longitude();
- double longiTo = geoTo.longitude();
- double deltaLongi = longiTo - longiFrom;
- if (qAbs(deltaLongi) > 180.0) {
- if (longiTo > 0.0)
- longiTo -= 360.0;
- else
- longiTo += 360.0;
- deltaLongi = longiTo - longiFrom;
- }
- deltaXs[i] = deltaXs[i-1] + deltaLongi;
- if (deltaXs[i] < minX) {
- minX = deltaXs[i];
- minId = i;
- }
- }
- return path.at(minId);
-}
-
-QGeoCoordinate QDeclarativePolylineMapItem::updateLeftBound(const QList<QGeoCoordinate> &path,
- QVector<double> &deltaXs,
- double &minX,
- QGeoCoordinate currentLeftBound)
-{
- if (path.isEmpty()) {
- deltaXs.clear();
- minX = qInf();
- return QGeoCoordinate();
- } else if (path.size() == 1) {
- deltaXs.resize(1);
- deltaXs[0] = minX = 0.0;
- return path.last();
- } else if ( path.size() != deltaXs.size() + 1 ) { // something went wrong. This case should not happen
- return computeLeftBound(path, deltaXs, minX);
- }
-
- const QGeoCoordinate &geoFrom = path.at(path.size()-2);
- const QGeoCoordinate &geoTo = path.last();
- double longiFrom = geoFrom.longitude();
- double longiTo = geoTo.longitude();
- double deltaLongi = longiTo - longiFrom;
- if (qAbs(deltaLongi) > 180.0) {
- if (longiTo > 0.0)
- longiTo -= 360.0;
- else
- longiTo += 360.0;
- deltaLongi = longiTo - longiFrom;
- }
-
- deltaXs.push_back(deltaXs.last() + deltaLongi);
- if (deltaXs.last() < minX) {
- minX = deltaXs.last();
- return path.last();
- } else {
- return currentLeftBound;
- }
-}
-
-QGeoCoordinate QDeclarativePolylineMapItem::getLeftBound(const QList<QGeoCoordinate> &path,
- QVector<double> &deltaXs,
- double &minX)
-{
- return QDeclarativePolylineMapItem::computeLeftBound(path, deltaXs, minX);
-}
-
-// Optimizing the common addCoordinate() path
-QGeoCoordinate QDeclarativePolylineMapItem::getLeftBound(const QList<QGeoCoordinate> &path,
- QVector<double> &deltaXs,
- double &minX,
- QGeoCoordinate currentLeftBound)
-{
- return QDeclarativePolylineMapItem::updateLeftBound(path, deltaXs, minX, currentLeftBound);
-}
-
/*!
\internal
*/
@@ -823,42 +805,21 @@ void QDeclarativePolylineMapItem::geometryChanged(const QRectF &newGeometry, con
QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
return;
}
+ // TODO: change the algorithm to preserve the distances and size!
+ QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false);
+ QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false);
+ if (!newCenter.isValid() || !oldCenter.isValid())
+ return;
+ double offsetLongi = newCenter.longitude() - oldCenter.longitude();
+ double offsetLati = newCenter.latitude() - oldCenter.latitude();
+ if (offsetLati == 0.0 && offsetLongi == 0.0)
+ return;
- QDoubleVector2D newPoint = QDoubleVector2D(x(),y()) + QDoubleVector2D(geometry_.firstPointOffset());
- QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(newPoint, false);
- if (newCoordinate.isValid()) {
- double firstLongitude = path_.at(0).longitude();
- double firstLatitude = path_.at(0).latitude();
- double minMaxLatitude = firstLatitude;
- // prevent dragging over valid min and max latitudes
- for (int i = 0; i < path_.count(); ++i) {
- double newLatitude = path_.at(i).latitude()
- + newCoordinate.latitude() - firstLatitude;
- if (!QLocationUtils::isValidLat(newLatitude)) {
- if (qAbs(newLatitude) > qAbs(minMaxLatitude)) {
- minMaxLatitude = newLatitude;
- }
- }
- }
- // calculate offset needed to re-position the item within map border
- double offsetLatitude = minMaxLatitude - QLocationUtils::clipLat(minMaxLatitude);
- for (int i = 0; i < path_.count(); ++i) {
- QGeoCoordinate coord = path_.at(i);
- // handle dateline crossing
- coord.setLongitude(QLocationUtils::wrapLong(coord.longitude()
- + newCoordinate.longitude() - firstLongitude));
- coord.setLatitude(coord.latitude()
- + newCoordinate.latitude() - firstLatitude - offsetLatitude);
- path_.replace(i, coord);
- }
-
- geoLeftBound_.setLongitude(QLocationUtils::wrapLong(geoLeftBound_.longitude()
- + newCoordinate.longitude() - firstLongitude));
- geometry_.setPreserveGeometry(true, geoLeftBound_);
- geometry_.markSourceDirty();
- polishAndUpdate();
- emit pathChanged();
- }
+ geopath_.translate(offsetLati, offsetLongi);
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markGeoGeometryDirty();
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
// Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
// call to this function.
@@ -872,27 +833,8 @@ void QDeclarativePolylineMapItem::afterViewportChanged(const QGeoMapViewportChan
if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
return;
- // if the scene is tilted, we must regenerate our geometry every frame
- if (map()->cameraCapabilities().supportsTilting()
- && (event.cameraData.tilt() > 0.1
- || event.cameraData.tilt() < -0.1)) {
- geometry_.markSourceDirty();
- }
-
- // if the scene is rolled, we must regen too
- if (map()->cameraCapabilities().supportsRolling()
- && (event.cameraData.roll() > 0.1
- || event.cameraData.roll() < -0.1)) {
- geometry_.markSourceDirty();
- }
-
- // otherwise, only regen on rotate, resize and zoom
- if (event.bearingChanged || event.mapSizeChanged || event.zoomLevelChanged) {
- geometry_.markSourceDirty();
- }
geometry_.setPreserveGeometry(true, geometry_.geoLeftBound());
- geometry_.markScreenDirty();
- polishAndUpdate();
+ markSourceDirtyAndUpdate();
}
/*!
@@ -900,19 +842,25 @@ void QDeclarativePolylineMapItem::afterViewportChanged(const QGeoMapViewportChan
*/
void QDeclarativePolylineMapItem::updatePolish()
{
- if (!map() || path_.count() == 0)
+ if (!map() || geopath_.path().length() == 0)
return;
QScopedValueRollback<bool> rollback(updatingGeometry_);
updatingGeometry_ = true;
- geometry_.updateSourcePoints(*map(), path_, geoLeftBound_);
+ geometry_.updateSourcePoints(*map(), geopath_.path(), geopath_.boundingGeoRectangle().topLeft());
geometry_.updateScreenPoints(*map(), line_.width());
setWidth(geometry_.sourceBoundingBox().width());
setHeight(geometry_.sourceBoundingBox().height());
- setPositionOnMap(path_.at(0), -1 * geometry_.sourceBoundingBox().topLeft());
+ setPositionOnMap(geometry_.origin(), -1 * geometry_.sourceBoundingBox().topLeft());
+}
+
+void QDeclarativePolylineMapItem::markSourceDirtyAndUpdate()
+{
+ geometry_.markSourceDirty();
+ polishAndUpdate();
}
/*!
@@ -954,6 +902,16 @@ bool QDeclarativePolylineMapItem::contains(const QPointF &point) const
return false;
}
+const QGeoShape &QDeclarativePolylineMapItem::geoShape() const
+{
+ return geopath_;
+}
+
+QGeoMap::ItemType QDeclarativePolylineMapItem::itemType() const
+{
+ return QGeoMap::MapPolyline;
+}
+
//////////////////////////////////////////////////////////////////////
/*!
diff --git a/src/imports/location/qdeclarativepolylinemapitem_p.h b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h
index 8c827b6f..55703258 100644
--- a/src/imports/location/qdeclarativepolylinemapitem_p.h
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h
@@ -48,9 +48,11 @@
// We mean it.
//
-#include "qdeclarativegeomapitembase_p.h"
-#include "qgeomapitemgeometry_p.h"
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qgeomapitemgeometry_p.h>
+#include <QtPositioning/QGeoPath>
+#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QSGGeometryNode>
#include <QSGFlatColorMaterial>
@@ -58,7 +60,7 @@ QT_BEGIN_NAMESPACE
class MapPolylineNode;
-class QDeclarativeMapLineProperties : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeMapLineProperties : public QObject
{
Q_OBJECT
@@ -95,14 +97,25 @@ public:
void updateScreenPoints(const QGeoMap &map,
qreal strokeWidth);
+protected:
+ QList<QList<QDoubleVector2D> > clipPath(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ QDoubleVector2D &leftBoundWrapped);
+
+ void pathToScreen(const QGeoMap &map,
+ const QList<QList<QDoubleVector2D> > &clippedPaths,
+ const QDoubleVector2D &leftBoundWrapped);
+
private:
QVector<qreal> srcPoints_;
QVector<QPainterPath::ElementType> srcPointTypes_;
-
+ friend class QDeclarativeCircleMapItem;
+ friend class QDeclarativePolygonMapItem;
+ friend class QDeclarativeRectangleMapItem;
};
-class QDeclarativePolylineMapItem : public QDeclarativeGeoMapItemBase
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItem : public QDeclarativeGeoMapItemBase
{
Q_OBJECT
@@ -130,14 +143,11 @@ public:
virtual void setPath(const QJSValue &value);
bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+ QGeoMap::ItemType itemType() const Q_DECL_OVERRIDE;
QDeclarativeMapLineProperties *line();
- static QGeoCoordinate computeLeftBound(const QList<QGeoCoordinate> &path, QVector<double> &deltaXs, double &minX);
- static QGeoCoordinate updateLeftBound(const QList<QGeoCoordinate> &path, QVector<double> &deltaXs, double &minX, QGeoCoordinate currentLeftBound);
- static QGeoCoordinate getLeftBound(const QList<QGeoCoordinate> &path, QVector<double> &deltaXs, double &minX);
- static QGeoCoordinate getLeftBound(const QList<QGeoCoordinate> &path, QVector<double> &deltaXs, double &minX, QGeoCoordinate currentLeftBound);
-
Q_SIGNALS:
void pathChanged();
@@ -147,22 +157,19 @@ protected:
void updatePolish() Q_DECL_OVERRIDE;
protected Q_SLOTS:
+ void markSourceDirtyAndUpdate();
void updateAfterLinePropertiesChanged();
virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
private:
void pathPropertyChanged();
+ QGeoPath geopath_;
QDeclarativeMapLineProperties line_;
- QList<QGeoCoordinate> path_;
- QGeoCoordinate geoLeftBound_;
QColor color_;
bool dirtyMaterial_;
QGeoMapPolylineGeometry geometry_;
bool updatingGeometry_;
- // for the left bound calculation
- QVector<double> deltaXs_; // longitude deltas from path_[0]
- double minX_; // minimum value inside deltaXs_
};
//////////////////////////////////////////////////////////////////////
diff --git a/src/imports/location/qdeclarativerectanglemapitem.cpp b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp
index b91c4c08..fbd2c79b 100644
--- a/src/imports/location/qdeclarativerectanglemapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp
@@ -42,6 +42,8 @@
#include <qnumeric.h>
#include <QRectF>
#include <QPointF>
+#include <QtLocation/private/qgeomap_p.h>
+#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QtCore/QScopedValueRollback>
QT_BEGIN_NAMESPACE
@@ -112,65 +114,6 @@ QT_BEGIN_NAMESPACE
\image api-maprectangle.png
*/
-struct Vertex
-{
- QVector2D position;
-};
-
-QGeoMapRectangleGeometry::QGeoMapRectangleGeometry()
-{
-}
-
-/*!
- \internal
-*/
-void QGeoMapRectangleGeometry::updatePoints(const QGeoMap &map,
- const QGeoCoordinate &topLeft,
- const QGeoCoordinate &bottomRight)
-{
- if (!screenDirty_ && !sourceDirty_)
- return;
-
- QDoubleVector2D tl = map.geoProjection().coordinateToItemPosition(topLeft, false);
- QDoubleVector2D br = map.geoProjection().coordinateToItemPosition(bottomRight, false);
-
- // 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(tl.x()) || !qIsFinite(tl.y()))
- return;
- if (!qIsFinite(br.x()) || !qIsFinite(br.y()))
- return;
-
- if ( preserveGeometry_ ) {
- double unwrapBelowX = map.geoProjection().coordinateToItemPosition(geoLeftBound_, false).x();
- if (br.x() < unwrapBelowX)
- br.setX(tl.x() + screenBounds_.width());
- }
-
- QRectF re(tl.toPointF(), br.toPointF());
- re.translate(-1 * tl.toPointF());
-
- clear();
- screenVertices_.reserve(6);
-
- screenVertices_ << re.topLeft();
- screenVertices_ << re.topRight();
- screenVertices_ << re.bottomLeft();
-
- screenVertices_ << re.topRight();
- screenVertices_ << re.bottomLeft();
- screenVertices_ << re.bottomRight();
-
- firstPointOffset_ = QPointF(0,0);
- srcOrigin_ = topLeft;
- screenBounds_ = re;
-
- screenOutline_ = QPainterPath();
- screenOutline_.addRect(re);
-
- geoLeftBound_ = topLeft;
-}
-
QDeclarativeRectangleMapItem::QDeclarativeRectangleMapItem(QQuickItem *parent)
: QDeclarativeGeoMapItemBase(parent), color_(Qt::transparent), dirtyMaterial_(true),
updatingGeometry_(false)
@@ -180,6 +123,10 @@ QDeclarativeRectangleMapItem::QDeclarativeRectangleMapItem(QQuickItem *parent)
this, SLOT(markSourceDirtyAndUpdate()));
QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
this, SLOT(markSourceDirtyAndUpdate()));
+ QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(markGeoMaterialDirty()));
+ QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(markGeoMaterialDirty()));
}
QDeclarativeRectangleMapItem::~QDeclarativeRectangleMapItem()
@@ -221,18 +168,18 @@ QDeclarativeMapLineProperties *QDeclarativeRectangleMapItem::border()
*/
void QDeclarativeRectangleMapItem::setTopLeft(const QGeoCoordinate &topLeft)
{
- if (topLeft_ == topLeft)
+ if (rectangle_.topLeft() == topLeft)
return;
- topLeft_ = topLeft;
-
+ rectangle_.setTopLeft(topLeft);
+ markGeoGeometryDirty();
markSourceDirtyAndUpdate();
- emit topLeftChanged(topLeft_);
+ emit topLeftChanged(topLeft);
}
QGeoCoordinate QDeclarativeRectangleMapItem::topLeft()
{
- return topLeft_;
+ return rectangle_.topLeft();
}
/*!
@@ -253,18 +200,18 @@ void QDeclarativeRectangleMapItem::markSourceDirtyAndUpdate()
*/
void QDeclarativeRectangleMapItem::setBottomRight(const QGeoCoordinate &bottomRight)
{
- if (bottomRight_ == bottomRight)
+ if (rectangle_.bottomRight() == bottomRight)
return;
- bottomRight_ = bottomRight;
-
+ rectangle_.setBottomRight(bottomRight);
+ markGeoGeometryDirty();
markSourceDirtyAndUpdate();
- emit bottomRightChanged(bottomRight_);
+ emit bottomRightChanged(bottomRight);
}
QGeoCoordinate QDeclarativeRectangleMapItem::bottomRight()
{
- return bottomRight_;
+ return rectangle_.bottomRight();
}
/*!
@@ -284,6 +231,7 @@ void QDeclarativeRectangleMapItem::setColor(const QColor &color)
return;
color_ = color;
dirtyMaterial_ = true;
+ geoMaterialDirty_ = true;
polishAndUpdate();
emit colorChanged(color_);
}
@@ -334,33 +282,48 @@ void QDeclarativeRectangleMapItem::updatePolish()
QScopedValueRollback<bool> rollback(updatingGeometry_);
updatingGeometry_ = true;
- geometry_.updatePoints(*map(), topLeft_, bottomRight_);
+ QList<QGeoCoordinate> path;
+ path << rectangle_.topLeft();
+ path << QGeoCoordinate(rectangle_.topLeft().latitude(), rectangle_.bottomRight().longitude());
+ path << rectangle_.bottomRight();
+ path << QGeoCoordinate(rectangle_.bottomRight().latitude(), rectangle_.topLeft().longitude());
- QList<QGeoCoordinate> pathClosed;
- pathClosed << topLeft_;
- pathClosed << QGeoCoordinate(topLeft_.latitude(), bottomRight_.longitude());
- pathClosed << bottomRight_;
- pathClosed << QGeoCoordinate(bottomRight_.latitude(), topLeft_.longitude());
- pathClosed << pathClosed.first();
+ geometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ geometry_.updateSourcePoints(*map(), path);
+ geometry_.updateScreenPoints(*map());
+
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
+ borderGeometry_.clear();
if (border_.color() != Qt::transparent && border_.width() > 0) {
- borderGeometry_.updateSourcePoints(*map(), pathClosed, topLeft_);
- borderGeometry_.updateScreenPoints(*map(), border_.width());
+ QList<QGeoCoordinate> closedPath = path;
+ closedPath << closedPath.first();
+
+ borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ const QGeoCoordinate &geometryOrigin = geometry_.origin();
- QList<QGeoMapItemGeometry *> geoms;
- geoms << &geometry_ << &borderGeometry_;
- QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ borderGeometry_.srcPoints_.clear();
+ borderGeometry_.srcPointTypes_.clear();
- setWidth(combined.width());
- setHeight(combined.height());
- } else {
- borderGeometry_.clear();
+ QDoubleVector2D borderLeftBoundWrapped;
+ QList<QList<QDoubleVector2D > > clippedPaths = borderGeometry_.clipPath(*map(), closedPath, borderLeftBoundWrapped);
+ if (clippedPaths.size()) {
+ borderLeftBoundWrapped = map()->geoProjection().geoToWrappedMapProjection(geometryOrigin);
+ borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
+ borderGeometry_.updateScreenPoints(*map(), border_.width());
- setWidth(geometry_.screenBoundingBox().width());
- setHeight(geometry_.screenBoundingBox().height());
+ geoms << &borderGeometry_;
+ } else {
+ borderGeometry_.clear();
+ }
}
- setPositionOnMap(pathClosed.at(0), geometry_.firstPointOffset());
+ QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ setWidth(combined.width());
+ setHeight(combined.height());
+
+ setPositionOnMap(geometry_.origin(), geometry_.firstPointOffset());
}
/*!
@@ -371,32 +334,9 @@ void QDeclarativeRectangleMapItem::afterViewportChanged(const QGeoMapViewportCha
if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
return;
- // if the scene is tilted, we must regenerate our geometry every frame
- if (map()->cameraCapabilities().supportsTilting()
- && (event.cameraData.tilt() > 0.1
- || event.cameraData.tilt() < -0.1)) {
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- }
-
- // if the scene is rolled, we must regen too
- if (map()->cameraCapabilities().supportsRolling()
- && (event.cameraData.roll() > 0.1
- || event.cameraData.roll() < -0.1)) {
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- }
-
- // otherwise, only regen on rotate, resize and zoom
- if (event.bearingChanged || event.mapSizeChanged || event.zoomLevelChanged) {
- geometry_.markSourceDirty();
- borderGeometry_.markSourceDirty();
- }
- geometry_.setPreserveGeometry(true, topLeft_);
- borderGeometry_.setPreserveGeometry(true, topLeft_);
- geometry_.markScreenDirty();
- borderGeometry_.markScreenDirty();
- polishAndUpdate();
+ geometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ markSourceDirtyAndUpdate();
}
/*!
@@ -407,6 +347,16 @@ bool QDeclarativeRectangleMapItem::contains(const QPointF &point) const
return (geometry_.contains(point) || borderGeometry_.contains(point));
}
+const QGeoShape &QDeclarativeRectangleMapItem::geoShape() const
+{
+ return rectangle_;
+}
+
+QGeoMap::ItemType QDeclarativeRectangleMapItem::itemType() const
+{
+ return QGeoMap::MapRectangle;
+}
+
/*!
\internal
*/
@@ -416,34 +366,23 @@ void QDeclarativeRectangleMapItem::geometryChanged(const QRectF &newGeometry, co
QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
return;
}
+ // TODO: change the algorithm to preserve the distances and size
+ QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false);
+ QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false);
+ if (!newCenter.isValid() || !oldCenter.isValid())
+ return;
+ double offsetLongi = newCenter.longitude() - oldCenter.longitude();
+ double offsetLati = newCenter.latitude() - oldCenter.latitude();
+ if (offsetLati == 0.0 && offsetLongi == 0.0)
+ return;
- QDoubleVector2D newTopLeftPoint = QDoubleVector2D(x(),y());
- QGeoCoordinate newTopLeft = map()->geoProjection().itemPositionToCoordinate(newTopLeftPoint, false);
- if (newTopLeft.isValid()) {
- // calculate new geo width while checking for dateline crossing
- const double lonW = bottomRight_.longitude() > topLeft_.longitude() ?
- bottomRight_.longitude() - topLeft_.longitude() :
- bottomRight_.longitude() + 360 - topLeft_.longitude();
- const double latH = qAbs(bottomRight_.latitude() - topLeft_.latitude());
- QGeoCoordinate newBottomRight;
- // prevent dragging over valid min and max latitudes
- if (QLocationUtils::isValidLat(newTopLeft.latitude() - latH)) {
- newBottomRight.setLatitude(newTopLeft.latitude() - latH);
- } else {
- newBottomRight.setLatitude(QLocationUtils::clipLat(newTopLeft.latitude() - latH));
- newTopLeft.setLatitude(newBottomRight.latitude() + latH);
- }
- // handle dateline crossing
- newBottomRight.setLongitude(QLocationUtils::wrapLong(newTopLeft.longitude() + lonW));
- newBottomRight.setAltitude(newTopLeft.altitude());
- topLeft_ = newTopLeft;
- bottomRight_ = newBottomRight;
- geometry_.setPreserveGeometry(true, newTopLeft);
- borderGeometry_.setPreserveGeometry(true, newTopLeft);
- markSourceDirtyAndUpdate();
- emit topLeftChanged(topLeft_);
- emit bottomRightChanged(bottomRight_);
- }
+ rectangle_.translate(offsetLati, offsetLongi);
+ geometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ markGeoGeometryDirty();
+ markSourceDirtyAndUpdate();
+ emit topLeftChanged(rectangle_.topLeft());
+ emit bottomRightChanged(rectangle_.bottomRight());
// Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
// call to this function.
diff --git a/src/imports/location/qdeclarativerectanglemapitem_p.h b/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h
index fb9936b0..b65db813 100644
--- a/src/imports/location/qdeclarativerectanglemapitem_p.h
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h
@@ -48,27 +48,18 @@
// We mean it.
//
-#include "qdeclarativegeomapitembase_p.h"
-#include "qgeomapitemgeometry_p.h"
-#include "qdeclarativepolylinemapitem_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qgeomapitemgeometry_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
+
#include <QSGGeometryNode>
#include <QSGFlatColorMaterial>
QT_BEGIN_NAMESPACE
-class QGeoMapRectangleGeometry : public QGeoMapItemGeometry
-{
-public:
- QGeoMapRectangleGeometry();
-
- void updatePoints(const QGeoMap &map,
- const QGeoCoordinate &topLeft,
- const QGeoCoordinate &bottomRight);
-};
-
-class MapRectangleNode;
-
-class QDeclarativeRectangleMapItem: public QDeclarativeGeoMapItemBase
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRectangleMapItem: public QDeclarativeGeoMapItemBase
{
Q_OBJECT
@@ -97,6 +88,8 @@ public:
QDeclarativeMapLineProperties *border();
bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+ QGeoMap::ItemType itemType() const Q_DECL_OVERRIDE;
Q_SIGNALS:
void topLeftChanged(const QGeoCoordinate &topLeft);
@@ -112,12 +105,11 @@ protected Q_SLOTS:
virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
private:
- QGeoCoordinate topLeft_;
- QGeoCoordinate bottomRight_;
+ QGeoRectangle rectangle_;
QDeclarativeMapLineProperties border_;
QColor color_;
bool dirtyMaterial_;
- QGeoMapRectangleGeometry geometry_;
+ QGeoMapPolygonGeometry geometry_;
QGeoMapPolylineGeometry borderGeometry_;
bool updatingGeometry_;
};
diff --git a/src/imports/location/qdeclarativeroutemapitem.cpp b/src/location/declarativemaps/qdeclarativeroutemapitem.cpp
index 19930cc3..1fbeeeb7 100644
--- a/src/imports/location/qdeclarativeroutemapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativeroutemapitem.cpp
@@ -43,6 +43,8 @@
#include <QtQml/QQmlInfo>
#include <QtGui/QPainter>
+QT_BEGIN_NAMESPACE
+
/*!
\qmltype MapRoute
\instantiates QDeclarativeRouteMapItem
@@ -143,3 +145,5 @@ void QDeclarativeRouteMapItem::setPath(const QJSValue &value)
qWarning() << "Can not set the path on QDeclarativeRouteMapItem."
<< "Please use the route property instead.";
}
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/qdeclarativeroutemapitem_p.h b/src/location/declarativemaps/qdeclarativeroutemapitem_p.h
index 3acac3cc..ad959837 100644
--- a/src/imports/location/qdeclarativeroutemapitem_p.h
+++ b/src/location/declarativemaps/qdeclarativeroutemapitem_p.h
@@ -48,9 +48,10 @@
// We mean it.
//
-#include "qdeclarativegeomapitembase_p.h"
-#include "qdeclarativegeomap_p.h"
-#include "qdeclarativepolylinemapitem_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
#include <QPen>
#include <QBrush>
@@ -58,7 +59,7 @@ QT_BEGIN_NAMESPACE
class QDeclarativeGeoRoute;
-class QDeclarativeRouteMapItem : public QDeclarativePolylineMapItem
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRouteMapItem : public QDeclarativePolylineMapItem
{
Q_OBJECT
diff --git a/src/imports/location/qgeomapitemgeometry.cpp b/src/location/declarativemaps/qgeomapitemgeometry.cpp
index ab90d0dd..2883c2bb 100644
--- a/src/imports/location/qgeomapitemgeometry.cpp
+++ b/src/location/declarativemaps/qgeomapitemgeometry.cpp
@@ -39,6 +39,7 @@
#include "qlocationutils_p.h"
#include <QtQuick/QSGGeometry>
#include "qdoublevector2d_p.h"
+#include <QtLocation/private/qgeomap_p.h>
QT_BEGIN_NAMESPACE
@@ -100,7 +101,6 @@ QRectF QGeoMapItemGeometry::translateToCommonOrigin(const QList<QGeoMapItemGeome
// first get max offset
QPointF maxOffset = geoms.at(0)->firstPointOffset();
foreach (QGeoMapItemGeometry *g, geoms) {
- Q_ASSERT(g->origin() == origin);
QPointF o = g->firstPointOffset();
maxOffset.setX(qMax(o.x(), maxOffset.x()));
maxOffset.setY(qMax(o.y(), maxOffset.y()));
diff --git a/src/imports/location/qgeomapitemgeometry_p.h b/src/location/declarativemaps/qgeomapitemgeometry_p.h
index 36b670f9..595107ae 100644
--- a/src/imports/location/qgeomapitemgeometry_p.h
+++ b/src/location/declarativemaps/qgeomapitemgeometry_p.h
@@ -48,6 +48,8 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
+
#include <QPainterPath>
#include <QPointF>
#include <QRectF>
@@ -73,7 +75,7 @@ public:
inline void markFullScreenDirty() { screenDirty_ = true; clipToViewport_ = false;}
inline void markClean() { screenDirty_ = (sourceDirty_ = false); clipToViewport_ = true;}
- inline void setPreserveGeometry(bool value, QGeoCoordinate geoLeftBound = QGeoCoordinate())
+ inline void setPreserveGeometry(bool value, const QGeoCoordinate &geoLeftBound = QGeoCoordinate())
{
preserveGeometry_ = value;
if (preserveGeometry_)
diff --git a/src/imports/location/qquickgeomapgesturearea.cpp b/src/location/declarativemaps/qquickgeomapgesturearea.cpp
index 50709292..e7242fd1 100644
--- a/src/imports/location/qquickgeomapgesturearea.cpp
+++ b/src/location/declarativemaps/qquickgeomapgesturearea.cpp
@@ -35,6 +35,7 @@
****************************************************************************/
#include "qquickgeomapgesturearea_p.h"
+#include "qquickgeocoordinateanimation_p.h"
#include "qdeclarativegeomap_p.h"
#include "error_messages.h"
@@ -46,10 +47,13 @@
#include <QtQuick/QQuickWindow>
#include <QPropertyAnimation>
#include <QDebug>
-#include <QtPositioning/private/qwebmercator_p.h>
#include "math.h"
+#include <cmath>
#include "qgeomap_p.h"
#include "qdoublevector2d_p.h"
+#include "qlocationutils_p.h"
+#include <QtGui/QMatrix4x4>
+
#define QML_MAP_FLICK_DEFAULTMAXVELOCITY 2500
#define QML_MAP_FLICK_MINIMUMDECELERATION 500
@@ -61,7 +65,80 @@
// before we perform a flick.
static const int FlickThreshold = 20;
// Really slow flicks can be annoying.
-const qreal MinimumFlickVelocity = 75.0;
+static const qreal MinimumFlickVelocity = 75.0;
+// Tolerance for detecting two finger sliding start
+static const qreal MaximumParallelPosition = 40.0; // in degrees
+// Tolerance for detecting parallel sliding
+static const qreal MaximumParallelSlidingAngle = 5.0; // in degrees
+// Tolerance for starting rotation
+static const qreal MinimumRotationStartingAngle = 15.0; // in degrees
+
+// Returns the new map center after anchoring coordinate to anchorPoint on the screen
+// Approach: find the displacement in (wrapped) mercator space, and apply that to the center
+static QGeoCoordinate anchorCoordinateToPoint(QGeoMap &map, const QGeoCoordinate &coordinate, const QPointF &anchorPoint)
+{
+ QDoubleVector2D centerProj = map.geoProjection().geoToWrappedMapProjection(map.cameraData().center());
+ QDoubleVector2D coordProj = map.geoProjection().geoToWrappedMapProjection(coordinate);
+
+ QDoubleVector2D anchorProj = map.geoProjection().itemPositionToWrappedMapProjection(QDoubleVector2D(anchorPoint));
+ // Y-clamping done in mercatorToCoord
+ return map.geoProjection().wrappedMapProjectionToGeo(centerProj + coordProj - anchorProj);
+}
+
+// Keeps it in +- 180
+static qreal touchAngle(const QPointF &p1, const QPointF &p2)
+{
+ qreal angle = QLineF(p1, p2).angle();
+ if (angle > 180)
+ angle -= 360;
+ return angle;
+}
+
+// Deals with angles crossing the +-180 edge, assumes that the delta can't be > 180
+static qreal angleDelta(const qreal angle1, const qreal angle2)
+{
+ qreal delta = angle1 - angle2;
+ if (delta > 180.0) // detect crossing angle1 positive, angle2 negative, rotation counterclockwise, difference negative
+ delta = angle1 - angle2 - 360.0;
+ else if (delta < -180.0) // detect crossing angle1 negative, angle2 positive, rotation clockwise, difference positive
+ delta = angle1 - angle2 + 360.0;
+
+ return delta;
+}
+
+static bool pointDragged(const QPointF &pOld, const QPointF &pNew)
+{
+ static const int startDragDistance = qApp->styleHints()->startDragDistance();
+ return ( qAbs(pNew.x() - pOld.x()) > startDragDistance
+ || qAbs(pNew.y() - pOld.y()) > startDragDistance);
+}
+
+static qreal vectorSize(const QPointF &vector)
+{
+ return std::sqrt(vector.x() * vector.x() + vector.y() * vector.y());
+}
+
+static bool movingParallel(const QPointF &p1old, const QPointF &p1new, const QPointF &p2old, const QPointF &p2new)
+{
+ if (!pointDragged(p1old, p1new) || !pointDragged(p2old, p2new))
+ return false;
+
+ QPointF v1 = p1new - p1old;
+ QPointF v2 = p2new - p2old;
+ qreal v1v2size = vectorSize(v1 + v2);
+
+ if (v1v2size < vectorSize(v1) || v1v2size < vectorSize(v2)) // going in opposite directions
+ return false;
+
+ const qreal newAngle = touchAngle(p1new, p2new);
+ const qreal oldAngle = touchAngle(p1old, p2old);
+ const qreal angleDiff = angleDelta(newAngle, oldAngle);
+
+ if (qAbs(angleDiff) > MaximumParallelSlidingAngle)
+ return false;
+
+ return true;
+}
QT_BEGIN_NAMESPACE
@@ -150,7 +227,8 @@ QT_BEGIN_NAMESPACE
\brief The MapGestureArea type provides Map gesture interaction.
MapGestureArea objects are used as part of a Map, to provide for panning,
- flicking and pinch-to-zoom gesture used on touch displays.
+ flicking and pinch-to-zoom gesture used on touch displays, as well as two finger rotation
+ and two finger parallel vertical sliding to tilt the map.
A MapGestureArea is automatically created with a new Map and available with
the \l{Map::gesture}{gesture} property. This is the only way
@@ -194,18 +272,34 @@ QT_BEGIN_NAMESPACE
/*!
\qmlproperty bool QtLocation::MapGestureArea::pinchActive
- This read-only property holds whether pinch gesture is active.
+ This read-only property holds whether the pinch gesture is active.
*/
/*!
\qmlproperty bool QtLocation::MapGestureArea::panActive
- This read-only property holds whether pan gesture is active.
+ This read-only property holds whether the pan gesture is active.
\note Change notifications for this property were introduced in Qt 5.5.
*/
/*!
+ \qmlproperty bool QtLocation::MapGestureArea::rotationActive
+
+ This read-only property holds whether the two-finger rotation gesture is active.
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapGestureArea::tiltActive
+
+ This read-only property holds whether the two-finger tilt gesture is active.
+
+ \since Qt Location 5.9
+*/
+
+/*!
\qmlproperty real QtLocation::MapGestureArea::maximumZoomLevelChange
This property holds the maximum zoom level change per pinch, essentially
@@ -296,22 +390,93 @@ QT_BEGIN_NAMESPACE
The corresponding handler is \c onFlickFinished.
*/
+/*!
+ \qmlsignal QtLocation::MapGestureArea::rotationStarted(PinchEvent event)
+
+ This signal is emitted when a two-finger rotation gesture is started.
+
+ The corresponding handler is \c onRotationStarted.
+
+ \sa rotationUpdated, rotationFinished
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::rotationUpdated(PinchEvent event)
+
+ This signal is emitted as the user's fingers move across the map,
+ after the \l rotationStarted signal is emitted.
+
+ The corresponding handler is \c onRotationUpdated.
+
+ \sa rotationStarted, rotationFinished
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::rotationFinished(PinchEvent event)
+
+ This signal is emitted at the end of a two-finger rotation gesture.
+
+ The corresponding handler is \c onRotationFinished.
+
+ \sa rotationStarted, rotationUpdated
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::tiltStarted(PinchEvent event)
+
+ This signal is emitted when a two-finger tilt gesture is started.
+
+ The corresponding handler is \c onTiltStarted.
+
+ \sa tiltUpdated, tiltFinished
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::tiltUpdated(PinchEvent event)
+
+ This signal is emitted as the user's fingers move across the map,
+ after the \l tiltStarted signal is emitted.
+
+ The corresponding handler is \c onTiltUpdated.
+
+ \sa tiltStarted, tiltFinished
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::tiltFinished(PinchEvent event)
+
+ This signal is emitted at the end of a two-finger tilt gesture.
+
+ The corresponding handler is \c onTiltFinished.
+
+ \sa tiltStarted, tiltUpdated
+
+ \since Qt Location 5.9
+*/
+
QQuickGeoMapGestureArea::QQuickGeoMapGestureArea(QDeclarativeGeoMap *map)
: QQuickItem(map),
m_map(0),
m_declarativeMap(map),
m_enabled(true),
- m_acceptedGestures(PinchGesture | PanGesture | FlickGesture),
- m_preventStealing(false),
- m_panEnabled(true)
-{
- m_flick.m_enabled = true,
- m_flick.m_maxVelocity = QML_MAP_FLICK_DEFAULTMAXVELOCITY;
- m_flick.m_deceleration = QML_MAP_FLICK_DEFAULTDECELERATION;
- m_flick.m_animation = 0;
+ m_acceptedGestures(PinchGesture | PanGesture | FlickGesture | RotationGesture | TiltGesture),
+ m_preventStealing(false)
+{
m_touchPointState = touchPoints0;
m_pinchState = pinchInactive;
m_flickState = flickInactive;
+ m_rotationState = rotationInactive;
+ m_tiltState = tiltInactive;
}
/*!
@@ -377,6 +542,8 @@ QQuickGeoMapGestureArea::~QQuickGeoMapGestureArea()
\li MapGestureArea.PinchGesture - Support the map pinch gesture (value: 0x0001).
\li MapGestureArea.PanGesture - Support the map pan gesture (value: 0x0002).
\li MapGestureArea.FlickGesture - Support the map flick gesture (value: 0x0004).
+ \li MapGestureArea.RotationGesture - Support the map rotation gesture (value: 0x0008).
+ \li MapGestureArea.TiltGesture - Support the map tilt gesture (value: 0x0010).
\endlist
*/
@@ -392,9 +559,13 @@ void QQuickGeoMapGestureArea::setAcceptedGestures(AcceptedGestures acceptedGestu
return;
m_acceptedGestures = acceptedGestures;
- setPanEnabled(acceptedGestures & PanGesture);
- setFlickEnabled(acceptedGestures & FlickGesture);
- setPinchEnabled(acceptedGestures & PinchGesture);
+ if (enabled()) {
+ setPanEnabled(acceptedGestures & PanGesture);
+ setFlickEnabled(acceptedGestures & FlickGesture);
+ setPinchEnabled(acceptedGestures & PinchGesture);
+ setRotationEnabled(acceptedGestures & RotationGesture);
+ setTiltEnabled(acceptedGestures & TiltGesture);
+ }
emit acceptedGesturesChanged();
}
@@ -410,6 +581,22 @@ bool QQuickGeoMapGestureArea::isPinchActive() const
/*!
\internal
*/
+bool QQuickGeoMapGestureArea::isRotationActive() const
+{
+ return m_rotationState == rotationActive;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::isTiltActive() const
+{
+ return m_tiltState == tiltActive;
+}
+
+/*!
+ \internal
+*/
bool QQuickGeoMapGestureArea::isPanActive() const
{
return m_flickState == panActive || m_flickState == flickActive;
@@ -436,22 +623,25 @@ void QQuickGeoMapGestureArea::setEnabled(bool enabled)
setPanEnabled(m_acceptedGestures & PanGesture);
setFlickEnabled(m_acceptedGestures & FlickGesture);
setPinchEnabled(m_acceptedGestures & PinchGesture);
+ setRotationEnabled(m_acceptedGestures & RotationGesture);
+ setTiltEnabled(m_acceptedGestures & TiltGesture);
} else {
setPanEnabled(false);
setFlickEnabled(false);
setPinchEnabled(false);
+ setRotationEnabled(false);
+ setTiltEnabled(false);
}
emit enabledChanged();
}
-
/*!
\internal
*/
bool QQuickGeoMapGestureArea::pinchEnabled() const
{
- return m_pinch.m_enabled;
+ return m_pinch.m_pinchEnabled;
}
/*!
@@ -459,9 +649,39 @@ bool QQuickGeoMapGestureArea::pinchEnabled() const
*/
void QQuickGeoMapGestureArea::setPinchEnabled(bool enabled)
{
- if (enabled == m_pinch.m_enabled)
- return;
- m_pinch.m_enabled = enabled;
+ m_pinch.m_pinchEnabled = enabled;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::rotationEnabled() const
+{
+ return m_pinch.m_rotationEnabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setRotationEnabled(bool enabled)
+{
+ m_pinch.m_rotationEnabled = enabled;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::tiltEnabled() const
+{
+ return m_pinch.m_tiltEnabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setTiltEnabled(bool enabled)
+{
+ m_pinch.m_tiltEnabled = enabled;
}
/*!
@@ -469,7 +689,7 @@ void QQuickGeoMapGestureArea::setPinchEnabled(bool enabled)
*/
bool QQuickGeoMapGestureArea::panEnabled() const
{
- return m_panEnabled;
+ return m_flick.m_panEnabled;
}
/*!
@@ -477,9 +697,9 @@ bool QQuickGeoMapGestureArea::panEnabled() const
*/
void QQuickGeoMapGestureArea::setPanEnabled(bool enabled)
{
- if (enabled == m_flick.m_enabled)
+ if (enabled == m_flick.m_panEnabled)
return;
- m_panEnabled = enabled;
+ m_flick.m_panEnabled = enabled;
// unlike the pinch, the pan existing functionality is to stop immediately
if (!enabled)
@@ -491,7 +711,7 @@ void QQuickGeoMapGestureArea::setPanEnabled(bool enabled)
*/
bool QQuickGeoMapGestureArea::flickEnabled() const
{
- return m_flick.m_enabled;
+ return m_flick.m_flickEnabled;
}
/*!
@@ -499,9 +719,9 @@ bool QQuickGeoMapGestureArea::flickEnabled() const
*/
void QQuickGeoMapGestureArea::setFlickEnabled(bool enabled)
{
- if (enabled == m_flick.m_enabled)
+ if (enabled == m_flick.m_flickEnabled)
return;
- m_flick.m_enabled = enabled;
+ m_flick.m_flickEnabled = enabled;
// unlike the pinch, the flick existing functionality is to stop immediately
if (!enabled) {
stopFlick();
@@ -516,6 +736,7 @@ void QQuickGeoMapGestureArea::setFlickEnabled(bool enabled)
*/
void QQuickGeoMapGestureArea::setMinimumZoomLevel(qreal min)
{
+ // TODO: remove m_zoom.m_minimum and m_maximum and use m_declarativeMap directly instead.
if (min >= 0)
m_pinch.m_zoom.m_minimum = min;
}
@@ -691,22 +912,16 @@ void QQuickGeoMapGestureArea::handleWheelEvent(QWheelEvent *event)
if (!m_map)
return;
- QGeoCoordinate wheelGeoPos = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(event->posF()), false);
- QPointF preZoomPoint = m_map->geoProjection().coordinateToItemPosition(wheelGeoPos, false).toPointF();
+ const QGeoCoordinate &wheelGeoPos = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(event->posF()), false);
+ const QPointF &preZoomPoint = event->posF();
- double zoomLevelDelta = event->angleDelta().y() * qreal(0.001);
+ const double zoomLevelDelta = event->angleDelta().y() * qreal(0.001);
m_declarativeMap->setZoomLevel(m_declarativeMap->zoomLevel() + zoomLevelDelta);
- QPointF postZoomPoint = m_map->geoProjection().coordinateToItemPosition(wheelGeoPos, false).toPointF();
+ const QPointF &postZoomPoint = m_map->geoProjection().coordinateToItemPosition(wheelGeoPos, false).toPointF();
- if (preZoomPoint != postZoomPoint)
- {
- qreal dx = postZoomPoint.x() - preZoomPoint.x();
- qreal dy = postZoomPoint.y() - preZoomPoint.y();
- QPointF mapCenterPoint(m_map->viewportWidth() / 2.0 + dx, m_map->viewportHeight() / 2.0 + dy);
+ if (preZoomPoint != postZoomPoint) // need to re-anchor the wheel geoPos to the event position
+ m_declarativeMap->setCenter(anchorCoordinateToPoint(*m_map, wheelGeoPos, preZoomPoint));
- QGeoCoordinate mapCenterCoordinate = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(mapCenterPoint), false);
- m_declarativeMap->setCenter(mapCenterCoordinate);
- }
event->accept();
}
@@ -717,8 +932,8 @@ void QQuickGeoMapGestureArea::clearTouchData()
{
m_velocityX = 0;
m_velocityY = 0;
- m_sceneCenter.setX(0);
- m_sceneCenter.setY(0);
+ m_touchPointsCentroid.setX(0);
+ m_touchPointsCentroid.setY(0);
m_touchCenterCoord.setLongitude(0);
m_touchCenterCoord.setLatitude(0);
m_startCoord.setLongitude(0);
@@ -754,7 +969,7 @@ void QQuickGeoMapGestureArea::updateVelocityList(const QPointF &pos)
bool QQuickGeoMapGestureArea::isActive() const
{
- return isPanActive() || isPinchActive();
+ return isPanActive() || isPinchActive() || isRotationActive() || isTiltActive();
}
/*!
@@ -765,7 +980,6 @@ void QQuickGeoMapGestureArea::update()
{
if (!m_map)
return;
-
// First state machine is for the number of touch points
//combine touch with mouse event
@@ -776,16 +990,27 @@ void QQuickGeoMapGestureArea::update()
touchPointStateMachine();
+ // Parallel state machine for tilt. Tilt goes first as it blocks anything else, when started.
+ // But tilting can also only start if nothing else is active.
+ if (isTiltActive() || m_pinch.m_tiltEnabled)
+ tiltStateMachine();
+
// Parallel state machine for pinch
- if (isPinchActive() || (m_enabled && m_pinch.m_enabled && (m_acceptedGestures & (PinchGesture))))
+ if (isPinchActive() || m_pinch.m_pinchEnabled)
pinchStateMachine();
// Parallel state machine for pan (since you can pan at the same time as pinching)
// The stopPan function ensures that pan stops immediately when disabled,
- // but the line below allows pan continue its current gesture if you disable
- // the whole gesture (enabled_ flag), this keeps the enabled_ consistent with the pinch
- if (isPanActive() || (m_enabled && m_flick.m_enabled && (m_acceptedGestures & (PanGesture | FlickGesture))))
+ // but the isPanActive() below allows pan continue its current gesture if you disable
+ // the whole gesture.
+ if (isPanActive() || m_flick.m_flickEnabled || m_flick.m_panEnabled)
panStateMachine();
+
+ // Parallel state machine for rotation.
+ // Rotation goes last because when panning and rotating, first the new center has to be set,
+ // then the rotation has to be applied
+ if (isRotationActive() || m_pinch.m_rotationEnabled)
+ rotationStateMachine();
}
/*!
@@ -810,7 +1035,7 @@ void QQuickGeoMapGestureArea::touchPointStateMachine()
if (m_allPoints.count() == 0) {
m_touchPointState = touchPoints0;
} else if (m_allPoints.count() == 2) {
- m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneCenter), false);
+ m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_touchPointsCentroid), false);
startTwoTouchPoints();
m_touchPointState = touchPoints2;
}
@@ -819,7 +1044,7 @@ void QQuickGeoMapGestureArea::touchPointStateMachine()
if (m_allPoints.count() == 0) {
m_touchPointState = touchPoints0;
} else if (m_allPoints.count() == 1) {
- m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneCenter), false);
+ m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_touchPointsCentroid), false);
startOneTouchPoint();
m_touchPointState = touchPoints1;
}
@@ -860,11 +1085,10 @@ void QQuickGeoMapGestureArea::startOneTouchPoint()
*/
void QQuickGeoMapGestureArea::updateOneTouchPoint()
{
- m_sceneCenter = mapFromScene(m_allPoints.at(0).scenePos());
- updateVelocityList(m_sceneCenter);
+ m_touchPointsCentroid = mapFromScene(m_allPoints.at(0).scenePos());
+ updateVelocityList(m_touchPointsCentroid);
}
-
/*!
\internal
*/
@@ -880,6 +1104,7 @@ void QQuickGeoMapGestureArea::startTwoTouchPoints()
m_touchCenterCoord.longitude());
m_startCoord.setLatitude(m_startCoord.latitude() + startCoord.latitude() -
m_touchCenterCoord.latitude());
+ m_twoTouchAngleStart = touchAngle(m_sceneStartPoint1, m_sceneStartPoint2); // Initial angle used for calculating rotation
}
/*!
@@ -892,12 +1117,280 @@ void QQuickGeoMapGestureArea::updateTwoTouchPoints()
qreal dx = p1.x() - p2.x();
qreal dy = p1.y() - p2.y();
m_distanceBetweenTouchPoints = sqrt(dx * dx + dy * dy);
- m_sceneCenter = (p1 + p2) / 2;
- updateVelocityList(m_sceneCenter);
+ m_touchPointsCentroid = (p1 + p2) / 2;
+ updateVelocityList(m_touchPointsCentroid);
+
+ m_twoTouchAngle = touchAngle(p1, p2);
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::tiltStateMachine()
+{
+ TiltState lastState = m_tiltState;
+ // Transitions:
+ switch (m_tiltState) {
+ case tiltInactive:
+ if (m_allPoints.count() >= 2) {
+ if (!isRotationActive() && !isPanActive() && !isPinchActive() && canStartTilt()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startTilt();
+ m_tiltState = tiltActive;
+ } else {
+ m_tiltState = tiltInactiveTwoPoints;
+ }
+ }
+ break;
+ case tiltInactiveTwoPoints:
+ if (m_allPoints.count() <= 1) {
+ m_tiltState = tiltInactive;
+ } else {
+ if (!isRotationActive() && !isPanActive() && !isPinchActive() && canStartTilt()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startTilt();
+ m_tiltState = tiltActive;
+ }
+ }
+ break;
+ case tiltActive:
+ if (m_allPoints.count() <= 1) {
+ m_tiltState = tiltInactive;
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ m_declarativeMap->setKeepTouchGrab(m_preventStealing);
+ endTilt();
+ }
+ break;
+ }
+ // This line implements an exclusive state machine, where the transitions and updates don't
+ // happen on the same frame
+ if (m_tiltState != lastState) {
+ emit tiltActiveChanged();
+ return;
+ }
+
+ // Update
+ switch (m_tiltState) {
+ case tiltInactive:
+ case tiltInactiveTwoPoints:
+ break; // do nothing
+ case tiltActive:
+ updateTilt();
+ break;
+ }
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::canStartTilt()
+{
+ if (m_allPoints.count() >= 2) {
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
+ if (qAbs(m_twoTouchAngle) < MaximumParallelPosition
+ && movingParallel(m_sceneStartPoint1, p1, m_sceneStartPoint2, p2)) {
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
+ m_pinch.m_event.setAngle(m_twoTouchAngle);
+ m_pinch.m_event.setPoint1(p1);
+ m_pinch.m_event.setPoint2(p2);
+ m_pinch.m_event.setPointCount(m_allPoints.count());
+ m_pinch.m_event.setAccepted(true);
+ emit tiltStarted(&m_pinch.m_event);
+ return m_pinch.m_event.accepted();
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startTilt()
+{
+ m_pinch.m_tilt.m_startTouchCentroid = m_touchPointsCentroid;
+ m_pinch.m_tilt.m_startTilt = m_declarativeMap->tilt();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateTilt()
+{
+ // Calculate the new tilt
+ qreal verticalDisplacement = (m_touchPointsCentroid - m_pinch.m_tilt.m_startTouchCentroid).y();
+
+ // Approach: 10pixel = 1 degree.
+ qreal tilt = verticalDisplacement / 10.0;
+ qreal newTilt = m_pinch.m_tilt.m_startTilt - tilt;
+ m_declarativeMap->setTilt(newTilt);
+
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
+ m_pinch.m_event.setAngle(m_twoTouchAngle);
+ m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
+ m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePos());
+ m_pinch.m_event.setPoint1(m_pinch.m_lastPoint1);
+ m_pinch.m_event.setPoint2(m_pinch.m_lastPoint2);
+ m_pinch.m_event.setPointCount(m_allPoints.count());
+ m_pinch.m_event.setAccepted(true);
+
+ emit tiltUpdated(&m_pinch.m_event);
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::endTilt()
+{
+ QPointF p1 = mapFromScene(m_pinch.m_lastPoint1);
+ QPointF p2 = mapFromScene(m_pinch.m_lastPoint2);
+ m_pinch.m_event.setCenter((p1 + p2) / 2);
+ m_pinch.m_event.setAngle(m_pinch.m_lastAngle);
+ m_pinch.m_event.setPoint1(p1);
+ m_pinch.m_event.setPoint2(p2);
+ m_pinch.m_event.setAccepted(true);
+ m_pinch.m_event.setPointCount(0);
+ emit tiltFinished(&m_pinch.m_event);
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::rotationStateMachine()
+{
+ RotationState lastState = m_rotationState;
+ // Transitions:
+ switch (m_rotationState) {
+ case rotationInactive:
+ if (m_allPoints.count() >= 2) {
+ if (!isTiltActive() && canStartRotation()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startRotation();
+ m_rotationState = rotationActive;
+ } else {
+ m_rotationState = rotationInactiveTwoPoints;
+ }
+ }
+ break;
+ case rotationInactiveTwoPoints:
+ if (m_allPoints.count() <= 1) {
+ m_rotationState = rotationInactive;
+ } else {
+ if (!isTiltActive() && canStartRotation()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startRotation();
+ m_rotationState = rotationActive;
+ }
+ }
+ break;
+ case rotationActive:
+ if (m_allPoints.count() <= 1) {
+ m_rotationState = rotationInactive;
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ m_declarativeMap->setKeepTouchGrab(m_preventStealing);
+ endRotation();
+ }
+ break;
+ }
+ // This line implements an exclusive state machine, where the transitions and updates don't
+ // happen on the same frame
+ if (m_rotationState != lastState) {
+ emit rotationActiveChanged();
+ return;
+ }
+
+ // Update
+ switch (m_rotationState) {
+ case rotationInactive:
+ case rotationInactiveTwoPoints:
+ break; // do nothing
+ case rotationActive:
+ updateRotation();
+ break;
+ }
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::canStartRotation()
+{
+ if (m_allPoints.count() >= 2) {
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
+ if (pointDragged(m_sceneStartPoint1, p1) || pointDragged(m_sceneStartPoint2, p2)) {
+ qreal delta = angleDelta(m_twoTouchAngleStart, m_twoTouchAngle);
+ if (qAbs(delta) < MinimumRotationStartingAngle) {
+ return false;
+ }
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
+ m_pinch.m_event.setAngle(m_twoTouchAngle);
+ m_pinch.m_event.setPoint1(p1);
+ m_pinch.m_event.setPoint2(p2);
+ m_pinch.m_event.setPointCount(m_allPoints.count());
+ m_pinch.m_event.setAccepted(true);
+ emit rotationStarted(&m_pinch.m_event);
+ return m_pinch.m_event.accepted();
+ }
+ }
+ return false;
+}
- m_twoTouchAngle = QLineF(p1, p2).angle();
- if (m_twoTouchAngle > 180)
- m_twoTouchAngle -= 360;
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startRotation()
+{
+ m_pinch.m_rotation.m_startBearing = m_declarativeMap->bearing();
+ m_pinch.m_rotation.m_previousTouchAngle = m_twoTouchAngleStart;
+ m_pinch.m_rotation.m_totalAngle = 0.0;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateRotation()
+{
+ // Calculate the new bearing
+ qreal angle = angleDelta(m_pinch.m_rotation.m_previousTouchAngle, m_twoTouchAngle);
+ if (qAbs(angle) < 0.2) // avoiding too many updates
+ return;
+
+ m_pinch.m_rotation.m_previousTouchAngle = m_twoTouchAngle;
+ m_pinch.m_rotation.m_totalAngle += angle;
+ qreal newBearing = m_pinch.m_rotation.m_startBearing - m_pinch.m_rotation.m_totalAngle;
+ m_declarativeMap->setBearing(newBearing);
+
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
+ m_pinch.m_event.setAngle(m_twoTouchAngle);
+ m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
+ m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePos());
+ m_pinch.m_event.setPoint1(m_pinch.m_lastPoint1);
+ m_pinch.m_event.setPoint2(m_pinch.m_lastPoint2);
+ m_pinch.m_event.setPointCount(m_allPoints.count());
+ m_pinch.m_event.setAccepted(true);
+
+ emit rotationUpdated(&m_pinch.m_event);
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::endRotation()
+{
+ QPointF p1 = mapFromScene(m_pinch.m_lastPoint1);
+ QPointF p2 = mapFromScene(m_pinch.m_lastPoint2);
+ m_pinch.m_event.setCenter((p1 + p2) / 2);
+ m_pinch.m_event.setAngle(m_pinch.m_lastAngle);
+ m_pinch.m_event.setPoint1(p1);
+ m_pinch.m_event.setPoint2(p2);
+ m_pinch.m_event.setAccepted(true);
+ m_pinch.m_event.setPointCount(0);
+ emit rotationFinished(&m_pinch.m_event);
}
/*!
@@ -910,7 +1403,7 @@ void QQuickGeoMapGestureArea::pinchStateMachine()
switch (m_pinchState) {
case pinchInactive:
if (m_allPoints.count() >= 2) {
- if (canStartPinch()) {
+ if (!isTiltActive() && canStartPinch()) {
m_declarativeMap->setKeepMouseGrab(true);
m_declarativeMap->setKeepTouchGrab(true);
startPinch();
@@ -924,7 +1417,7 @@ void QQuickGeoMapGestureArea::pinchStateMachine()
if (m_allPoints.count() <= 1) {
m_pinchState = pinchInactive;
} else {
- if (canStartPinch()) {
+ if (!isTiltActive() && canStartPinch()) {
m_declarativeMap->setKeepMouseGrab(true);
m_declarativeMap->setKeepTouchGrab(true);
startPinch();
@@ -933,7 +1426,7 @@ void QQuickGeoMapGestureArea::pinchStateMachine()
}
break;
case pinchActive:
- if (m_allPoints.count() <= 1) {
+ if (m_allPoints.count() <= 1) { // Once started, pinch goes off only when finger(s) are release
m_pinchState = pinchInactive;
m_declarativeMap->setKeepMouseGrab(m_preventStealing);
m_declarativeMap->setKeepTouchGrab(m_preventStealing);
@@ -964,16 +1457,12 @@ void QQuickGeoMapGestureArea::pinchStateMachine()
*/
bool QQuickGeoMapGestureArea::canStartPinch()
{
- const int startDragDistance = qApp->styleHints()->startDragDistance();
-
if (m_allPoints.count() >= 2) {
QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
- if (qAbs(p1.x()-m_sceneStartPoint1.x()) > startDragDistance
- || qAbs(p1.y()-m_sceneStartPoint1.y()) > startDragDistance
- || qAbs(p2.x()-m_sceneStartPoint2.x()) > startDragDistance
- || qAbs(p2.y()-m_sceneStartPoint2.y()) > startDragDistance) {
- m_pinch.m_event.setCenter(mapFromScene(m_sceneCenter));
+ if (pointDragged(m_sceneStartPoint1, p1)
+ || pointDragged(m_sceneStartPoint2, p2)) {
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
m_pinch.m_event.setAngle(m_twoTouchAngle);
m_pinch.m_event.setPoint1(p1);
m_pinch.m_event.setPoint2(p2);
@@ -1018,7 +1507,7 @@ void QQuickGeoMapGestureArea::updatePinch()
m_pinch.m_zoom.m_start;
}
- m_pinch.m_event.setCenter(mapFromScene(m_sceneCenter));
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
m_pinch.m_event.setAngle(m_twoTouchAngle);
m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
@@ -1068,9 +1557,9 @@ void QQuickGeoMapGestureArea::panStateMachine()
// Transitions
switch (m_flickState) {
case flickInactive:
- if (canStartPan()) {
+ if (!isTiltActive() && canStartPan()) {
// Update startCoord_ to ensure smooth start for panning when going over startDragDistance
- QGeoCoordinate newStartCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneCenter), false);
+ QGeoCoordinate newStartCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_touchPointsCentroid), false);
m_startCoord.setLongitude(newStartCoord.longitude());
m_startCoord.setLatitude(newStartCoord.latitude());
m_declarativeMap->setKeepMouseGrab(true);
@@ -1083,7 +1572,7 @@ void QQuickGeoMapGestureArea::panStateMachine()
{
m_flickState = flickInactive;
// mark as inactive for use by camera
- if (m_pinchState == pinchInactive) {
+ if (m_pinchState == pinchInactive && m_rotationState == rotationInactive && m_tiltState == tiltInactive) {
m_declarativeMap->setKeepMouseGrab(m_preventStealing);
m_map->prefetchData();
}
@@ -1145,13 +1634,7 @@ bool QQuickGeoMapGestureArea::canStartPan()
*/
void QQuickGeoMapGestureArea::updatePan()
{
- QPointF startPoint = m_map->geoProjection().coordinateToItemPosition(m_startCoord, false).toPointF();
- int dx = static_cast<int>(m_sceneCenter.x() - startPoint.x());
- int dy = static_cast<int>(m_sceneCenter.y() - startPoint.y());
- QPointF mapCenterPoint;
- mapCenterPoint.setY(m_map->viewportHeight() / 2.0 - dy);
- mapCenterPoint.setX(m_map->viewportWidth() / 2.0 - dx);
- QGeoCoordinate animationStartCoordinate = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(mapCenterPoint), false);
+ QGeoCoordinate animationStartCoordinate = anchorCoordinateToPoint(*m_map, m_startCoord, m_touchPointsCentroid);
m_declarativeMap->setCenter(animationStartCoordinate);
}
@@ -1173,7 +1656,7 @@ bool QQuickGeoMapGestureArea::tryStartFlick()
int flickTimeX = 0;
int flickPixelsX = 0;
int flickPixelsY = 0;
- if (qAbs(velocityY) > MinimumFlickVelocity && qAbs(m_sceneCenter.y() - m_sceneStartPoint1.y()) > FlickThreshold) {
+ if (qAbs(velocityY) > MinimumFlickVelocity && qAbs(m_touchPointsCentroid.y() - m_sceneStartPoint1.y()) > FlickThreshold) {
// calculate Y flick animation values
qreal acceleration = m_flick.m_deceleration;
if ((velocityY > 0.0f) == (m_flick.m_deceleration > 0.0f))
@@ -1181,7 +1664,7 @@ bool QQuickGeoMapGestureArea::tryStartFlick()
flickTimeY = static_cast<int>(-1000 * velocityY / acceleration);
flickPixelsY = (flickTimeY * velocityY) / (1000.0 * 2);
}
- if (qAbs(velocityX) > MinimumFlickVelocity && qAbs(m_sceneCenter.x() - m_sceneStartPoint1.x()) > FlickThreshold) {
+ if (qAbs(velocityX) > MinimumFlickVelocity && qAbs(m_touchPointsCentroid.x() - m_sceneStartPoint1.x()) > FlickThreshold) {
// calculate X flick animation values
qreal acceleration = m_flick.m_deceleration;
if ((velocityX > 0.0f) == (m_flick.m_deceleration > 0.0f))
@@ -1214,28 +1697,23 @@ void QQuickGeoMapGestureArea::startFlick(int dx, int dy, int timeMs)
QGeoCoordinate animationEndCoordinate = m_declarativeMap->center();
m_flick.m_animation->setDuration(timeMs);
+ QPointF delta(dx, dy);
+ QMatrix4x4 matBearing;
+ matBearing.rotate(m_map->cameraData().bearing(), 0, 0, 1);
+ delta = matBearing * delta;
+
double zoom = pow(2.0, m_declarativeMap->zoomLevel());
- double longitude = animationStartCoordinate.longitude() - (dx / zoom);
- double latitude = animationStartCoordinate.latitude() + (dy / zoom);
+ double longitude = animationStartCoordinate.longitude() - (delta.x() / zoom);
+ double latitude = animationStartCoordinate.latitude() + (delta.y() / zoom);
- if (dx > 0)
+ if (delta.x() > 0)
m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::East);
else
m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::West);
//keep animation in correct bounds
- if (latitude > 85.05113)
- latitude = 85.05113;
- else if (latitude < -85.05113)
- latitude = -85.05113;
-
- if (longitude > 180)
- longitude = longitude - 360;
- else if (longitude < -180)
- longitude = longitude + 360;
-
- animationEndCoordinate.setLongitude(longitude);
- animationEndCoordinate.setLatitude(latitude);
+ animationEndCoordinate.setLongitude(QLocationUtils::wrapLong(longitude));
+ animationEndCoordinate.setLatitude(QLocationUtils::clipLat(latitude, QLocationUtils::mercatorMaxLatitude()));
m_flick.m_animation->setFrom(animationStartCoordinate);
m_flick.m_animation->setTo(animationEndCoordinate);
diff --git a/src/imports/location/qquickgeomapgesturearea_p.h b/src/location/declarativemaps/qquickgeomapgesturearea_p.h
index 51c5cc1e..5cafec0d 100644
--- a/src/imports/location/qquickgeomapgesturearea_p.h
+++ b/src/location/declarativemaps/qquickgeomapgesturearea_p.h
@@ -48,23 +48,24 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
+
#include <QtQuick/QQuickItem>
#include <QTouchEvent>
#include <QDebug>
#include <QElapsedTimer>
-#include "qgeocoordinate.h"
-#include "qgeomap_p.h"
-#include "qquickgeocoordinateanimation_p.h"
+#include <QtPositioning/qgeocoordinate.h>
QT_BEGIN_NAMESPACE
class QGraphicsSceneMouseEvent;
+class QQuickGeoCoordinateAnimation;
class QDeclarativeGeoMap;
class QTouchEvent;
class QWheelEvent;
class QGeoMap;
-class QGeoMapPinchEvent : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QGeoMapPinchEvent : public QObject
{
Q_OBJECT
@@ -110,7 +111,7 @@ private:
bool m_accepted;
};
-class QQuickGeoMapGestureArea: public QQuickItem
+class Q_LOCATION_PRIVATE_EXPORT QQuickGeoMapGestureArea: public QQuickItem
{
Q_OBJECT
Q_ENUMS(GeoMapGesture)
@@ -119,6 +120,8 @@ class QQuickGeoMapGestureArea: public QQuickItem
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(bool pinchActive READ isPinchActive NOTIFY pinchActiveChanged)
Q_PROPERTY(bool panActive READ isPanActive NOTIFY panActiveChanged)
+ Q_PROPERTY(bool rotationActive READ isRotationActive NOTIFY rotationActiveChanged)
+ Q_PROPERTY(bool tiltActive READ isTiltActive NOTIFY tiltActiveChanged)
Q_PROPERTY(AcceptedGestures acceptedGestures READ acceptedGestures WRITE setAcceptedGestures NOTIFY acceptedGesturesChanged)
Q_PROPERTY(qreal maximumZoomLevelChange READ maximumZoomLevelChange WRITE setMaximumZoomLevelChange NOTIFY maximumZoomLevelChangeChanged)
Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
@@ -132,7 +135,9 @@ public:
NoGesture = 0x0000,
PinchGesture = 0x0001,
PanGesture = 0x0002,
- FlickGesture = 0x004
+ FlickGesture = 0x0004,
+ RotationGesture = 0x0008,
+ TiltGesture = 0x0010
};
Q_DECLARE_FLAGS(AcceptedGestures, GeoMapGesture)
@@ -141,6 +146,8 @@ public:
void setAcceptedGestures(AcceptedGestures acceptedGestures);
bool isPinchActive() const;
+ bool isRotationActive() const;
+ bool isTiltActive() const;
bool isPanActive() const;
bool isActive() const;
@@ -175,6 +182,8 @@ public:
Q_SIGNALS:
void panActiveChanged();
void pinchActiveChanged();
+ void rotationActiveChanged();
+ void tiltActiveChanged();
void enabledChanged();
void maximumZoomLevelChangeChanged();
void acceptedGesturesChanged();
@@ -186,6 +195,12 @@ Q_SIGNALS:
void panFinished();
void flickStarted();
void flickFinished();
+ void rotationStarted(QGeoMapPinchEvent *pinch);
+ void rotationUpdated(QGeoMapPinchEvent *pinch);
+ void rotationFinished(QGeoMapPinchEvent *pinch);
+ void tiltStarted(QGeoMapPinchEvent *pinch);
+ void tiltUpdated(QGeoMapPinchEvent *pinch);
+ void tiltFinished(QGeoMapPinchEvent *pinch);
void preventStealingChanged();
private:
void update();
@@ -197,6 +212,20 @@ private:
void startTwoTouchPoints();
void updateTwoTouchPoints();
+ // All two fingers vertical parallel panning related code, which encompasses tilting
+ void tiltStateMachine();
+ bool canStartTilt();
+ void startTilt();
+ void updateTilt();
+ void endTilt();
+
+ // All two fingers rotation related code, which encompasses rotation
+ void rotationStateMachine();
+ bool canStartRotation();
+ void startRotation();
+ void updateRotation();
+ void endRotation();
+
// All pinch related code, which encompasses zoom
void pinchStateMachine();
bool canStartPinch();
@@ -215,6 +244,10 @@ private:
bool pinchEnabled() const;
void setPinchEnabled(bool enabled);
+ bool rotationEnabled() const;
+ void setRotationEnabled(bool enabled);
+ bool tiltEnabled() const;
+ void setTiltEnabled(bool enabled);
bool panEnabled() const;
void setPanEnabled(bool enabled);
bool flickEnabled() const;
@@ -234,15 +267,19 @@ private:
QDeclarativeGeoMap *m_declarativeMap;
bool m_enabled;
+ // This should be intended as a "two fingers gesture" struct
struct Pinch
{
- Pinch() : m_enabled(true), m_startDist(0), m_lastAngle(0.0) {}
+ Pinch() : m_pinchEnabled(true), m_rotationEnabled(true), m_tiltEnabled(true),
+ m_startDist(0), m_lastAngle(0.0) {}
QGeoMapPinchEvent m_event;
- bool m_enabled;
+ bool m_pinchEnabled;
+ bool m_rotationEnabled;
+ bool m_tiltEnabled;
struct Zoom
{
- Zoom() : m_minimum(-1.0), m_maximum(20.0), m_start(0.0), m_previous(0.0),
+ Zoom() : m_minimum(0.0), m_maximum(30.0), m_start(0.0), m_previous(0.0),
maximumChange(4.0) {}
qreal m_minimum;
qreal m_maximum;
@@ -251,6 +288,21 @@ private:
qreal maximumChange;
} m_zoom;
+ struct Rotation
+ {
+ Rotation() : m_startBearing(0.0), m_previousTouchAngle(0.0), m_totalAngle(0.0) {}
+ qreal m_startBearing;
+ qreal m_previousTouchAngle; // needed for detecting crossing +- 180 in a safer way
+ qreal m_totalAngle;
+ } m_rotation;
+
+ struct Tilt
+ {
+ Tilt() {}
+ QPointF m_startTouchCentroid;
+ qreal m_startTilt;
+ } m_tilt;
+
QPointF m_lastPoint1;
QPointF m_lastPoint2;
qreal m_startDist;
@@ -261,10 +313,13 @@ private:
struct Pan
{
+ Pan() : m_maxVelocity(2500), m_deceleration(2500), m_animation(0), m_flickEnabled(true), m_panEnabled(true) {}
+
qreal m_maxVelocity;
qreal m_deceleration;
QQuickGeoCoordinateAnimation *m_animation;
- bool m_enabled;
+ bool m_flickEnabled;
+ bool m_panEnabled;
} m_flick;
@@ -283,8 +338,9 @@ private:
QGeoCoordinate m_startCoord;
QGeoCoordinate m_touchCenterCoord;
qreal m_twoTouchAngle;
+ qreal m_twoTouchAngleStart;
qreal m_distanceBetweenTouchPoints;
- QPointF m_sceneCenter;
+ QPointF m_touchPointsCentroid;
bool m_preventStealing;
bool m_panEnabled;
@@ -303,6 +359,20 @@ private:
pinchActive
} m_pinchState;
+ enum RotationState
+ {
+ rotationInactive,
+ rotationInactiveTwoPoints,
+ rotationActive
+ } m_rotationState;
+
+ enum TiltState
+ {
+ tiltInactive,
+ tiltInactiveTwoPoints,
+ tiltActive
+ } m_tiltState;
+
enum FlickState
{
flickInactive,
diff --git a/src/imports/location/declarativeplaces/declarativeplaces.pri b/src/location/declarativeplaces/declarativeplaces.pri
index b580ee4b..82f60c23 100644
--- a/src/imports/location/declarativeplaces/declarativeplaces.pri
+++ b/src/location/declarativeplaces/declarativeplaces.pri
@@ -1,4 +1,5 @@
-INCLUDEPATH *= $$PWD
+INCLUDEPATH += declarativeplaces
+
SOURCES += \
#models
declarativeplaces/qdeclarativeplacecontentmodel.cpp \
@@ -19,15 +20,13 @@ SOURCES += \
declarativeplaces/qdeclarativesupplier.cpp \
declarativeplaces/qdeclarativesearchmodelbase.cpp
-HEADERS += \
+PRIVATE_HEADERS += \
#models
- declarativeplaces/qdeclarativeplacecontentmodel.h \
declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h \
declarativeplaces/qdeclarativesearchsuggestionmodel_p.h \
declarativeplaces/qdeclarativesearchresultmodel_p.h \
declarativeplaces/qdeclarativereviewmodel_p.h \
declarativeplaces/qdeclarativeplaceimagemodel_p.h \
- declarativeplaces/qdeclarativeplaceeditorialmodel.h \
#data
declarativeplaces/qdeclarativecontactdetail_p.h \
declarativeplaces/qdeclarativecategory_p.h \
@@ -37,7 +36,9 @@ HEADERS += \
declarativeplaces/qdeclarativeplaceuser_p.h \
declarativeplaces/qdeclarativeratings_p.h \
declarativeplaces/qdeclarativesupplier_p.h \
- declarativeplaces/qdeclarativesearchmodelbase.h
+ declarativeplaces/qdeclarativesearchmodelbase_p.h \
+ declarativeplaces/qdeclarativeplacecontentmodel_p.h \
+ declarativeplaces/qdeclarativeplaceeditorialmodel_p.h
diff --git a/src/imports/location/declarativeplaces/qdeclarativecategory.cpp b/src/location/declarativeplaces/qdeclarativecategory.cpp
index ae496c1b..c58ec3a2 100644
--- a/src/imports/location/declarativeplaces/qdeclarativecategory.cpp
+++ b/src/location/declarativeplaces/qdeclarativecategory.cpp
@@ -44,7 +44,7 @@
#include <QtLocation/QPlaceManager>
#include <QCoreApplication>
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
/*!
\qmltype Category
@@ -454,3 +454,5 @@ QPlaceManager *QDeclarativeCategory::manager()
return placeManager;
}
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativecategory_p.h b/src/location/declarativeplaces/qdeclarativecategory_p.h
index 63b255b4..c32072f4 100644
--- a/src/imports/location/declarativeplaces/qdeclarativecategory_p.h
+++ b/src/location/declarativeplaces/qdeclarativecategory_p.h
@@ -48,13 +48,14 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
#include <QtQml/qqml.h>
#include <QtQml/QQmlParserStatus>
#include <QObject>
-#include <qplacecategory.h>
+#include <QtLocation/qplacecategory.h>
-#include "qdeclarativegeoserviceprovider_p.h"
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
QT_BEGIN_NAMESPACE
@@ -62,7 +63,7 @@ class QDeclarativePlaceIcon;
class QPlaceReply;
class QPlaceManager;
-class QDeclarativeCategory : public QObject, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeCategory : public QObject, public QQmlParserStatus
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativecontactdetail.cpp b/src/location/declarativeplaces/qdeclarativecontactdetail.cpp
index c16c2018..7a7a4c33 100644
--- a/src/imports/location/declarativeplaces/qdeclarativecontactdetail.cpp
+++ b/src/location/declarativeplaces/qdeclarativecontactdetail.cpp
@@ -36,6 +36,8 @@
#include "qdeclarativecontactdetail_p.h"
+QT_BEGIN_NAMESPACE
+
/*!
\qmltype ContactDetails
\instantiates QDeclarativeContactDetails
@@ -217,3 +219,5 @@ void QDeclarativeContactDetail::setValue(const QString &value)
emit valueChanged();
}
}
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativecontactdetail_p.h b/src/location/declarativeplaces/qdeclarativecontactdetail_p.h
index 9d404def..ad60c3b5 100644
--- a/src/imports/location/declarativeplaces/qdeclarativecontactdetail_p.h
+++ b/src/location/declarativeplaces/qdeclarativecontactdetail_p.h
@@ -48,6 +48,7 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
#include <QtCore/QObject>
#include <QtLocation/QPlaceContactDetail>
#include <QtQml/QQmlPropertyMap>
@@ -55,7 +56,7 @@
QT_BEGIN_NAMESPACE
-class QDeclarativeContactDetails : public QQmlPropertyMap
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeContactDetails : public QQmlPropertyMap
{
Q_OBJECT
@@ -64,7 +65,7 @@ public:
virtual QVariant updateValue(const QString &key, const QVariant &input);
};
-class QDeclarativeContactDetail : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeContactDetail : public QObject
{
Q_OBJECT
@@ -98,5 +99,6 @@ private:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QDeclarativeContactDetail)
+QML_DECLARE_TYPE(QDeclarativeContactDetails)
#endif
diff --git a/src/imports/location/declarativeplaces/qdeclarativeperiod_p.h b/src/location/declarativeplaces/qdeclarativeperiod_p.h
index 3ded0109..3ded0109 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeperiod_p.h
+++ b/src/location/declarativeplaces/qdeclarativeperiod_p.h
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplace.cpp b/src/location/declarativeplaces/qdeclarativeplace.cpp
index 834737ff..91ef2026 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplace.cpp
+++ b/src/location/declarativeplaces/qdeclarativeplace.cpp
@@ -52,7 +52,7 @@
#include <QtLocation/QPlaceIdReply>
#include <QtLocation/QPlaceContactDetail>
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
/*!
\qmltype Place
@@ -1225,3 +1225,5 @@ QString QDeclarativePlace::primaryValue(const QString &contactType) const
return QString();
}
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplace_p.h b/src/location/declarativeplaces/qdeclarativeplace_p.h
index 78557091..5a1470fe 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplace_p.h
+++ b/src/location/declarativeplaces/qdeclarativeplace_p.h
@@ -48,20 +48,21 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
#include <QtCore/QObject>
#include <QtQml/QQmlListProperty>
#include <QtQml/QQmlParserStatus>
#include <QtQml/QQmlPropertyMap>
#include <QtLocation/QPlace>
-#include "qdeclarativegeolocation_p.h"
-#include "qdeclarativecategory_p.h"
-#include "qdeclarativecontactdetail_p.h"
-#include "qdeclarativesupplier_p.h"
-#include "qdeclarativeratings_p.h"
-#include "qdeclarativereviewmodel_p.h"
-#include "qdeclarativeplaceimagemodel_p.h"
-#include "qdeclarativeplaceeditorialmodel.h"
+#include <QtPositioning/private/qdeclarativegeolocation_p.h>
+#include <QtLocation/private/qdeclarativecategory_p.h>
+#include <QtLocation/private/qdeclarativecontactdetail_p.h>
+#include <QtLocation/private/qdeclarativesupplier_p.h>
+#include <QtLocation/private/qdeclarativeratings_p.h>
+#include <QtLocation/private/qdeclarativereviewmodel_p.h>
+#include <QtLocation/private/qdeclarativeplaceimagemodel_p.h>
+#include <QtLocation/private/qdeclarativeplaceeditorialmodel_p.h>
QT_BEGIN_NAMESPACE
@@ -70,7 +71,7 @@ class QPlaceReply;
class QPlaceManager;
class QDeclarativePlaceIcon;
-class QDeclarativePlace : public QObject, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlace : public QObject, public QQmlParserStatus
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplaceattribute.cpp b/src/location/declarativeplaces/qdeclarativeplaceattribute.cpp
index 9a04d383..20adbafb 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplaceattribute.cpp
+++ b/src/location/declarativeplaces/qdeclarativeplaceattribute.cpp
@@ -36,6 +36,8 @@
#include "qdeclarativeplaceattribute_p.h"
+QT_BEGIN_NAMESPACE
+
/*!
\qmltype ExtendedAttributes
\instantiates QQmlPropertyMap
@@ -215,3 +217,5 @@ QString QDeclarativePlaceAttribute::text() const
{
return m_attribute.text();
}
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplaceattribute_p.h b/src/location/declarativeplaces/qdeclarativeplaceattribute_p.h
index f1c873c3..8079df9c 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplaceattribute_p.h
+++ b/src/location/declarativeplaces/qdeclarativeplaceattribute_p.h
@@ -48,15 +48,16 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
#include <QObject>
#include <QtQml/qqml.h>
#include <QString>
-#include <qplaceattribute.h>
+#include <QtLocation/qplaceattribute.h>
QT_BEGIN_NAMESPACE
-class QDeclarativePlaceAttribute : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceAttribute : public QObject
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp b/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp
index b031e0c9..faf7e418 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp
+++ b/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp
@@ -34,7 +34,7 @@
**
****************************************************************************/
-#include "qdeclarativeplacecontentmodel.h"
+#include "qdeclarativeplacecontentmodel_p.h"
#include "qdeclarativeplace_p.h"
#include "qdeclarativegeoserviceprovider_p.h"
#include "qdeclarativeplaceuser_p.h"
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplacecontentmodel.h b/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h
index d839b92d..05b559ae 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplacecontentmodel.h
+++ b/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h
@@ -37,6 +37,18 @@
#ifndef QDECLARATIVEPLACECONTENTMODEL_H
#define QDECLARATIVEPLACECONTENTMODEL_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
#include <QtCore/QAbstractListModel>
#include <QtQml/QQmlParserStatus>
#include <QtLocation/QPlaceContent>
@@ -50,7 +62,7 @@ class QGeoServiceProvider;
class QDeclarativeSupplier;
class QDeclarativePlaceUser;
-class QDeclarativePlaceContentModel : public QAbstractListModel, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceContentModel : public QAbstractListModel, public QQmlParserStatus
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp
index ebde46c0..dbc23737 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp
+++ b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp
@@ -34,7 +34,7 @@
**
****************************************************************************/
-#include "qdeclarativeplaceeditorialmodel.h"
+#include "qdeclarativeplaceeditorialmodel_p.h"
#include <QtCore/QUrl>
#include <QtLocation/QPlaceEditorial>
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplaceeditorialmodel.h b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel_p.h
index eb2faf66..b00e2af3 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplaceeditorialmodel.h
+++ b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel_p.h
@@ -37,11 +37,23 @@
#ifndef QDECLARATIVEPLACEEDITORIALMODEL_H
#define QDECLARATIVEPLACEEDITORIALMODEL_H
-#include "qdeclarativeplacecontentmodel.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/qdeclarativeplacecontentmodel_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativePlaceEditorialModel : public QDeclarativePlaceContentModel
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceEditorialModel : public QDeclarativePlaceContentModel
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplaceicon.cpp b/src/location/declarativeplaces/qdeclarativeplaceicon.cpp
index 1d3fb2c1..24891138 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplaceicon.cpp
+++ b/src/location/declarativeplaces/qdeclarativeplaceicon.cpp
@@ -42,7 +42,7 @@
#include <QtQml/QQmlInfo>
#include <QCoreApplication>
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
/*!
\qmltype Icon
@@ -246,3 +246,5 @@ void QDeclarativePlaceIcon::initParameters(const QVariantMap &parameterMap)
m_parameters->insert(key, value);
}
}
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplaceicon_p.h b/src/location/declarativeplaces/qdeclarativeplaceicon_p.h
index 23acb36e..535d98eb 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplaceicon_p.h
+++ b/src/location/declarativeplaces/qdeclarativeplaceicon_p.h
@@ -48,9 +48,10 @@
// We mean it.
//
-#include "qdeclarativegeoserviceprovider_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
-#include <qplaceicon.h>
+#include <QtLocation/qplaceicon.h>
#include <QtQml/qqml.h>
#include <QtQml/QQmlPropertyMap>
@@ -60,7 +61,7 @@ QT_BEGIN_NAMESPACE
class QQmlPropertyMap;
-class QDeclarativePlaceIcon : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceIcon : public QObject
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp b/src/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp
index 4da37081..4da37081 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp
+++ b/src/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h b/src/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h
index 8f8f3f4e..2c244219 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h
+++ b/src/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h
@@ -48,13 +48,14 @@
// We mean it.
//
-#include "qdeclarativeplacecontentmodel.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativeplacecontentmodel_p.h>
QT_BEGIN_NAMESPACE
class QDeclarativeSupplier;
-class QDeclarativePlaceImageModel : public QDeclarativePlaceContentModel
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceImageModel : public QDeclarativePlaceContentModel
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplaceuser.cpp b/src/location/declarativeplaces/qdeclarativeplaceuser.cpp
index d8bae3fe..86901a98 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplaceuser.cpp
+++ b/src/location/declarativeplaces/qdeclarativeplaceuser.cpp
@@ -36,7 +36,7 @@
#include "qdeclarativeplaceuser_p.h"
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
/*!
\qmltype User
@@ -136,3 +136,4 @@ QString QDeclarativePlaceUser::name() const
return m_user.name();
}
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativeplaceuser_p.h b/src/location/declarativeplaces/qdeclarativeplaceuser_p.h
index 6c6ececf..8cd64493 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeplaceuser_p.h
+++ b/src/location/declarativeplaces/qdeclarativeplaceuser_p.h
@@ -48,13 +48,14 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
#include <QtCore/QObject>
#include <QtQml/qqml.h>
#include <QtLocation/QPlaceUser>
QT_BEGIN_NAMESPACE
-class QDeclarativePlaceUser : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceUser : public QObject
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativeratings.cpp b/src/location/declarativeplaces/qdeclarativeratings.cpp
index ff044124..150e5966 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeratings.cpp
+++ b/src/location/declarativeplaces/qdeclarativeratings.cpp
@@ -36,7 +36,7 @@
#include "qdeclarativeratings_p.h"
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
/*!
\qmltype Ratings
@@ -150,3 +150,4 @@ int QDeclarativeRatings::count() const
return m_ratings.count();
}
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativeratings_p.h b/src/location/declarativeplaces/qdeclarativeratings_p.h
index 7583e703..5ee530dc 100644
--- a/src/imports/location/declarativeplaces/qdeclarativeratings_p.h
+++ b/src/location/declarativeplaces/qdeclarativeratings_p.h
@@ -48,14 +48,15 @@
// We mean it.
//
-#include <qplaceratings.h>
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/qplaceratings.h>
#include <QtQml/qqml.h>
#include <QObject>
QT_BEGIN_NAMESPACE
-class QDeclarativeRatings : public QObject
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRatings : public QObject
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativereviewmodel.cpp b/src/location/declarativeplaces/qdeclarativereviewmodel.cpp
index b7237bc9..b7237bc9 100644
--- a/src/imports/location/declarativeplaces/qdeclarativereviewmodel.cpp
+++ b/src/location/declarativeplaces/qdeclarativereviewmodel.cpp
diff --git a/src/imports/location/declarativeplaces/qdeclarativereviewmodel_p.h b/src/location/declarativeplaces/qdeclarativereviewmodel_p.h
index 06bf7aa8..e6d2bd95 100644
--- a/src/imports/location/declarativeplaces/qdeclarativereviewmodel_p.h
+++ b/src/location/declarativeplaces/qdeclarativereviewmodel_p.h
@@ -48,11 +48,12 @@
// We mean it.
//
-#include "qdeclarativeplacecontentmodel.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativeplacecontentmodel_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeReviewModel : public QDeclarativePlaceContentModel
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeReviewModel : public QDeclarativePlaceContentModel
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativesearchmodelbase.cpp b/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp
index acfb54df..3a3faa56 100644
--- a/src/imports/location/declarativeplaces/qdeclarativesearchmodelbase.cpp
+++ b/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp
@@ -34,7 +34,7 @@
**
****************************************************************************/
-#include "qdeclarativesearchmodelbase.h"
+#include "qdeclarativesearchmodelbase_p.h"
#include "qdeclarativeplace_p.h"
#include "error_messages.h"
@@ -46,6 +46,8 @@
#include <QtLocation/QPlaceSearchReply>
#include <QtPositioning/QGeoCircle>
+QT_BEGIN_NAMESPACE
+
QDeclarativeSearchModelBase::QDeclarativeSearchModelBase(QObject *parent)
: QAbstractListModel(parent), m_plugin(0), m_reply(0), m_complete(false), m_status(Null)
{
@@ -356,3 +358,5 @@ void QDeclarativeSearchModelBase::setNextPageRequest(const QPlaceSearchRequest &
m_nextPageRequest = next;
emit nextPagesAvailableChanged();
}
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativesearchmodelbase.h b/src/location/declarativeplaces/qdeclarativesearchmodelbase_p.h
index 45470458..2bf1aab5 100644
--- a/src/imports/location/declarativeplaces/qdeclarativesearchmodelbase.h
+++ b/src/location/declarativeplaces/qdeclarativesearchmodelbase_p.h
@@ -37,14 +37,25 @@
#ifndef QDECLARATIVESEARCHMODELBASE_H
#define QDECLARATIVESEARCHMODELBASE_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/qdeclarativegeoserviceprovider_p.h>
#include <QtCore/QAbstractListModel>
#include <QtQml/QQmlParserStatus>
#include <QtLocation/QPlaceSearchRequest>
#include <QtLocation/QPlaceSearchResult>
#include <QtLocation/QPlaceReply>
-#include "qdeclarativegeoserviceprovider_p.h"
-
QT_BEGIN_NAMESPACE
class QPlaceManager;
@@ -52,7 +63,7 @@ class QPlaceSearchRequest;
class QPlaceSearchReply;
class QDeclarativePlace;
-class QDeclarativeSearchModelBase : public QAbstractListModel, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSearchModelBase : public QAbstractListModel, public QQmlParserStatus
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativesearchresultmodel.cpp b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp
index 3c7c2610..31d152db 100644
--- a/src/imports/location/declarativeplaces/qdeclarativesearchresultmodel.cpp
+++ b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp
@@ -48,7 +48,7 @@
#include <QtLocation/QPlaceResult>
#include <QtLocation/QPlaceProposedSearchResult>
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
/*!
\qmltype PlaceSearchModel
@@ -777,7 +777,7 @@ void QDeclarativeSearchResultModel::queryFinished()
}
QVariantMap params;
- params.insert(QPlaceMatchRequest::AlternativeId, QString::fromLatin1("x_id_") + m_plugin->name());
+ params.insert(QPlaceMatchRequest::AlternativeId, QVariant(QString::fromLatin1("x_id_") + m_plugin->name()));
request.setParameters(params);
} else {
request.setParameters(m_matchParameters);
@@ -914,3 +914,4 @@ int QDeclarativeSearchResultModel::getRow(const QString &placeId) const
The corresponding handler is \c onDataChanged.
*/
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativesearchresultmodel_p.h b/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h
index 73bf16d3..77526fd0 100644
--- a/src/imports/location/declarativeplaces/qdeclarativesearchresultmodel_p.h
+++ b/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h
@@ -48,16 +48,17 @@
// We mean it.
//
-#include "qdeclarativesearchmodelbase.h"
-#include "qdeclarativecategory_p.h"
-#include "qdeclarativeplace_p.h"
-#include "qdeclarativeplaceicon_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativesearchmodelbase_p.h>
+#include <QtLocation/private/qdeclarativecategory_p.h>
+#include <QtLocation/private/qdeclarativeplace_p.h>
+#include <QtLocation/private/qdeclarativeplaceicon_p.h>
QT_BEGIN_NAMESPACE
class QDeclarativeGeoServiceProvider;
-class QDeclarativeSearchResultModel : public QDeclarativeSearchModelBase
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSearchResultModel : public QDeclarativeSearchModelBase
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp
index abc845f2..95cd3277 100644
--- a/src/imports/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp
+++ b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp
@@ -43,7 +43,7 @@
#include <qplacemanager.h>
#include <qplacesearchrequest.h>
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
/*!
\qmltype PlaceSearchSuggestionModel
@@ -349,3 +349,5 @@ QPlaceReply *QDeclarativeSearchSuggestionModel::sendQuery(QPlaceManager *manager
{
return manager->searchSuggestions(request);
}
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h
index 49e09980..5d75ee4b 100644
--- a/src/imports/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h
+++ b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h
@@ -48,7 +48,8 @@
// We mean it.
//
-#include "qdeclarativesearchmodelbase.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativesearchmodelbase_p.h>
#include <QtCore/QStringList>
@@ -57,7 +58,7 @@ QT_BEGIN_NAMESPACE
class QDeclarativeGeoServiceProvider;
class QGeoServiceProvider;
-class QDeclarativeSearchSuggestionModel : public QDeclarativeSearchModelBase
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSearchSuggestionModel : public QDeclarativeSearchModelBase
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativesupplier.cpp b/src/location/declarativeplaces/qdeclarativesupplier.cpp
index 8fca9e8c..92e9a8fd 100644
--- a/src/imports/location/declarativeplaces/qdeclarativesupplier.cpp
+++ b/src/location/declarativeplaces/qdeclarativesupplier.cpp
@@ -38,7 +38,7 @@
#include <QtCore/QUrl>
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
/*!
\qmltype Supplier
@@ -217,3 +217,5 @@ void QDeclarativeSupplier::setIcon(QDeclarativePlaceIcon *icon)
m_icon = icon;
emit iconChanged();
}
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativesupplier_p.h b/src/location/declarativeplaces/qdeclarativesupplier_p.h
index 35b1dbda..b344d674 100644
--- a/src/imports/location/declarativeplaces/qdeclarativesupplier_p.h
+++ b/src/location/declarativeplaces/qdeclarativesupplier_p.h
@@ -48,17 +48,18 @@
// We mean it.
//
+#include <QtLocation/private/qlocationglobal_p.h>
#include <QObject>
#include <QtCore/QUrl>
#include <QtQml/qqml.h>
#include <QtQml/QQmlParserStatus>
-#include <qplacesupplier.h>
+#include <QtLocation/qplacesupplier.h>
-#include "qdeclarativeplaceicon_p.h"
+#include <QtLocation/private/qdeclarativeplaceicon_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeSupplier : public QObject, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSupplier : public QObject, public QQmlParserStatus
{
Q_OBJECT
diff --git a/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp
index 2865957b..d832ff40 100644
--- a/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp
+++ b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp
@@ -45,7 +45,7 @@
#include <QtLocation/QPlaceManager>
#include <QtLocation/QPlaceIcon>
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
/*!
\qmltype CategoryModel
@@ -685,3 +685,5 @@ int QDeclarativeSupportedCategoriesModel::rowToAddChild(PlaceCategoryNode *node,
The corresponding handler is \c onDataChanged.
*/
+
+QT_END_NAMESPACE
diff --git a/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h
index 98167892..9f17ab4d 100644
--- a/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h
+++ b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h
@@ -48,7 +48,8 @@
// We mean it.
//
-#include <qdeclarativegeoserviceprovider_p.h>
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
#include <QObject>
#include <QtCore/QStringList>
@@ -59,7 +60,7 @@
#include <QtLocation/QPlaceCategory>
-#include "qdeclarativecategory_p.h"
+#include <QtLocation/private/qdeclarativecategory_p.h>
QT_BEGIN_NAMESPACE
@@ -75,7 +76,7 @@ public:
QSharedPointer<QDeclarativeCategory> declCategory;
};
-class QDeclarativeSupportedCategoriesModel : public QAbstractItemModel, public QQmlParserStatus
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSupportedCategoriesModel : public QAbstractItemModel, public QQmlParserStatus
{
Q_OBJECT
diff --git a/src/location/doc/images/api-mapitemgroup.png b/src/location/doc/images/api-mapitemgroup.png
new file mode 100644
index 00000000..4dbdfe65
--- /dev/null
+++ b/src/location/doc/images/api-mapitemgroup.png
Binary files differ
diff --git a/src/location/doc/src/plugins/mapboxgl.qdoc b/src/location/doc/src/plugins/mapboxgl.qdoc
new file mode 100644
index 00000000..ad71fc2c
--- /dev/null
+++ b/src/location/doc/src/plugins/mapboxgl.qdoc
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2017 Mapbox, Inc.
+** Copyright (C) 2014 Canonical Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page location-plugin-mapboxgl.html
+\title Qt Location Mapbox GL Plugin
+\ingroup QtLocation-plugins
+
+\brief Uses Mapbox GL for location services.
+
+\section1 Overview
+
+This geo services plugin allows applications to access
+\l {http://mapbox.com}{Mapbox} mapping services using the Qt Location API.
+The use of these services is governed by the \l {https://www.mapbox.com/tos}{Mapbox terms of service}.
+
+This plugin differs from the \l {http://doc.qt.io/qt-5/location-plugin-mapbox.html}{Mapbox} plugin because it uses
+the \l {https://github.com/mapbox/mapbox-gl-native/} {Mapbox GL map engine} for rendering both raster tiles and \l
+{https://www.mapbox.com/vector-tiles} {vector tiles} in real-time. The benefits are: text staying upright, font
+antialiasing, labels flowing between zoom levels, smooth pan, tilt, rotation and continuous zoom.
+
+The appearance and behavior of vector maps can be customized by creating custom map styles. This can be
+done with tools like \l {https://www.mapbox.com/studio} {Mapbox Studio}.
+
+The Mapbox GL geo services plugin can be loaded by using the plugin key "mapboxgl".
+
+Both Mapbox geo services plugins require an access token to access map styles
+and tiles hosted by Mapbox. To create a Mapbox account visit \l{https://www.mapbox.com/pricing}.
+
+\section2 Optional parameters
+
+The following table lists optional parameters that can be passed to the Mapbox plugin.
+
+\table
+\header
+ \li Parameter
+ \li Description
+\row
+ \li mapboxgl.access_token
+ \li \l{https://www.mapbox.com/help/define-access-token}{Access token} provided by Mapbox.
+\row
+ \li mapboxgl.mapping.additional_style_urls
+ \li Additional, comma separated, Mapbox \l{https://www.mapbox.com/help/define-style-url}
+ {style URLs} to be added to the available style URLs. Additional styles will be prepended to
+ the \l[QML]{QtLocation::Map::}{supportedMapTypes} property of the \l{QtLocation::Map}{Map} item.
+\row
+ \li mapboxgl.mapping.cache.directory
+ \li Absolute path to map tile cache directory used as network disk cache.
+
+ The default place for the cache is \c{QtLocation/mapboxgl} directory in \l {QStandardPaths::writableLocation()}
+ {QStandardPaths::writableLocation}(\l{QStandardPaths::GenericCacheLocation}). On systems that have no concept
+ of a shared cache, the application-specific \l{QStandardPaths::CacheLocation} is used instead.
+
+ This is an \l {https://www.mapbox.com/help/mobile-offline/#ambient-caching} {ambient cache}, meaning it will
+ get populated on the fly until it reaches the size limit, and when that happens, it will evict the least used
+ tiles.
+
+ This cache can also be used for storing \l {https://www.mapbox.com/help/mobile-offline}{offline tiles},
+ but the offline database must be populated using the \l {https://github.com/mapbox/mapbox-gl-native/blob/master/bin/offline.cpp}
+ {offline tool}. The offline database will work alongside with the ambient cache in the same file.
+ Make sure to comply with Mapbox Terms of Service before creating an offline database.
+\row
+ \li mapboxgl.mapping.cache.memory
+ \li Whether or not the cache should be in-memory only. Valid values are \b true and \b false. The default
+ value is \b false. When set to \b true, the disk cache is never created. The ambient cache will work in-memory,
+ but the offline database cannot be used with this option enabled.
+\row
+ \li mapboxgl.mapping.cache.size
+ \li Cache size for map resources in bytes.
+ The default size of this cache is 50 MiB.
+ Make sure to comply with Mapbox Terms of Service before increasing this value.
+*/
diff --git a/src/location/doc/src/plugins/osm.qdoc b/src/location/doc/src/plugins/osm.qdoc
index bb520601..2b27724d 100644
--- a/src/location/doc/src/plugins/osm.qdoc
+++ b/src/location/doc/src/plugins/osm.qdoc
@@ -125,7 +125,8 @@ a prefix.
\li osm.mapping.cache.directory
\li Absolute path to map tile cache directory used as network disk cache.
- The default place for the cache is \c{QtLocation/osm} directory in \l {QStandardPaths::writableLocation()} {QStandardPaths::writableLocation}(\l{QStandardPaths::GenericCacheLocation}).
+ The default place for the cache is the \c{QtLocation/osm} subdirectory in the location returned by
+ QStandardPaths::writableLocation(), called with QStandardPaths::GenericCacheLocation as a parameter.
On systems that have no concept of a shared cache, the application-specific \l{QStandardPaths::CacheLocation} is used instead.
\row
\li osm.mapping.offline.directory
diff --git a/src/location/location.pro b/src/location/location.pro
index 225df556..b43d626a 100644
--- a/src/location/location.pro
+++ b/src/location/location.pro
@@ -1,11 +1,19 @@
TARGET = QtLocation
QT = core-private positioning-private
-
android {
# adding qtconcurrent dependency here for the osm plugin
QT += concurrent
}
+CONFIG += simd optimize_full
+
+INCLUDEPATH += ../3rdparty/poly2tri
+INCLUDEPATH += ../3rdparty/clipper
+INCLUDEPATH += ../3rdparty/clip2tri
+INCLUDEPATH += ../positioning
+INCLUDEPATH += ../imports/positioning
+INCLUDEPATH *= $$PWD
+
MODULE_PLUGIN_TYPES = \
geoservices
@@ -14,6 +22,7 @@ OTHER_FILES += doc/src/*.qdoc # show .qdoc files in Qt Creator
PUBLIC_HEADERS += \
qlocation.h \
+ qlocationglobal_p.h \
qlocationglobal.h
PRIVATE_HEADERS += \
@@ -24,7 +33,11 @@ SOURCES += \
include(maps/maps.pri)
include(places/places.pri)
+include(declarativemaps/declarativemaps.pri)
+include(declarativeplaces/declarativeplaces.pri)
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
load(qt_module)
+
+LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lclip2tri$$qtPlatformTargetSuffix()
diff --git a/src/location/maps/qgeocameracapabilities.cpp b/src/location/maps/qgeocameracapabilities.cpp
index 97ff5790..568476fd 100644
--- a/src/location/maps/qgeocameracapabilities.cpp
+++ b/src/location/maps/qgeocameracapabilities.cpp
@@ -62,6 +62,7 @@ public:
bool supportsTilting_;
// this is mutable so that it can be set from accessor functions that are const
+ // TODO: remove the mutable here
mutable bool valid_;
double minZoom_;
@@ -69,6 +70,8 @@ public:
double minTilt_;
double maxTilt_;
int tileSize_;
+ double minimumFieldOfView_;
+ double maximumFieldOfView_;
};
QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate()
@@ -80,7 +83,9 @@ QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate()
maxZoom_(0.0),
minTilt_(0.0),
maxTilt_(0.0),
- tileSize_(256) {}
+ tileSize_(256),
+ minimumFieldOfView_(45.0), // Defaulting to a fixed FOV of 45 degrees. Too large FOVs cause the loading of too many tiles
+ maximumFieldOfView_(45.0) {}
QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate(const QGeoCameraCapabilitiesPrivate &other)
@@ -93,7 +98,10 @@ QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate(const QGeoCameraCap
maxZoom_(other.maxZoom_),
minTilt_(other.minTilt_),
maxTilt_(other.maxTilt_),
- tileSize_(other.tileSize_) {}
+ tileSize_(other.tileSize_),
+ minimumFieldOfView_(other.minimumFieldOfView_),
+ maximumFieldOfView_(other.maximumFieldOfView_) {}
+
QGeoCameraCapabilitiesPrivate::~QGeoCameraCapabilitiesPrivate() {}
@@ -111,6 +119,8 @@ QGeoCameraCapabilitiesPrivate &QGeoCameraCapabilitiesPrivate::operator = (const
minTilt_ = other.minTilt_;
maxTilt_ = other.maxTilt_;
tileSize_ = other.tileSize_;
+ minimumFieldOfView_ = other.minimumFieldOfView_;
+ maximumFieldOfView_ = other.maximumFieldOfView_;
return *this;
}
@@ -347,4 +357,51 @@ double QGeoCameraCapabilities::maximumTilt() const
return d->maxTilt_;
}
+/*!
+ Sets the minimum field of view supported by the associated plugin to \a minimumFieldOfView.
+ The value is in degrees and is clamped against a [1, 179] range.
+
+ \since 5.9
+*/
+void QGeoCameraCapabilities::setMinimumFieldOfView(double minimumFieldOfView)
+{
+ d->minimumFieldOfView_ = qBound(1.0, minimumFieldOfView, 179.0);
+ d->valid_ = true;
+}
+
+/*!
+ Returns the minimum field of view supported by the associated plugin.
+ The value is in degrees.
+
+ \since 5.9
+*/
+double QGeoCameraCapabilities::minimumFieldOfView() const
+{
+ return d->minimumFieldOfView_;
+}
+
+/*!
+ Sets the maximum field of view supported by the associated plugin to \a maximumFieldOfView.
+ The value is in degrees and is clamped against a [1, 179] range.
+
+ \since 5.9
+*/
+void QGeoCameraCapabilities::setMaximumFieldOfView(double maximumFieldOfView)
+{
+ d->maximumFieldOfView_ = maximumFieldOfView;
+ d->valid_ = true;
+}
+
+/*!
+ Returns the maximum field of view supported by the associated plugin.
+ The value is in degrees.
+
+ \since 5.9
+*/
+double QGeoCameraCapabilities::maximumFieldOfView() const
+{
+ return d->maximumFieldOfView_;
+}
+
+
QT_END_NAMESPACE
diff --git a/src/location/maps/qgeocameracapabilities_p.h b/src/location/maps/qgeocameracapabilities_p.h
index 7de6ece0..c9da53e9 100644
--- a/src/location/maps/qgeocameracapabilities_p.h
+++ b/src/location/maps/qgeocameracapabilities_p.h
@@ -91,6 +91,12 @@ public:
void setMaximumTilt(double maximumTilt);
double maximumTilt() const;
+ void setMinimumFieldOfView(double minimumFieldOfView);
+ double minimumFieldOfView() const;
+
+ void setMaximumFieldOfView(double maximumFieldOfView);
+ double maximumFieldOfView() const;
+
bool isValid() const;
private:
diff --git a/src/location/maps/qgeocameradata.cpp b/src/location/maps/qgeocameradata.cpp
index 909145fe..ecf7d46a 100644
--- a/src/location/maps/qgeocameradata.cpp
+++ b/src/location/maps/qgeocameradata.cpp
@@ -55,6 +55,7 @@ public:
double m_bearing;
double m_tilt;
double m_roll;
+ double m_fieldOfView;
double m_zoomLevel;
};
@@ -64,6 +65,7 @@ QGeoCameraDataPrivate::QGeoCameraDataPrivate()
m_bearing(0.0),
m_tilt(0.0),
m_roll(0.0),
+ m_fieldOfView(45.0),
m_zoomLevel(0.0) {}
QGeoCameraDataPrivate::QGeoCameraDataPrivate(const QGeoCameraDataPrivate &rhs)
@@ -72,6 +74,7 @@ QGeoCameraDataPrivate::QGeoCameraDataPrivate(const QGeoCameraDataPrivate &rhs)
m_bearing(rhs.m_bearing),
m_tilt(rhs.m_tilt),
m_roll(rhs.m_roll),
+ m_fieldOfView(rhs.m_fieldOfView),
m_zoomLevel(rhs.m_zoomLevel) {}
QGeoCameraDataPrivate &QGeoCameraDataPrivate::operator = (const QGeoCameraDataPrivate &rhs)
@@ -83,6 +86,7 @@ QGeoCameraDataPrivate &QGeoCameraDataPrivate::operator = (const QGeoCameraDataPr
m_bearing = rhs.m_bearing;
m_tilt = rhs.m_tilt;
m_roll = rhs.m_roll;
+ m_fieldOfView = rhs.m_fieldOfView;
m_zoomLevel = rhs.m_zoomLevel;
return *this;
@@ -94,6 +98,7 @@ bool QGeoCameraDataPrivate::operator == (const QGeoCameraDataPrivate &rhs) const
&& (m_bearing == rhs.m_bearing)
&& (m_tilt == rhs.m_tilt)
&& (m_roll == rhs.m_roll)
+ && (m_fieldOfView == rhs.m_fieldOfView)
&& (m_zoomLevel == rhs.m_zoomLevel));
}
@@ -123,6 +128,7 @@ QVariant cameraInterpolator(const QGeoCameraData &start,
result.setBearing(sf * start.bearing() + ef * end.bearing());
result.setTilt(sf * start.tilt() + ef * end.tilt());
result.setRoll(sf * start.roll() + ef * end.roll());
+ result.setFieldOfView(sf * start.fieldOfView() + ef * end.fieldOfView());
result.setZoomLevel(sf * start.zoomLevel() + ef * end.zoomLevel());
return QVariant::fromValue(result);
@@ -201,6 +207,16 @@ double QGeoCameraData::roll() const
return d->m_roll;
}
+void QGeoCameraData::setFieldOfView(double fieldOfView)
+{
+ d->m_fieldOfView = fieldOfView;
+}
+
+double QGeoCameraData::fieldOfView() const
+{
+ return d->m_fieldOfView;
+}
+
void QGeoCameraData::setZoomLevel(double zoomFactor)
{
d->m_zoomLevel = zoomFactor;
diff --git a/src/location/maps/qgeocameradata_p.h b/src/location/maps/qgeocameradata_p.h
index c245fbfd..4912ec3e 100644
--- a/src/location/maps/qgeocameradata_p.h
+++ b/src/location/maps/qgeocameradata_p.h
@@ -82,6 +82,9 @@ public:
void setRoll(double roll);
double roll() const;
+ void setFieldOfView(double fieldOfView);
+ double fieldOfView() const;
+
// Zoom level is intended to be relative to a tileSize of 256^2 pixels.
// E.g., a zoom level of 0 must result in a mapWidth of 256, and so on.
void setZoomLevel(double zoomLevel);
diff --git a/src/location/maps/qgeocameratiles.cpp b/src/location/maps/qgeocameratiles.cpp
index 0eaa4668..27044ee0 100644
--- a/src/location/maps/qgeocameratiles.cpp
+++ b/src/location/maps/qgeocameratiles.cpp
@@ -41,12 +41,25 @@
#include <QtPositioning/private/qwebmercator_p.h>
#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QtPositioning/private/qdoublevector3d_p.h>
+#include <QtPositioning/private/qlocationutils_p.h>
+#include <QtGui/QMatrix4x4>
#include <QVector>
#include <QMap>
#include <QPair>
#include <QSet>
#include <QSize>
#include <cmath>
+#include <limits>
+
+static QVector3D toVector3D(const QDoubleVector3D& in)
+{
+ return QVector3D(in.x(), in.y(), in.z());
+}
+
+static QDoubleVector3D toDoubleVector3D(const QVector3D& in)
+{
+ return QDoubleVector3D(in.x(), in.y(), in.z());
+}
QT_BEGIN_NAMESPACE
@@ -88,7 +101,7 @@ public:
void updateMetadata();
void updateGeometry();
- Frustum createFrustum(double fieldOfViewGradient) const;
+ Frustum createFrustum(double viewExpansion) const;
class LengthSorter
{
@@ -100,11 +113,21 @@ public:
}
};
+ struct ClippedFootprint
+ {
+ ClippedFootprint(const PolygonVector &left_, const PolygonVector &mid_, const PolygonVector &right_)
+ : left(left_), mid(mid_), right(right_)
+ {}
+ PolygonVector left;
+ PolygonVector mid;
+ PolygonVector right;
+ };
+
void appendZIntersects(const QDoubleVector3D &start, const QDoubleVector3D &end, double z, QVector<QDoubleVector3D> &results) const;
PolygonVector frustumFootprint(const Frustum &frustum) const;
QPair<PolygonVector, PolygonVector> splitPolygonAtAxisValue(const PolygonVector &polygon, int axis, double value) const;
- QPair<PolygonVector, PolygonVector> clipFootprintToMap(const PolygonVector &footprint) const;
+ ClippedFootprint clipFootprintToMap(const PolygonVector &footprint) const;
QList<QPair<double, int> > tileIntersections(double p1, int t1, double p2, int t2) const;
QSet<QGeoTileSpec> tilesFromPolygon(const PolygonVector &polygon) const;
@@ -259,29 +282,36 @@ void QGeoCameraTilesPrivate::updateGeometry()
PolygonVector footprint = frustumFootprint(f);
// Clip the polygon to the map, split it up if it cross the dateline
- QPair<PolygonVector, PolygonVector> polygons = clipFootprintToMap(footprint);
+ ClippedFootprint polygons = clipFootprintToMap(footprint);
- if (!polygons.first.isEmpty()) {
- QSet<QGeoTileSpec> tilesLeft = tilesFromPolygon(polygons.first);
+ if (!polygons.left.isEmpty()) {
+ QSet<QGeoTileSpec> tilesLeft = tilesFromPolygon(polygons.left);
m_tiles.unite(tilesLeft);
}
- if (!polygons.second.isEmpty()) {
- QSet<QGeoTileSpec> tilesRight = tilesFromPolygon(polygons.second);
+ if (!polygons.right.isEmpty()) {
+ QSet<QGeoTileSpec> tilesRight = tilesFromPolygon(polygons.right);
+ m_tiles.unite(tilesRight);
+ }
+
+ if (!polygons.mid.isEmpty()) {
+ QSet<QGeoTileSpec> tilesRight = tilesFromPolygon(polygons.mid);
m_tiles.unite(tilesRight);
}
}
-Frustum QGeoCameraTilesPrivate::createFrustum(double fieldOfViewGradient) const
+Frustum QGeoCameraTilesPrivate::createFrustum(double viewExpansion) const
{
+ double apertureSize = 1.0;
+ if (m_camera.fieldOfView() != 90.0) //aperture(90 / 2) = 1
+ apertureSize = tan(QLocationUtils::radians(m_camera.fieldOfView()) * 0.5);
QDoubleVector3D center = m_sideLength * QWebMercator::coordToMercator(m_camera.center());
- center.setZ(0.0);
double f = qMin(m_screenSize.width(), m_screenSize.height());
- double z = std::pow(2.0, m_camera.zoomLevel() - m_intZoomLevel) * m_tileSize;
+ double z = std::pow(2.0, m_camera.zoomLevel() - m_intZoomLevel) * m_tileSize; // between 1 and 2 * m_tileSize
- double altitude = f / (2.0 * z);
+ double altitude = (f / (2.0 * z)) / apertureSize;
QDoubleVector3D eye = center;
eye.setZ(altitude);
@@ -289,28 +319,48 @@ Frustum QGeoCameraTilesPrivate::createFrustum(double fieldOfViewGradient) const
QDoubleVector3D side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
QDoubleVector3D up = QDoubleVector3D::normal(side, view);
+ QMatrix4x4 mBearing;
+ // The rotation direction here is the opposite of QGeoTiledMapScene::setupCamera,
+ // as this is basically rotating the map against a fixed view frustum.
+ mBearing.rotate(1.0 * m_camera.bearing(), toVector3D(view));
+ up = toDoubleVector3D(mBearing * toVector3D(up));
+
+ // same for tilting
+ QDoubleVector3D side2 = QDoubleVector3D::normal(up, view);
+ QMatrix4x4 mTilt;
+ mTilt.rotate(-1.0 * m_camera.tilt(), toVector3D(side2));
+ eye = toDoubleVector3D((mTilt * toVector3D(view)) + toVector3D(center));
+
+ view = eye - center;
+ side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
+ up = QDoubleVector3D::normal(view, side2);
+
double nearPlane = 1 / (4.0 * m_tileSize );
- double farPlane = altitude + 1.0;
+ // farPlane plays a role on how much gets clipped when the map gets tilted. It used to be altitude + 1.0
+ // The value of 8.0 has been chosen as an acceptable compromise.
+ // TODO: use m_camera.clipDistance(); when this will be introduced
+ double farPlane = altitude + 8.0;
double aspectRatio = 1.0 * m_screenSize.width() / m_screenSize.height();
- double hn,wn,hf,wf = 0.0;
-
- // fixes field of view at 45 degrees
- // this assumes that viewSize = 2*nearPlane x 2*nearPlane
+ // Half values. Half width near, far, height near, far.
+ double hhn,hwn,hhf,hwf = 0.0;
+ // This used to fix the (half) field of view at 45 degrees
+ // half because this assumed that viewSize = 2*nearPlane x 2*nearPlane
+ viewExpansion *= apertureSize;
if (aspectRatio > 1.0) {
- hn = 2 * fieldOfViewGradient * nearPlane;
- wn = hn * aspectRatio;
+ hhn = viewExpansion * nearPlane;
+ hwn = hhn * aspectRatio;
- hf = 2 * fieldOfViewGradient * farPlane;
- wf = hf * aspectRatio;
+ hhf = viewExpansion * farPlane;
+ hwf = hhf * aspectRatio;
} else {
- wn = 2 * fieldOfViewGradient * nearPlane;
- hn = wn / aspectRatio;
+ hwn = viewExpansion * nearPlane;
+ hhn = hwn / aspectRatio;
- wf = 2 * fieldOfViewGradient * farPlane;
- hf = wf / aspectRatio;
+ hwf = viewExpansion * farPlane;
+ hhf = hwf / aspectRatio;
}
QDoubleVector3D d = center - eye;
@@ -323,15 +373,15 @@ Frustum QGeoCameraTilesPrivate::createFrustum(double fieldOfViewGradient) const
Frustum frustum;
- frustum.topLeftFar = cf + (up * hf / 2) - (right * wf / 2);
- frustum.topRightFar = cf + (up * hf / 2) + (right * wf / 2);
- frustum.bottomLeftFar = cf - (up * hf / 2) - (right * wf / 2);
- frustum.bottomRightFar = cf - (up * hf / 2) + (right * wf / 2);
+ frustum.topLeftFar = cf + (up * hhf) - (right * hwf);
+ frustum.topRightFar = cf + (up * hhf) + (right * hwf);
+ frustum.bottomLeftFar = cf - (up * hhf) - (right * hwf);
+ frustum.bottomRightFar = cf - (up * hhf) + (right * hwf);
- frustum.topLeftNear = cn + (up * hn / 2) - (right * wn / 2);
- frustum.topRightNear = cn + (up * hn / 2) + (right * wn / 2);
- frustum.bottomLeftNear = cn - (up * hn / 2) - (right * wn / 2);
- frustum.bottomRightNear = cn - (up * hn / 2) + (right * wn / 2);
+ frustum.topLeftNear = cn + (up * hhn) - (right * hwn);
+ frustum.topRightNear = cn + (up * hhn) + (right * hwn);
+ frustum.bottomLeftNear = cn - (up * hhn) - (right * hwn);
+ frustum.bottomRightNear = cn - (up * hhn) + (right * hwn);
return frustum;
}
@@ -579,8 +629,13 @@ QPair<PolygonVector, PolygonVector> QGeoCameraTilesPrivate::splitPolygonAtAxisVa
return QPair<PolygonVector, PolygonVector>(polygonBelow, polygonAbove);
}
+static void addXOffset(PolygonVector &footprint, double xoff)
+{
+ for (QDoubleVector3D &v: footprint)
+ v.setX(v.x() + xoff);
+}
-QPair<PolygonVector, PolygonVector> QGeoCameraTilesPrivate::clipFootprintToMap(const PolygonVector &footprint) const
+QGeoCameraTilesPrivate::ClippedFootprint QGeoCameraTilesPrivate::clipFootprintToMap(const PolygonVector &footprint) const
{
bool clipX0 = false;
bool clipX1 = false;
@@ -588,20 +643,13 @@ QPair<PolygonVector, PolygonVector> QGeoCameraTilesPrivate::clipFootprintToMap(c
bool clipY1 = false;
double side = 1.0 * m_sideLength;
+ double minX = std::numeric_limits<double>::max();
+ double maxX = std::numeric_limits<double>::lowest();
- typedef PolygonVector::const_iterator const_iter;
-
- const_iter i = footprint.constBegin();
- const_iter end = footprint.constEnd();
- for (; i != end; ++i) {
- QDoubleVector3D p = *i;
- if ((p.x() < 0.0) || (qFuzzyIsNull(p.x())))
- clipX0 = true;
- if ((side < p.x()) || (qFuzzyCompare(side, p.x())))
- clipX1 = true;
+ for (const QDoubleVector3D &p: footprint) {
if (p.y() < 0.0)
clipY0 = true;
- if (side < p.y())
+ if (p.y() > side)
clipY1 = true;
}
@@ -615,11 +663,39 @@ QPair<PolygonVector, PolygonVector> QGeoCameraTilesPrivate::clipFootprintToMap(c
results = splitPolygonAtAxisValue(results, 1, side).first;
}
+ for (const QDoubleVector3D &p: results) {
+ if ((p.x() < 0.0) || (qFuzzyIsNull(p.x())))
+ clipX0 = true;
+ if ((p.x() > side) || (qFuzzyCompare(side, p.x())))
+ clipX1 = true;
+ }
+
+ for (const QDoubleVector3D &v : results) {
+ minX = qMin(v.x(), minX);
+ maxX = qMax(v.x(), maxX);
+ }
+
+ double footprintWidth = maxX - minX;
+
if (clipX0) {
if (clipX1) {
- results = splitPolygonAtAxisValue(results, 0, 0.0).second;
- results = splitPolygonAtAxisValue(results, 0, side).first;
- return QPair<PolygonVector, PolygonVector>(results, PolygonVector());
+ if (footprintWidth > side) {
+ PolygonVector rightPart = splitPolygonAtAxisValue(results, 0, side).second;
+ addXOffset(rightPart, -side);
+ rightPart = splitPolygonAtAxisValue(rightPart, 0, side).first; // clip it again, should it tend to infinite or so
+
+ PolygonVector leftPart = splitPolygonAtAxisValue(results, 0, 0).first;
+ addXOffset(leftPart, side);
+ leftPart = splitPolygonAtAxisValue(leftPart, 0, 0).second; // same here
+
+ results = splitPolygonAtAxisValue(results, 0, 0.0).second;
+ results = splitPolygonAtAxisValue(results, 0, side).first;
+ return ClippedFootprint(leftPart, results, rightPart);
+ } else { // fitting the WebMercator square exactly?
+ results = splitPolygonAtAxisValue(results, 0, 0.0).second;
+ results = splitPolygonAtAxisValue(results, 0, side).first;
+ return ClippedFootprint(PolygonVector(), results, PolygonVector());
+ }
} else {
QPair<PolygonVector, PolygonVector> pair = splitPolygonAtAxisValue(results, 0, 0.0);
if (pair.first.isEmpty()) {
@@ -649,11 +725,11 @@ QPair<PolygonVector, PolygonVector> QGeoCameraTilesPrivate::clipFootprintToMap(c
pair.first.append(QDoubleVector3D(side, y - 0.001, 0.0));
}
} else {
- for (int i = 0; i < pair.first.size(); ++i) {
- pair.first[i].setX(pair.first.at(i).x() + side);
- }
+ addXOffset(pair.first, side);
+ if (footprintWidth > side)
+ pair.first = splitPolygonAtAxisValue(pair.first, 0, 0).second;
}
- return pair;
+ return ClippedFootprint(pair.first, pair.second, PolygonVector());
}
} else {
if (clipX1) {
@@ -685,13 +761,13 @@ QPair<PolygonVector, PolygonVector> QGeoCameraTilesPrivate::clipFootprintToMap(c
pair.second.append(QDoubleVector3D(0.0, y + 0.001, 0.0));
}
} else {
- for (int i = 0; i < pair.second.size(); ++i) {
- pair.second[i].setX(pair.second.at(i).x() - side);
- }
+ addXOffset(pair.second, -side);
+ if (footprintWidth > side)
+ pair.second = splitPolygonAtAxisValue(pair.second, 0, side).first;
}
- return pair;
+ return ClippedFootprint(PolygonVector(), pair.first, pair.second);
} else {
- return QPair<PolygonVector, PolygonVector>(results, PolygonVector());
+ return ClippedFootprint(PolygonVector(), results, PolygonVector());
}
}
diff --git a/src/location/maps/qgeomap.cpp b/src/location/maps/qgeomap.cpp
index 325ca83f..4529cc0a 100644
--- a/src/location/maps/qgeomap.cpp
+++ b/src/location/maps/qgeomap.cpp
@@ -38,6 +38,7 @@
#include "qgeomap_p_p.h"
#include "qgeocameracapabilities_p.h"
#include "qgeomappingmanagerengine_p.h"
+#include "qdeclarativegeomapitembase_p.h"
#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -49,6 +50,7 @@ QGeoMap::QGeoMap(QGeoMapPrivate &dd, QObject *parent)
QGeoMap::~QGeoMap()
{
+ clearParameters();
}
void QGeoMap::setViewportSize(const QSize& size)
@@ -118,10 +120,10 @@ double QGeoMap::minimumZoom() const
return d->m_geoProjection->minimumZoom();
}
-double QGeoMap::maximumCenterLatitudeAtZoom(double zoomLevel) const
+double QGeoMap::maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const
{
Q_D(const QGeoMap);
- return d->m_geoProjection->maximumCenterLatitudeAtZoom(zoomLevel);
+ return d->m_geoProjection->maximumCenterLatitudeAtZoom(cameraData);
}
double QGeoMap::mapWidth() const
@@ -187,6 +189,38 @@ void QGeoMap::clearParameters()
d->m_mapParameters.clear();
}
+QGeoMap::ItemTypes QGeoMap::supportedMapItemTypes() const
+{
+ Q_D(const QGeoMap);
+ return d->supportedMapItemTypes();
+}
+
+void QGeoMap::addMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ Q_D(QGeoMap);
+ if (item && !d->m_mapItems.contains(item) && d->supportedMapItemTypes() & item->itemType()) {
+ d->m_mapItems.insert(item);
+ d->addMapItem(item);
+ }
+}
+
+void QGeoMap::removeMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ Q_D(QGeoMap);
+ if (item && d->m_mapItems.contains(item)) {
+ d->removeMapItem(item);
+ d->m_mapItems.remove(item);
+ }
+}
+
+void QGeoMap::clearMapItems()
+{
+ Q_D(QGeoMap);
+ for (QDeclarativeGeoMapItemBase *p : d->m_mapItems)
+ d->removeMapItem(p);
+ d->m_mapItems.clear();
+}
+
QGeoMapPrivate::QGeoMapPrivate(QGeoMappingManagerEngine *engine, QGeoProjection *geoProjection)
: QObjectPrivate(),
m_geoProjection(geoProjection),
@@ -211,4 +245,19 @@ void QGeoMapPrivate::removeParameter(QGeoMapParameter *param)
Q_UNUSED(param)
}
+QGeoMap::ItemTypes QGeoMapPrivate::supportedMapItemTypes() const
+{
+ return QGeoMap::NoItem;
+}
+
+void QGeoMapPrivate::addMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ Q_UNUSED(item)
+}
+
+void QGeoMapPrivate::removeMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ Q_UNUSED(item)
+}
+
QT_END_NAMESPACE
diff --git a/src/location/maps/qgeomap_p.h b/src/location/maps/qgeomap_p.h
index b5e51014..4838cb4e 100644
--- a/src/location/maps/qgeomap_p.h
+++ b/src/location/maps/qgeomap_p.h
@@ -49,6 +49,7 @@
#include <QtLocation/private/qgeocameradata_p.h>
#include <QtLocation/private/qgeomaptype_p.h>
+#include <QtLocation/private/qgeocameracapabilities_p.h>
#include <QtCore/QObject>
#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QtLocation/private/qgeoprojection_p.h>
@@ -58,11 +59,11 @@ QT_BEGIN_NAMESPACE
class QGeoMappingManagerEngine;
class QGeoMapPrivate;
class QGeoMapController;
-class QGeoCameraCapabilities;
class QGeoCoordinate;
class QSGNode;
class QQuickWindow;
class QGeoMapParameter;
+class QDeclarativeGeoMapItemBase;
class Q_LOCATION_EXPORT QGeoMap : public QObject
{
@@ -70,6 +71,18 @@ class Q_LOCATION_EXPORT QGeoMap : public QObject
Q_DECLARE_PRIVATE(QGeoMap)
public:
+ enum ItemType {
+ NoItem = 0x0000,
+ MapRectangle = 0x0001,
+ MapCircle = 0x0002,
+ MapPolyline = 0x0004,
+ MapPolygon = 0x0008,
+ MapQuickItem = 0x0010,
+ CustomMapItem = 0x8000
+ };
+
+ Q_DECLARE_FLAGS(ItemTypes, ItemType)
+
virtual ~QGeoMap();
// Sets the display size
@@ -87,7 +100,7 @@ public:
// returns the minimum zoom at the current viewport size
double minimumZoom() const;
- double maximumCenterLatitudeAtZoom(double zoomLevel) const;
+ double maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const;
// returns the size of the underlying map, at the current zoom level. Unrelated to width()/height()/size().
double mapWidth() const;
@@ -102,6 +115,12 @@ public:
void removeParameter(QGeoMapParameter *param);
void clearParameters();
+ ItemTypes supportedMapItemTypes() const;
+
+ void addMapItem(QDeclarativeGeoMapItemBase *item);
+ void removeMapItem(QDeclarativeGeoMapItemBase *item);
+ void clearMapItems();
+
protected:
QGeoMap(QGeoMapPrivate &dd, QObject *parent = 0);
void setCameraData(const QGeoCameraData &cameraData);
@@ -119,6 +138,8 @@ private:
friend class QDeclarativeGeoMap; //updateSceneGraph
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGeoMap::ItemTypes)
+
QT_END_NAMESPACE
#endif // QGEOMAP_P_H
diff --git a/src/location/maps/qgeomap_p_p.h b/src/location/maps/qgeomap_p_p.h
index 625cd676..ab603be7 100644
--- a/src/location/maps/qgeomap_p_p.h
+++ b/src/location/maps/qgeomap_p_p.h
@@ -54,6 +54,7 @@
#include <QtCore/private/qobject_p.h>
#include <QtCore/QSize>
#include <QtCore/QSet>
+#include "qgeomap_p.h"
QT_BEGIN_NAMESPACE
@@ -62,6 +63,7 @@ class QGeoMappingManagerEngine;
class QGeoMap;
class QGeoMapController;
class QGeoMapParameter;
+class QDeclarativeGeoMapItemBase;
class Q_LOCATION_PRIVATE_EXPORT QGeoMapPrivate : public QObjectPrivate
{
@@ -76,6 +78,10 @@ protected:
virtual void addParameter(QGeoMapParameter *param);
virtual void removeParameter(QGeoMapParameter *param);
+ virtual QGeoMap::ItemTypes supportedMapItemTypes() const;
+ virtual void addMapItem(QDeclarativeGeoMapItemBase *item);
+ virtual void removeMapItem(QDeclarativeGeoMapItemBase *item);
+
virtual void changeViewportSize(const QSize &size) = 0; // called by QGeoMap::setSize()
virtual void changeCameraData(const QGeoCameraData &oldCameraData) = 0; // called by QGeoMap::setCameraData()
virtual void changeActiveMapType(const QGeoMapType mapType) = 0; // called by QGeoMap::setActiveMapType()
@@ -87,6 +93,7 @@ protected:
QGeoCameraData m_cameraData;
QGeoMapType m_activeMapType;
QSet<QGeoMapParameter *> m_mapParameters;
+ QSet<QDeclarativeGeoMapItemBase *> m_mapItems;
};
QT_END_NAMESPACE
diff --git a/src/location/maps/qgeoprojection.cpp b/src/location/maps/qgeoprojection.cpp
index dc7e78f8..586dcb02 100644
--- a/src/location/maps/qgeoprojection.cpp
+++ b/src/location/maps/qgeoprojection.cpp
@@ -37,12 +37,23 @@
#include "qgeoprojection_p.h"
#include <QtPositioning/private/qwebmercator_p.h>
#include <QtPositioning/private/qlocationutils_p.h>
+#include <QtPositioning/private/qclipperutils_p.h>
#include <QSize>
#include <cmath>
-QT_BEGIN_NAMESPACE
+namespace {
+ static const double defaultTileSize = 256.0;
+ static const QDoubleVector3D xyNormal(0.0, 0.0, 1.0);
+ static const QDoubleVector3D xyPoint(0.0, 0.0, 0.0);
+ static const QGeoProjectionWebMercator::Plane xyPlane(QDoubleVector3D(0,0,0), QDoubleVector3D(0,0,1));
+ static const QList<QDoubleVector2D> mercatorGeometry = {
+ QDoubleVector2D(-1.0,0.0),
+ QDoubleVector2D( 2.0,0.0),
+ QDoubleVector2D( 2.0,1.0),
+ QDoubleVector2D(-1.0,1.0) };
+}
-static const double defaultTileSize = 256.0;
+QT_BEGIN_NAMESPACE
QGeoProjection::QGeoProjection()
{
@@ -58,7 +69,6 @@ QGeoProjection::~QGeoProjection()
* QGeoProjectionWebMercator implementation
*/
-
QGeoProjectionWebMercator::QGeoProjectionWebMercator()
: QGeoProjection(),
m_mapEdgeSize(256), // at zl 0
@@ -75,9 +85,8 @@ QGeoProjectionWebMercator::QGeoProjectionWebMercator()
m_farPlane(0.0),
m_halfWidth(0.0),
m_halfHeight(0.0),
- m_plane(QDoubleVector3D(0,0,0), QDoubleVector3D(0,0,1))
+ m_minimumUnprojectableY(0.0)
{
-
}
QGeoProjectionWebMercator::~QGeoProjectionWebMercator()
@@ -98,9 +107,9 @@ double QGeoProjectionWebMercator::minimumZoom() const
// the amount of pixels between the center and the borders changes
// 2) when the zoom level changes, because the amount of pixels between the center
// and the borders stays the same, but the meters per pixel change
-double QGeoProjectionWebMercator::maximumCenterLatitudeAtZoom(double zoomLevel) const
+double QGeoProjectionWebMercator::maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const
{
- double mapEdgeSize = std::pow(2.0, zoomLevel) * defaultTileSize;
+ double mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * defaultTileSize;
// At init time weird things happen
int clampedWindowHeight = (m_viewportHeight > mapEdgeSize) ? mapEdgeSize : m_viewportHeight;
@@ -187,19 +196,14 @@ QDoubleVector2D QGeoProjectionWebMercator::wrappedMapProjectionToItemPosition(co
QDoubleVector2D QGeoProjectionWebMercator::itemPositionToWrappedMapProjection(const QDoubleVector2D &itemPosition) const
{
QDoubleVector2D pos = itemPosition;
- pos /= QDoubleVector2D(m_viewportWidth, m_viewportHeight);
+ // when the camera is tilted, picking a point above the horizon returns a coordinate behind the camera
+ if (pos.y() < m_minimumUnprojectableY)
+ pos.setY(m_minimumUnprojectableY);
+ pos *= QDoubleVector2D(m_1_viewportWidth, m_1_viewportHeight);
pos *= 2.0;
pos -= QDoubleVector2D(1.0,1.0);
- pos *= QDoubleVector2D(m_halfWidth, m_halfHeight);
-
- QDoubleVector3D p = m_centerNearPlane;
- p -= m_up * pos.y();
- p -= m_side * pos.x();
- QDoubleVector3D ray = p - m_eye;
- ray.normalize();
-
- return (m_plane.lineIntersection(m_eye, ray) / m_sideLength).toVector2D();
+ return viewportToWrappedMapProjection(pos);
}
/* Default implementations */
@@ -235,78 +239,144 @@ QDoubleVector2D QGeoProjectionWebMercator::coordinateToItemPosition(const QGeoCo
return pos;
}
+QDoubleVector2D QGeoProjectionWebMercator::geoToWrappedMapProjection(const QGeoCoordinate &coordinate) const
+{
+ return wrapMapProjection(geoToMapProjection(coordinate));
+}
+
+QGeoCoordinate QGeoProjectionWebMercator::wrappedMapProjectionToGeo(const QDoubleVector2D &wrappedProjection) const
+{
+ return mapProjectionToGeo(unwrapMapProjection(wrappedProjection));
+}
+
bool QGeoProjectionWebMercator::isProjectable(const QDoubleVector2D &wrappedProjection) const
{
- QDoubleVector3D pos = wrappedProjection * m_sideLength;
+ if (m_cameraData.tilt() == 0.0)
+ return true;
- // TODO: add an offset to the eye
- QDoubleVector3D p = m_eye - pos;
+ QDoubleVector3D pos = wrappedProjection * m_sideLength;
+ // use m_centerNearPlane in order to add an offset to m_eye.
+ QDoubleVector3D p = m_centerNearPlane - pos;
double dot = QDoubleVector3D::dotProduct(p , m_viewNormalized);
- if (dot < 0.0) // behind the eye
+ if (dot < 0.0) // behind the near plane
return false;
return true;
}
+QList<QDoubleVector2D> QGeoProjectionWebMercator::visibleRegion() const
+{
+ return m_visibleRegion;
+}
+
+QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition) const
+{
+ QDoubleVector2D pos = itemPosition;
+ pos *= QDoubleVector2D(m_halfWidth, m_halfHeight);
+
+ QDoubleVector3D p = m_centerNearPlane;
+ p -= m_up * pos.y();
+ p -= m_side * pos.x();
+
+ QDoubleVector3D ray = p - m_eye;
+ ray.normalize();
+
+ return (xyPlane.lineIntersection(m_eye, ray) / m_sideLength).toVector2D();
+}
+
void QGeoProjectionWebMercator::setupCamera()
{
- QDoubleVector2D camCenterMercator = geoToMapProjection(m_cameraData.center());
- m_cameraCenterXMercator = camCenterMercator.x();
- m_cameraCenterYMercator = camCenterMercator.y();
+ m_centerMercator = geoToMapProjection(m_cameraData.center());
+ m_cameraCenterXMercator = m_centerMercator.x();
+ m_cameraCenterYMercator = m_centerMercator.y();
int intZoomLevel = static_cast<int>(std::floor(m_cameraData.zoomLevel()));
m_sideLength = (1 << intZoomLevel) * defaultTileSize;
- m_center = camCenterMercator * m_sideLength;
+ m_center = m_centerMercator * m_sideLength;
double f = 1.0 * qMin(m_viewportWidth, m_viewportHeight);
double z = std::pow(2.0, m_cameraData.zoomLevel() - intZoomLevel) * defaultTileSize;
- double altitude = f / (2.0 * z) ;
+ double altitude = f / (2.0 * z);
+ // Also in mercator space
+ double z_mercator = std::pow(2.0, m_cameraData.zoomLevel()) * defaultTileSize;
+ double altitude_mercator = f / (2.0 * z_mercator);
+ //aperture(90 / 2) = 1
+ m_aperture = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5);
// calculate eye
- // TODO: support field of view with apertureSize = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5);
- double m_aperture = 1.0; //aperture(90 / 2) = 1
-
m_eye = m_center;
m_eye.setZ(altitude * defaultTileSize / m_aperture);
+ // And in mercator space
+ m_eyeMercator = m_centerMercator;
+ m_eyeMercator.setZ(altitude_mercator);
+
m_view = m_eye - m_center;
QDoubleVector3D side = QDoubleVector3D::normal(m_view, QDoubleVector3D(0.0, 1.0, 0.0));
m_up = QDoubleVector3D::normal(side, m_view);
+ // In mercator space too
+ m_viewMercator = m_eyeMercator - m_centerMercator;
+ QDoubleVector3D sideMercator = QDoubleVector3D::normal(m_viewMercator, QDoubleVector3D(0.0, 1.0, 0.0));
+ m_upMercator = QDoubleVector3D::normal(sideMercator, m_viewMercator);
+
if (m_cameraData.bearing() > 0.0) {
- // old bearing, tilt and roll code
QDoubleMatrix4x4 mBearing;
mBearing.rotate(m_cameraData.bearing(), m_view);
m_up = mBearing * m_up;
+
+ // In mercator space too
+ QDoubleMatrix4x4 mBearingMercator;
+ mBearingMercator.rotate(m_cameraData.bearing(), m_viewMercator);
+ m_upMercator = mBearingMercator * m_upMercator;
}
m_side = QDoubleVector3D::normal(m_up, m_view);
+ m_sideMercator = QDoubleVector3D::normal(m_upMercator, m_viewMercator);
- if (m_cameraData.tilt() > 0.0) {
+ if (m_cameraData.tilt() > 0.0) { // tilt has been already thresholded by QGeoCameraData::setTilt
QDoubleMatrix4x4 mTilt;
mTilt.rotate(-m_cameraData.tilt(), m_side);
m_eye = mTilt * m_view + m_center;
+
+ // In mercator space too
+ QDoubleMatrix4x4 mTiltMercator;
+ mTiltMercator.rotate(-m_cameraData.tilt(), m_sideMercator);
+ m_eyeMercator = mTiltMercator * m_viewMercator + m_centerMercator;
}
m_view = m_eye - m_center;
m_viewNormalized = m_view.normalized();
m_up = QDoubleVector3D::normal(m_view, m_side);
- m_nearPlane = 1;
- // 10000.0 to make sure that everything fits in the frustum even at high zoom levels
- // (that is, with a very large map)
- // TODO: extend this to support clip distance
- m_farPlane = (altitude + 10000.0) * defaultTileSize;
+ m_nearPlane = 1.0;
+ // At ZL 20 the map has 2^20 tiles per side. That is 1048576.
+ // Placing the camera on one corner of the map, rotated toward the opposite corner, and tilted
+ // at almost 90 degrees would require a frustum that can span the whole size of this map.
+ // For this reason, the far plane is set to 2 * 2^20 * defaultTileSize.
+ // That is, in order to make sure that the whole map would fit in the frustum at this ZL.
+ // Since we are using a double matrix, and since the largest value in the matrix is going to be
+ // 2 * m_farPlane (as near plane is 1.0), there should be sufficient precision left.
+ //
+ // TODO: extend this to support clip distance.
+ m_farPlane = (altitude + 2097152.0) * defaultTileSize;
+
+ m_viewMercator = m_eyeMercator - m_centerMercator;
+ m_upMercator = QDoubleVector3D::normal(m_viewMercator, m_sideMercator);
+ m_nearPlaneMercator = 1.0 / m_sideLength;
double aspectRatio = 1.0 * m_viewportWidth / m_viewportHeight;
- m_halfWidth = 1 * m_aperture;
- m_halfHeight = 1 * m_aperture;
+ m_halfWidth = m_aperture;
+ m_halfHeight = m_aperture;
+ double verticalAperture = m_aperture;
if (aspectRatio > 1.0) {
m_halfWidth *= aspectRatio;
} else if (aspectRatio > 0.0 && aspectRatio < 1.0) {
m_halfHeight /= aspectRatio;
+ verticalAperture /= aspectRatio;
}
+ double verticalHalfFOV = QLocationUtils::degrees(atan(verticalAperture));
QDoubleMatrix4x4 cameraMatrix;
cameraMatrix.lookAt(m_eye, m_center, m_up);
@@ -315,7 +385,114 @@ void QGeoProjectionWebMercator::setupCamera()
projectionMatrix.frustum(-m_halfWidth, m_halfWidth, -m_halfHeight, m_halfHeight, m_nearPlane, m_farPlane);
m_transformation = projectionMatrix * cameraMatrix;
- m_centerNearPlane = m_eye + m_view.normalized();
+ m_centerNearPlane = m_eye + m_viewNormalized;
+ m_centerNearPlaneMercator = m_eyeMercator + m_viewNormalized * m_nearPlaneMercator;
+
+ // The method does not support tilting angles >= 90.0 or < 0.
+
+ // The following formula is used to have a growing epsilon with the zoom level,
+ // in order not to have too large values at low zl, which would overflow when converted to Clipper::cInt.
+ const double upperBoundEpsilon = 1.0 / std::pow(10, 1.0 + m_cameraData.zoomLevel() / 5.0);
+ const double elevationUpperBound = 90.0 - upperBoundEpsilon;
+ const double maxRayElevation = qMin(elevationUpperBound - m_cameraData.tilt(), verticalHalfFOV);
+ double maxHalfAperture = 0;
+ double verticalEstateToSkip = 0;
+ if (maxRayElevation < verticalHalfFOV) {
+ maxHalfAperture = tan(QLocationUtils::radians(maxRayElevation));
+ verticalEstateToSkip = 1.0 - maxHalfAperture / verticalAperture;
+ }
+
+ m_minimumUnprojectableY = verticalEstateToSkip * 0.5 * m_viewportHeight; // verticalEstateToSkip is relative to half aperture
+
+ QDoubleVector2D tl = viewportToWrappedMapProjection(QDoubleVector2D(-1, -1 + verticalEstateToSkip ));
+ QDoubleVector2D tr = viewportToWrappedMapProjection(QDoubleVector2D( 1, -1 + verticalEstateToSkip ));
+ QDoubleVector2D bl = viewportToWrappedMapProjection(QDoubleVector2D(-1, 1 ));
+ QDoubleVector2D br = viewportToWrappedMapProjection(QDoubleVector2D( 1, 1 ));
+
+ QList<QDoubleVector2D> mapRect;
+ mapRect.push_back(QDoubleVector2D(-1.0, 1.0));
+ mapRect.push_back(QDoubleVector2D( 2.0, 1.0));
+ mapRect.push_back(QDoubleVector2D( 2.0, 0.0));
+ mapRect.push_back(QDoubleVector2D(-1.0, 0.0));
+
+ QList<QDoubleVector2D> viewportRect;
+ viewportRect.push_back(bl);
+ viewportRect.push_back(br);
+ viewportRect.push_back(tr);
+ viewportRect.push_back(tl);
+
+ c2t::clip2tri clipper;
+ clipper.clearClipper();
+ clipper.addSubjectPath(QClipperUtils::qListToPath(mapRect), true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(viewportRect));
+
+ Paths res = clipper.execute(c2t::clip2tri::Intersection);
+ m_visibleRegion.clear();
+ if (res.size())
+ m_visibleRegion = QClipperUtils::pathToQList(res[0]); // Intersection between two convex quadrilaterals should always be a single polygon
+}
+
+/*
+ *
+ * Line implementation
+ *
+ */
+
+QGeoProjectionWebMercator::Line2D::Line2D()
+{
+
+}
+
+QGeoProjectionWebMercator::Line2D::Line2D(const QDoubleVector2D &linePoint, const QDoubleVector2D &lineDirection)
+ : m_point(linePoint), m_direction(lineDirection.normalized())
+{
+
+}
+
+bool QGeoProjectionWebMercator::Line2D::isValid() const
+{
+ return (m_direction.length() > 0.5);
+}
+
+/*
+ *
+ * Plane implementation
+ *
+ */
+
+QGeoProjectionWebMercator::Plane::Plane()
+{
+
+}
+
+QGeoProjectionWebMercator::Plane::Plane(const QDoubleVector3D &planePoint, const QDoubleVector3D &planeNormal)
+ : m_point(planePoint), m_normal(planeNormal.normalized()) { }
+
+QDoubleVector3D QGeoProjectionWebMercator::Plane::lineIntersection(const QDoubleVector3D &linePoint, const QDoubleVector3D &lineDirection) const
+{
+ QDoubleVector3D w = linePoint - m_point;
+ // s = -n.dot(w) / n.dot(u). p = p0 + su; u is lineDirection
+ double s = QDoubleVector3D::dotProduct(-m_normal, w) / QDoubleVector3D::dotProduct(m_normal, lineDirection);
+ return linePoint + lineDirection * s;
+}
+
+QGeoProjectionWebMercator::Line2D QGeoProjectionWebMercator::Plane::planeXYIntersection() const
+{
+ // cross product of the two normals for the line direction
+ QDoubleVector3D lineDirection = QDoubleVector3D::crossProduct(m_normal, xyNormal);
+ lineDirection.setZ(0.0);
+ lineDirection.normalize();
+
+ // cross product of the line direction and the plane normal to find the direction on the plane
+ // intersecting the xy plane
+ QDoubleVector3D directionToXY = QDoubleVector3D::crossProduct(m_normal, lineDirection);
+ QDoubleVector3D p = xyPlane.lineIntersection(m_point, directionToXY);
+ return Line2D(p.toVector2D(), lineDirection.toVector2D());
+}
+
+bool QGeoProjectionWebMercator::Plane::isValid() const
+{
+ return (m_normal.length() > 0.5);
}
QT_END_NAMESPACE
diff --git a/src/location/maps/qgeoprojection_p.h b/src/location/maps/qgeoprojection_p.h
index 61059fdd..6ea8fd6e 100644
--- a/src/location/maps/qgeoprojection_p.h
+++ b/src/location/maps/qgeoprojection_p.h
@@ -65,12 +65,15 @@ public:
// returns the minimum zoom at the current viewport size
virtual double minimumZoom() const = 0;
- virtual double maximumCenterLatitudeAtZoom(double zoomLevel) const = 0;
+ virtual double maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const = 0;
// returns the size of the underlying map, at the current zoom level.
virtual double mapWidth() const = 0;
virtual double mapHeight() const = 0;
+ virtual bool isProjectable(const QDoubleVector2D &wrappedProjection) const = 0;
+ virtual QList<QDoubleVector2D> visibleRegion() const = 0;
+
// Conversion methods for QGeoCoordinate <-> screen.
// This currently assumes that the "MapProjection" space is [0, 1][0, 1] for every type of possibly supported map projection
virtual QDoubleVector2D geoToMapProjection(const QGeoCoordinate &coordinate) const = 0;
@@ -83,9 +86,10 @@ public:
virtual QDoubleVector2D itemPositionToWrappedMapProjection(const QDoubleVector2D &itemPosition) const = 0;
// Convenience methods to avoid the chain itemPositionToWrappedProjection(wrapProjection(geoToProjection()))
- // These also come with a default implementation that can, however, be overridden.
virtual QGeoCoordinate itemPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport = true) const = 0;
virtual QDoubleVector2D coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport = true) const = 0;
+ virtual QDoubleVector2D geoToWrappedMapProjection(const QGeoCoordinate &coordinate) const = 0;
+ virtual QGeoCoordinate wrappedMapProjectionToGeo(const QDoubleVector2D &wrappedProjection) const = 0;
};
class Q_LOCATION_PRIVATE_EXPORT QGeoProjectionWebMercator : public QGeoProjection
@@ -95,7 +99,7 @@ public:
~QGeoProjectionWebMercator();
double minimumZoom() const Q_DECL_OVERRIDE;
- double maximumCenterLatitudeAtZoom(double zoomLevel) const Q_DECL_OVERRIDE;
+ double maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const Q_DECL_OVERRIDE;
// The size of the underlying map, at the current zoom level.
double mapWidth() const Q_DECL_OVERRIDE;
@@ -115,11 +119,42 @@ public:
QGeoCoordinate itemPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport = true) const Q_DECL_OVERRIDE;
QDoubleVector2D coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport = true) const Q_DECL_OVERRIDE;
+ QDoubleVector2D geoToWrappedMapProjection(const QGeoCoordinate &coordinate) const Q_DECL_OVERRIDE;
+ QGeoCoordinate wrappedMapProjectionToGeo(const QDoubleVector2D &wrappedProjection) const Q_DECL_OVERRIDE;
+
+ bool isProjectable(const QDoubleVector2D &wrappedProjection) const Q_DECL_OVERRIDE;
+ QList<QDoubleVector2D> visibleRegion() const Q_DECL_OVERRIDE;
+
+ inline QDoubleVector2D viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition) const;
- bool isProjectable(const QDoubleVector2D &wrappedProjection) const;
private:
void setupCamera();
+public:
+ struct Line2D
+ {
+ Line2D();
+ Line2D(const QDoubleVector2D &linePoint, const QDoubleVector2D &lineDirection);
+
+ bool isValid() const;
+
+ QDoubleVector2D m_point;
+ QDoubleVector2D m_direction;
+ };
+
+ struct Plane
+ {
+ Plane();
+ Plane(const QDoubleVector3D &planePoint, const QDoubleVector3D &planeNormal);
+
+ QDoubleVector3D lineIntersection(const QDoubleVector3D &linePoint, const QDoubleVector3D &lineDirection) const;
+ Line2D planeXYIntersection() const;
+ bool isValid() const;
+
+ QDoubleVector3D m_point;
+ QDoubleVector3D m_normal;
+ };
+
private:
QGeoCameraData m_cameraData;
double m_mapEdgeSize;
@@ -148,24 +183,21 @@ private:
double m_farPlane;
double m_halfWidth;
double m_halfHeight;
+ double m_minimumUnprojectableY;
- struct Plane
- {
- Plane() {}
- Plane(const QDoubleVector3D &planePoint, const QDoubleVector3D &planeNormal)
- : m_point(planePoint), m_normal(planeNormal) { }
-
- QDoubleVector3D lineIntersection(const QDoubleVector3D &linePoint, const QDoubleVector3D &lineDirection) const
- {
- QDoubleVector3D w = linePoint - m_point;
- // s = -n.dot(w) / n.dot(u). p = p0 + su; u is lineDirection
- double s = QDoubleVector3D::dotProduct(-m_normal, w) / QDoubleVector3D::dotProduct(m_normal, lineDirection);
- return linePoint + lineDirection * s;
- }
+ // For the clipping region
+ QDoubleVector3D m_centerMercator;
+ QDoubleVector3D m_eyeMercator;
+ QDoubleVector3D m_viewMercator;
+ QDoubleVector3D m_upMercator;
+ QDoubleVector3D m_sideMercator;
+ QDoubleVector3D m_centerNearPlaneMercator;
+ double m_nearPlaneMercator;
+ Line2D m_nearPlaneMapIntersection;
- QDoubleVector3D m_point;
- QDoubleVector3D m_normal;
- } m_plane;
+ QList<QDoubleVector2D> m_visibleRegion;
+
+ Q_DISABLE_COPY(QGeoProjectionWebMercator)
};
QT_END_NAMESPACE
diff --git a/src/location/maps/qgeotiledmapscene.cpp b/src/location/maps/qgeotiledmapscene.cpp
index 404dcd19..fbd05645 100644
--- a/src/location/maps/qgeotiledmapscene.cpp
+++ b/src/location/maps/qgeotiledmapscene.cpp
@@ -43,7 +43,16 @@
#include <QtCore/private/qobject_p.h>
#include <QtQuick/QSGImageNode>
#include <QtQuick/QQuickWindow>
+#include <QtGui/QVector3D>
#include <cmath>
+#include <QtPositioning/private/qlocationutils_p.h>
+#include <QtPositioning/private/qdoublematrix4x4_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
+
+static QVector3D toVector3D(const QDoubleVector3D& in)
+{
+ return QVector3D(in.x(), in.y(), in.z());
+}
QT_BEGIN_NAMESPACE
@@ -75,6 +84,7 @@ public:
// the number of tiles in each direction for the whole map (earth) at the current zoom level.
// it is 1<<zoomLevel
int m_sideLength;
+ double m_mapEdgeSize;
QHash<QGeoTileSpec, QSharedPointer<QGeoTileTexture> > m_textures;
@@ -85,32 +95,18 @@ public:
int m_maxTileY;
int m_tileXWrapsBelow; // the wrap point as a tile index
- // cameraToScreen transform
- double m_screenWidth; // in pixels
- double m_screenHeight; // in pixels
bool m_linearScaling;
bool m_dropTextures;
void addTile(const QGeoTileSpec &spec, QSharedPointer<QGeoTileTexture> texture);
- QDoubleVector2D itemPositionToMercator(const QDoubleVector2D &pos) const;
- QDoubleVector2D mercatorToItemPosition(const QDoubleVector2D &mercator) const;
-
- QDoubleVector2D geoToMapProjection(const QGeoCoordinate &coordinate) const;
- QGeoCoordinate mapProjectionToGeo(const QDoubleVector2D &projection) const;
-
- QDoubleVector2D wrapMapProjection(const QDoubleVector2D &projection) const;
- QDoubleVector2D unwrapMapProjection(const QDoubleVector2D &wrappedProjection) const;
-
- QDoubleVector2D wrappedMapProjectionToItemPosition(const QDoubleVector2D &wrappedProjection) const;
- QDoubleVector2D itemPositionToWrappedMapProjection(const QDoubleVector2D &itemPosition) const;
-
- void setVisibleTiles(const QSet<QGeoTileSpec> &tiles);
+ void setVisibleTiles(const QSet<QGeoTileSpec> &visibleTiles);
void removeTiles(const QSet<QGeoTileSpec> &oldTiles);
bool buildGeometry(const QGeoTileSpec &spec, QSGImageNode *imageNode);
- void setTileBounds(const QSet<QGeoTileSpec> &tiles);
+ void updateTileBounds(const QSet<QGeoTileSpec> &tiles);
void setupCamera();
+ inline bool isTiltedOrRotated() { return (m_cameraData.tilt() > 0.0) || (m_cameraData.bearing() > 0.0); }
};
QGeoTiledMapScene::QGeoTiledMapScene(QObject *parent)
@@ -140,8 +136,9 @@ void QGeoTiledMapScene::setCameraData(const QGeoCameraData &cameraData)
d->m_cameraData = cameraData;
d->m_intZoomLevel = static_cast<int>(std::floor(d->m_cameraData.zoomLevel()));
float delta = cameraData.zoomLevel() - d->m_intZoomLevel;
- d->m_linearScaling = qAbs(delta) > 0.05;
+ d->m_linearScaling = qAbs(delta) > 0.05 || d->isTiltedOrRotated();
d->m_sideLength = 1 << d->m_intZoomLevel;
+ d->m_mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * d->m_tileSize;
}
void QGeoTiledMapScene::setVisibleTiles(const QSet<QGeoTileSpec> &tiles)
@@ -190,8 +187,6 @@ QGeoTiledMapScenePrivate::QGeoTiledMapScenePrivate()
m_maxTileX(-1),
m_maxTileY(-1),
m_tileXWrapsBelow(0),
- m_screenWidth(0.0),
- m_screenHeight(0.0),
m_linearScaling(false),
m_dropTextures(false)
{
@@ -244,19 +239,19 @@ void QGeoTiledMapScenePrivate::addTile(const QGeoTileSpec &spec, QSharedPointer<
m_textures.insert(spec, texture);
}
-void QGeoTiledMapScenePrivate::setVisibleTiles(const QSet<QGeoTileSpec> &tiles)
+void QGeoTiledMapScenePrivate::setVisibleTiles(const QSet<QGeoTileSpec> &visibleTiles)
{
// work out the tile bounds for the new scene
- setTileBounds(tiles);
+ updateTileBounds(visibleTiles);
// set up the gl camera for the new scene
setupCamera();
- QSet<QGeoTileSpec> toRemove = m_visibleTiles - tiles;
+ QSet<QGeoTileSpec> toRemove = m_visibleTiles - visibleTiles;
if (!toRemove.isEmpty())
removeTiles(toRemove);
- m_visibleTiles = tiles;
+ m_visibleTiles = visibleTiles;
}
void QGeoTiledMapScenePrivate::removeTiles(const QSet<QGeoTileSpec> &oldTiles)
@@ -271,7 +266,7 @@ void QGeoTiledMapScenePrivate::removeTiles(const QSet<QGeoTileSpec> &oldTiles)
}
}
-void QGeoTiledMapScenePrivate::setTileBounds(const QSet<QGeoTileSpec> &tiles)
+void QGeoTiledMapScenePrivate::updateTileBounds(const QSet<QGeoTileSpec> &tiles)
{
if (tiles.isEmpty()) {
m_minTileX = -1;
@@ -353,26 +348,24 @@ void QGeoTiledMapScenePrivate::setTileBounds(const QSet<QGeoTileSpec> &tiles)
void QGeoTiledMapScenePrivate::setupCamera()
{
+ // NOTE: The following instruction is correct only because WebMercator is a square projection!
double f = 1.0 * qMin(m_screenSize.width(), m_screenSize.height());
- // fraction of zoom level
+ // Using fraction of zoom level, z varies between [ m_tileSize , 2 * m_tileSize [
double z = std::pow(2.0, m_cameraData.zoomLevel() - m_intZoomLevel) * m_tileSize;
- // Maps smaller than screen size are NOT supported. But we can't simply return here, as this call
- // might be invoked also before a valid zoom level is set.
-
// calculate altitude that allows the visible map tiles
- // to fit in the screen correctly (note that a larger f would cause
- // the camera be higher, resulting in empty areas displayed around
- // the tiles or repeated tiles)
- double altitude = f / (2.0 * z) ;
+ // to fit in the screen correctly (note that a larger f will cause
+ // the camera be higher, resulting in gray areas displayed around
+ // the tiles)
+ double altitude = f / (2.0 * z);
// calculate center
double edge = m_scaleFactor * m_tileSize;
// first calculate the camera center in map space in the range of 0 <-> sideLength (2^z)
QDoubleVector2D camCenterMercator = QWebMercator::coordToMercator(m_cameraData.center());
- QDoubleVector3D center = m_sideLength * camCenterMercator;
+ QDoubleVector3D center = (m_sideLength * camCenterMercator);
// wrap the center if necessary (due to dateline crossing)
if (center.x() < m_tileXWrapsBelow)
@@ -382,16 +375,15 @@ void QGeoTiledMapScenePrivate::setupCamera()
center.setX(center.x() - 1.0 * m_minTileX);
center.setY(1.0 * m_minTileY - center.y());
- m_screenHeight = m_screenSize.height();
- m_screenWidth = m_screenSize.width();
-
// apply necessary scaling to the camera center
center *= edge;
// calculate eye
-
+ double apertureSize = 1.0;
+ if (m_cameraData.fieldOfView() != 90.0) //aperture(90 / 2) = 1
+ apertureSize = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5);
QDoubleVector3D eye = center;
- eye.setZ(altitude * edge);
+ eye.setZ(altitude * edge / apertureSize);
// calculate up
@@ -399,19 +391,24 @@ void QGeoTiledMapScenePrivate::setupCamera()
QDoubleVector3D side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
QDoubleVector3D up = QDoubleVector3D::normal(side, view);
- // old bearing, tilt and roll code
- // QMatrix4x4 mBearing;
- // mBearing.rotate(-1.0 * camera.bearing(), view);
- // up = mBearing * up;
-
- // QDoubleVector3D side2 = QDoubleVector3D::normal(up, view);
- // QMatrix4x4 mTilt;
- // mTilt.rotate(camera.tilt(), side2);
- // eye = (mTilt * view) + center;
+ // old bearing, tilt and roll code.
+ // Now using double matrices until distilling the transformation to QMatrix4x4
+ QDoubleMatrix4x4 mBearing;
+ // -1.0 * bearing removed, now map north goes in the bearing direction
+ mBearing.rotate(-1.0 * m_cameraData.bearing(), view);
+ up = mBearing * up;
+
+ QDoubleVector3D side2 = QDoubleVector3D::normal(up, view);
+ if (m_cameraData.tilt() > 0.01) {
+ QDoubleMatrix4x4 mTilt;
+ mTilt.rotate(m_cameraData.tilt(), side2);
+ eye = mTilt * view + center;
+ }
- // view = eye - center;
- // side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
- // up = QDoubleVector3D::normal(view, side2);
+ view = eye - center;
+ view.normalize();
+ side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
+ up = QDoubleVector3D::normal(view, side2);
// QMatrix4x4 mRoll;
// mRoll.rotate(camera.roll(), view);
@@ -420,15 +417,19 @@ void QGeoTiledMapScenePrivate::setupCamera()
// near plane and far plane
double nearPlane = 1.0;
- double farPlane = (altitude + 1.0) * edge;
+ // Clip plane. Used to be (altitude + 1.0) * edge. This does not affect the perspective. minimum value would be > 0.0
+ // Since, for some reasons possibly related to how QSG works, this clipping plane is unable to clip part of tiles,
+ // Instead of farPlane = (altitude + m_cameraData.clipDistance()) * edge , we use a fixed large clipDistance, and
+ // leave the clipping only in QGeoCameraTiles::createFrustum
+ double farPlane = (altitude + 10000.0) * edge;
m_cameraUp = up;
m_cameraCenter = center;
m_cameraEye = eye;
double aspectRatio = 1.0 * m_screenSize.width() / m_screenSize.height();
- float halfWidth = 1;
- float halfHeight = 1;
+ float halfWidth = 1 * apertureSize;
+ float halfHeight = 1 * apertureSize;
if (aspectRatio > 1.0) {
halfWidth *= aspectRatio;
} else if (aspectRatio > 0.0f && aspectRatio < 1.0f) {
@@ -502,14 +503,33 @@ public:
QHash<QGeoTileSpec, QSGTexture *> textures;
};
-static bool qgeotiledmapscene_isTileInViewport(const QRectF &tileRect, const QMatrix4x4 &matrix) {
+static bool qgeotiledmapscene_isTileInViewport_Straight(const QRectF &tileRect, const QMatrix4x4 &matrix)
+{
const QRectF boundingRect = QRectF(matrix * tileRect.topLeft(), matrix * tileRect.bottomRight());
return QRectF(-1, -1, 2, 2).intersects(boundingRect);
}
-static QVector3D toVector3D(const QDoubleVector3D& in)
+static bool qgeotiledmapscene_isTileInViewport_rotationTilt(const QRectF &tileRect, const QMatrix4x4 &matrix)
{
- return QVector3D(in.x(), in.y(), in.z());
+ // Transformed corners
+ const QPointF tlt = matrix * tileRect.topLeft();
+ const QPointF trt = matrix * tileRect.topRight();
+ const QPointF blt = matrix * tileRect.bottomLeft();
+ const QPointF brt = matrix * tileRect.bottomRight();
+
+ const QRectF boundingRect = QRectF(QPointF(qMin(qMin(qMin(tlt.x(), trt.x()), blt.x()), brt.x())
+ ,qMax(qMax(qMax(tlt.y(), trt.y()), blt.y()), brt.y()))
+ ,QPointF(qMax(qMax(qMax(tlt.x(), trt.x()), blt.x()), brt.x())
+ ,qMin(qMin(qMin(tlt.y(), trt.y()), blt.y()), brt.y()))
+ );
+ return QRectF(-1, -1, 2, 2).intersects(boundingRect);
+}
+
+static bool qgeotiledmapscene_isTileInViewport(const QRectF &tileRect, const QMatrix4x4 &matrix, const bool straight)
+{
+ if (straight)
+ return qgeotiledmapscene_isTileInViewport_Straight(tileRect, matrix);
+ return qgeotiledmapscene_isTileInViewport_rotationTilt(tileRect, matrix);
}
void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root,
@@ -532,11 +552,13 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root,
foreach (const QGeoTileSpec &s, toRemove)
delete root->tiles.take(s);
+ bool straight = !d->isTiltedOrRotated();
for (QHash<QGeoTileSpec, QSGImageNode *>::iterator it = root->tiles.begin();
it != root->tiles.end(); ) {
QSGImageNode *node = it.value();
- bool ok = d->buildGeometry(it.key(), node) && qgeotiledmapscene_isTileInViewport(node->rect(), root->matrix());
+ bool ok = d->buildGeometry(it.key(), node)
+ && qgeotiledmapscene_isTileInViewport(node->rect(), root->matrix(), straight);
QSGNode::DirtyState dirtyBits = 0;
@@ -566,7 +588,8 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root,
QSGImageNode *tileNode = window->createImageNode();
// note: setTexture will update coordinates so do it here, before we buildGeometry
tileNode->setTexture(textures.value(s));
- if (d->buildGeometry(s, tileNode) && qgeotiledmapscene_isTileInViewport(tileNode->rect(), root->matrix())) {
+ if (d->buildGeometry(s, tileNode)
+ && qgeotiledmapscene_isTileInViewport(tileNode->rect(), root->matrix(), straight)) {
if (tileNode->texture()->textureSize().width() > d->m_tileSize) {
tileNode->setFiltering(QSGTexture::Linear); // with mipmapping QSGTexture::Nearest generates artifacts
tileNode->setMipmapFiltering(QSGTexture::Linear);
@@ -595,7 +618,7 @@ QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *win
mapRoot = new QGeoTiledMapRootNode();
// Setting clip rect to fullscreen, as now the map can never be smaller than the viewport.
- mapRoot->setClipRect(QRect(0, 0, d->m_screenWidth, d->m_screenHeight));
+ mapRoot->setClipRect(QRect(0, 0, w, h));
QMatrix4x4 itemSpaceMatrix;
itemSpaceMatrix.scale(w / 2, h / 2);
diff --git a/src/plugins/geoservices/esri/geotiledmap_esri.cpp b/src/plugins/geoservices/esri/geotiledmap_esri.cpp
index 9171fc2b..8caf055d 100644
--- a/src/plugins/geoservices/esri/geotiledmap_esri.cpp
+++ b/src/plugins/geoservices/esri/geotiledmap_esri.cpp
@@ -44,6 +44,11 @@
QT_BEGIN_NAMESPACE
+static QString bodify(const QString &html)
+{
+ return QStringLiteral("<body>") + html + QStringLiteral("</body>");
+}
+
GeoTiledMapEsri::GeoTiledMapEsri(GeoTiledMappingManagerEngineEsri *engine, QObject *parent) :
QGeoTiledMap(engine, parent), m_engine(engine), m_mapId(-1)
{
@@ -67,7 +72,7 @@ void GeoTiledMapEsri::evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles)
GeoMapSource *mapSource = engine()->mapSource(m_mapId);
if (mapSource)
- emit copyrightsChanged(mapSource->copyright());
+ emit copyrightsChanged(bodify(mapSource->copyright()));
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp b/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp
index abcb3779..a0f00615 100644
--- a/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp
+++ b/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp
@@ -95,7 +95,12 @@ GeoTiledMappingManagerEngineEsri::GeoTiledMappingManagerEngineEsri(const QVarian
cameraCaps.setMinimumZoomLevel(minimumZoomLevel);
cameraCaps.setMaximumZoomLevel(maximumZoomLevel);
-
+ cameraCaps.setSupportsBearing(true);
+ cameraCaps.setSupportsTilting(true);
+ cameraCaps.setMinimumTilt(0);
+ cameraCaps.setMaximumTilt(80);
+ cameraCaps.setMinimumFieldOfView(20.0);
+ cameraCaps.setMaximumFieldOfView(120.0);
setCameraCapabilities(cameraCaps);
setTileSize(QSize(256, 256));
diff --git a/src/plugins/geoservices/geoservices.pro b/src/plugins/geoservices/geoservices.pro
index 7a392b57..a70822dd 100644
--- a/src/plugins/geoservices/geoservices.pro
+++ b/src/plugins/geoservices/geoservices.pro
@@ -1,3 +1,17 @@
TEMPLATE = subdirs
SUBDIRS = nokia osm mapbox esri
+
+linux|android: {
+ equals(QT_GCC_MAJOR_VERSION, 4): greaterThan(QT_GCC_MINOR_VERSION, 8) {
+ SUBDIRS += mapboxgl
+ }
+
+ greaterThan(QT_GCC_MAJOR_VERSION, 4) {
+ SUBDIRS += mapboxgl
+ }
+}
+
+ios|macos: {
+ SUBDIRS += mapboxgl
+}
diff --git a/src/plugins/geoservices/mapbox/qgeotiledmappingmanagerenginemapbox.cpp b/src/plugins/geoservices/mapbox/qgeotiledmappingmanagerenginemapbox.cpp
index 5404eb30..4b62aece 100644
--- a/src/plugins/geoservices/mapbox/qgeotiledmappingmanagerenginemapbox.cpp
+++ b/src/plugins/geoservices/mapbox/qgeotiledmappingmanagerenginemapbox.cpp
@@ -50,6 +50,12 @@ QGeoTiledMappingManagerEngineMapbox::QGeoTiledMappingManagerEngineMapbox(const Q
QGeoCameraCapabilities cameraCaps;
cameraCaps.setMinimumZoomLevel(0.0);
cameraCaps.setMaximumZoomLevel(19.0);
+ cameraCaps.setSupportsBearing(true);
+ cameraCaps.setSupportsTilting(true);
+ cameraCaps.setMinimumTilt(0);
+ cameraCaps.setMaximumTilt(80);
+ cameraCaps.setMinimumFieldOfView(20.0);
+ cameraCaps.setMaximumFieldOfView(120.0);
setCameraCapabilities(cameraCaps);
setTileSize(QSize(256, 256));
diff --git a/src/plugins/geoservices/mapboxgl/mapboxgl.pro b/src/plugins/geoservices/mapboxgl/mapboxgl.pro
new file mode 100644
index 00000000..630bd6a9
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/mapboxgl.pro
@@ -0,0 +1,30 @@
+TARGET = qtgeoservices_mapboxgl
+
+QT += \
+ quick-private \
+ location-private \
+ positioning-private \
+ network
+
+HEADERS += \
+ qgeoserviceproviderpluginmapboxgl.h \
+ qgeomappingmanagerenginemapboxgl.h \
+ qgeomapmapboxgl.h \
+ qsgmapboxglnode.h
+
+SOURCES += \
+ qgeoserviceproviderpluginmapboxgl.cpp \
+ qgeomappingmanagerenginemapboxgl.cpp \
+ qgeomapmapboxgl.cpp \
+ qsgmapboxglnode.cpp
+
+OTHER_FILES += \
+ mapboxgl_plugin.json
+
+INCLUDEPATH += ../../../3rdparty/mapbox-gl-native/platform/qt/include
+
+LIBS_PRIVATE += -L$$OUT_PWD/../../../3rdparty/mapbox-gl-native/ -lqmapboxgl
+
+PLUGIN_TYPE = geoservices
+PLUGIN_CLASS_NAME = QGeoServiceProviderFactoryMapboxGL
+load(qt_plugin)
diff --git a/src/plugins/geoservices/mapboxgl/mapboxgl_plugin.json b/src/plugins/geoservices/mapboxgl/mapboxgl_plugin.json
new file mode 100644
index 00000000..0031e08f
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/mapboxgl_plugin.json
@@ -0,0 +1,11 @@
+{
+ "Keys": ["mapboxgl"],
+ "Provider": "mapboxgl",
+ "Version": 100,
+ "Experimental": false,
+ "Features": [
+ "OnlineMappingFeature",
+ "OfflineMappingFeature",
+ "LocalizedMappingFeature"
+ ]
+}
diff --git a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp
new file mode 100644
index 00000000..6cbab7a2
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp
@@ -0,0 +1,377 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2017 Mapbox, Inc.
+** 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 "qgeomapmapboxgl.h"
+#include "qsgmapboxglnode.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTimer>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFramebufferObject>
+#include <QtLocation/private/qgeomap_p_p.h>
+#include <QtLocation/private/qgeoprojection_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+
+#include "qgeopath.h"
+
+#include <QtQuick/QQuickWindow>
+#include <QtQuick/QSGImageNode>
+#include <QtQuick/private/qsgtexture_p.h>
+
+#include <QMapboxGL>
+
+#include <cmath>
+
+// FIXME: Expose from Mapbox GL constants
+#define MBGL_TILE_SIZE 512.0
+
+namespace {
+
+static const double invLog2 = 1.0 / std::log(2.0);
+
+static double zoomLevelFrom256(double zoomLevelFor256, double tileSize)
+{
+ return std::log(std::pow(2.0, zoomLevelFor256) * 256.0 / tileSize) * invLog2;
+}
+
+} // namespace
+
+class QGeoMapMapboxGLPrivate : public QGeoMapPrivate
+{
+ Q_DECLARE_PUBLIC(QGeoMapMapboxGL)
+
+public:
+ QGeoMapMapboxGLPrivate(QGeoMappingManagerEngineMapboxGL *engine);
+
+ ~QGeoMapMapboxGLPrivate();
+
+ QSGNode *updateSceneGraph(QSGNode *oldNode, QQuickWindow *window);
+
+ QGeoMap::ItemTypes supportedMapItemTypes() const Q_DECL_OVERRIDE;
+ void addMapItem(QDeclarativeGeoMapItemBase *item) Q_DECL_OVERRIDE;
+ void removeMapItem(QDeclarativeGeoMapItemBase *item) Q_DECL_OVERRIDE;
+
+ /* Data members */
+ enum SyncState : int {
+ NoSync = 0,
+ ViewportSync = 1 << 0,
+ CameraDataSync = 1 << 1,
+ MapTypeSync = 1 << 2
+ };
+ Q_DECLARE_FLAGS(SyncStates, SyncState);
+
+ QMapboxGLSettings m_settings;
+
+ QTimer m_refresh;
+ bool m_shouldRefresh = true;
+ bool m_warned = false;
+
+ QHash<QDeclarativeGeoMapItemBase *, QMapbox::AnnotationID> m_managedMapItems;
+ QList<QDeclarativeGeoMapItemBase *> m_mapItemsToAdd;
+ QList<QDeclarativeGeoMapItemBase *> m_mapItemsToUpdate;
+ QList<QDeclarativeGeoMapItemBase *> m_mapItemsToRemove;
+
+ SyncStates m_syncState = NoSync;
+
+protected:
+ void changeViewportSize(const QSize &size) Q_DECL_OVERRIDE;
+ void changeCameraData(const QGeoCameraData &oldCameraData) Q_DECL_OVERRIDE;
+ void changeActiveMapType(const QGeoMapType mapType) Q_DECL_OVERRIDE;
+
+private:
+ Q_DISABLE_COPY(QGeoMapMapboxGLPrivate)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGeoMapMapboxGLPrivate::SyncStates)
+
+QGeoMapMapboxGLPrivate::QGeoMapMapboxGLPrivate(QGeoMappingManagerEngineMapboxGL *engine)
+ : QGeoMapPrivate(engine, new QGeoProjectionWebMercator)
+{
+}
+
+QGeoMapMapboxGLPrivate::~QGeoMapMapboxGLPrivate()
+{
+}
+
+QSGNode *QGeoMapMapboxGLPrivate::updateSceneGraph(QSGNode *oldNode, QQuickWindow *window)
+{
+ Q_Q(QGeoMapMapboxGL);
+
+ if (!m_warned) {
+ if (window->openglContext()->thread() != QCoreApplication::instance()->thread()) {
+ qWarning() << "Threaded rendering is not supported by Mapbox GL plugin.";
+ QMetaObject::invokeMethod(&m_refresh, "start", Qt::QueuedConnection);
+ }
+
+ m_warned = true;
+ }
+
+ QSGMapboxGLNode *mbglNode = static_cast<QSGMapboxGLNode *>(oldNode);
+ if (!mbglNode) {
+ mbglNode = new QSGMapboxGLNode(m_settings, m_viewportSize, window->devicePixelRatio(), q);
+ m_syncState = MapTypeSync | CameraDataSync | ViewportSync;
+ }
+
+ QMapboxGL *map = mbglNode->map();
+
+ if (m_syncState & MapTypeSync) {
+ map->setStyleUrl(m_activeMapType.name());
+ }
+
+ for (QDeclarativeGeoMapItemBase *mapItem : m_mapItemsToRemove) {
+ Q_ASSERT(m_managedMapItems.contains(mapItem));
+ q->disconnect(mapItem);
+
+ QDeclarativePolylineMapItem *polyline = qobject_cast<QDeclarativePolylineMapItem *>(mapItem);
+ QDeclarativeMapLineProperties *lineStyle = polyline->line();
+ q->disconnect(lineStyle);
+
+ map->removeAnnotation(m_managedMapItems.take(mapItem));
+ if (m_mapItemsToUpdate.contains(mapItem)) {
+ m_mapItemsToUpdate.removeAll(mapItem);
+ }
+ }
+ m_mapItemsToRemove.clear();
+
+ for (QDeclarativeGeoMapItemBase *mapItem : m_mapItemsToAdd) {
+ Q_ASSERT(!m_managedMapItems.contains(mapItem));
+
+ QMapbox::Coordinates coordinates;
+ const QGeoPath *path = static_cast<const QGeoPath *>(&mapItem->geoShape());
+ for (const QGeoCoordinate &coordinate : path->path()) {
+ coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() };
+ }
+
+ QDeclarativePolylineMapItem *polyline = qobject_cast<QDeclarativePolylineMapItem *>(mapItem);
+ QObject::connect(polyline, &QDeclarativePolylineMapItem::pathChanged, q, &QGeoMapMapboxGL::onMapItemLinePathChange);
+ QObject::connect(polyline, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemLineOpacityChange);
+
+ QDeclarativeMapLineProperties *lineStyle = polyline->line();
+ QObject::connect(lineStyle, &QDeclarativeMapLineProperties::widthChanged, q, &QGeoMapMapboxGL::onMapItemLineWidthChange);
+ QObject::connect(lineStyle, &QDeclarativeMapLineProperties::colorChanged, q, &QGeoMapMapboxGL::onMapItemLineColorChange);
+
+ const float opacity = mapItem->mapItemOpacity();
+ const float width = lineStyle->width();
+ const QColor color = lineStyle->color();
+
+ QMapbox::CoordinatesCollections geometry { { coordinates } };
+ QMapbox::LineAnnotation lineAnnotation { { QMapbox::ShapeAnnotationGeometry::Type::LineStringType, geometry }, opacity, width, color };
+ QMapbox::Annotation annotation { QVariant::fromValue<QMapbox::LineAnnotation>(lineAnnotation) };
+
+ m_managedMapItems.insert(mapItem, map->addAnnotation(annotation));
+ }
+ m_mapItemsToAdd.clear();
+
+ for (QDeclarativeGeoMapItemBase *mapItem: m_mapItemsToUpdate) {
+ Q_ASSERT(m_managedMapItems.contains(mapItem));
+ QMapbox::Coordinates coordinates;
+ const QGeoPath *path = static_cast<const QGeoPath *>(&mapItem->geoShape());
+ for (const QGeoCoordinate &coordinate : path->path()) {
+ coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() };
+ }
+
+ QDeclarativePolylineMapItem *polyline = qobject_cast<QDeclarativePolylineMapItem *>(mapItem);
+ QDeclarativeMapLineProperties *lineStyle = polyline->line();
+
+ const float opacity = mapItem->mapItemOpacity();
+ const float width = lineStyle->width();
+ const QColor color = lineStyle->color();
+
+ QMapbox::CoordinatesCollections geometry { { coordinates } };
+ QMapbox::LineAnnotation lineAnnotation { { QMapbox::ShapeAnnotationGeometry::Type::LineStringType, geometry }, opacity, width, color };
+ QMapbox::Annotation annotation { QVariant::fromValue<QMapbox::LineAnnotation>(lineAnnotation) };
+
+ map->updateAnnotation(m_managedMapItems.value(mapItem), annotation);
+ }
+ m_mapItemsToUpdate.clear();
+
+ if (m_syncState & CameraDataSync) {
+ map->setZoom(zoomLevelFrom256(m_cameraData.zoomLevel() , MBGL_TILE_SIZE));
+ map->setBearing(m_cameraData.bearing());
+ map->setPitch(m_cameraData.tilt());
+
+ QGeoCoordinate coordinate = m_cameraData.center();
+ map->setCoordinate(QMapbox::Coordinate(coordinate.latitude(), coordinate.longitude()));
+ }
+
+ if (m_syncState & ViewportSync) {
+ mbglNode->resize(m_viewportSize, window->devicePixelRatio());
+ }
+
+ mbglNode->render();
+
+ m_syncState = NoSync;
+
+ return mbglNode;
+}
+
+QGeoMap::ItemTypes QGeoMapMapboxGLPrivate::supportedMapItemTypes() const
+{
+ return QGeoMap::MapPolyline;
+}
+
+void QGeoMapMapboxGLPrivate::addMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ Q_Q(QGeoMapMapboxGL);
+
+ switch (item->itemType()) {
+ case QGeoMap::NoItem:
+ case QGeoMap::MapRectangle:
+ case QGeoMap::MapCircle:
+ case QGeoMap::MapPolygon:
+ case QGeoMap::MapQuickItem:
+ case QGeoMap::CustomMapItem:
+ return;
+ case QGeoMap::MapPolyline:
+ m_mapItemsToAdd << item;
+ break;
+ }
+
+ emit q->sgNodeChanged();
+}
+
+void QGeoMapMapboxGLPrivate::removeMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ Q_Q(QGeoMapMapboxGL);
+
+ switch (item->itemType()) {
+ case QGeoMap::NoItem:
+ case QGeoMap::MapRectangle:
+ case QGeoMap::MapCircle:
+ case QGeoMap::MapPolygon:
+ case QGeoMap::MapQuickItem:
+ case QGeoMap::CustomMapItem:
+ return;
+ case QGeoMap::MapPolyline:
+ m_mapItemsToRemove << item;
+ break;
+ }
+
+ emit q->sgNodeChanged();
+}
+
+void QGeoMapMapboxGLPrivate::changeViewportSize(const QSize &)
+{
+ Q_Q(QGeoMapMapboxGL);
+
+ m_syncState = m_syncState | ViewportSync;
+ emit q->sgNodeChanged();
+}
+
+void QGeoMapMapboxGLPrivate::changeCameraData(const QGeoCameraData &)
+{
+ Q_Q(QGeoMapMapboxGL);
+
+ m_syncState = m_syncState | CameraDataSync;
+ emit q->sgNodeChanged();
+}
+
+void QGeoMapMapboxGLPrivate::changeActiveMapType(const QGeoMapType)
+{
+ Q_Q(QGeoMapMapboxGL);
+
+ m_syncState = m_syncState | MapTypeSync;
+ emit q->sgNodeChanged();
+}
+
+/*
+ * QGeoMapMapboxGL implementation
+ */
+
+QGeoMapMapboxGL::QGeoMapMapboxGL(QGeoMappingManagerEngineMapboxGL *engine, QObject *parent)
+ : QGeoMap(*new QGeoMapMapboxGLPrivate(engine), parent), m_engine(engine)
+{
+ Q_D(QGeoMapMapboxGL);
+
+ connect(&d->m_refresh, &QTimer::timeout, this, &QGeoMap::sgNodeChanged);
+ d->m_refresh.setInterval(250);
+}
+
+QGeoMapMapboxGL::~QGeoMapMapboxGL()
+{
+}
+
+void QGeoMapMapboxGL::setMapboxGLSettings(const QMapboxGLSettings& settings)
+{
+ Q_D(QGeoMapMapboxGL);
+
+ d->m_settings = settings;
+}
+
+QSGNode *QGeoMapMapboxGL::updateSceneGraph(QSGNode *oldNode, QQuickWindow *window)
+{
+ Q_D(QGeoMapMapboxGL);
+ return d->updateSceneGraph(oldNode, window);
+}
+
+void QGeoMapMapboxGL::onMapItemLinePathChange()
+{
+ Q_D(QGeoMapMapboxGL);
+ QDeclarativeGeoMapItemBase *mapItem = static_cast<QDeclarativeGeoMapItemBase *>(sender());
+ if (mapItem && !d->m_mapItemsToUpdate.contains(mapItem)) {
+ d->m_mapItemsToUpdate << mapItem;
+ }
+}
+
+void QGeoMapMapboxGL::onMapItemLineOpacityChange()
+{
+ Q_D(QGeoMapMapboxGL);
+ QDeclarativeGeoMapItemBase *mapItem = static_cast<QDeclarativeGeoMapItemBase *>(sender());
+ if (mapItem && !d->m_mapItemsToUpdate.contains(mapItem)) {
+ d->m_mapItemsToUpdate << mapItem;
+ }
+}
+
+void QGeoMapMapboxGL::onMapItemLineWidthChange(qreal)
+{
+ Q_D(QGeoMapMapboxGL);
+ QDeclarativeGeoMapItemBase *mapItem = static_cast<QDeclarativeGeoMapItemBase *>(sender()->parent());
+ if (mapItem && !d->m_mapItemsToUpdate.contains(mapItem)) {
+ d->m_mapItemsToUpdate << mapItem;
+ }
+}
+
+void QGeoMapMapboxGL::onMapItemLineColorChange(const QColor &)
+{
+ Q_D(QGeoMapMapboxGL);
+ QDeclarativeGeoMapItemBase *mapItem = static_cast<QDeclarativeGeoMapItemBase *>(sender()->parent());
+ if (mapItem && !d->m_mapItemsToUpdate.contains(mapItem)) {
+ d->m_mapItemsToUpdate << mapItem;
+ }
+}
diff --git a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h
new file mode 100644
index 00000000..2d601c42
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2017 Mapbox, Inc.
+** 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 QGEOMAPMAPBOXGL_H
+#define QGEOMAPMAPBOXGL_H
+
+#include "qgeomappingmanagerenginemapboxgl.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+class QGeoMapMapboxGLPrivate;
+class QGeoMapMapboxGL : public QGeoMap
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGeoMapMapboxGL)
+
+public:
+ QGeoMapMapboxGL(QGeoMappingManagerEngineMapboxGL *engine, QObject *parent);
+ virtual ~QGeoMapMapboxGL();
+
+ void setMapboxGLSettings(const QMapboxGLSettings &);
+
+private Q_SLOTS:
+ void onMapItemLinePathChange();
+ void onMapItemLineOpacityChange();
+ void onMapItemLineWidthChange(qreal);
+ void onMapItemLineColorChange(const QColor &);
+
+protected:
+ QSGNode *updateSceneGraph(QSGNode *oldNode, QQuickWindow *window) Q_DECL_OVERRIDE;
+
+ QGeoMappingManagerEngineMapboxGL *m_engine;
+};
+
+#endif // QGEOMAPMAPBOXGL_H
diff --git a/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp
new file mode 100644
index 00000000..04a800aa
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2017 Mapbox, Inc.
+** 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 "qgeomappingmanagerenginemapboxgl.h"
+#include "qgeomapmapboxgl.h"
+
+#include <QtCore/qstandardpaths.h>
+#include <QtLocation/private/qabstractgeotilecache_p.h>
+#include <QtLocation/private/qgeocameracapabilities_p.h>
+#include <QtLocation/private/qgeomaptype_p.h>
+
+#include <QDir>
+
+QT_BEGIN_NAMESPACE
+
+QGeoMappingManagerEngineMapboxGL::QGeoMappingManagerEngineMapboxGL(const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString)
+: QGeoMappingManagerEngine()
+{
+ *error = QGeoServiceProvider::NoError;
+ errorString->clear();
+
+ QGeoCameraCapabilities cameraCaps;
+ cameraCaps.setMinimumZoomLevel(0.0);
+ cameraCaps.setMaximumZoomLevel(20.0);
+ cameraCaps.setTileSize(512);
+ cameraCaps.setSupportsBearing(true);
+ cameraCaps.setSupportsTilting(true);
+ cameraCaps.setMinimumTilt(0);
+ cameraCaps.setMaximumTilt(60);
+ cameraCaps.setMinimumFieldOfView(36.87);
+ cameraCaps.setMaximumFieldOfView(36.87);
+ setCameraCapabilities(cameraCaps);
+
+ QList<QGeoMapType> mapTypes;
+ int mapId = 0;
+
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/streets-v9"),
+ tr("Streets"), false, false, ++mapId);
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/basic-v9"),
+ tr("Basic"), false, false, ++mapId);
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/bright-v9"),
+ tr("Bright"), false, false, ++mapId);
+ mapTypes << QGeoMapType(QGeoMapType::TerrainMap, QStringLiteral("mapbox://styles/mapbox/outdoors-v9"),
+ tr("Outdoors"), false, false, ++mapId);
+ mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, QStringLiteral("mapbox://styles/mapbox/satellite-v9"),
+ tr("Satellite"), false, false, ++mapId);
+ mapTypes << QGeoMapType(QGeoMapType::HybridMap, QStringLiteral("mapbox://styles/mapbox/satellite-streets-v9"),
+ tr("Satellite Streets"), false, false, ++mapId);
+ mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/light-v9"),
+ tr("Light"), false, false, ++mapId);
+ mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/dark-v9"),
+ tr("Dark"), false, false, ++mapId);
+ mapTypes << QGeoMapType(QGeoMapType::TransitMap, QStringLiteral("mapbox://styles/mapbox/traffic-day-v1"),
+ tr("Streets Traffic Day"), false, false, ++mapId);
+ mapTypes << QGeoMapType(QGeoMapType::TransitMap, QStringLiteral("mapbox://styles/mapbox/traffic-night-v1"),
+ tr("Streets Traffic Night"), false, true, ++mapId);
+
+ if (parameters.contains(QStringLiteral("mapboxgl.mapping.additional_style_urls"))) {
+ const QString ids = parameters.value(QStringLiteral("mapboxgl.mapping.additional_style_urls")).toString();
+ const QStringList idList = ids.split(',', QString::SkipEmptyParts);
+
+ for (auto it = idList.crbegin(), end = idList.crend(); it != end; ++it) {
+ if ((*it).isEmpty())
+ continue;
+
+ mapTypes.prepend(QGeoMapType(QGeoMapType::CustomMap, *it,
+ tr("User provided style"), false, false, ++mapId));
+ }
+ }
+
+ setSupportedMapTypes(mapTypes);
+
+ if (parameters.contains(QStringLiteral("mapboxgl.access_token"))) {
+ m_settings.setAccessToken(parameters.value(QStringLiteral("mapboxgl.access_token")).toString());
+ }
+
+ bool memoryCache = false;
+ if (parameters.contains(QStringLiteral("mapboxgl.mapping.cache.memory"))) {
+ memoryCache = parameters.value(QStringLiteral("mapboxgl.mapping.cache.memory")).toBool();
+ m_settings.setCacheDatabasePath(QStringLiteral(":memory:"));
+ }
+
+ QString cacheDirectory;
+ if (parameters.contains(QStringLiteral("mapboxgl.mapping.cache.directory"))) {
+ cacheDirectory = parameters.value(QStringLiteral("mapboxgl.mapping.cache.directory")).toString();
+ } else {
+ cacheDirectory = QAbstractGeoTileCache::baseLocationCacheDirectory() + QStringLiteral("mapboxgl/");
+ }
+
+ if (!memoryCache && QDir::root().mkpath(cacheDirectory)) {
+ m_settings.setCacheDatabasePath(cacheDirectory + "/mapboxgl.db");
+ }
+
+ if (parameters.contains(QStringLiteral("mapboxgl.mapping.cache.size"))) {
+ bool ok = false;
+ int cacheSize = parameters.value(QStringLiteral("mapboxgl.mapping.cache.size")).toString().toInt(&ok);
+
+ if (ok)
+ m_settings.setCacheDatabaseMaximumSize(cacheSize);
+ }
+
+ engineInitialized();
+}
+
+QGeoMappingManagerEngineMapboxGL::~QGeoMappingManagerEngineMapboxGL()
+{
+}
+
+QGeoMap *QGeoMappingManagerEngineMapboxGL::createMap()
+{
+ QGeoMapMapboxGL* map = new QGeoMapMapboxGL(this, 0);
+ map->setMapboxGLSettings(m_settings);
+
+ return map;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h
new file mode 100644
index 00000000..1bf44064
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2017 Mapbox, Inc.
+** 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 QGEOTILEDMAPPINGMANAGERENGINEMAPBOXGL_H
+#define QGEOTILEDMAPPINGMANAGERENGINEMAPBOXGL_H
+
+#include <QtLocation/QGeoServiceProvider>
+#include <QtLocation/private/qgeomappingmanagerengine_p.h>
+
+#include <QMapboxGL>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoMappingManagerEngineMapboxGL : public QGeoMappingManagerEngine
+{
+ Q_OBJECT
+
+public:
+ QGeoMappingManagerEngineMapboxGL(const QVariantMap &parameters,
+ QGeoServiceProvider::Error *error, QString *errorString);
+ ~QGeoMappingManagerEngineMapboxGL();
+
+ QGeoMap *createMap() Q_DECL_OVERRIDE;
+
+private:
+ QMapboxGLSettings m_settings;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOTILEDMAPPINGMANAGERENGINEMAPBOXGL_H
diff --git a/src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.cpp b/src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.cpp
new file mode 100644
index 00000000..30c01f8c
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2017 Mapbox, Inc.
+** 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 "qgeoserviceproviderpluginmapboxgl.h"
+#include "qgeomappingmanagerenginemapboxgl.h"
+
+
+QT_BEGIN_NAMESPACE
+
+QGeoCodingManagerEngine *QGeoServiceProviderFactoryMapboxGL::createGeocodingManagerEngine(
+ const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString) const
+{
+ Q_UNUSED(parameters)
+ Q_UNUSED(error)
+ Q_UNUSED(errorString)
+
+ return 0;
+}
+
+QGeoMappingManagerEngine *QGeoServiceProviderFactoryMapboxGL::createMappingManagerEngine(
+ const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString) const
+{
+ return new QGeoMappingManagerEngineMapboxGL(parameters, error, errorString);
+}
+
+QGeoRoutingManagerEngine *QGeoServiceProviderFactoryMapboxGL::createRoutingManagerEngine(
+ const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString) const
+{
+ Q_UNUSED(parameters)
+ Q_UNUSED(error)
+ Q_UNUSED(errorString)
+
+ return 0;
+}
+
+QPlaceManagerEngine *QGeoServiceProviderFactoryMapboxGL::createPlaceManagerEngine(
+ const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString) const
+{
+ Q_UNUSED(parameters)
+ Q_UNUSED(error)
+ Q_UNUSED(errorString)
+
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.h b/src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.h
new file mode 100644
index 00000000..2bba96f1
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2017 Mapbox, Inc.
+** 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 QGEOSERVICEPROVIDER_MAPBOXGL_H
+#define QGEOSERVICEPROVIDER_MAPBOXGL_H
+
+#include <QtCore/QObject>
+#include <QtLocation/QGeoServiceProviderFactory>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoServiceProviderFactoryMapboxGL: public QObject, public QGeoServiceProviderFactory
+{
+ Q_OBJECT
+ Q_INTERFACES(QGeoServiceProviderFactory)
+ Q_PLUGIN_METADATA(IID "org.qt-project.qt.geoservice.serviceproviderfactory/5.0"
+ FILE "mapboxgl_plugin.json")
+
+public:
+ QGeoCodingManagerEngine *createGeocodingManagerEngine(const QVariantMap &parameters,
+ QGeoServiceProvider::Error *error,
+ QString *errorString) const;
+ QGeoMappingManagerEngine *createMappingManagerEngine(const QVariantMap &parameters,
+ QGeoServiceProvider::Error *error,
+ QString *errorString) const;
+ QGeoRoutingManagerEngine *createRoutingManagerEngine(const QVariantMap &parameters,
+ QGeoServiceProvider::Error *error,
+ QString *errorString) const;
+ QPlaceManagerEngine *createPlaceManagerEngine(const QVariantMap &parameters,
+ QGeoServiceProvider::Error *error,
+ QString *errorString) const;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/geoservices/mapboxgl/qsgmapboxglnode.cpp b/src/plugins/geoservices/mapboxgl/qsgmapboxglnode.cpp
new file mode 100644
index 00000000..f4e8a264
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/qsgmapboxglnode.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2017 Mapbox, Inc.
+** 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 <qsgmapboxglnode.h>
+#include <qgeomapmapboxgl.h>
+
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+
+QSGMapboxGLNode::QSGMapboxGLNode(const QMapboxGLSettings &settings, const QSize &size, qreal pixelRatio, QGeoMapMapboxGL *geoMap)
+ : QSGSimpleTextureNode()
+{
+ setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
+
+ m_map.reset(new QMapboxGL(nullptr, settings, size, pixelRatio));
+
+ QObject::connect(m_map.data(), &QMapboxGL::needsRendering, geoMap, &QGeoMap::sgNodeChanged);
+ QObject::connect(m_map.data(), &QMapboxGL::copyrightsChanged, geoMap,
+ static_cast<void (QGeoMap::*)(const QString &)>(&QGeoMapMapboxGL::copyrightsChanged));
+}
+
+void QSGMapboxGLNode::resize(const QSize &size, qreal pixelRatio)
+{
+ const QSize fbSize = size * pixelRatio;
+ m_map->resize(size, fbSize);
+
+ m_fbo.reset(new QOpenGLFramebufferObject(fbSize, QOpenGLFramebufferObject::CombinedDepthStencil));
+
+ QSGPlainTexture *fboTexture = static_cast<QSGPlainTexture *>(texture());
+ if (!fboTexture)
+ fboTexture = new QSGPlainTexture;
+
+ fboTexture->setTextureId(m_fbo->texture());
+ fboTexture->setTextureSize(fbSize);
+
+ if (!texture()) {
+ setTexture(fboTexture);
+ setOwnsTexture(true);
+ }
+
+ setRect(QRectF(QPointF(), size));
+ markDirty(QSGNode::DirtyGeometry);
+}
+
+void QSGMapboxGLNode::render()
+{
+ QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
+ f->glViewport(0, 0, m_fbo->width(), m_fbo->height());
+
+ m_fbo->bind();
+ m_map->render(m_fbo.data());
+ m_fbo->release();
+
+ markDirty(QSGNode::DirtyMaterial);
+}
+
+QMapboxGL* QSGMapboxGLNode::map() const
+{
+ return m_map.data();
+}
+
+QMapbox::AnnotationID QSGMapboxGLNode::addAnnotation(const QMapbox::Annotation &annotation)
+{
+ return m_map->addAnnotation(annotation);
+}
+
+void QSGMapboxGLNode::updateAnnotation(QMapbox::AnnotationID id,const QMapbox::Annotation &annotation)
+{
+ m_map->updateAnnotation(id, annotation);
+}
+
+void QSGMapboxGLNode::removeAnnotation(QMapbox::AnnotationID annotationId)
+{
+ m_map->removeAnnotation(annotationId);
+}
+
diff --git a/src/plugins/geoservices/mapboxgl/qsgmapboxglnode.h b/src/plugins/geoservices/mapboxgl/qsgmapboxglnode.h
new file mode 100644
index 00000000..08d8f21b
--- /dev/null
+++ b/src/plugins/geoservices/mapboxgl/qsgmapboxglnode.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2017 Mapbox, Inc.
+** 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 QSGMAPBOXGLNODE_H
+#define QSGMAPBOXGLNODE_H
+
+#include <QtQuick/QSGSimpleTextureNode>
+#include <QtQuick/private/qsgtexture_p.h>
+#include <QtGui/QOpenGLFramebufferObject>
+
+#include <QMapboxGL>
+
+class QGeoMapMapboxGL;
+
+class QSGMapboxGLNode : public QSGSimpleTextureNode
+{
+public:
+ QSGMapboxGLNode(const QMapboxGLSettings &, const QSize &, qreal pixelRatio, QGeoMapMapboxGL *geoMap);
+
+ void resize(const QSize &size, qreal pixelRatio);
+ void render();
+
+ QMapboxGL* map() const;
+
+ QMapbox::AnnotationID addAnnotation(const QMapbox::Annotation &);
+ void updateAnnotation(QMapbox::AnnotationID, const QMapbox::Annotation &);
+ void removeAnnotation(QMapbox::AnnotationID);
+
+private:
+ QScopedPointer<QMapboxGL> m_map;
+ QScopedPointer<QOpenGLFramebufferObject> m_fbo;
+};
+
+#endif // QSGMAPBOXGLNODE_H
diff --git a/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp b/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp
index 3a9ac277..e5809018 100644
--- a/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp
@@ -67,7 +67,12 @@ QGeoTiledMappingManagerEngineNokia::QGeoTiledMappingManagerEngineNokia(
capabilities.setMinimumZoomLevel(0.0);
capabilities.setMaximumZoomLevel(20.0);
-
+ capabilities.setSupportsBearing(true);
+ capabilities.setSupportsTilting(true);
+ capabilities.setMinimumTilt(0);
+ capabilities.setMaximumTilt(80);
+ capabilities.setMinimumFieldOfView(20.0);
+ capabilities.setMaximumFieldOfView(120.0);
setCameraCapabilities(capabilities);
setTileSize(QSize(256, 256));
diff --git a/src/plugins/geoservices/osm/qgeotiledmaposm.cpp b/src/plugins/geoservices/osm/qgeotiledmaposm.cpp
index d94a40a6..e1383afb 100644
--- a/src/plugins/geoservices/osm/qgeotiledmaposm.cpp
+++ b/src/plugins/geoservices/osm/qgeotiledmaposm.cpp
@@ -45,6 +45,11 @@
QT_BEGIN_NAMESPACE
+static QString bodify(const QString &html)
+{
+ return QStringLiteral("<body>") + html + QStringLiteral("</body>");
+}
+
QGeoTiledMapOsm::QGeoTiledMapOsm(QGeoTiledMappingManagerEngineOsm *engine, QObject *parent)
: QGeoTiledMap(engine, parent), m_mapId(-1), m_engine(engine)
{
@@ -95,13 +100,13 @@ void QGeoTiledMapOsm::onProviderDataUpdated(const QGeoTileProviderOsm *provider)
}
if (!dataCopy.isEmpty()) {
if (!copyRights.isEmpty())
- copyRights += QStringLiteral("<br/>");
+ copyRights += QStringLiteral(" | ");
copyRights += QStringLiteral("Data &copy; ");
copyRights += dataCopy;
}
if (!styleCopy.isEmpty()) {
if (!copyRights.isEmpty())
- copyRights += QStringLiteral("<br/>");
+ copyRights += QStringLiteral(" | ");
copyRights += QStringLiteral("Style &copy; ");
copyRights += styleCopy;
}
@@ -109,7 +114,7 @@ void QGeoTiledMapOsm::onProviderDataUpdated(const QGeoTileProviderOsm *provider)
if (copyRights.isEmpty() && provider->mapType().style() == QGeoMapType::CustomMap)
copyRights = m_engine->customCopyright();
- emit copyrightsChanged(copyRights);
+ emit copyrightsChanged(bodify(copyRights));
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
index 3228b31b..e9e48008 100644
--- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
+++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
@@ -57,6 +57,12 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian
QGeoCameraCapabilities cameraCaps;
cameraCaps.setMinimumZoomLevel(0.0);
cameraCaps.setMaximumZoomLevel(19.0);
+ cameraCaps.setSupportsBearing(true);
+ cameraCaps.setSupportsTilting(true);
+ cameraCaps.setMinimumTilt(0);
+ cameraCaps.setMaximumTilt(80);
+ cameraCaps.setMinimumFieldOfView(20.0);
+ cameraCaps.setMaximumFieldOfView(120.0);
setCameraCapabilities(cameraCaps);
setTileSize(QSize(256, 256));
diff --git a/src/positioning/positioning.pro b/src/positioning/positioning.pro
index c4c9cc6c..0df56a71 100644
--- a/src/positioning/positioning.pro
+++ b/src/positioning/positioning.pro
@@ -1,6 +1,10 @@
TARGET = QtPositioning
QT = core-private
+#INCLUDEPATH += ../3rdparty/poly2tri
+INCLUDEPATH += ../3rdparty/clipper
+INCLUDEPATH += ../3rdparty/clip2tri
+
QMAKE_DOCS = $$PWD/doc/qtpositioning.qdocconf
OTHER_FILES += doc/src/*.qdoc # show .qdoc files in Qt Creator
@@ -53,7 +57,8 @@ PRIVATE_HEADERS += \
qpositioningglobal_p.h \
qlocationdata_simulator_p.h \
qdoublematrix4x4_p.h \
- qgeopath_p.h
+ qgeopath_p.h \
+ qclipperutils_p.h
SOURCES += \
qgeoaddress.cpp \
@@ -78,9 +83,12 @@ SOURCES += \
qgeopath.cpp \
qlocationdata_simulator.cpp \
qwebmercator.cpp \
- qdoublematrix4x4.cpp
+ qdoublematrix4x4.cpp \
+ qclipperutils.cpp
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
load(qt_module)
+
+LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lclip2tri$$qtPlatformTargetSuffix()
diff --git a/src/positioning/qclipperutils.cpp b/src/positioning/qclipperutils.cpp
new file mode 100644
index 00000000..08e65712
--- /dev/null
+++ b/src/positioning/qclipperutils.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtPositioning module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qclipperutils_p.h"
+
+QT_BEGIN_NAMESPACE
+
+static const double kClipperScaleFactor = 281474976710656.0; // 48 bits of precision
+static const double kClipperScaleFactorInv = 1.0 / kClipperScaleFactor;
+
+double QClipperUtils::clipperScaleFactor()
+{
+ return kClipperScaleFactor;
+}
+
+QDoubleVector2D QClipperUtils::toVector2D(const IntPoint &p)
+{
+ return QDoubleVector2D(double(p.X) * kClipperScaleFactorInv, double(p.Y) * kClipperScaleFactorInv);
+}
+
+IntPoint QClipperUtils::toIntPoint(const QDoubleVector2D &p)
+{
+ return IntPoint(cInt(p.x() * kClipperScaleFactor), cInt(p.y() * kClipperScaleFactor));
+}
+
+QList<QDoubleVector2D> QClipperUtils::pathToQList(const Path &path)
+{
+ QList<QDoubleVector2D> res;
+ res.reserve(path.size());
+ for (const IntPoint &ip: path)
+ res.append(toVector2D(ip));
+ return res;
+}
+
+QList<QList<QDoubleVector2D> > QClipperUtils::pathsToQList(const Paths &paths)
+{
+ QList<QList<QDoubleVector2D> > res;
+ res.reserve(paths.size());
+ for (const Path &p: paths) {
+ res.append(pathToQList(p));
+ }
+ return res;
+}
+
+Path QClipperUtils::qListToPath(const QList<QDoubleVector2D> &list)
+{
+ Path res;
+ res.reserve(list.size());
+ for (const QDoubleVector2D &p: list)
+ res.push_back(toIntPoint(p));
+ return res;
+}
+
+Paths QClipperUtils::qListToPaths(const QList<QList<QDoubleVector2D> > &lists)
+{
+ Paths res;
+ res.reserve(lists.size());
+ for (const QList<QDoubleVector2D> &l: lists) {
+ res.push_back(qListToPath(l));
+ }
+ return res;
+}
+
+QT_END_NAMESPACE
diff --git a/src/positioning/qclipperutils_p.h b/src/positioning/qclipperutils_p.h
new file mode 100644
index 00000000..f05d9838
--- /dev/null
+++ b/src/positioning/qclipperutils_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtPositioning module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QCLIPPERUTILS_P_H
+#define QCLIPPERUTILS_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.
+//
+
+/*
+ * This file is intended to be include only in source files of
+ * QtPositioning/QtLocation. It is in QtPositioning to enable manipulation
+ * of geo polygons
+ */
+
+#include <QtPositioning/private/qpositioningglobal_p.h>
+#include <QtCore/QtGlobal>
+#include <QtCore/QList>
+#include <cmath>
+/* clip2tri triangulator includes */
+#include <clip2tri.h>
+#include <QtPositioning/private/qdoublevector2d_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_POSITIONING_PRIVATE_EXPORT QClipperUtils
+{
+public:
+ static double clipperScaleFactor();
+
+ static QDoubleVector2D toVector2D(const IntPoint &p);
+ static IntPoint toIntPoint(const QDoubleVector2D &p);
+
+ static QList<QDoubleVector2D> pathToQList(const Path &path);
+ static QList<QList<QDoubleVector2D> > pathsToQList(const Paths &paths);
+
+ static Path qListToPath(const QList<QDoubleVector2D> &list);
+ static Paths qListToPaths(const QList<QList<QDoubleVector2D> > &lists);
+};
+
+QT_END_NAMESPACE
+
+#endif // QCLIPPERUTILS_P_H
diff --git a/src/positioning/qgeocircle.cpp b/src/positioning/qgeocircle.cpp
index 4b4370bf..6fccb8af 100644
--- a/src/positioning/qgeocircle.cpp
+++ b/src/positioning/qgeocircle.cpp
@@ -316,11 +316,11 @@ void QGeoCirclePrivate::updateBoundingBox()
));
QGeoCoordinate topLeft;
- topLeft.setLatitude(m_center.latitude() + lat_delta_in_deg);
- topLeft.setLongitude(m_center.longitude() - lon_delta_in_deg);
+ topLeft.setLatitude(QLocationUtils::clipLat(m_center.latitude() + lat_delta_in_deg));
+ topLeft.setLongitude(QLocationUtils::wrapLong(m_center.longitude() - lon_delta_in_deg));
QGeoCoordinate bottomRight;
- bottomRight.setLatitude(m_center.latitude() - lat_delta_in_deg);
- bottomRight.setLongitude(m_center.longitude() + lon_delta_in_deg);
+ bottomRight.setLatitude(QLocationUtils::clipLat(m_center.latitude() - lat_delta_in_deg));
+ bottomRight.setLongitude(QLocationUtils::wrapLong(m_center.longitude() + lon_delta_in_deg));
m_bbox = QGeoRectangle(topLeft, bottomRight);
}
diff --git a/src/positioning/qgeopath.cpp b/src/positioning/qgeopath.cpp
index a8e77e10..87f4a9d4 100644
--- a/src/positioning/qgeopath.cpp
+++ b/src/positioning/qgeopath.cpp
@@ -66,7 +66,7 @@ QT_BEGIN_NAMESPACE
but never crosses the poles.
This is relevant for the calculation of the bounding box returned by
- \l QGeoShape::geoBoundingBox() for this shape, which will have the latitude of
+ \l QGeoShape::boundingGeoRectangle() for this shape, which will have the latitude of
the top left corner set to the maximum latitude in the path point set.
Similarly, the latitude of the bottom right corner will be the minimum latitude
in the path point set.
diff --git a/src/positioning/qlocationutils_p.h b/src/positioning/qlocationutils_p.h
index 552ec33f..f66179e1 100644
--- a/src/positioning/qlocationutils_p.h
+++ b/src/positioning/qlocationutils_p.h
@@ -52,18 +52,16 @@
#include <QtCore/QtGlobal>
#include <math.h>
+#include <QtPositioning/QGeoCoordinate>
-#ifndef M_PI
-#define M_PI 3.14159265358979323846264338327950288
-#endif
-
-#ifndef M_1_180
-#define M_1_180 0.0055555555555555555555555555555555555555556
-#endif
-
-#ifndef M_1_PI
-#define M_1_PI 0.31830988618379067154
-#endif
+static const double M_PID = 3.14159265358979323846264338327950288; // to get more precision than float
+static const double M_1_180D = 0.0055555555555555555555555555555555555555556;
+static const double M_1_PID = 1.0 / M_PID;
+static const double M_PI_180D = M_PID / 180.0; //0.0174532925199432954743716805978692718781530857086181640625;
+static const double M_180_PID = 180.0 / M_PID; // 57.29577951308232286464772187173366546630859375
+static const double offsetEpsilon = 0.0000000000001;
+static const double leftOffset = -180.0 + offsetEpsilon;
+static const double rightOffset = 180.0 - offsetEpsilon;
QT_BEGIN_NAMESPACE
class QTime;
@@ -93,25 +91,25 @@ public:
};
inline static bool isValidLat(double lat) {
- return lat >= -90 && lat <= 90;
+ return lat >= -90.0 && lat <= 90.0;
}
inline static bool isValidLong(double lng) {
- return lng >= -180 && lng <= 180;
+ return lng >= -180.0 && lng <= 180.0;
}
- inline static double clipLat(double lat) {
- if (lat > 90)
- lat = 90;
- else if (lat < -90)
- lat = -90;
+ inline static double clipLat(double lat, double clipValue = 90.0) {
+ if (lat > clipValue)
+ lat = clipValue;
+ else if (lat < -clipValue)
+ lat = -clipValue;
return lat;
}
inline static double wrapLong(double lng) {
- if (lng > 180)
- lng -= 360;
- else if (lng < -180)
- lng += 360;
+ if (lng > 180.0)
+ lng -= 360.0;
+ else if (lng < -180.0)
+ lng += 360.0;
return lng;
}
@@ -211,12 +209,12 @@ public:
inline static double radians(double degrees)
{
- return degrees * M_PI * M_1_180;
+ return degrees * M_PI_180D;
}
inline static double degrees(double radians)
{
- return radians * 180.0 * M_1_PI;
+ return radians * M_180_PID;
}
inline static double earthMeanRadius()
@@ -224,11 +222,33 @@ public:
return 6371007.2;
}
+ inline static double earthMeanDiameter()
+ {
+ return earthMeanRadius() * 2.0 * M_PID;
+ }
+
inline static double mercatorMaxLatitude()
{
return 85.05113;
}
+ inline static QGeoCoordinate antipodalPoint(const QGeoCoordinate &p)
+ {
+ return QGeoCoordinate(-p.latitude(), wrapLong(p.longitude() + 180.0));
+ }
+
+ // Leftmost longitude before wrapping kicks in
+ inline static double mapLeftLongitude(double centerLongitude)
+ {
+ return wrapLong(centerLongitude + leftOffset);
+ }
+
+ // Rightmost longitude before wrapping kicks in
+ inline static double mapRightLongitude(double centerLongitude)
+ {
+ return wrapLong(centerLongitude - leftOffset);
+ }
+
/*
Creates a QGeoPositionInfo from a GGA, GLL, RMC, VTG or ZDA sentence.
diff --git a/src/positioning/qwebmercator.cpp b/src/positioning/qwebmercator.cpp
index d22258a7..da35c7d7 100644
--- a/src/positioning/qwebmercator.cpp
+++ b/src/positioning/qwebmercator.cpp
@@ -101,6 +101,30 @@ QGeoCoordinate QWebMercator::mercatorToCoord(const QDoubleVector2D &mercator)
return QGeoCoordinate(lat, lng, 0.0);
}
+QGeoCoordinate QWebMercator::mercatorToCoordClamped(const QDoubleVector2D &mercator)
+{
+ double fx = mercator.x();
+ double fy = mercator.y();
+
+ if (fy < 0.0)
+ fy = 0.0;
+ else if (fy > 1.0)
+ fy = 1.0;
+
+ double lat = (180.0 / M_PI) * (2.0 * std::atan(std::exp(M_PI * (1.0 - 2.0 * fy))) - (M_PI / 2.0));
+
+ double lng;
+ if (fx >= 0) {
+ lng = realmod(fx, 1.0);
+ } else {
+ lng = realmod(1.0 - realmod(-1.0 * fx, 1.0), 1.0);
+ }
+
+ lng = lng * 360.0 - 180.0;
+
+ return QGeoCoordinate(lat, lng, 0.0);
+}
+
QGeoCoordinate QWebMercator::coordinateInterpolation(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
{
QDoubleVector2D s = QWebMercator::coordToMercator(from);
diff --git a/src/positioning/qwebmercator_p.h b/src/positioning/qwebmercator_p.h
index 8c324710..2b8e9564 100644
--- a/src/positioning/qwebmercator_p.h
+++ b/src/positioning/qwebmercator_p.h
@@ -65,6 +65,7 @@ class Q_POSITIONING_PRIVATE_EXPORT QWebMercator
public:
static QDoubleVector2D coordToMercator(const QGeoCoordinate &coord);
static QGeoCoordinate mercatorToCoord(const QDoubleVector2D &mercator);
+ static QGeoCoordinate mercatorToCoordClamped(const QDoubleVector2D &mercator);
static QGeoCoordinate coordinateInterpolation(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress);
private:
diff --git a/src/src.pro b/src/src.pro
index 4b9c4985..a64ac534 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,7 +1,7 @@
TEMPLATE = subdirs
SUBDIRS += positioning
-plugins.depends += positioning
+plugins.depends += positioning 3rdparty
qtHaveModule(quick) {
SUBDIRS += 3rdparty