summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--.qmake.conf2
-rw-r--r--config.tests/winrt/main.cpp2
-rw-r--r--examples/location/mapviewer/main.cpp24
-rw-r--r--examples/location/mapviewer/map/MapComponent.qml4
-rw-r--r--examples/location/places/main.cpp18
-rw-r--r--examples/location/planespotter/main.cpp4
-rw-r--r--src/3rdparty/3rdparty.pro14
-rw-r--r--src/3rdparty/clip2tri/clip2tri.cpp99
-rw-r--r--src/3rdparty/clip2tri/clip2tri.h18
-rw-r--r--src/3rdparty/clip2tri/clip2tri.pro3
-rw-r--r--src/3rdparty/clipper/clipper.cpp1689
-rw-r--r--src/3rdparty/clipper/clipper.h148
m---------src/3rdparty/mapbox-gl-native0
-rw-r--r--src/imports/location/location.cpp66
-rw-r--r--src/imports/location/location.pro61
-rw-r--r--src/imports/location/qdeclarativegeomapcopyrightsnotice.cpp168
-rw-r--r--src/imports/positioning/locationsingleton.cpp26
-rw-r--r--src/imports/positioning/locationsingleton.h4
-rw-r--r--src/imports/positioning/positioning.cpp5
-rw-r--r--src/imports/positioning/qdeclarativepositionsource.cpp2
-rw-r--r--src/imports/positioning/qquickgeocoordinateanimation.cpp14
-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)430
-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)6
-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)738
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap_p.h (renamed from src/imports/location/qdeclarativegeomap_p.h)74
-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)63
-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)4
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapparameter.cpp125
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapparameter_p.h90
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapquickitem.cpp (renamed from src/imports/location/qdeclarativegeomapquickitem.cpp)31
-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)3
-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)62
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutemodel_p.h (renamed from src/imports/location/qdeclarativegeoroutemodel_p.h)10
-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)5
-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)350
-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)478
-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)6
-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)673
-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)6
-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)8
-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/maps.pri6
-rw-r--r--src/location/maps/qabstractgeotilecache_p.h16
-rw-r--r--src/location/maps/qgeocameracapabilities.cpp99
-rw-r--r--src/location/maps/qgeocameracapabilities_p.h11
-rw-r--r--src/location/maps/qgeocameradata.cpp19
-rw-r--r--src/location/maps/qgeocameradata_p.h13
-rw-r--r--src/location/maps/qgeocameratiles.cpp192
-rw-r--r--src/location/maps/qgeocodereply.cpp12
-rw-r--r--src/location/maps/qgeocodereply.h1
-rw-r--r--src/location/maps/qgeofiletilecache.cpp6
-rw-r--r--src/location/maps/qgeofiletilecache_p.h2
-rw-r--r--src/location/maps/qgeomap.cpp121
-rw-r--r--src/location/maps/qgeomap_p.h44
-rw-r--r--src/location/maps/qgeomap_p_p.h19
-rw-r--r--src/location/maps/qgeomapparameter.cpp74
-rw-r--r--src/location/maps/qgeomapparameter_p.h84
-rw-r--r--src/location/maps/qgeoprojection.cpp498
-rw-r--r--src/location/maps/qgeoprojection_p.h205
-rw-r--r--src/location/maps/qgeoroutereply.cpp12
-rw-r--r--src/location/maps/qgeoroutereply.h1
-rw-r--r--src/location/maps/qgeotiledmap.cpp122
-rw-r--r--src/location/maps/qgeotiledmap_p.h21
-rw-r--r--src/location/maps/qgeotiledmap_p_p.h16
-rw-r--r--src/location/maps/qgeotiledmappingmanagerengine.cpp6
-rw-r--r--src/location/maps/qgeotiledmappingmanagerengine_p.h22
-rw-r--r--src/location/maps/qgeotiledmappingmanagerengine_p_p.h2
-rw-r--r--src/location/maps/qgeotiledmapreply.cpp1
-rw-r--r--src/location/maps/qgeotiledmapreply_p.h1
-rw-r--r--src/location/maps/qgeotiledmapscene.cpp264
-rw-r--r--src/location/maps/qgeotiledmapscene_p.h7
-rw-r--r--src/location/maps/qgeotilefetcher_p.h2
-rw-r--r--src/location/places/qplacereply.cpp14
-rw-r--r--src/location/places/qplacereply.h1
-rw-r--r--src/plugins/geoservices/esri/geocodereply_esri.cpp53
-rw-r--r--src/plugins/geoservices/esri/geocodereply_esri.h5
-rw-r--r--src/plugins/geoservices/esri/georoutereply_esri.cpp50
-rw-r--r--src/plugins/geoservices/esri/georoutereply_esri.h7
-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/esri/geotiledmapreply_esri.cpp62
-rw-r--r--src/plugins/geoservices/esri/geotiledmapreply_esri.h8
-rw-r--r--src/plugins/geoservices/geoservices.pro14
-rw-r--r--src/plugins/geoservices/mapbox/qgeomapreplymapbox.cpp55
-rw-r--r--src/plugins/geoservices/mapbox/qgeomapreplymapbox.h5
-rw-r--r--src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp53
-rw-r--r--src/plugins/geoservices/mapbox/qgeoroutereplymapbox.h5
-rw-r--r--src/plugins/geoservices/mapbox/qgeoroutingmanagerenginemapbox.cpp17
-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/placesv2/qplacecontentreplyimpl.cpp82
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.h3
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.cpp60
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.h3
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp62
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.h4
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.cpp48
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.h6
-rw-r--r--src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp51
-rw-r--r--src/plugins/geoservices/nokia/qgeocodereply_nokia.h3
-rw-r--r--src/plugins/geoservices/nokia/qgeomapreply_nokia.cpp51
-rw-r--r--src/plugins/geoservices/nokia/qgeomapreply_nokia.h7
-rw-r--r--src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp70
-rw-r--r--src/plugins/geoservices/nokia/qgeoroutereply_nokia.h3
-rw-r--r--src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp12
-rw-r--r--src/plugins/geoservices/osm/qgeocodereplyosm.cpp48
-rw-r--r--src/plugins/geoservices/osm/qgeocodereplyosm.h5
-rw-r--r--src/plugins/geoservices/osm/qgeomapreplyosm.cpp57
-rw-r--r--src/plugins/geoservices/osm/qgeomapreplyosm.h11
-rw-r--r--src/plugins/geoservices/osm/qgeoroutereplyosm.cpp51
-rw-r--r--src/plugins/geoservices/osm/qgeoroutereplyosm.h5
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmaposm.cpp11
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp6
-rw-r--r--src/plugins/geoservices/osm/qplacemanagerengineosm.cpp3
-rw-r--r--src/plugins/geoservices/osm/qplacesearchreplyosm.cpp41
-rw-r--r--src/plugins/geoservices/osm/qplacesearchreplyosm.h6
-rw-r--r--src/plugins/position/corelocation/corelocation.pro4
-rw-r--r--src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp11
-rw-r--r--src/positioning/positioning.pro23
-rw-r--r--src/positioning/qclipperutils.cpp100
-rw-r--r--src/positioning/qclipperutils_p.h86
-rw-r--r--src/positioning/qdoublematrix4x4.cpp1111
-rw-r--r--src/positioning/qdoublematrix4x4_p.h946
-rw-r--r--src/positioning/qdoublevector2d_p.h8
-rw-r--r--src/positioning/qgeocircle.cpp143
-rw-r--r--src/positioning/qgeocircle.h5
-rw-r--r--src/positioning/qgeocircle_p.h11
-rw-r--r--src/positioning/qgeocoordinate.cpp8
-rw-r--r--src/positioning/qgeopath.cpp679
-rw-r--r--src/positioning/qgeopath.h102
-rw-r--r--src/positioning/qgeopath_p.h111
-rw-r--r--src/positioning/qgeorectangle.cpp89
-rw-r--r--src/positioning/qgeorectangle.h86
-rw-r--r--src/positioning/qgeorectangle_p.h2
-rw-r--r--src/positioning/qgeoshape.cpp52
-rw-r--r--src/positioning/qgeoshape.h93
-rw-r--r--src/positioning/qgeoshape_p.h3
-rw-r--r--src/positioning/qlocationutils_p.h95
-rw-r--r--src/positioning/qwebmercator.cpp (renamed from src/positioning/qgeoprojection.cpp)40
-rw-r--r--src/positioning/qwebmercator_p.h (renamed from src/positioning/qgeoprojection_p.h)16
-rw-r--r--src/src.pro2
-rw-r--r--tests/auto/auto.pro1
-rw-r--r--tests/auto/declarative_ui/ItemGroup.qml62
-rw-r--r--tests/auto/declarative_ui/declarative_ui.pro3
-rw-r--r--tests/auto/declarative_ui/tst_map.qml97
-rw-r--r--tests/auto/declarative_ui/tst_map_error.qml10
-rw-r--r--tests/auto/declarative_ui/tst_map_item.qml10
-rw-r--r--tests/auto/geotestplugin/geotestplugin.pro3
-rw-r--r--tests/auto/geotestplugin/qgeocodingmanagerengine_test.h5
-rw-r--r--tests/auto/geotestplugin/qgeoroutingmanagerengine_test.h6
-rw-r--r--tests/auto/geotestplugin/qgeotiledmap_test.cpp88
-rw-r--r--tests/auto/geotestplugin/qgeotiledmap_test.h14
-rw-r--r--tests/auto/geotestplugin/qgeotiledmappingmanagerengine_test.h3
-rw-r--r--tests/auto/qgeocameracapabilities/tst_qgeocameracapabilities.cpp4
-rw-r--r--tests/auto/qgeocameradata/qgeocameradata.pro2
-rw-r--r--tests/auto/qgeocameratiles/qgeocameratiles.pro2
-rw-r--r--tests/auto/qgeocameratiles/tst_qgeocameratiles.cpp12
-rw-r--r--tests/auto/qgeocircle/tst_qgeocircle.cpp50
-rw-r--r--tests/auto/qgeopath/qgeopath.pro8
-rw-r--r--tests/auto/qgeopath/tst_qgeopath.cpp385
-rw-r--r--tests/auto/qgeorectangle/tst_qgeorectangle.cpp43
-rw-r--r--tests/auto/qgeoroutereply/tst_qgeoroutereply.cpp2
-rw-r--r--tests/auto/qgeoserviceprovider/tst_qgeoserviceprovider.cpp2
-rw-r--r--tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp7
-rw-r--r--tests/auto/qgeotiledmapscene/qgeotiledmapscene.pro2
-rw-r--r--tests/auto/qgeotiledmapscene/tst_qgeotiledmapscene.cpp178
244 files changed, 11987 insertions, 3862 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..29caa86d
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "src/3rdparty/mapbox-gl-native"]
+ path = src/3rdparty/mapbox-gl-native
+ url = ../qtlocation-mapboxgl.git
diff --git a/.qmake.conf b/.qmake.conf
index fec66b73..b1c22d3b 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,3 @@
load(qt_build_config)
-MODULE_VERSION = 5.8.1
+MODULE_VERSION = 5.9.0
diff --git a/config.tests/winrt/main.cpp b/config.tests/winrt/main.cpp
index e1b14959..ff1eb810 100644
--- a/config.tests/winrt/main.cpp
+++ b/config.tests/winrt/main.cpp
@@ -36,9 +36,7 @@ using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Devices::Geolocation;
using namespace ABI::Windows::Foundation;
-#if _MSC_VER >= 1900
typedef IAsyncOperationCompletedHandler<GeolocationAccessStatus> AccessHandler;
-#endif
int main(int, char**)
{
diff --git a/examples/location/mapviewer/main.cpp b/examples/location/mapviewer/main.cpp
index 1b526435..3eedd8dd 100644
--- a/examples/location/mapviewer/main.cpp
+++ b/examples/location/mapviewer/main.cpp
@@ -84,11 +84,35 @@ static bool parseArgs(QStringList& args, QVariantMap& parameters)
int main(int argc, char *argv[])
{
+ const QByteArray additionalLibraryPaths = qgetenv("QTLOCATION_EXTRA_LIBRARY_PATH");
+ for (const QByteArray &p : additionalLibraryPaths.split(':'))
+ QCoreApplication::addLibraryPath(QString(p));
+
QGuiApplication application(argc, argv);
QVariantMap parameters;
QStringList args(QCoreApplication::arguments());
+ // Fetch tokens from the environment, if present
+ const QByteArray mapboxMapID = qgetenv("MAPBOX_MAP_ID");
+ const QByteArray mapboxAccessToken = qgetenv("MAPBOX_ACCESS_TOKEN");
+ const QByteArray hereAppID = qgetenv("HERE_APP_ID");
+ const QByteArray hereToken = qgetenv("HERE_TOKEN");
+ const QByteArray esriToken = qgetenv("ESRI_TOKEN");
+
+ if (!mapboxMapID.isEmpty())
+ parameters["mapbox.map_id"] = QString::fromLocal8Bit(mapboxMapID);
+ if (!mapboxAccessToken.isEmpty()) {
+ parameters["mapbox.access_token"] = QString::fromLocal8Bit(mapboxAccessToken);
+ parameters["mapboxgl.access_token"] = QString::fromLocal8Bit(mapboxAccessToken);
+ }
+ if (!hereAppID.isEmpty())
+ parameters["here.app_id"] = QString::fromLocal8Bit(hereAppID);
+ if (!hereToken.isEmpty())
+ parameters["here.token"] = QString::fromLocal8Bit(hereToken);
+ if (!esriToken.isEmpty())
+ parameters["esri.token"] = QString::fromLocal8Bit(esriToken);
+
if (parseArgs(args, parameters))
return 0;
if (!args.contains(QStringLiteral("osm.useragent")))
diff --git a/examples/location/mapviewer/map/MapComponent.qml b/examples/location/mapviewer/map/MapComponent.qml
index 008a4a00..3525e5f1 100644
--- a/examples/location/mapviewer/map/MapComponent.qml
+++ b/examples/location/mapviewer/map/MapComponent.qml
@@ -39,7 +39,7 @@
****************************************************************************/
import QtQuick 2.5
import QtQuick.Controls 1.4
-import QtLocation 5.6
+import QtLocation 5.9
import QtPositioning 5.5
import "../helper.js" as Helper
@@ -269,7 +269,7 @@ Map {
//! [mapnavigation]
// Enable pan, flick, and pinch gestures to zoom in and out
- gesture.acceptedGestures: MapGestureArea.PanGesture | MapGestureArea.FlickGesture | MapGestureArea.PinchGesture
+ gesture.acceptedGestures: MapGestureArea.PanGesture | MapGestureArea.FlickGesture | MapGestureArea.PinchGesture | MapGestureArea.RotationGesture | MapGestureArea.TiltGesture
gesture.flickDeceleration: 3000
gesture.enabled: true
//! [mapnavigation]
diff --git a/examples/location/places/main.cpp b/examples/location/places/main.cpp
index 8c3b64ed..a30fb857 100644
--- a/examples/location/places/main.cpp
+++ b/examples/location/places/main.cpp
@@ -90,6 +90,24 @@ int main(int argc, char *argv[])
QVariantMap parameters;
QStringList args(QCoreApplication::arguments());
+ // Fetch tokens from the environment, if present
+ const QByteArray mapboxMapID = qgetenv("MAPBOX_MAP_ID");
+ const QByteArray mapboxAccessToken = qgetenv("MAPBOX_ACCESS_TOKEN");
+ const QByteArray hereAppID = qgetenv("HERE_APP_ID");
+ const QByteArray hereToken = qgetenv("HERE_TOKEN");
+ const QByteArray esriToken = qgetenv("ESRI_TOKEN");
+
+ if (!mapboxMapID.isEmpty())
+ parameters["mapbox.map_id"] = QString::fromLocal8Bit(mapboxMapID);
+ if (!mapboxAccessToken.isEmpty())
+ parameters["mapbox.access_token"] = QString::fromLocal8Bit(mapboxAccessToken);
+ if (!hereAppID.isEmpty())
+ parameters["here.app_id"] = QString::fromLocal8Bit(hereAppID);
+ if (!hereToken.isEmpty())
+ parameters["here.token"] = QString::fromLocal8Bit(hereToken);
+ if (!esriToken.isEmpty())
+ parameters["esri.token"] = QString::fromLocal8Bit(esriToken);
+
if (parseArgs(args, parameters))
return 0;
diff --git a/examples/location/planespotter/main.cpp b/examples/location/planespotter/main.cpp
index c71a6999..76b706c9 100644
--- a/examples/location/planespotter/main.cpp
+++ b/examples/location/planespotter/main.cpp
@@ -47,7 +47,7 @@
#include <QDebug>
#include <QEasingCurve>
#include <QGeoCoordinate>
-#include <QtPositioning/private/qgeoprojection_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
#define ANIMATION_DURATION 4000
@@ -162,7 +162,7 @@ private:
progress = ((qreal)startTime.msecsTo(current) / ANIMATION_DURATION);
}
- setPosition(QGeoProjection::coordinateInterpolation(
+ setPosition(QWebMercator::coordinateInterpolation(
fromCoordinate, toCoordinate, easingCurve.valueForProgress(progress)));
if (!timer.isActive())
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 86870fc1..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,7 +43,6 @@ namespace c2t
static const F32 CLIPPER_SCALE_FACT = 1000.0f;
static const F32 CLIPPER_SCALE_FACT_INVERSE = 0.001f;
-
/////////////////////////////////
Point::Point()
@@ -59,7 +60,7 @@ Point::Point(const Point& pt)
/////////////////////////////////
-clip2tri::clip2tri()
+clip2tri::clip2tri() : openSubject(false)
{
// Do nothing!
}
@@ -83,6 +84,94 @@ void clip2tri::triangulate(const vector<vector<Point> > &inputPolygons, vector<P
triangulateComplex(outputTriangles, bounds, solution);
}
+void clip2tri::addClipPolygon(const Path &path)
+{
+ try // prevent any exception to spill into Qt
+ {
+ clipper.AddPath(path, ptClip, true);
+ }
+ catch(ClipperLib::clipperException &e)
+ {
+ printf("addClipPolygon: %s\n", e.what());
+ }
+}
+
+void clip2tri::addSubjectPath(const Path &path, bool closed)
+{
+ try // prevent any exception to spill into Qt
+ {
+ clipper.AddPath(path, ptSubject, closed);
+ }
+ catch(ClipperLib::clipperException &e)
+ {
+ printf("addSubjectPath: %s\n", e.what());
+ return;
+ }
+ if (!closed)
+ openSubject = true;
+}
+
+void clip2tri::clearClipper()
+{
+ // clear doesn't throw
+ clipper.Clear();
+ openSubject = false;
+}
+
+static ClipperLib::ClipType operation(const clip2tri::Operation &op)
+{
+ 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;
+ }
+ 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 std::string("Intersection");
+}
+
+Paths clip2tri::execute(const clip2tri::Operation op, const PolyFillType subjFillType, const PolyFillType clipFillType)
+{
+ Paths solution;
+ try // prevent any exception from spilling into Qt
+ {
+ 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(ClipperLib::clipperException &e)
+ {
+ printf("executing %s: %s\n", operationName(op).c_str(), e.what());
+ }
+ return solution;
+}
Path clip2tri::upscaleClipperPoints(const vector<Point> &inputPolygon)
{
@@ -148,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 982c8049..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,7 +57,6 @@ struct Point
Point(T in_x, U in_y) { x = static_cast<F32>(in_x); y = static_cast<F32>(in_y); }
};
-
class clip2tri
{
private:
@@ -74,11 +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);
+
+ // 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 Path &path, bool closed);
+
+ void clearClipper();
+
+ 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/clipper/clipper.cpp b/src/3rdparty/clipper/clipper.cpp
index 7a27bc44..d4c82344 100644
--- a/src/3rdparty/clipper/clipper.cpp
+++ b/src/3rdparty/clipper/clipper.cpp
@@ -1,10 +1,10 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
-* Version : 6.1.3a *
-* Date : 22 January 2014 *
+* Version : 6.4.0 *
+* Date : 2 July 2015 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2014 *
+* Copyright : Angus Johnson 2010-2015 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
@@ -50,15 +50,6 @@
namespace ClipperLib {
-#ifdef use_int32
- static cInt const loRange = 46340;
- static cInt const hiRange = 46340;
-#else
- static cInt const loRange = 0x3FFFFFFF;
- static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
- typedef unsigned long long ulong64;
-#endif
-
static double const pi = 3.141592653589793238;
static double const two_pi = pi *2;
static double const def_arc_tolerance = 0.25;
@@ -74,12 +65,11 @@ static int const Skip = -2; //edge that would otherwise close a path
struct TEdge {
IntPoint Bot;
- IntPoint Curr;
+ IntPoint Curr; //current (updated for every new scanbeam)
IntPoint Top;
- IntPoint Delta;
double Dx;
PolyType PolyTyp;
- EdgeSide Side;
+ EdgeSide Side; //side only refers to current side of solution poly
int WindDelta; //1 or -1 depending on winding direction
int WindCnt;
int WindCnt2; //winding count of the opposite polytype
@@ -99,15 +89,16 @@ struct IntersectNode {
IntPoint Pt;
};
-struct LocalMinima {
+struct LocalMinimum {
cInt Y;
TEdge *LeftBound;
TEdge *RightBound;
- LocalMinima *Next;
};
struct OutPt;
+//OutRec: contains a path in the clipping solution. Edges in the AEL will
+//carry a pointer to an OutRec when they are part of the clipping solution.
struct OutRec {
int Idx;
bool IsHole;
@@ -131,6 +122,14 @@ struct Join {
IntPoint OffPt;
};
+struct LocMinSorter
+{
+ inline bool operator()(const LocalMinimum& locMin1, const LocalMinimum& locMin2)
+ {
+ return locMin2.Y < locMin1.Y;
+ }
+};
+
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
@@ -170,7 +169,10 @@ PolyNode* PolyTree::GetFirst() const
int PolyTree::Total() const
{
- return (int)AllNodes.size();
+ int result = (int)AllNodes.size();
+ //with negative offsets, ignore the hidden outer polygon ...
+ if (result > 0 && Childs[0] != AllNodes[0]) result--;
+ return result;
}
//------------------------------------------------------------------------------
@@ -240,8 +242,8 @@ bool PolyNode::IsOpen() const
//------------------------------------------------------------------------------
// Int128 class (enables safe math on signed 64bit integers)
-// eg Int128 val1((cInt)9223372036854775807); //ie 2^63 -1
-// Int128 val2((cInt)9223372036854775807);
+// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1
+// Int128 val2((long64)9223372036854775807);
// Int128 val3 = val1 * val2;
// val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
//------------------------------------------------------------------------------
@@ -249,22 +251,21 @@ bool PolyNode::IsOpen() const
class Int128
{
public:
+ ulong64 lo;
+ long64 hi;
- cUInt lo;
- cInt hi;
-
- Int128(cInt _lo = 0)
+ Int128(long64 _lo = 0)
{
- lo = (cUInt)_lo;
+ lo = (ulong64)_lo;
if (_lo < 0) hi = -1; else hi = 0;
}
Int128(const Int128 &val): lo(val.lo), hi(val.hi){}
- Int128(const cInt& _hi, const ulong64& _lo): lo(_lo), hi(_hi){}
+ Int128(const long64& _hi, const ulong64& _lo): lo(_lo), hi(_hi){}
- Int128& operator = (const cInt &val)
+ Int128& operator = (const long64 &val)
{
lo = (ulong64)val;
if (val < 0) hi = -1; else hi = 0;
@@ -330,81 +331,18 @@ class Int128
Int128 operator-() const //unary negation
{
if (lo == 0)
- return Int128(-hi,0);
- else
- return Int128(~hi,~lo +1);
- }
-
- Int128 operator/ (const Int128 &rhs) const
- {
- if (rhs.lo == 0 && rhs.hi == 0)
- throw "Int128 operator/: divide by zero";
-
- bool negate = (rhs.hi < 0) != (hi < 0);
- Int128 dividend = *this;
- Int128 divisor = rhs;
- if (dividend.hi < 0) dividend = -dividend;
- if (divisor.hi < 0) divisor = -divisor;
-
- if (divisor < dividend)
- {
- Int128 result = Int128(0);
- Int128 cntr = Int128(1);
- while (divisor.hi >= 0 && !(divisor > dividend))
- {
- divisor.hi <<= 1;
- if ((cInt)divisor.lo < 0) divisor.hi++;
- divisor.lo <<= 1;
-
- cntr.hi <<= 1;
- if ((cInt)cntr.lo < 0) cntr.hi++;
- cntr.lo <<= 1;
- }
- divisor.lo >>= 1;
- if ((divisor.hi & 1) == 1)
- divisor.lo |= 0x8000000000000000LL;
- divisor.hi = (ulong64)divisor.hi >> 1;
-
- cntr.lo >>= 1;
- if ((cntr.hi & 1) == 1)
- cntr.lo |= 0x8000000000000000LL;
- cntr.hi >>= 1;
-
- while (cntr.hi != 0 || cntr.lo != 0)
- {
- if (!(dividend < divisor))
- {
- dividend -= divisor;
- result.hi |= cntr.hi;
- result.lo |= cntr.lo;
- }
- divisor.lo >>= 1;
- if ((divisor.hi & 1) == 1)
- divisor.lo |= 0x8000000000000000LL;
- divisor.hi >>= 1;
-
- cntr.lo >>= 1;
- if ((cntr.hi & 1) == 1)
- cntr.lo |= 0x8000000000000000LL;
- cntr.hi >>= 1;
- }
- if (negate) result = -result;
- return result;
- }
- else if (rhs.hi == this->hi && rhs.lo == this->lo)
- return Int128(negate ? -1: 1);
+ return Int128(-hi, 0);
else
- return Int128(0);
+ return Int128(~hi, ~lo + 1);
}
- double AsDouble() const
+ operator double() const
{
const double shift64 = 18446744073709551616.0; //2^64
if (hi < 0)
{
- cUInt lo_ = ~lo + 1;
- if (lo_ == 0) return (double)hi * shift64;
- else return -(double)(lo_ + ~hi * shift64);
+ if (lo == 0) return (double)hi * shift64;
+ else return -(double)(~lo + ~hi * shift64);
}
else
return (double)(lo + hi * shift64);
@@ -413,7 +351,7 @@ class Int128
};
//------------------------------------------------------------------------------
-Int128 Int128Mul (cInt lhs, cInt rhs)
+Int128 Int128Mul (long64 lhs, long64 rhs)
{
bool negate = (lhs < 0) != (rhs < 0);
@@ -431,9 +369,9 @@ Int128 Int128Mul (cInt lhs, cInt rhs)
ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi;
Int128 tmp;
- tmp.hi = cInt(a + (c >> 32));
- tmp.lo = cInt(c << 32);
- tmp.lo += cInt(b);
+ tmp.hi = long64(a + (c >> 32));
+ tmp.lo = long64(c << 32);
+ tmp.lo += long64(b);
if (tmp.lo < b) tmp.hi++;
if (negate) tmp = -tmp;
return tmp;
@@ -465,19 +403,25 @@ double Area(const Path &poly)
}
//------------------------------------------------------------------------------
-double Area(const OutRec &outRec)
+double Area(const OutPt *op)
{
- OutPt *op = outRec.Pts;
+ const OutPt *startOp = op;
if (!op) return 0;
double a = 0;
do {
a += (double)(op->Prev->Pt.X + op->Pt.X) * (double)(op->Prev->Pt.Y - op->Pt.Y);
op = op->Next;
- } while (op != outRec.Pts);
+ } while (op != startOp);
return a * 0.5;
}
//------------------------------------------------------------------------------
+double Area(const OutRec &outRec)
+{
+ return Area(outRec.Pts);
+}
+//------------------------------------------------------------------------------
+
bool PointIsVertex(const IntPoint &Pt, OutPt *pp)
{
OutPt *pp2 = pp;
@@ -491,10 +435,11 @@ bool PointIsVertex(const IntPoint &Pt, OutPt *pp)
}
//------------------------------------------------------------------------------
-int PointInPolygon (const IntPoint &pt, const Path &path)
+//See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos
+//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
+int PointInPolygon(const IntPoint &pt, const Path &path)
{
//returns 0 if false, +1 if true, -1 if pt ON polygon boundary
- //http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
int result = 0;
size_t cnt = path.size();
if (cnt < 3) return 0;
@@ -539,7 +484,6 @@ int PointInPolygon (const IntPoint &pt, const Path &path)
int PointInPolygon (const IntPoint &pt, OutPt *op)
{
//returns 0 if false, +1 if true, -1 if pt ON polygon boundary
- //http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
int result = 0;
OutPt* startOp = op;
for(;;)
@@ -584,8 +528,9 @@ bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
OutPt* op = OutPt1;
do
{
+ //nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon
int res = PointInPolygon(op->Pt, OutPt2);
- if (res >= 0) return res != 0;
+ if (res >= 0) return res > 0;
op = op->Next;
}
while (op != OutPt1);
@@ -597,10 +542,12 @@ bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range)
{
#ifndef use_int32
if (UseFullInt64Range)
- return Int128Mul(e1.Delta.Y, e2.Delta.X) == Int128Mul(e1.Delta.X, e2.Delta.Y);
+ return Int128Mul(e1.Top.Y - e1.Bot.Y, e2.Top.X - e2.Bot.X) ==
+ Int128Mul(e1.Top.X - e1.Bot.X, e2.Top.Y - e2.Bot.Y);
else
#endif
- return e1.Delta.Y * e2.Delta.X == e1.Delta.X * e2.Delta.Y;
+ return (e1.Top.Y - e1.Bot.Y) * (e2.Top.X - e2.Bot.X) ==
+ (e1.Top.X - e1.Bot.X) * (e2.Top.Y - e2.Bot.Y);
}
//------------------------------------------------------------------------------
@@ -630,7 +577,7 @@ bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
inline bool IsHorizontal(TEdge &e)
{
- return e.Delta.Y == 0;
+ return e.Dx == HORIZONTAL;
}
//------------------------------------------------------------------------------
@@ -643,11 +590,9 @@ inline double GetDx(const IntPoint pt1, const IntPoint pt2)
inline void SetDx(TEdge &e)
{
- e.Delta.X = (e.Top.X - e.Bot.X);
- e.Delta.Y = (e.Top.Y - e.Bot.Y);
-
- if (e.Delta.Y == 0) e.Dx = HORIZONTAL;
- else e.Dx = (double)(e.Delta.X) / e.Delta.Y;
+ cInt dy = (e.Top.Y - e.Bot.Y);
+ if (dy == 0) e.Dx = HORIZONTAL;
+ else e.Dx = (double)(e.Top.X - e.Bot.X) / dy;
}
//---------------------------------------------------------------------------
@@ -674,22 +619,20 @@ inline cInt TopX(TEdge &edge, const cInt currentY)
}
//------------------------------------------------------------------------------
-bool IntersectPoint(TEdge &Edge1, TEdge &Edge2,
- IntPoint &ip, bool UseFullInt64Range)
+void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
{
#ifdef use_xyz
ip.Z = 0;
#endif
+
double b1, b2;
- //nb: with very large coordinate values, it's possible for SlopesEqual() to
- //return false but for the edge.Dx value be equal due to double precision rounding.
- if (SlopesEqual(Edge1, Edge2, UseFullInt64Range) || Edge1.Dx == Edge2.Dx)
+ if (Edge1.Dx == Edge2.Dx)
{
- if (Edge2.Bot.Y > Edge1.Bot.Y) ip = Edge2.Bot;
- else ip = Edge1.Bot;
- return false;
+ ip.Y = Edge1.Curr.Y;
+ ip.X = TopX(Edge1, ip.Y);
+ return;
}
- else if (Edge1.Delta.X == 0)
+ else if (Edge1.Dx == 0)
{
ip.X = Edge1.Bot.X;
if (IsHorizontal(Edge2))
@@ -700,7 +643,7 @@ bool IntersectPoint(TEdge &Edge1, TEdge &Edge2,
ip.Y = Round(ip.X / Edge2.Dx + b2);
}
}
- else if (Edge2.Delta.X == 0)
+ else if (Edge2.Dx == 0)
{
ip.X = Edge2.Bot.X;
if (IsHorizontal(Edge1))
@@ -734,7 +677,15 @@ bool IntersectPoint(TEdge &Edge1, TEdge &Edge2,
else
ip.X = TopX(Edge2, ip.Y);
}
- return true;
+ //finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ...
+ if (ip.Y > Edge1.Curr.Y)
+ {
+ ip.Y = Edge1.Curr.Y;
+ //use the more vertical edge to derive X ...
+ if (std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx))
+ ip.X = TopX(Edge2, ip.Y); else
+ ip.X = TopX(Edge1, ip.Y);
+ }
}
//------------------------------------------------------------------------------
@@ -807,13 +758,9 @@ inline void ReverseHorizontal(TEdge &e)
//swap horizontal edges' Top and Bottom x's so they follow the natural
//progression of the bounds - ie so their xbots will align with the
//adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
- cInt tmp = e.Top.X;
- e.Top.X = e.Bot.X;
- e.Bot.X = tmp;
+ std::swap(e.Top.X, e.Bot.X);
#ifdef use_xyz
- tmp = e.Top.Z;
- e.Top.Z = e.Bot.Z;
- e.Bot.Z = tmp;
+ std::swap(e.Top.Z, e.Bot.Z);
#endif
}
//------------------------------------------------------------------------------
@@ -863,7 +810,12 @@ bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2)
p = btmPt2->Next;
while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next;
double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt));
- return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
+
+ if (std::max(dx1p, dx1n) == std::max(dx2p, dx2n) &&
+ std::min(dx1p, dx1n) == std::min(dx2p, dx2n))
+ return Area(btmPt1) > 0; //if otherwise identical use orientation
+ else
+ return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
}
//------------------------------------------------------------------------------
@@ -905,26 +857,6 @@ OutPt* GetBottomPt(OutPt *pp)
}
//------------------------------------------------------------------------------
-bool FindSegment(OutPt* &pp, bool UseFullInt64Range,
- IntPoint &pt1, IntPoint &pt2)
-{
- //OutPt1 & OutPt2 => the overlap segment (if the function returns true)
- if (!pp) return false;
- OutPt* pp2 = pp;
- IntPoint pt1a = pt1, pt2a = pt2;
- do
- {
- if (SlopesEqual(pt1a, pt2a, pp->Pt, pp->Prev->Pt, UseFullInt64Range) &&
- SlopesEqual(pt1a, pt2a, pp->Pt, UseFullInt64Range) &&
- GetOverlapSegment(pt1a, pt2a, pp->Pt, pp->Prev->Pt, pt1, pt2))
- return true;
- pp = pp->Next;
- }
- while (pp != pp2);
- return false;
-}
-//------------------------------------------------------------------------------
-
bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1,
const IntPoint pt2, const IntPoint pt3)
{
@@ -937,50 +869,20 @@ bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1,
}
//------------------------------------------------------------------------------
-OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint Pt)
-{
- if (p1 == p2) throw "JoinError";
- OutPt* result = new OutPt;
- result->Pt = Pt;
- if (p2 == p1->Next)
- {
- p1->Next = result;
- p2->Prev = result;
- result->Next = p2;
- result->Prev = p1;
- } else
- {
- p2->Next = result;
- p1->Prev = result;
- result->Next = p1;
- result->Prev = p2;
- }
- return result;
-}
-//------------------------------------------------------------------------------
-
-bool HorzSegmentsOverlap(const IntPoint& pt1a, const IntPoint& pt1b,
- const IntPoint& pt2a, const IntPoint& pt2b)
+bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
{
- //precondition: both segments are horizontal
- if ((pt1a.X > pt2a.X) == (pt1a.X < pt2b.X)) return true;
- else if ((pt1b.X > pt2a.X) == (pt1b.X < pt2b.X)) return true;
- else if ((pt2a.X > pt1a.X) == (pt2a.X < pt1b.X)) return true;
- else if ((pt2b.X > pt1a.X) == (pt2b.X < pt1b.X)) return true;
- else if ((pt1a.X == pt2a.X) && (pt1b.X == pt2b.X)) return true;
- else if ((pt1a.X == pt2b.X) && (pt1b.X == pt2a.X)) return true;
- else return false;
+ if (seg1a > seg1b) std::swap(seg1a, seg1b);
+ if (seg2a > seg2b) std::swap(seg2a, seg2b);
+ return (seg1a < seg2b) && (seg2a < seg1b);
}
-
//------------------------------------------------------------------------------
// ClipperBase class methods ...
//------------------------------------------------------------------------------
ClipperBase::ClipperBase() //constructor
{
- m_MinimaList = 0;
- m_CurrentLM = 0;
+ m_CurrentLM = m_MinimaList.begin(); //begin() == end() here
m_UseFullRange = false;
}
//------------------------------------------------------------------------------
@@ -996,7 +898,7 @@ void RangeTest(const IntPoint& Pt, bool& useFullRange)
if (useFullRange)
{
if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange)
- throw "Coordinate outside allowed range";
+ throw clipperException("Coordinate outside allowed range");
}
else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange)
{
@@ -1023,114 +925,119 @@ TEdge* FindNextLocMin(TEdge* E)
}
//------------------------------------------------------------------------------
-TEdge* ClipperBase::ProcessBound(TEdge* E, bool IsClockwise)
+TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward)
{
- TEdge *EStart = E, *Result = E;
+ TEdge *Result = E;
TEdge *Horz = 0;
- cInt StartX;
- if (IsHorizontal(*E))
- {
- //it's possible for adjacent overlapping horz edges to start heading left
- //before finishing right, so ...
- if (IsClockwise) StartX = E->Prev->Bot.X;
- else StartX = E->Next->Bot.X;
- if (E->Bot.X != StartX) ReverseHorizontal(*E);
- }
-
- if (Result->OutIdx != Skip)
- {
- if (IsClockwise)
- {
- while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip)
- Result = Result->Next;
- if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip)
- {
- //nb: at the top of a bound, horizontals are added to the bound
- //only when the preceding edge attaches to the horizontal's left vertex
- //unless a Skip edge is encountered when that becomes the top divide
- Horz = Result;
- while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev;
- if (Horz->Prev->Top.X == Result->Next->Top.X)
- {
- if (!IsClockwise) Result = Horz->Prev;
- }
- else if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev;
- }
- while (E != Result)
- {
- E->NextInLML = E->Next;
- if (IsHorizontal(*E) && E != EStart &&
- E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
- E = E->Next;
- }
- if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X)
- ReverseHorizontal(*E);
- Result = Result->Next; //move to the edge just beyond current bound
- } else
- {
- while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip)
- Result = Result->Prev;
- if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip)
- {
- Horz = Result;
- while (IsHorizontal(*Horz->Next)) Horz = Horz->Next;
- if (Horz->Next->Top.X == Result->Prev->Top.X)
- {
- if (!IsClockwise) Result = Horz->Next;
- }
- else if (Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next;
- }
- while (E != Result)
- {
- E->NextInLML = E->Prev;
- if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
- ReverseHorizontal(*E);
- E = E->Prev;
- }
- if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
- ReverseHorizontal(*E);
- Result = Result->Prev; //move to the edge just beyond current bound
- }
- }
-
- if (Result->OutIdx == Skip)
+ if (E->OutIdx == Skip)
{
//if edges still remain in the current bound beyond the skip edge then
//create another LocMin and call ProcessBound once more
- E = Result;
- if (IsClockwise)
+ if (NextIsForward)
{
while (E->Top.Y == E->Next->Bot.Y) E = E->Next;
//don't include top horizontals when parsing a bound a second time,
//they will be contained in the opposite bound ...
while (E != Result && IsHorizontal(*E)) E = E->Prev;
- } else
+ }
+ else
{
while (E->Top.Y == E->Prev->Bot.Y) E = E->Prev;
while (E != Result && IsHorizontal(*E)) E = E->Next;
}
+
if (E == Result)
{
- if (IsClockwise) Result = E->Next;
+ if (NextIsForward) Result = E->Next;
else Result = E->Prev;
- } else
+ }
+ else
{
//there are more edges in the bound beyond result starting with E
- if (IsClockwise)
- E = Result->Next;
+ if (NextIsForward)
+ E = Result->Next;
else
E = Result->Prev;
- LocalMinima* locMin = new LocalMinima;
- locMin->Next = 0;
- locMin->Y = E->Bot.Y;
- locMin->LeftBound = 0;
- locMin->RightBound = E;
- locMin->RightBound->WindDelta = 0;
- Result = ProcessBound(locMin->RightBound, IsClockwise);
- InsertLocalMinima(locMin);
+ MinimaList::value_type locMin;
+ locMin.Y = E->Bot.Y;
+ locMin.LeftBound = 0;
+ locMin.RightBound = E;
+ E->WindDelta = 0;
+ Result = ProcessBound(E, NextIsForward);
+ m_MinimaList.push_back(locMin);
}
+ return Result;
}
+
+ TEdge *EStart;
+
+ if (IsHorizontal(*E))
+ {
+ //We need to be careful with open paths because this may not be a
+ //true local minima (ie E may be following a skip edge).
+ //Also, consecutive horz. edges may start heading left before going right.
+ if (NextIsForward)
+ EStart = E->Prev;
+ else
+ EStart = E->Next;
+ if (IsHorizontal(*EStart)) //ie an adjoining horizontal skip edge
+ {
+ if (EStart->Bot.X != E->Bot.X && EStart->Top.X != E->Bot.X)
+ ReverseHorizontal(*E);
+ }
+ else if (EStart->Bot.X != E->Bot.X)
+ ReverseHorizontal(*E);
+ }
+
+ EStart = E;
+ if (NextIsForward)
+ {
+ while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip)
+ Result = Result->Next;
+ if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip)
+ {
+ //nb: at the top of a bound, horizontals are added to the bound
+ //only when the preceding edge attaches to the horizontal's left vertex
+ //unless a Skip edge is encountered when that becomes the top divide
+ Horz = Result;
+ while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev;
+ if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev;
+ }
+ while (E != Result)
+ {
+ E->NextInLML = E->Next;
+ if (IsHorizontal(*E) && E != EStart &&
+ E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
+ E = E->Next;
+ }
+ if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X)
+ ReverseHorizontal(*E);
+ Result = Result->Next; //move to the edge just beyond current bound
+ } else
+ {
+ while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip)
+ Result = Result->Prev;
+ if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip)
+ {
+ Horz = Result;
+ while (IsHorizontal(*Horz->Next)) Horz = Horz->Next;
+ if (Horz->Next->Top.X == Result->Prev->Top.X ||
+ Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next;
+ }
+
+ while (E != Result)
+ {
+ E->NextInLML = E->Prev;
+ if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
+ ReverseHorizontal(*E);
+ E = E->Prev;
+ }
+ if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
+ ReverseHorizontal(*E);
+ Result = Result->Prev; //move to the edge just beyond current bound
+ }
+
return Result;
}
//------------------------------------------------------------------------------
@@ -1179,7 +1086,8 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
TEdge *E = eStart, *eLoopStop = eStart;
for (;;)
{
- if ((E->Curr == E->Next->Curr))
+ //nb: allows matching start and end points when not Closed ...
+ if (E->Curr == E->Next->Curr && (Closed || E->Next != eStart))
{
if (E == E->Next) break;
if (E == eStart) eStart = E->Next;
@@ -1205,7 +1113,7 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
continue;
}
E = E->Next;
- if (E == eLoopStop) break;
+ if ((E == eLoopStop) || (!Closed && E->Next == eStart)) break;
}
if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next)))
@@ -1242,28 +1150,32 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
return false;
}
E->Prev->OutIdx = Skip;
- if (E->Prev->Bot.X < E->Prev->Top.X) ReverseHorizontal(*E->Prev);
- LocalMinima* locMin = new LocalMinima();
- locMin->Next = 0;
- locMin->Y = E->Bot.Y;
- locMin->LeftBound = 0;
- locMin->RightBound = E;
- locMin->RightBound->Side = esRight;
- locMin->RightBound->WindDelta = 0;
- while (E->Next->OutIdx != Skip)
+ MinimaList::value_type locMin;
+ locMin.Y = E->Bot.Y;
+ locMin.LeftBound = 0;
+ locMin.RightBound = E;
+ locMin.RightBound->Side = esRight;
+ locMin.RightBound->WindDelta = 0;
+ for (;;)
{
- E->NextInLML = E->Next;
if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
+ if (E->Next->OutIdx == Skip) break;
+ E->NextInLML = E->Next;
E = E->Next;
}
- InsertLocalMinima(locMin);
+ m_MinimaList.push_back(locMin);
m_edges.push_back(edges);
return true;
}
m_edges.push_back(edges);
- bool clockwise;
+ bool leftBoundIsForward;
TEdge* EMin = 0;
+
+ //workaround to avoid an endless loop in the while loop below when
+ //open paths have matching start and end points ...
+ if (E->Prev->Bot == E->Prev->Top) E = E->Next;
+
for (;;)
{
E = FindNextLocMin(E);
@@ -1272,38 +1184,38 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
//E and E.Prev now share a local minima (left aligned if horizontal).
//Compare their slopes to find which starts which bound ...
- LocalMinima* locMin = new LocalMinima;
- locMin->Next = 0;
- locMin->Y = E->Bot.Y;
+ MinimaList::value_type locMin;
+ locMin.Y = E->Bot.Y;
if (E->Dx < E->Prev->Dx)
{
- locMin->LeftBound = E->Prev;
- locMin->RightBound = E;
- clockwise = false; //Q.nextInLML = Q.prev
+ locMin.LeftBound = E->Prev;
+ locMin.RightBound = E;
+ leftBoundIsForward = false; //Q.nextInLML = Q.prev
} else
{
- locMin->LeftBound = E;
- locMin->RightBound = E->Prev;
- clockwise = true; //Q.nextInLML = Q.next
+ locMin.LeftBound = E;
+ locMin.RightBound = E->Prev;
+ leftBoundIsForward = true; //Q.nextInLML = Q.next
}
- locMin->LeftBound->Side = esLeft;
- locMin->RightBound->Side = esRight;
-
- if (!Closed) locMin->LeftBound->WindDelta = 0;
- else if (locMin->LeftBound->Next == locMin->RightBound)
- locMin->LeftBound->WindDelta = -1;
- else locMin->LeftBound->WindDelta = 1;
- locMin->RightBound->WindDelta = -locMin->LeftBound->WindDelta;
-
- E = ProcessBound(locMin->LeftBound, clockwise);
- TEdge* E2 = ProcessBound(locMin->RightBound, !clockwise);
-
- if (locMin->LeftBound->OutIdx == Skip)
- locMin->LeftBound = 0;
- else if (locMin->RightBound->OutIdx == Skip)
- locMin->RightBound = 0;
- InsertLocalMinima(locMin);
- if (!clockwise) E = E2;
+
+ if (!Closed) locMin.LeftBound->WindDelta = 0;
+ else if (locMin.LeftBound->Next == locMin.RightBound)
+ locMin.LeftBound->WindDelta = -1;
+ else locMin.LeftBound->WindDelta = 1;
+ locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta;
+
+ E = ProcessBound(locMin.LeftBound, leftBoundIsForward);
+ if (E->OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward);
+
+ TEdge* E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward);
+ if (E2->OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward);
+
+ if (locMin.LeftBound->OutIdx == Skip)
+ locMin.LeftBound = 0;
+ else if (locMin.RightBound->OutIdx == Skip)
+ locMin.RightBound = 0;
+ m_MinimaList.push_back(locMin);
+ if (!leftBoundIsForward) E = E2;
}
return true;
}
@@ -1318,34 +1230,11 @@ bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed)
}
//------------------------------------------------------------------------------
-void ClipperBase::InsertLocalMinima(LocalMinima *newLm)
-{
- if( ! m_MinimaList )
- {
- m_MinimaList = newLm;
- }
- else if( newLm->Y >= m_MinimaList->Y )
- {
- newLm->Next = m_MinimaList;
- m_MinimaList = newLm;
- } else
- {
- LocalMinima* tmpLm = m_MinimaList;
- while( tmpLm->Next && ( newLm->Y < tmpLm->Next->Y ) )
- tmpLm = tmpLm->Next;
- newLm->Next = tmpLm->Next;
- tmpLm->Next = newLm;
- }
-}
-//------------------------------------------------------------------------------
-
void ClipperBase::Clear()
{
DisposeLocalMinimaList();
for (EdgeList::size_type i = 0; i < m_edges.size(); ++i)
{
- //for each edge array in turn, find the first used edge and
- //check for and remove any hiddenPts in each edge in the array.
TEdge* edges = m_edges[i];
delete [] edges;
}
@@ -1357,13 +1246,15 @@ void ClipperBase::Clear()
void ClipperBase::Reset()
{
- m_CurrentLM = m_MinimaList;
- if( !m_CurrentLM ) return; //ie nothing to process
+ m_CurrentLM = m_MinimaList.begin();
+ if (m_CurrentLM == m_MinimaList.end()) return; //ie nothing to process
+ std::sort(m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter());
+ m_Scanbeam = ScanbeamList(); //clears/resets priority_queue
//reset all edges ...
- LocalMinima* lm = m_MinimaList;
- while( lm )
+ for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm)
{
+ InsertScanbeam(lm->Y);
TEdge* e = lm->LeftBound;
if (e)
{
@@ -1379,35 +1270,33 @@ void ClipperBase::Reset()
e->Side = esRight;
e->OutIdx = Unassigned;
}
- lm = lm->Next;
}
+ m_ActiveEdges = 0;
+ m_CurrentLM = m_MinimaList.begin();
}
//------------------------------------------------------------------------------
void ClipperBase::DisposeLocalMinimaList()
{
- while( m_MinimaList )
- {
- LocalMinima* tmpLm = m_MinimaList->Next;
- delete m_MinimaList;
- m_MinimaList = tmpLm;
- }
- m_CurrentLM = 0;
+ m_MinimaList.clear();
+ m_CurrentLM = m_MinimaList.begin();
}
//------------------------------------------------------------------------------
-void ClipperBase::PopLocalMinima()
+bool ClipperBase::PopLocalMinima(cInt Y, const LocalMinimum *&locMin)
{
- if( ! m_CurrentLM ) return;
- m_CurrentLM = m_CurrentLM->Next;
+ if (m_CurrentLM == m_MinimaList.end() || (*m_CurrentLM).Y != Y) return false;
+ locMin = &(*m_CurrentLM);
+ ++m_CurrentLM;
+ return true;
}
//------------------------------------------------------------------------------
IntRect ClipperBase::GetBounds()
{
IntRect result;
- LocalMinima* lm = m_MinimaList;
- if (!lm)
+ MinimaList::iterator lm = m_MinimaList.begin();
+ if (lm == m_MinimaList.end())
{
result.left = result.top = result.right = result.bottom = 0;
return result;
@@ -1416,10 +1305,10 @@ IntRect ClipperBase::GetBounds()
result.top = lm->LeftBound->Bot.Y;
result.right = lm->LeftBound->Bot.X;
result.bottom = lm->LeftBound->Bot.Y;
- while (lm)
+ while (lm != m_MinimaList.end())
{
- if (lm->LeftBound->Bot.Y > result.bottom)
- result.bottom = lm->LeftBound->Bot.Y;
+ //todo - needs fixing for open paths
+ result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y);
TEdge* e = lm->LeftBound;
for (;;) {
TEdge* bottomE = e;
@@ -1429,19 +1318,154 @@ IntRect ClipperBase::GetBounds()
if (e->Bot.X > result.right) result.right = e->Bot.X;
e = e->NextInLML;
}
- if (e->Bot.X < result.left) result.left = e->Bot.X;
- if (e->Bot.X > result.right) result.right = e->Bot.X;
- if (e->Top.X < result.left) result.left = e->Top.X;
- if (e->Top.X > result.right) result.right = e->Top.X;
- if (e->Top.Y < result.top) result.top = e->Top.Y;
-
+ result.left = std::min(result.left, e->Bot.X);
+ result.right = std::max(result.right, e->Bot.X);
+ result.left = std::min(result.left, e->Top.X);
+ result.right = std::max(result.right, e->Top.X);
+ result.top = std::min(result.top, e->Top.Y);
if (bottomE == lm->LeftBound) e = lm->RightBound;
else break;
}
- lm = lm->Next;
+ ++lm;
}
return result;
}
+//------------------------------------------------------------------------------
+
+void ClipperBase::InsertScanbeam(const cInt Y)
+{
+ m_Scanbeam.push(Y);
+}
+//------------------------------------------------------------------------------
+
+bool ClipperBase::PopScanbeam(cInt &Y)
+{
+ if (m_Scanbeam.empty()) return false;
+ Y = m_Scanbeam.top();
+ m_Scanbeam.pop();
+ while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); } // Pop duplicates.
+ return true;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::DisposeAllOutRecs(){
+ for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
+ DisposeOutRec(i);
+ m_PolyOuts.clear();
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::DisposeOutRec(PolyOutList::size_type index)
+{
+ OutRec *outRec = m_PolyOuts[index];
+ if (outRec->Pts) DisposeOutPts(outRec->Pts);
+ delete outRec;
+ m_PolyOuts[index] = 0;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::DeleteFromAEL(TEdge *e)
+{
+ TEdge* AelPrev = e->PrevInAEL;
+ TEdge* AelNext = e->NextInAEL;
+ if (!AelPrev && !AelNext && (e != m_ActiveEdges)) return; //already deleted
+ if (AelPrev) AelPrev->NextInAEL = AelNext;
+ else m_ActiveEdges = AelNext;
+ if (AelNext) AelNext->PrevInAEL = AelPrev;
+ e->NextInAEL = 0;
+ e->PrevInAEL = 0;
+}
+//------------------------------------------------------------------------------
+
+OutRec* ClipperBase::CreateOutRec()
+{
+ OutRec* result = new OutRec;
+ result->IsHole = false;
+ result->IsOpen = false;
+ result->FirstLeft = 0;
+ result->Pts = 0;
+ result->BottomPt = 0;
+ result->PolyNd = 0;
+ m_PolyOuts.push_back(result);
+ result->Idx = (int)m_PolyOuts.size() - 1;
+ return result;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2)
+{
+ //check that one or other edge hasn't already been removed from AEL ...
+ if (Edge1->NextInAEL == Edge1->PrevInAEL ||
+ Edge2->NextInAEL == Edge2->PrevInAEL) return;
+
+ if (Edge1->NextInAEL == Edge2)
+ {
+ TEdge* Next = Edge2->NextInAEL;
+ if (Next) Next->PrevInAEL = Edge1;
+ TEdge* Prev = Edge1->PrevInAEL;
+ if (Prev) Prev->NextInAEL = Edge2;
+ Edge2->PrevInAEL = Prev;
+ Edge2->NextInAEL = Edge1;
+ Edge1->PrevInAEL = Edge2;
+ Edge1->NextInAEL = Next;
+ }
+ else if (Edge2->NextInAEL == Edge1)
+ {
+ TEdge* Next = Edge1->NextInAEL;
+ if (Next) Next->PrevInAEL = Edge2;
+ TEdge* Prev = Edge2->PrevInAEL;
+ if (Prev) Prev->NextInAEL = Edge1;
+ Edge1->PrevInAEL = Prev;
+ Edge1->NextInAEL = Edge2;
+ Edge2->PrevInAEL = Edge1;
+ Edge2->NextInAEL = Next;
+ }
+ else
+ {
+ TEdge* Next = Edge1->NextInAEL;
+ TEdge* Prev = Edge1->PrevInAEL;
+ Edge1->NextInAEL = Edge2->NextInAEL;
+ if (Edge1->NextInAEL) Edge1->NextInAEL->PrevInAEL = Edge1;
+ Edge1->PrevInAEL = Edge2->PrevInAEL;
+ if (Edge1->PrevInAEL) Edge1->PrevInAEL->NextInAEL = Edge1;
+ Edge2->NextInAEL = Next;
+ if (Edge2->NextInAEL) Edge2->NextInAEL->PrevInAEL = Edge2;
+ Edge2->PrevInAEL = Prev;
+ if (Edge2->PrevInAEL) Edge2->PrevInAEL->NextInAEL = Edge2;
+ }
+
+ if (!Edge1->PrevInAEL) m_ActiveEdges = Edge1;
+ else if (!Edge2->PrevInAEL) m_ActiveEdges = Edge2;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e)
+{
+ if (!e->NextInLML)
+ throw clipperException("UpdateEdgeIntoAEL: invalid call");
+
+ e->NextInLML->OutIdx = e->OutIdx;
+ TEdge* AelPrev = e->PrevInAEL;
+ TEdge* AelNext = e->NextInAEL;
+ if (AelPrev) AelPrev->NextInAEL = e->NextInLML;
+ else m_ActiveEdges = e->NextInLML;
+ if (AelNext) AelNext->PrevInAEL = e->NextInLML;
+ e->NextInLML->Side = e->Side;
+ e->NextInLML->WindDelta = e->WindDelta;
+ e->NextInLML->WindCnt = e->WindCnt;
+ e->NextInLML->WindCnt2 = e->WindCnt2;
+ e = e->NextInLML;
+ e->Curr = e->Bot;
+ e->PrevInAEL = AelPrev;
+ e->NextInAEL = AelNext;
+ if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y);
+}
+//------------------------------------------------------------------------------
+
+bool ClipperBase::LocalMinimaPending()
+{
+ return (m_CurrentLM != m_MinimaList.end());
+}
//------------------------------------------------------------------------------
// TClipper methods ...
@@ -1449,8 +1473,6 @@ IntRect ClipperBase::GetBounds()
Clipper::Clipper(int initOptions) : ClipperBase() //constructor
{
- m_ActiveEdges = 0;
- m_SortedEdges = 0;
m_ExecuteLocked = false;
m_UseFullRange = false;
m_ReverseOutput = ((initOptions & ioReverseSolution) != 0);
@@ -1463,33 +1485,23 @@ Clipper::Clipper(int initOptions) : ClipperBase() //constructor
}
//------------------------------------------------------------------------------
-Clipper::~Clipper() //destructor
-{
- Clear();
- m_Scanbeam.clear();
-}
-//------------------------------------------------------------------------------
-
#ifdef use_xyz
-void Clipper::ZFillFunction(TZFillCallback zFillFunc)
+void Clipper::ZFillFunction(ZFillCallback zFillFunc)
{
m_ZFill = zFillFunc;
}
//------------------------------------------------------------------------------
#endif
-void Clipper::Reset()
+bool Clipper::Execute(ClipType clipType, Paths &solution, PolyFillType fillType)
{
- ClipperBase::Reset();
- m_Scanbeam.clear();
- m_ActiveEdges = 0;
- m_SortedEdges = 0;
- LocalMinima* lm = m_MinimaList;
- while (lm)
- {
- InsertScanbeam(lm->Y);
- lm = lm->Next;
- }
+ return Execute(clipType, solution, fillType, fillType);
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::Execute(ClipType clipType, PolyTree &polytree, PolyFillType fillType)
+{
+ return Execute(clipType, polytree, fillType, fillType);
}
//------------------------------------------------------------------------------
@@ -1498,7 +1510,7 @@ bool Clipper::Execute(ClipType clipType, Paths &solution,
{
if( m_ExecuteLocked ) return false;
if (m_HasOpenPaths)
- throw clipperException("Error: PolyTree struct is need for open path clipping.");
+ throw clipperException("Error: PolyTree struct is needed for open path clipping.");
m_ExecuteLocked = true;
solution.resize(0);
m_SubjFillType = subjFillType;
@@ -1550,19 +1562,26 @@ bool Clipper::ExecuteInternal()
bool succeeded = true;
try {
Reset();
- if (!m_CurrentLM) return false;
- cInt botY = PopScanbeam();
- do {
- InsertLocalMinimaIntoAEL(botY);
- ClearGhostJoins();
- ProcessHorizontals(false);
- if (m_Scanbeam.empty()) break;
- cInt topY = PopScanbeam();
- succeeded = ProcessIntersections(botY, topY);
- if (!succeeded) break;
+ m_Maxima = MaximaList();
+ m_SortedEdges = 0;
+
+ succeeded = true;
+ cInt botY, topY;
+ if (!PopScanbeam(botY)) return false;
+ InsertLocalMinimaIntoAEL(botY);
+ while (PopScanbeam(topY) || LocalMinimaPending())
+ {
+ ProcessHorizontals();
+ ClearGhostJoins();
+ if (!ProcessIntersections(topY))
+ {
+ succeeded = false;
+ break;
+ }
ProcessEdgesAtTopOfScanbeam(topY);
botY = topY;
- } while (!m_Scanbeam.empty() || m_CurrentLM);
+ InsertLocalMinimaIntoAEL(botY);
+ }
}
catch(...)
{
@@ -1586,7 +1605,10 @@ bool Clipper::ExecuteInternal()
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec *outRec = m_PolyOuts[i];
- if (outRec->Pts && !outRec->IsOpen)
+ if (!outRec->Pts) continue;
+ if (outRec->IsOpen)
+ FixupOutPolyline(*outRec);
+ else
FixupOutPolygon(*outRec);
}
@@ -1599,36 +1621,6 @@ bool Clipper::ExecuteInternal()
}
//------------------------------------------------------------------------------
-void Clipper::InsertScanbeam(const cInt Y)
-{
- m_Scanbeam.insert(Y);
-}
-//------------------------------------------------------------------------------
-
-cInt Clipper::PopScanbeam()
-{
- cInt Y = *m_Scanbeam.begin();
- m_Scanbeam.erase(m_Scanbeam.begin());
- return Y;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DisposeAllOutRecs(){
- for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
- DisposeOutRec(i);
- m_PolyOuts.clear();
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DisposeOutRec(PolyOutList::size_type index)
-{
- OutRec *outRec = m_PolyOuts[index];
- if (outRec->Pts) DisposeOutPts(outRec->Pts);
- delete outRec;
- m_PolyOuts[index] = 0;
-}
-//------------------------------------------------------------------------------
-
void Clipper::SetWindingCount(TEdge &edge)
{
TEdge *e = edge.PrevInAEL;
@@ -1636,7 +1628,13 @@ void Clipper::SetWindingCount(TEdge &edge)
while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL;
if (!e)
{
- edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta);
+ if (edge.WindDelta == 0)
+ {
+ PolyFillType pft = (edge.PolyTyp == ptSubject ? m_SubjFillType : m_ClipFillType);
+ edge.WindCnt = (pft == pftNegative ? -1 : 1);
+ }
+ else
+ edge.WindCnt = edge.WindDelta;
edge.WindCnt2 = 0;
e = m_ActiveEdges; //ie get ready to calc WindCnt2
}
@@ -1868,13 +1866,16 @@ OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt)
prevE = e->PrevInAEL;
}
- if (prevE && prevE->OutIdx >= 0 &&
- (TopX(*prevE, Pt.Y) == TopX(*e, Pt.Y)) &&
- SlopesEqual(*e, *prevE, m_UseFullRange) &&
- (e->WindDelta != 0) && (prevE->WindDelta != 0))
+ if (prevE && prevE->OutIdx >= 0)
{
- OutPt* outPt = AddOutPt(prevE, Pt);
- AddJoin(result, outPt, e->Top);
+ cInt xPrev = TopX(*prevE, Pt.Y);
+ cInt xE = TopX(*e, Pt.Y);
+ if (xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0) &&
+ SlopesEqual(IntPoint(xPrev, Pt.Y), prevE->Top, IntPoint(xE, Pt.Y), e->Top, m_UseFullRange))
+ {
+ OutPt* outPt = AddOutPt(prevE, Pt);
+ AddJoin(result, outPt, e->Top);
+ }
}
return result;
}
@@ -1916,6 +1917,15 @@ void Clipper::AddEdgeToSEL(TEdge *edge)
}
//------------------------------------------------------------------------------
+bool Clipper::PopEdgeFromSEL(TEdge *&edge)
+{
+ if (!m_SortedEdges) return false;
+ edge = m_SortedEdges;
+ DeleteFromSEL(m_SortedEdges);
+ return true;
+}
+//------------------------------------------------------------------------------
+
void Clipper::CopyAELToSEL()
{
TEdge* e = m_ActiveEdges;
@@ -1967,11 +1977,12 @@ void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt)
void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
{
- while( m_CurrentLM && ( m_CurrentLM->Y == botY ) )
+ const LocalMinimum *lm;
+ while (PopLocalMinima(botY, lm))
{
- TEdge* lb = m_CurrentLM->LeftBound;
- TEdge* rb = m_CurrentLM->RightBound;
- PopLocalMinima();
+ TEdge* lb = lm->LeftBound;
+ TEdge* rb = lm->RightBound;
+
OutPt *Op1 = 0;
if (!lb)
{
@@ -2003,8 +2014,13 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
if (rb)
{
- if(IsHorizontal(*rb)) AddEdgeToSEL(rb);
- else InsertScanbeam( rb->Top.Y );
+ if (IsHorizontal(*rb))
+ {
+ AddEdgeToSEL(rb);
+ if (rb->NextInLML)
+ InsertScanbeam(rb->NextInLML->Top.Y);
+ }
+ else InsertScanbeam( rb->Top.Y );
}
if (!lb || !rb) continue;
@@ -2018,7 +2034,7 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
Join* jr = m_GhostJoins[i];
//if the horizontal Rb and a 'ghost' horizontal overlap, then convert
//the 'ghost' join to a real join ready for later ...
- if (HorzSegmentsOverlap(jr->OutPt1->Pt, jr->OffPt, rb->Bot, rb->Top))
+ if (HorzSegmentsOverlap(jr->OutPt1->Pt.X, jr->OffPt.X, rb->Bot.X, rb->Top.X))
AddJoin(jr->OutPt1, Op1, jr->OffPt);
}
}
@@ -2026,7 +2042,7 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
if (lb->OutIdx >= 0 && lb->PrevInAEL &&
lb->PrevInAEL->Curr.X == lb->Bot.X &&
lb->PrevInAEL->OutIdx >= 0 &&
- SlopesEqual(*lb->PrevInAEL, *lb, m_UseFullRange) &&
+ SlopesEqual(lb->PrevInAEL->Bot, lb->PrevInAEL->Top, lb->Curr, lb->Top, m_UseFullRange) &&
(lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0))
{
OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot);
@@ -2037,7 +2053,7 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
{
if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 &&
- SlopesEqual(*rb->PrevInAEL, *rb, m_UseFullRange) &&
+ SlopesEqual(rb->PrevInAEL->Curr, rb->PrevInAEL->Top, rb->Curr, rb->Top, m_UseFullRange) &&
(rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0))
{
OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot);
@@ -2061,19 +2077,6 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
}
//------------------------------------------------------------------------------
-void Clipper::DeleteFromAEL(TEdge *e)
-{
- TEdge* AelPrev = e->PrevInAEL;
- TEdge* AelNext = e->NextInAEL;
- if( !AelPrev && !AelNext && (e != m_ActiveEdges) ) return; //already deleted
- if( AelPrev ) AelPrev->NextInAEL = AelNext;
- else m_ActiveEdges = AelNext;
- if( AelNext ) AelNext->PrevInAEL = AelPrev;
- e->NextInAEL = 0;
- e->PrevInAEL = 0;
-}
-//------------------------------------------------------------------------------
-
void Clipper::DeleteFromSEL(TEdge *e)
{
TEdge* SelPrev = e->PrevInSEL;
@@ -2088,45 +2091,34 @@ void Clipper::DeleteFromSEL(TEdge *e)
//------------------------------------------------------------------------------
#ifdef use_xyz
-
-void Clipper::SetZ(IntPoint& pt, TEdge& e)
+void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2)
{
- pt.Z = 0;
- if (m_ZFill)
- {
- //put the 'preferred' point as first parameter ...
- if (e.OutIdx < 0)
- (*m_ZFill)(e.Bot, e.Top, pt); //outside a path so presume entering
- else
- (*m_ZFill)(e.Top, e.Bot, pt); //inside a path so presume exiting
- }
+ if (pt.Z != 0 || !m_ZFill) return;
+ else if (pt == e1.Bot) pt.Z = e1.Bot.Z;
+ else if (pt == e1.Top) pt.Z = e1.Top.Z;
+ else if (pt == e2.Bot) pt.Z = e2.Bot.Z;
+ else if (pt == e2.Top) pt.Z = e2.Top.Z;
+ else (*m_ZFill)(e1.Bot, e1.Top, e2.Bot, e2.Top, pt);
}
//------------------------------------------------------------------------------
#endif
-void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
- const IntPoint &Pt, bool protect)
+void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt)
{
- //e1 will be to the Left of e2 BELOW the intersection. Therefore e1 is before
- //e2 in AEL except when e1 is being inserted at the intersection point ...
- bool e1stops = !protect && !e1->NextInLML &&
- e1->Top.X == Pt.X && e1->Top.Y == Pt.Y;
- bool e2stops = !protect && !e2->NextInLML &&
- e2->Top.X == Pt.X && e2->Top.Y == Pt.Y;
bool e1Contributing = ( e1->OutIdx >= 0 );
bool e2Contributing = ( e2->OutIdx >= 0 );
+#ifdef use_xyz
+ SetZ(Pt, *e1, *e2);
+#endif
+
#ifdef use_lines
//if either edge is on an OPEN path ...
if (e1->WindDelta == 0 || e2->WindDelta == 0)
{
//ignore subject-subject open path intersections UNLESS they
//are both open paths, AND they are both 'contributing maximas' ...
- if (e1->WindDelta == 0 && e2->WindDelta == 0)
- {
- if ((e1stops || e2stops) && e1Contributing && e2Contributing)
- AddLocalMaxPoly(e1, e2, Pt);
- }
+ if (e1->WindDelta == 0 && e2->WindDelta == 0) return;
//if intersecting a subj line with a subj poly ...
else if (e1->PolyTyp == e2->PolyTyp &&
@@ -2165,13 +2157,6 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
if (e2Contributing) e2->OutIdx = Unassigned;
}
}
-
- if (e1stops)
- if (e1->OutIdx < 0) DeleteFromAEL(e1);
- else throw clipperException("Error intersecting polylines");
- if (e2stops)
- if (e2->OutIdx < 0) DeleteFromAEL(e2);
- else throw clipperException("Error intersecting polylines");
return;
}
#endif
@@ -2236,10 +2221,11 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
if ( e1Contributing && e2Contributing )
{
- if ( e1stops || e2stops ||
- (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
+ if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
(e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) )
- AddLocalMaxPoly(e1, e2, Pt);
+ {
+ AddLocalMaxPoly(e1, e2, Pt);
+ }
else
{
AddOutPt(e1, Pt);
@@ -2266,8 +2252,7 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
SwapPolyIndexes(*e1, *e2);
}
}
- else if ( (e1Wc == 0 || e1Wc == 1) &&
- (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops )
+ else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1))
{
//neither edge is currently contributing ...
@@ -2286,7 +2271,9 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
}
if (e1->PolyTyp != e2->PolyTyp)
- AddLocalMinPoly(e1, e2, Pt);
+ {
+ AddLocalMinPoly(e1, e2, Pt);
+ }
else if (e1Wc == 1 && e2Wc == 1)
switch( m_ClipType ) {
case ctIntersection:
@@ -2308,35 +2295,32 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
else
SwapSides( *e1, *e2 );
}
-
- if( (e1stops != e2stops) &&
- ( (e1stops && (e1->OutIdx >= 0)) || (e2stops && (e2->OutIdx >= 0)) ) )
- {
- SwapSides( *e1, *e2 );
- SwapPolyIndexes( *e1, *e2 );
- }
-
- //finally, delete any non-contributing maxima edges ...
- if( e1stops ) DeleteFromAEL( e1 );
- if( e2stops ) DeleteFromAEL( e2 );
}
//------------------------------------------------------------------------------
void Clipper::SetHoleState(TEdge *e, OutRec *outrec)
{
- bool IsHole = false;
TEdge *e2 = e->PrevInAEL;
+ TEdge *eTmp = 0;
while (e2)
{
if (e2->OutIdx >= 0 && e2->WindDelta != 0)
{
- IsHole = !IsHole;
- if (! outrec->FirstLeft)
- outrec->FirstLeft = m_PolyOuts[e2->OutIdx];
+ if (!eTmp) eTmp = e2;
+ else if (eTmp->OutIdx == e2->OutIdx) eTmp = 0;
}
e2 = e2->PrevInAEL;
}
- if (IsHole) outrec->IsHole = true;
+ if (!eTmp)
+ {
+ outrec->FirstLeft = 0;
+ outrec->IsHole = false;
+ }
+ else
+ {
+ outrec->FirstLeft = m_PolyOuts[eTmp->OutIdx];
+ outrec->IsHole = !outrec->FirstLeft->IsHole;
+ }
}
//------------------------------------------------------------------------------
@@ -2360,7 +2344,7 @@ OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
}
//------------------------------------------------------------------------------
-bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2)
+bool OutRec1RightOfOutRec2(OutRec* outRec1, OutRec* outRec2)
{
do
{
@@ -2387,9 +2371,9 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
OutRec *outRec2 = m_PolyOuts[e2->OutIdx];
OutRec *holeStateRec;
- if (Param1RightOfParam2(outRec1, outRec2))
+ if (OutRec1RightOfOutRec2(outRec1, outRec2))
holeStateRec = outRec2;
- else if (Param1RightOfParam2(outRec2, outRec1))
+ else if (OutRec1RightOfOutRec2(outRec2, outRec1))
holeStateRec = outRec1;
else
holeStateRec = GetLowermostRec(outRec1, outRec2);
@@ -2402,7 +2386,6 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
OutPt* p2_lft = outRec2->Pts;
OutPt* p2_rt = p2_lft->Prev;
- EdgeSide Side;
//join e2 poly onto e1 poly and delete pointers to e2 ...
if( e1->Side == esLeft )
{
@@ -2424,7 +2407,6 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
p1_rt->Next = p2_lft;
outRec1->Pts = p2_lft;
}
- Side = esLeft;
} else
{
if( e2->Side == esRight )
@@ -2443,7 +2425,6 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
p1_lft->Prev = p2_rt;
p2_rt->Next = p1_lft;
}
- Side = esRight;
}
outRec1->BottomPt = 0;
@@ -2469,7 +2450,7 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
if( e->OutIdx == ObsoleteIdx )
{
e->OutIdx = OKIdx;
- e->Side = Side;
+ e->Side = e1->Side;
break;
}
e = e->NextInAEL;
@@ -2479,24 +2460,8 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
}
//------------------------------------------------------------------------------
-OutRec* Clipper::CreateOutRec()
-{
- OutRec* result = new OutRec;
- result->IsHole = false;
- result->IsOpen = false;
- result->FirstLeft = 0;
- result->Pts = 0;
- result->BottomPt = 0;
- result->PolyNd = 0;
- m_PolyOuts.push_back(result);
- result->Idx = (int)m_PolyOuts.size()-1;
- return result;
-}
-//------------------------------------------------------------------------------
-
OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
{
- bool ToFront = (e->Side == esLeft);
if( e->OutIdx < 0 )
{
OutRec *outRec = CreateOutRec();
@@ -2509,12 +2474,7 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
newOp->Prev = newOp;
if (!outRec->IsOpen)
SetHoleState(e, outRec);
-#ifdef use_xyz
- if (pt == e->Bot) newOp->Pt = e->Bot;
- else if (pt == e->Top) newOp->Pt = e->Top;
- else SetZ(newOp->Pt, *e);
-#endif
- e->OutIdx = outRec->Idx; //nb: do this after SetZ !
+ e->OutIdx = outRec->Idx;
return newOp;
} else
{
@@ -2522,7 +2482,8 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
//OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most'
OutPt* op = outRec->Pts;
- if (ToFront && (pt == op->Pt)) return op;
+ bool ToFront = (e->Side == esLeft);
+ if (ToFront && (pt == op->Pt)) return op;
else if (!ToFront && (pt == op->Prev->Pt)) return op->Prev;
OutPt* newOp = new OutPt;
@@ -2533,25 +2494,26 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
newOp->Prev->Next = newOp;
op->Prev = newOp;
if (ToFront) outRec->Pts = newOp;
-#ifdef use_xyz
- if (pt == e->Bot) newOp->Pt = e->Bot;
- else if (pt == e->Top) newOp->Pt = e->Top;
- else SetZ(newOp->Pt, *e);
-#endif
return newOp;
}
}
//------------------------------------------------------------------------------
-void Clipper::ProcessHorizontals(bool IsTopOfScanbeam)
+OutPt* Clipper::GetLastOutPt(TEdge *e)
{
- TEdge* horzEdge = m_SortedEdges;
- while(horzEdge)
- {
- DeleteFromSEL(horzEdge);
- ProcessHorizontal(horzEdge, IsTopOfScanbeam);
- horzEdge = m_SortedEdges;
- }
+ OutRec *outRec = m_PolyOuts[e->OutIdx];
+ if (e->Side == esLeft)
+ return outRec->Pts;
+ else
+ return outRec->Pts->Prev;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::ProcessHorizontals()
+{
+ TEdge* horzEdge;
+ while (PopEdgeFromSEL(horzEdge))
+ ProcessHorizontal(horzEdge);
}
//------------------------------------------------------------------------------
@@ -2575,64 +2537,21 @@ inline bool IsIntermediate(TEdge *e, const cInt Y)
TEdge *GetMaximaPair(TEdge *e)
{
- TEdge* result = 0;
if ((e->Next->Top == e->Top) && !e->Next->NextInLML)
- result = e->Next;
+ return e->Next;
else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML)
- result = e->Prev;
-
- if (result && (result->OutIdx == Skip ||
- //result is false if both NextInAEL & PrevInAEL are nil & not horizontal ...
- (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result))))
- return 0;
- return result;
+ return e->Prev;
+ else return 0;
}
//------------------------------------------------------------------------------
-void Clipper::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2)
+TEdge *GetMaximaPairEx(TEdge *e)
{
- //check that one or other edge hasn't already been removed from AEL ...
- if (Edge1->NextInAEL == Edge1->PrevInAEL ||
- Edge2->NextInAEL == Edge2->PrevInAEL) return;
-
- if( Edge1->NextInAEL == Edge2 )
- {
- TEdge* Next = Edge2->NextInAEL;
- if( Next ) Next->PrevInAEL = Edge1;
- TEdge* Prev = Edge1->PrevInAEL;
- if( Prev ) Prev->NextInAEL = Edge2;
- Edge2->PrevInAEL = Prev;
- Edge2->NextInAEL = Edge1;
- Edge1->PrevInAEL = Edge2;
- Edge1->NextInAEL = Next;
- }
- else if( Edge2->NextInAEL == Edge1 )
- {
- TEdge* Next = Edge1->NextInAEL;
- if( Next ) Next->PrevInAEL = Edge2;
- TEdge* Prev = Edge2->PrevInAEL;
- if( Prev ) Prev->NextInAEL = Edge1;
- Edge1->PrevInAEL = Prev;
- Edge1->NextInAEL = Edge2;
- Edge2->PrevInAEL = Edge1;
- Edge2->NextInAEL = Next;
- }
- else
- {
- TEdge* Next = Edge1->NextInAEL;
- TEdge* Prev = Edge1->PrevInAEL;
- Edge1->NextInAEL = Edge2->NextInAEL;
- if( Edge1->NextInAEL ) Edge1->NextInAEL->PrevInAEL = Edge1;
- Edge1->PrevInAEL = Edge2->PrevInAEL;
- if( Edge1->PrevInAEL ) Edge1->PrevInAEL->NextInAEL = Edge1;
- Edge2->NextInAEL = Next;
- if( Edge2->NextInAEL ) Edge2->NextInAEL->PrevInAEL = Edge2;
- Edge2->PrevInAEL = Prev;
- if( Edge2->PrevInAEL ) Edge2->PrevInAEL->NextInAEL = Edge2;
- }
-
- if( !Edge1->PrevInAEL ) m_ActiveEdges = Edge1;
- else if( !Edge2->PrevInAEL ) m_ActiveEdges = Edge2;
+ //as GetMaximaPair() but returns 0 if MaxPair isn't in AEL (unless it's horizontal)
+ TEdge* result = GetMaximaPair(e);
+ if (result && (result->OutIdx == Skip ||
+ (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result)))) return 0;
+ return result;
}
//------------------------------------------------------------------------------
@@ -2704,37 +2623,6 @@ void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right)
}
//------------------------------------------------------------------------
-void Clipper::PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam)
-{
- //get the last Op for this horizontal edge
- //the point may be anywhere along the horizontal ...
- OutPt* outPt = m_PolyOuts[horzEdge->OutIdx]->Pts;
- if (horzEdge->Side != esLeft) outPt = outPt->Prev;
-
- //First, match up overlapping horizontal edges (eg when one polygon's
- //intermediate horz edge overlaps an intermediate horz edge of another, or
- //when one polygon sits on top of another) ...
- //for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i)
- //{
- // Join* j = m_GhostJoins[i];
- // if (HorzSegmentsOverlap(j->OutPt1->Pt, j->OffPt, horzEdge->Bot, horzEdge->Top))
- // AddJoin(j->OutPt1, outPt, j->OffPt);
- //}
-
- //Also, since horizontal edges at the top of one SB are often removed from
- //the AEL before we process the horizontal edges at the bottom of the next,
- //we need to create 'ghost' Join records of 'contrubuting' horizontals that
- //we can compare with horizontals at the bottom of the next SB.
- if (isTopOfScanbeam)
- {
- if (outPt->Pt == horzEdge->Top)
- AddGhostJoin(outPt, horzEdge->Bot);
- else
- AddGhostJoin(outPt, horzEdge->Top);
- }
-}
-//------------------------------------------------------------------------------
-
/*******************************************************************************
* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or *
* Bottom of a scanbeam) are processed as if layered. The order in which HEs *
@@ -2745,10 +2633,11 @@ void Clipper::PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam)
* the AEL. These 'promoted' edges may in turn intersect [%] with other HEs. *
*******************************************************************************/
-void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
+void Clipper::ProcessHorizontal(TEdge *horzEdge)
{
Direction dir;
cInt horzLeft, horzRight;
+ bool IsOpen = (horzEdge->WindDelta == 0);
GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
@@ -2758,69 +2647,146 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
if (!eLastHorz->NextInLML)
eMaxPair = GetMaximaPair(eLastHorz);
- for (;;)
+ MaximaList::const_iterator maxIt;
+ MaximaList::const_reverse_iterator maxRit;
+ if (m_Maxima.size() > 0)
{
+ //get the first maxima in range (X) ...
+ if (dir == dLeftToRight)
+ {
+ maxIt = m_Maxima.begin();
+ while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.X) maxIt++;
+ if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.X)
+ maxIt = m_Maxima.end();
+ }
+ else
+ {
+ maxRit = m_Maxima.rbegin();
+ while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.X) maxRit++;
+ if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.X)
+ maxRit = m_Maxima.rend();
+ }
+ }
+
+ OutPt* op1 = 0;
+
+ for (;;) //loop through consec. horizontal edges
+ {
+
bool IsLastHorz = (horzEdge == eLastHorz);
TEdge* e = GetNextInAEL(horzEdge, dir);
while(e)
{
- //Break if we've got to the end of an intermediate horizontal edge ...
- //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
- if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML &&
- e->Dx < horzEdge->NextInLML->Dx) break;
- TEdge* eNext = GetNextInAEL(e, dir); //saves eNext for later
-
- if ((dir == dLeftToRight && e->Curr.X <= horzRight) ||
- (dir == dRightToLeft && e->Curr.X >= horzLeft))
- {
- if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0)
- PrepareHorzJoins(horzEdge, isTopOfScanbeam);
- //so far we're still in range of the horizontal Edge but make sure
+ //this code block inserts extra coords into horizontal edges (in output
+ //polygons) whereever maxima touch these horizontal edges. This helps
+ //'simplifying' polygons (ie if the Simplify property is set).
+ if (m_Maxima.size() > 0)
+ {
+ if (dir == dLeftToRight)
+ {
+ while (maxIt != m_Maxima.end() && *maxIt < e->Curr.X)
+ {
+ if (horzEdge->OutIdx >= 0 && !IsOpen)
+ AddOutPt(horzEdge, IntPoint(*maxIt, horzEdge->Bot.Y));
+ maxIt++;
+ }
+ }
+ else
+ {
+ while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.X)
+ {
+ if (horzEdge->OutIdx >= 0 && !IsOpen)
+ AddOutPt(horzEdge, IntPoint(*maxRit, horzEdge->Bot.Y));
+ maxRit++;
+ }
+ }
+ };
+
+ if ((dir == dLeftToRight && e->Curr.X > horzRight) ||
+ (dir == dRightToLeft && e->Curr.X < horzLeft)) break;
+
+ //Also break if we've got to the end of an intermediate horizontal edge ...
+ //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
+ if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML &&
+ e->Dx < horzEdge->NextInLML->Dx) break;
+
+ if (horzEdge->OutIdx >= 0 && !IsOpen) //note: may be done multiple times
+ {
+ op1 = AddOutPt(horzEdge, e->Curr);
+ TEdge* eNextHorz = m_SortedEdges;
+ while (eNextHorz)
+ {
+ if (eNextHorz->OutIdx >= 0 &&
+ HorzSegmentsOverlap(horzEdge->Bot.X,
+ horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
+ {
+ OutPt* op2 = GetLastOutPt(eNextHorz);
+ AddJoin(op2, op1, eNextHorz->Top);
+ }
+ eNextHorz = eNextHorz->NextInSEL;
+ }
+ AddGhostJoin(op1, horzEdge->Bot);
+ }
+
+ //OK, so far we're still in range of the horizontal Edge but make sure
//we're at the last of consec. horizontals when matching with eMaxPair
if(e == eMaxPair && IsLastHorz)
{
- if (dir == dLeftToRight)
- IntersectEdges(horzEdge, e, e->Top);
- else
- IntersectEdges(e, horzEdge, e->Top);
- if (eMaxPair->OutIdx >= 0) throw clipperException("ProcessHorizontal error");
+ if (horzEdge->OutIdx >= 0)
+ AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top);
+ DeleteFromAEL(horzEdge);
+ DeleteFromAEL(eMaxPair);
return;
}
- else if(dir == dLeftToRight)
+
+ if(dir == dLeftToRight)
{
IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
- IntersectEdges(horzEdge, e, Pt, true);
+ IntersectEdges(horzEdge, e, Pt);
}
else
{
IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
- IntersectEdges( e, horzEdge, Pt, true);
+ IntersectEdges( e, horzEdge, Pt);
}
+ TEdge* eNext = GetNextInAEL(e, dir);
SwapPositionsInAEL( horzEdge, e );
- }
- else if( (dir == dLeftToRight && e->Curr.X >= horzRight) ||
- (dir == dRightToLeft && e->Curr.X <= horzLeft) ) break;
- e = eNext;
- } //end while
+ e = eNext;
+ } //end while(e)
- if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0)
- PrepareHorzJoins(horzEdge, isTopOfScanbeam);
+ //Break out of loop if HorzEdge.NextInLML is not also horizontal ...
+ if (!horzEdge->NextInLML || !IsHorizontal(*horzEdge->NextInLML)) break;
+
+ UpdateEdgeIntoAEL(horzEdge);
+ if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot);
+ GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
- if (horzEdge->NextInLML && IsHorizontal(*horzEdge->NextInLML))
- {
- UpdateEdgeIntoAEL(horzEdge);
- if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot);
- GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
- } else
- break;
} //end for (;;)
- if(horzEdge->NextInLML)
+ if (horzEdge->OutIdx >= 0 && !op1)
+ {
+ op1 = GetLastOutPt(horzEdge);
+ TEdge* eNextHorz = m_SortedEdges;
+ while (eNextHorz)
+ {
+ if (eNextHorz->OutIdx >= 0 &&
+ HorzSegmentsOverlap(horzEdge->Bot.X,
+ horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
+ {
+ OutPt* op2 = GetLastOutPt(eNextHorz);
+ AddJoin(op2, op1, eNextHorz->Top);
+ }
+ eNextHorz = eNextHorz->NextInSEL;
+ }
+ AddGhostJoin(op1, horzEdge->Top);
+ }
+
+ if (horzEdge->NextInLML)
{
if(horzEdge->OutIdx >= 0)
{
- OutPt* op1 = AddOutPt( horzEdge, horzEdge->Top);
+ op1 = AddOutPt( horzEdge, horzEdge->Top);
UpdateEdgeIntoAEL(horzEdge);
if (horzEdge->WindDelta == 0) return;
//nb: HorzEdge is no longer horizontal here
@@ -2846,22 +2812,7 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
else
UpdateEdgeIntoAEL(horzEdge);
}
- else if (eMaxPair)
- {
- if (eMaxPair->OutIdx >= 0)
- {
- if (dir == dLeftToRight)
- IntersectEdges(horzEdge, eMaxPair, horzEdge->Top);
- else
- IntersectEdges(eMaxPair, horzEdge, horzEdge->Top);
- if (eMaxPair->OutIdx >= 0)
- throw clipperException("ProcessHorizontal error");
- } else
- {
- DeleteFromAEL(horzEdge);
- DeleteFromAEL(eMaxPair);
- }
- } else
+ else
{
if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top);
DeleteFromAEL(horzEdge);
@@ -2869,34 +2820,11 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
}
//------------------------------------------------------------------------------
-void Clipper::UpdateEdgeIntoAEL(TEdge *&e)
-{
- if( !e->NextInLML ) throw
- clipperException("UpdateEdgeIntoAEL: invalid call");
-
- e->NextInLML->OutIdx = e->OutIdx;
- TEdge* AelPrev = e->PrevInAEL;
- TEdge* AelNext = e->NextInAEL;
- if (AelPrev) AelPrev->NextInAEL = e->NextInLML;
- else m_ActiveEdges = e->NextInLML;
- if (AelNext) AelNext->PrevInAEL = e->NextInLML;
- e->NextInLML->Side = e->Side;
- e->NextInLML->WindDelta = e->WindDelta;
- e->NextInLML->WindCnt = e->WindCnt;
- e->NextInLML->WindCnt2 = e->WindCnt2;
- e = e->NextInLML;
- e->Curr = e->Bot;
- e->PrevInAEL = AelPrev;
- e->NextInAEL = AelNext;
- if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y);
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::ProcessIntersections(const cInt botY, const cInt topY)
+bool Clipper::ProcessIntersections(const cInt topY)
{
if( !m_ActiveEdges ) return true;
try {
- BuildIntersectList(botY, topY);
+ BuildIntersectList(topY);
size_t IlSize = m_IntersectList.size();
if (IlSize == 0) return true;
if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList();
@@ -2921,7 +2849,7 @@ void Clipper::DisposeIntersectNodes()
}
//------------------------------------------------------------------------------
-void Clipper::BuildIntersectList(const cInt botY, const cInt topY)
+void Clipper::BuildIntersectList(const cInt topY)
{
if ( !m_ActiveEdges ) return;
@@ -2948,16 +2876,8 @@ void Clipper::BuildIntersectList(const cInt botY, const cInt topY)
IntPoint Pt;
if(e->Curr.X > eNext->Curr.X)
{
- if (!IntersectPoint(*e, *eNext, Pt, m_UseFullRange) && e->Curr.X > eNext->Curr.X +1)
- throw clipperException("Intersection error");
- if (Pt.Y > botY)
- {
- Pt.Y = botY;
- if (std::fabs(e->Dx) > std::fabs(eNext->Dx))
- Pt.X = TopX(*eNext, botY); else
- Pt.X = TopX(*e, botY);
- }
-
+ IntersectPoint(*e, *eNext, Pt);
+ if (Pt.Y < topY) Pt = IntPoint(TopX(*e, topY), topY);
IntersectNode * newNode = new IntersectNode;
newNode->Edge1 = e;
newNode->Edge2 = eNext;
@@ -2985,7 +2905,7 @@ void Clipper::ProcessIntersectList()
{
IntersectNode* iNode = m_IntersectList[i];
{
- IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt, true);
+ IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt);
SwapPositionsInAEL( iNode->Edge1 , iNode->Edge2 );
}
delete iNode;
@@ -3032,7 +2952,7 @@ bool Clipper::FixupIntersectionOrder()
void Clipper::DoMaxima(TEdge *e)
{
- TEdge* eMaxPair = GetMaximaPair(e);
+ TEdge* eMaxPair = GetMaximaPairEx(e);
if (!eMaxPair)
{
if (e->OutIdx >= 0)
@@ -3044,7 +2964,7 @@ void Clipper::DoMaxima(TEdge *e)
TEdge* eNext = e->NextInAEL;
while(eNext && eNext != eMaxPair)
{
- IntersectEdges(e, eNext, e->Top, true);
+ IntersectEdges(e, eNext, e->Top);
SwapPositionsInAEL(e, eNext);
eNext = e->NextInAEL;
}
@@ -3056,7 +2976,9 @@ void Clipper::DoMaxima(TEdge *e)
}
else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 )
{
- IntersectEdges( e, eMaxPair, e->Top);
+ if (e->OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e->Top);
+ DeleteFromAEL(e);
+ DeleteFromAEL(eMaxPair);
}
#ifdef use_lines
else if (e->WindDelta == 0)
@@ -3091,12 +3013,13 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
if(IsMaximaEdge)
{
- TEdge* eMaxPair = GetMaximaPair(e);
+ TEdge* eMaxPair = GetMaximaPairEx(e);
IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair));
}
if(IsMaximaEdge)
{
+ if (m_StrictSimple) m_Maxima.push_back(e->Top.X);
TEdge* ePrev = e->PrevInAEL;
DoMaxima(e);
if( !ePrev ) e = m_ActiveEdges;
@@ -3118,15 +3041,21 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
e->Curr.Y = topY;
}
+ //When StrictlySimple and 'e' is being touched by another edge, then
+ //make sure both edges have a vertex here ...
if (m_StrictSimple)
{
TEdge* ePrev = e->PrevInAEL;
if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) &&
(ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0))
{
- OutPt* op = AddOutPt(ePrev, e->Curr);
- OutPt* op2 = AddOutPt(e, e->Curr);
- AddJoin(op, op2, e->Curr); //StrictlySimple (type-3) join
+ IntPoint pt = e->Curr;
+#ifdef use_xyz
+ SetZ(pt, *ePrev, *e);
+#endif
+ OutPt* op = AddOutPt(ePrev, pt);
+ OutPt* op2 = AddOutPt(e, pt);
+ AddJoin(op, op2, pt); //StrictlySimple (type-3) join
}
}
@@ -3135,7 +3064,9 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
}
//3. Process horizontals at the Top of the scanbeam ...
- ProcessHorizontals(true);
+ m_Maxima.sort();
+ ProcessHorizontals();
+ m_Maxima.clear();
//4. Promote intermediate vertices ...
e = m_ActiveEdges;
@@ -3154,7 +3085,7 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
if (ePrev && ePrev->Curr.X == e->Bot.X &&
ePrev->Curr.Y == e->Bot.Y && op &&
ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
- SlopesEqual(*e, *ePrev, m_UseFullRange) &&
+ SlopesEqual(e->Curr, e->Top, ePrev->Curr, ePrev->Top, m_UseFullRange) &&
(e->WindDelta != 0) && (ePrev->WindDelta != 0))
{
OutPt* op2 = AddOutPt(ePrev, e->Bot);
@@ -3163,7 +3094,7 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
else if (eNext && eNext->Curr.X == e->Bot.X &&
eNext->Curr.Y == e->Bot.Y && op &&
eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y &&
- SlopesEqual(*e, *eNext, m_UseFullRange) &&
+ SlopesEqual(e->Curr, e->Top, eNext->Curr, eNext->Top, m_UseFullRange) &&
(e->WindDelta != 0) && (eNext->WindDelta != 0))
{
OutPt* op2 = AddOutPt(eNext, e->Bot);
@@ -3175,44 +3106,71 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
}
//------------------------------------------------------------------------------
-void Clipper::FixupOutPolygon(OutRec &outrec)
+void Clipper::FixupOutPolyline(OutRec &outrec)
{
- //FixupOutPolygon() - removes duplicate points and simplifies consecutive
- //parallel edges by removing the middle vertex.
- OutPt *lastOK = 0;
- outrec.BottomPt = 0;
OutPt *pp = outrec.Pts;
-
- for (;;)
+ OutPt *lastPP = pp->Prev;
+ while (pp != lastPP)
{
- if (pp->Prev == pp || pp->Prev == pp->Next )
+ pp = pp->Next;
+ if (pp->Pt == pp->Prev->Pt)
{
- DisposeOutPts(pp);
- outrec.Pts = 0;
- return;
+ if (pp == lastPP) lastPP = pp->Prev;
+ OutPt *tmpPP = pp->Prev;
+ tmpPP->Next = pp->Next;
+ pp->Next->Prev = tmpPP;
+ delete pp;
+ pp = tmpPP;
}
+ }
- //test for duplicate points and collinear edges ...
- if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) ||
- (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) &&
- (!m_PreserveCollinear ||
- !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt))))
- {
- lastOK = 0;
- OutPt *tmp = pp;
- pp->Prev->Next = pp->Next;
- pp->Next->Prev = pp->Prev;
- pp = pp->Prev;
- delete tmp;
- }
- else if (pp == lastOK) break;
- else
+ if (pp == pp->Prev)
+ {
+ DisposeOutPts(pp);
+ outrec.Pts = 0;
+ return;
+ }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::FixupOutPolygon(OutRec &outrec)
+{
+ //FixupOutPolygon() - removes duplicate points and simplifies consecutive
+ //parallel edges by removing the middle vertex.
+ OutPt *lastOK = 0;
+ outrec.BottomPt = 0;
+ OutPt *pp = outrec.Pts;
+ bool preserveCol = m_PreserveCollinear || m_StrictSimple;
+
+ for (;;)
{
- if (!lastOK) lastOK = pp;
- pp = pp->Next;
+ if (pp->Prev == pp || pp->Prev == pp->Next)
+ {
+ DisposeOutPts(pp);
+ outrec.Pts = 0;
+ return;
+ }
+
+ //test for duplicate points and collinear edges ...
+ if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) ||
+ (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) &&
+ (!preserveCol || !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt))))
+ {
+ lastOK = 0;
+ OutPt *tmp = pp;
+ pp->Prev->Next = pp->Next;
+ pp->Next->Prev = pp->Prev;
+ pp = pp->Prev;
+ delete tmp;
+ }
+ else if (pp == lastOK) break;
+ else
+ {
+ if (!lastOK) lastOK = pp;
+ pp = pp->Next;
+ }
}
- }
- outrec.Pts = pp;
+ outrec.Pts = pp;
}
//------------------------------------------------------------------------------
@@ -3496,7 +3454,7 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
OutPt *op2 = j->OutPt2, *op2b;
//There are 3 kinds of joins for output polygons ...
- //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are a vertices anywhere
+ //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere
//along (horizontal) collinear edges (& Join.OffPt is on the same horizontal).
//2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same
//location at the Bottom of the overlapping segment (& Join.OffPt is above).
@@ -3508,6 +3466,7 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
(j->OffPt == j->OutPt2->Pt))
{
//Strictly Simple join ...
+ if (outRec1 != outRec2) return false;
op1b = j->OutPt1->Next;
while (op1b != op1 && (op1b->Pt == j->OffPt))
op1b = op1b->Next;
@@ -3648,13 +3607,22 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
}
//----------------------------------------------------------------------
+static OutRec* ParseFirstLeft(OutRec* FirstLeft)
+{
+ while (FirstLeft && !FirstLeft->Pts)
+ FirstLeft = FirstLeft->FirstLeft;
+ return FirstLeft;
+}
+//------------------------------------------------------------------------------
+
void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec)
{
-
+ //tests if NewOutRec contains the polygon before reassigning FirstLeft
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec* outRec = m_PolyOuts[i];
- if (outRec->Pts && outRec->FirstLeft == OldOutRec)
+ OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
+ if (outRec->Pts && firstLeft == OldOutRec)
{
if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts))
outRec->FirstLeft = NewOutRec;
@@ -3663,23 +3631,43 @@ void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec)
}
//----------------------------------------------------------------------
-void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec)
-{
+void Clipper::FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec)
+{
+ //A polygon has split into two such that one is now the inner of the other.
+ //It's possible that these polygons now wrap around other polygons, so check
+ //every polygon that's also contained by OuterOutRec's FirstLeft container
+ //(including 0) to see if they've become inner to the new inner polygon ...
+ OutRec* orfl = OuterOutRec->FirstLeft;
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec* outRec = m_PolyOuts[i];
- if (outRec->FirstLeft == OldOutRec) outRec->FirstLeft = NewOutRec;
+
+ if (!outRec->Pts || outRec == OuterOutRec || outRec == InnerOutRec)
+ continue;
+ OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
+ if (firstLeft != orfl && firstLeft != InnerOutRec && firstLeft != OuterOutRec)
+ continue;
+ if (Poly2ContainsPoly1(outRec->Pts, InnerOutRec->Pts))
+ outRec->FirstLeft = InnerOutRec;
+ else if (Poly2ContainsPoly1(outRec->Pts, OuterOutRec->Pts))
+ outRec->FirstLeft = OuterOutRec;
+ else if (outRec->FirstLeft == InnerOutRec || outRec->FirstLeft == OuterOutRec)
+ outRec->FirstLeft = orfl;
}
}
//----------------------------------------------------------------------
-
-static OutRec* ParseFirstLeft(OutRec* FirstLeft)
+void Clipper::FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec)
{
- while (FirstLeft && !FirstLeft->Pts)
- FirstLeft = FirstLeft->FirstLeft;
- return FirstLeft;
+ //reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon
+ for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
+ {
+ OutRec* outRec = m_PolyOuts[i];
+ OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
+ if (outRec->Pts && outRec->FirstLeft == OldOutRec)
+ outRec->FirstLeft = NewOutRec;
+ }
}
-//------------------------------------------------------------------------------
+//----------------------------------------------------------------------
void Clipper::JoinCommonEdges()
{
@@ -3691,13 +3679,14 @@ void Clipper::JoinCommonEdges()
OutRec *outRec2 = GetOutRec(join->OutPt2->Idx);
if (!outRec1->Pts || !outRec2->Pts) continue;
+ if (outRec1->IsOpen || outRec2->IsOpen) continue;
//get the polygon fragment with the correct hole state (FirstLeft)
//before calling JoinPoints() ...
OutRec *holeStateRec;
if (outRec1 == outRec2) holeStateRec = outRec1;
- else if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2;
- else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1;
+ else if (OutRec1RightOfOutRec2(outRec1, outRec2)) holeStateRec = outRec2;
+ else if (OutRec1RightOfOutRec2(outRec2, outRec1)) holeStateRec = outRec1;
else holeStateRec = GetLowermostRec(outRec1, outRec2);
if (!JoinPoints(join, outRec1, outRec2)) continue;
@@ -3714,25 +3703,12 @@ void Clipper::JoinCommonEdges()
//update all OutRec2.Pts Idx's ...
UpdateOutPtIdxs(*outRec2);
- //We now need to check every OutRec.FirstLeft pointer. If it points
- //to OutRec1 it may need to point to OutRec2 instead ...
- if (m_UsingPolyTree)
- for (PolyOutList::size_type j = 0; j < m_PolyOuts.size() - 1; j++)
- {
- OutRec* oRec = m_PolyOuts[j];
- if (!oRec->Pts || ParseFirstLeft(oRec->FirstLeft) != outRec1 ||
- oRec->IsHole == outRec1->IsHole) continue;
- if (Poly2ContainsPoly1(oRec->Pts, join->OutPt2))
- oRec->FirstLeft = outRec2;
- }
-
if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts))
{
- //outRec2 is contained by outRec1 ...
+ //outRec1 contains outRec2 ...
outRec2->IsHole = !outRec1->IsHole;
outRec2->FirstLeft = outRec1;
- //fixup FirstLeft pointers that may need reassigning to OutRec1
if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1);
if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0))
@@ -3740,13 +3716,12 @@ void Clipper::JoinCommonEdges()
} else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts))
{
- //outRec1 is contained by outRec2 ...
+ //outRec2 contains outRec1 ...
outRec2->IsHole = outRec1->IsHole;
outRec1->IsHole = !outRec2->IsHole;
outRec2->FirstLeft = outRec1->FirstLeft;
outRec1->FirstLeft = outRec2;
- //fixup FirstLeft pointers that may need reassigning to OutRec1
if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2);
if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0))
@@ -3775,8 +3750,7 @@ void Clipper::JoinCommonEdges()
outRec1->FirstLeft = outRec2->FirstLeft;
outRec2->FirstLeft = outRec1;
- //fixup FirstLeft pointers that may need reassigning to OutRec1
- if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1);
+ if (m_UsingPolyTree) FixupFirstLefts3(outRec2, outRec1);
}
}
}
@@ -3848,8 +3822,7 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
(path[i].Y == newNode->Contour[k].Y &&
path[i].X < newNode->Contour[k].X)) k = j;
}
- if ((endType == etClosedPolygon && j < 2) ||
- (endType != etClosedPolygon && j < 0))
+ if (endType == etClosedPolygon && j < 2)
{
delete newNode;
return;
@@ -3859,7 +3832,7 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
//if this path's lowest pt is lower than all the others then update m_lowest
if (endType != etClosedPolygon) return;
if (m_lowest.X < 0)
- m_lowest = IntPoint(0, k);
+ m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k);
else
{
IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y];
@@ -3965,6 +3938,7 @@ void ClipperOffset::Execute(PolyTree& solution, double delta)
PolyNode* outerNode = solution.Childs[0];
solution.Childs.reserve(outerNode->ChildCount());
solution.Childs[0] = outerNode->Childs[0];
+ solution.Childs[0]->Parent = outerNode->Parent;
for (int i = 1; i < outerNode->ChildCount(); ++i)
solution.AddChild(*outerNode->Childs[i]);
}
@@ -4149,8 +4123,20 @@ void ClipperOffset::DoOffset(double delta)
void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype)
{
+ //cross product ...
m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y);
- if (m_sinA < 0.00005 && m_sinA > -0.00005) return;
+ if (std::fabs(m_sinA * m_delta) < 1.0)
+ {
+ //dot product ...
+ double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y );
+ if (cosA > 0) // angle => 0 degrees
+ {
+ m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
+ Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
+ return;
+ }
+ //else angle => 180 degrees
+ }
else if (m_sinA > 1.0) m_sinA = 1.0;
else if (m_sinA < -1.0) m_sinA = -1.0;
@@ -4204,7 +4190,7 @@ void ClipperOffset::DoRound(int j, int k)
{
double a = std::atan2(m_sinA,
m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y);
- int steps = (int)Round(m_StepsPerRad * std::fabs(a));
+ int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1);
double X = m_normals[k].X, Y = m_normals[k].Y, X2;
for (int i = 0; i < steps; ++i)
@@ -4232,7 +4218,7 @@ void Clipper::DoSimplePolygons()
{
OutRec* outrec = m_PolyOuts[i++];
OutPt* op = outrec->Pts;
- if (!op) continue;
+ if (!op || outrec->IsOpen) continue;
do //for each Pt in Polygon until duplicate found do ...
{
OutPt* op2 = op->Next;
@@ -4257,6 +4243,7 @@ void Clipper::DoSimplePolygons()
//OutRec2 is contained by OutRec1 ...
outrec2->IsHole = !outrec->IsHole;
outrec2->FirstLeft = outrec;
+ if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec);
}
else
if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts))
@@ -4266,12 +4253,15 @@ void Clipper::DoSimplePolygons()
outrec->IsHole = !outrec2->IsHole;
outrec2->FirstLeft = outrec->FirstLeft;
outrec->FirstLeft = outrec2;
- } else
+ if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2);
+ }
+ else
{
//the 2 polygons are separate ...
outrec2->IsHole = outrec->IsHole;
outrec2->FirstLeft = outrec->FirstLeft;
- }
+ if (m_UsingPolyTree) FixupFirstLefts1(outrec, outrec2);
+ }
op2 = op; //ie get ready for the Next iteration
}
op2 = op2->Next;
@@ -4331,7 +4321,12 @@ inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2)
double DistanceFromLineSqrd(
const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2)
{
- //see https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
+ //The equation of a line in general form (Ax + By + C = 0)
+ //given 2 points (x¹,y¹) & (x²,y²) is ...
+ //(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0
+ //A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹
+ //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²)
+ //see http://en.wikipedia.org/wiki/Perpendicular_distance
double A = double(ln1.Y - ln2.Y);
double B = double(ln2.X - ln1.X);
double C = A * ln1.X + B * ln1.Y;
@@ -4343,7 +4338,27 @@ double DistanceFromLineSqrd(
bool SlopesNearCollinear(const IntPoint& pt1,
const IntPoint& pt2, const IntPoint& pt3, double distSqrd)
{
- return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
+ //this function is more accurate when the point that's geometrically
+ //between the other 2 points is the one that's tested for distance.
+ //ie makes it more likely to pick up 'spikes' ...
+ if (Abs(pt1.X - pt2.X) > Abs(pt1.Y - pt2.Y))
+ {
+ if ((pt1.X > pt2.X) == (pt1.X < pt3.X))
+ return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
+ else if ((pt2.X > pt1.X) == (pt2.X < pt3.X))
+ return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
+ else
+ return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
+ }
+ else
+ {
+ if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y))
+ return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
+ else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y))
+ return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
+ else
+ return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
+ }
}
//------------------------------------------------------------------------------
@@ -4433,6 +4448,7 @@ void CleanPolygon(Path& poly, double distance)
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance)
{
+ out_polys.resize(in_polys.size());
for (Paths::size_type i = 0; i < in_polys.size(); ++i)
CleanPolygon(in_polys[i], out_polys[i], distance);
}
@@ -4471,8 +4487,8 @@ void Minkowski(const Path& poly, const Path& path,
pp.push_back(p);
}
- Paths quads;
- quads.reserve((pathCnt + delta) * (polyCnt + 1));
+ solution.clear();
+ solution.reserve((pathCnt + delta) * (polyCnt + 1));
for (size_t i = 0; i < pathCnt - 1 + delta; ++i)
for (size_t j = 0; j < polyCnt; ++j)
{
@@ -4483,23 +4499,30 @@ void Minkowski(const Path& poly, const Path& path,
quad.push_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]);
quad.push_back(pp[i % pathCnt][(j + 1) % polyCnt]);
if (!Orientation(quad)) ReversePath(quad);
- quads.push_back(quad);
+ solution.push_back(quad);
}
+}
+//------------------------------------------------------------------------------
+void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed)
+{
+ Minkowski(pattern, path, solution, true, pathIsClosed);
Clipper c;
- c.AddPaths(quads, ptSubject, true);
+ c.AddPaths(solution, ptSubject, true);
c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
}
//------------------------------------------------------------------------------
-void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed)
+void TranslatePath(const Path& input, Path& output, const IntPoint delta)
{
- Minkowski(pattern, path, solution, true, pathIsClosed);
+ //precondition: input != output
+ output.resize(input.size());
+ for (size_t i = 0; i < input.size(); ++i)
+ output[i] = IntPoint(input[i].X + delta.X, input[i].Y + delta.Y);
}
//------------------------------------------------------------------------------
-void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution,
- PolyFillType pathFillType, bool pathIsClosed)
+void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed)
{
Clipper c;
for (size_t i = 0; i < paths.size(); ++i)
@@ -4507,21 +4530,29 @@ void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution,
Paths tmp;
Minkowski(pattern, paths[i], tmp, true, pathIsClosed);
c.AddPaths(tmp, ptSubject, true);
+ if (pathIsClosed)
+ {
+ Path tmp2;
+ TranslatePath(paths[i], tmp2, pattern[0]);
+ c.AddPath(tmp2, ptClip, true);
+ }
}
- if (pathIsClosed) c.AddPaths(paths, ptClip, true);
- c.Execute(ctUnion, solution, pathFillType, pathFillType);
+ c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
}
//------------------------------------------------------------------------------
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution)
{
Minkowski(poly1, poly2, solution, false, true);
+ Clipper c;
+ c.AddPaths(solution, ptSubject, true);
+ c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
}
//------------------------------------------------------------------------------
enum NodeType {ntAny, ntOpen, ntClosed};
-void AddPolyNodeToPolygons(const PolyNode& polynode, NodeType nodetype, Paths& paths)
+void AddPolyNodeToPaths(const PolyNode& polynode, NodeType nodetype, Paths& paths)
{
bool match = true;
if (nodetype == ntClosed) match = !polynode.IsOpen();
@@ -4530,7 +4561,7 @@ void AddPolyNodeToPolygons(const PolyNode& polynode, NodeType nodetype, Paths& p
if (!polynode.Contour.empty() && match)
paths.push_back(polynode.Contour);
for (int i = 0; i < polynode.ChildCount(); ++i)
- AddPolyNodeToPolygons(*polynode.Childs[i], nodetype, paths);
+ AddPolyNodeToPaths(*polynode.Childs[i], nodetype, paths);
}
//------------------------------------------------------------------------------
@@ -4538,7 +4569,7 @@ void PolyTreeToPaths(const PolyTree& polytree, Paths& paths)
{
paths.resize(0);
paths.reserve(polytree.Total());
- AddPolyNodeToPolygons(polytree, ntAny, paths);
+ AddPolyNodeToPaths(polytree, ntAny, paths);
}
//------------------------------------------------------------------------------
@@ -4546,7 +4577,7 @@ void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths)
{
paths.resize(0);
paths.reserve(polytree.Total());
- AddPolyNodeToPolygons(polytree, ntClosed, paths);
+ AddPolyNodeToPaths(polytree, ntClosed, paths);
}
//------------------------------------------------------------------------------
@@ -4588,18 +4619,4 @@ std::ostream& operator <<(std::ostream &s, const Paths &p)
}
//------------------------------------------------------------------------------
-#ifdef use_deprecated
-
-void OffsetPaths(const Paths &in_polys, Paths &out_polys,
- double delta, JoinType jointype, EndType_ endtype, double limit)
-{
- ClipperOffset co(limit, limit);
- co.AddPaths(in_polys, jointype, (EndType)endtype);
- co.Execute(out_polys, delta);
-}
-//------------------------------------------------------------------------------
-
-#endif
-
-
} //ClipperLib namespace
diff --git a/src/3rdparty/clipper/clipper.h b/src/3rdparty/clipper/clipper.h
index 84870141..2472ac77 100644
--- a/src/3rdparty/clipper/clipper.h
+++ b/src/3rdparty/clipper/clipper.h
@@ -1,10 +1,10 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
-* Version : 6.1.3a *
-* Date : 22 January 2014 *
+* Version : 6.4.0 *
+* Date : 2 July 2015 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2014 *
+* Copyright : Angus Johnson 2010-2015 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
@@ -34,7 +34,7 @@
#ifndef clipper_hpp
#define clipper_hpp
-#define CLIPPER_VERSION "6.1.3"
+#define CLIPPER_VERSION "6.2.6"
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
//improve performance but coordinate values are limited to the range +/- 46340
@@ -44,19 +44,20 @@
//#define use_xyz
//use_lines: Enables line clipping. Adds a very minor cost to performance.
-//#define use_lines
+#define use_lines
-//use_deprecated: Enables support for the obsolete OffsetPaths() function
-//which has been replace with the ClipperOffset class.
-#define use_deprecated
+//use_deprecated: Enables temporary support for the obsolete functions
+//#define use_deprecated
#include <vector>
+#include <list>
#include <set>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
#include <functional>
+#include <queue>
namespace ClipperLib {
@@ -69,11 +70,16 @@ enum PolyType { ptSubject, ptClip };
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
#ifdef use_int32
-typedef int cInt;
-typedef unsigned int cUInt;
+ typedef int cInt;
+ static cInt const loRange = 0x7FFF;
+ static cInt const hiRange = 0x7FFF;
#else
-typedef signed long long cInt;
-typedef unsigned long long cUInt;
+ typedef signed long long cInt;
+ static cInt const loRange = 0x3FFFFFFF;
+ static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
+ typedef signed long long long64; //used by Int128 class
+ typedef unsigned long long ulong64;
+
#endif
struct IntPoint {
@@ -117,15 +123,12 @@ struct DoublePoint
//------------------------------------------------------------------------------
#ifdef use_xyz
-typedef void (*TZFillCallback)(IntPoint& z1, IntPoint& z2, IntPoint& pt);
+typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt);
#endif
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
enum JoinType {jtSquare, jtRound, jtMiter};
enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound};
-#ifdef use_deprecated
- enum EndType_ {etClosed, etButt = 2, etSquare, etRound};
-#endif
class PolyNode;
typedef std::vector< PolyNode* > PolyNodes;
@@ -134,6 +137,7 @@ class PolyNode
{
public:
PolyNode();
+ virtual ~PolyNode(){};
Path Contour;
PolyNodes Childs;
PolyNode* Parent;
@@ -168,11 +172,6 @@ bool Orientation(const Path &poly);
double Area(const Path &poly);
int PointInPolygon(const IntPoint &pt, const Path &path);
-#ifdef use_deprecated
- void OffsetPaths(const Paths &in_polys, Paths &out_polys,
- double delta, JoinType jointype, EndType_ endtype, double limit = 0);
-#endif
-
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
@@ -183,8 +182,7 @@ void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.
void CleanPolygons(Paths& polys, double distance = 1.415);
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
-void MinkowskiSum(const Path& pattern, const Paths& paths,
- Paths& solution, PolyFillType pathFillType, bool pathIsClosed);
+void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed);
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
@@ -202,8 +200,7 @@ enum EdgeSide { esLeft = 1, esRight = 2};
//forward declarations (for stuff used internally) ...
struct TEdge;
struct IntersectNode;
-struct LocalMinima;
-struct Scanbeam;
+struct LocalMinimum;
struct OutPt;
struct OutRec;
struct Join;
@@ -213,7 +210,6 @@ typedef std::vector < TEdge* > EdgeList;
typedef std::vector < Join* > JoinList;
typedef std::vector < IntersectNode* > IntersectList;
-
//------------------------------------------------------------------------------
//ClipperBase is the ancestor to the Clipper class. It should not be
@@ -224,7 +220,7 @@ class ClipperBase
public:
ClipperBase();
virtual ~ClipperBase();
- bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
+ virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
virtual void Clear();
IntRect GetBounds();
@@ -233,19 +229,32 @@ public:
protected:
void DisposeLocalMinimaList();
TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
- void PopLocalMinima();
virtual void Reset();
TEdge* ProcessBound(TEdge* E, bool IsClockwise);
- void InsertLocalMinima(LocalMinima *newLm);
- void DoMinimaLML(TEdge* E1, TEdge* E2, bool IsClosed);
- TEdge* DescendToMin(TEdge *&E);
- void AscendToMax(TEdge *&E, bool Appending, bool IsClosed);
- LocalMinima *m_CurrentLM;
- LocalMinima *m_MinimaList;
+ void InsertScanbeam(const cInt Y);
+ bool PopScanbeam(cInt &Y);
+ bool LocalMinimaPending();
+ bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin);
+ OutRec* CreateOutRec();
+ void DisposeAllOutRecs();
+ void DisposeOutRec(PolyOutList::size_type index);
+ void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
+ void DeleteFromAEL(TEdge *e);
+ void UpdateEdgeIntoAEL(TEdge *&e);
+
+ typedef std::vector<LocalMinimum> MinimaList;
+ MinimaList::iterator m_CurrentLM;
+ MinimaList m_MinimaList;
+
bool m_UseFullRange;
EdgeList m_edges;
- bool m_PreserveCollinear;
- bool m_HasOpenPaths;
+ bool m_PreserveCollinear;
+ bool m_HasOpenPaths;
+ PolyOutList m_PolyOuts;
+ TEdge *m_ActiveEdges;
+
+ typedef std::priority_queue<cInt> ScanbeamList;
+ ScanbeamList m_Scanbeam;
};
//------------------------------------------------------------------------------
@@ -253,34 +262,37 @@ class Clipper : public virtual ClipperBase
{
public:
Clipper(int initOptions = 0);
- ~Clipper();
bool Execute(ClipType clipType,
- Paths &solution,
- PolyFillType subjFillType = pftEvenOdd,
- PolyFillType clipFillType = pftEvenOdd);
+ Paths &solution,
+ PolyFillType fillType = pftEvenOdd);
+ bool Execute(ClipType clipType,
+ Paths &solution,
+ PolyFillType subjFillType,
+ PolyFillType clipFillType);
bool Execute(ClipType clipType,
- PolyTree &polytree,
- PolyFillType subjFillType = pftEvenOdd,
- PolyFillType clipFillType = pftEvenOdd);
- bool ReverseSolution() {return m_ReverseOutput;};
+ PolyTree &polytree,
+ PolyFillType fillType = pftEvenOdd);
+ bool Execute(ClipType clipType,
+ PolyTree &polytree,
+ PolyFillType subjFillType,
+ PolyFillType clipFillType);
+ bool ReverseSolution() { return m_ReverseOutput; };
void ReverseSolution(bool value) {m_ReverseOutput = value;};
bool StrictlySimple() {return m_StrictSimple;};
void StrictlySimple(bool value) {m_StrictSimple = value;};
//set the callback function for z value filling on intersections (otherwise Z is 0)
#ifdef use_xyz
- void ZFillFunction(TZFillCallback zFillFunc);
+ void ZFillFunction(ZFillCallback zFillFunc);
#endif
protected:
- void Reset();
virtual bool ExecuteInternal();
private:
- PolyOutList m_PolyOuts;
- JoinList m_Joins;
- JoinList m_GhostJoins;
- IntersectList m_IntersectList;
- ClipType m_ClipType;
- std::set< cInt, std::greater<cInt> > m_Scanbeam;
- TEdge *m_ActiveEdges;
+ JoinList m_Joins;
+ JoinList m_GhostJoins;
+ IntersectList m_IntersectList;
+ ClipType m_ClipType;
+ typedef std::list<cInt> MaximaList;
+ MaximaList m_Maxima;
TEdge *m_SortedEdges;
bool m_ExecuteLocked;
PolyFillType m_ClipFillType;
@@ -289,40 +301,32 @@ private:
bool m_UsingPolyTree;
bool m_StrictSimple;
#ifdef use_xyz
- TZFillCallback m_ZFill; //custom callback
+ ZFillCallback m_ZFill; //custom callback
#endif
void SetWindingCount(TEdge& edge);
bool IsEvenOddFillType(const TEdge& edge) const;
bool IsEvenOddAltFillType(const TEdge& edge) const;
- void InsertScanbeam(const cInt Y);
- cInt PopScanbeam();
void InsertLocalMinimaIntoAEL(const cInt botY);
void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
void AddEdgeToSEL(TEdge *edge);
+ bool PopEdgeFromSEL(TEdge *&edge);
void CopyAELToSEL();
void DeleteFromSEL(TEdge *e);
- void DeleteFromAEL(TEdge *e);
- void UpdateEdgeIntoAEL(TEdge *&e);
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
bool IsContributing(const TEdge& edge) const;
bool IsTopHorz(const cInt XPos);
- void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
void DoMaxima(TEdge *e);
- void PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam);
- void ProcessHorizontals(bool IsTopOfScanbeam);
- void ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam);
+ void ProcessHorizontals();
+ void ProcessHorizontal(TEdge *horzEdge);
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutRec* GetOutRec(int idx);
void AppendPolygon(TEdge *e1, TEdge *e2);
- void IntersectEdges(TEdge *e1, TEdge *e2,
- const IntPoint &pt, bool protect = false);
- OutRec* CreateOutRec();
+ void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
- void DisposeAllOutRecs();
- void DisposeOutRec(PolyOutList::size_type index);
- bool ProcessIntersections(const cInt botY, const cInt topY);
- void BuildIntersectList(const cInt botY, const cInt topY);
+ OutPt* GetLastOutPt(TEdge *e);
+ bool ProcessIntersections(const cInt topY);
+ void BuildIntersectList(const cInt topY);
void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
void BuildResult(Paths& polys);
@@ -331,6 +335,7 @@ private:
void DisposeIntersectNodes();
bool FixupIntersectionOrder();
void FixupOutPolygon(OutRec &outrec);
+ void FixupOutPolyline(OutRec &outrec);
bool IsHole(TEdge *e);
bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
void FixHoleLinkage(OutRec &outrec);
@@ -342,9 +347,10 @@ private:
void JoinCommonEdges();
void DoSimplePolygons();
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
- void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec);
+ void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec);
+ void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec);
#ifdef use_xyz
- void SetZ(IntPoint& pt, TEdge& e);
+ void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
#endif
};
//------------------------------------------------------------------------------
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 a2428b4c..a0b61d6e 100644
--- a/src/imports/location/location.cpp
+++ b/src/imports/location/location.cpp
@@ -34,36 +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 <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>
@@ -166,6 +170,12 @@ public:
minor = 8;
qmlRegisterType<QDeclarativeGeoManeuver>(uri, major, minor, "RouteManeuver");
+ // 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>();
qRegisterMetaType<QPlace>();
diff --git a/src/imports/location/location.pro b/src/imports/location/location.pro
index 57172ad8..dec1149b 100644
--- a/src/imports/location/location.pro
+++ b/src/imports/location/location.pro
@@ -1,69 +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
-
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
-
-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/imports/positioning/locationsingleton.cpp b/src/imports/positioning/locationsingleton.cpp
index f12486b0..a48c1a96 100644
--- a/src/imports/positioning/locationsingleton.cpp
+++ b/src/imports/positioning/locationsingleton.cpp
@@ -179,6 +179,19 @@ QGeoCircle LocationSingleton::circle(const QGeoCoordinate &center, qreal radius)
}
/*!
+ \qmlmethod geopath QtPositioning::path() const
+
+ Constructs an empty geopath.
+
+ \sa {geopath}
+ \since 5.9
+*/
+QGeoPath LocationSingleton::path() const
+{
+ return QGeoPath();
+}
+
+/*!
\qmlmethod geocircle QtPositioning::shapeToCircle(geoshape shape) const
Converts \a shape to a geocircle.
@@ -204,3 +217,16 @@ QGeoRectangle LocationSingleton::shapeToRectangle(const QGeoShape &shape) const
return QGeoRectangle(shape);
}
+/*!
+ \qmlmethod geopath QtPositioning::shapeToPath(geoshape shape) const
+
+ Converts \a shape to a geopath.
+
+ \sa {geopath}
+ \since 5.9
+*/
+QGeoPath LocationSingleton::shapeToPath(const QGeoShape &shape) const
+{
+ return QGeoPath(shape);
+}
+
diff --git a/src/imports/positioning/locationsingleton.h b/src/imports/positioning/locationsingleton.h
index cc4ea5ce..9a5320e0 100644
--- a/src/imports/positioning/locationsingleton.h
+++ b/src/imports/positioning/locationsingleton.h
@@ -46,6 +46,7 @@
#include <QtPositioning/QGeoShape>
#include <QtPositioning/QGeoRectangle>
#include <QtPositioning/QGeoCircle>
+#include <QtPositioning/QGeoPath>
#include <QVariant>
class LocationSingleton : public QObject
@@ -71,8 +72,11 @@ public:
Q_INVOKABLE QGeoCircle circle() const;
Q_INVOKABLE QGeoCircle circle(const QGeoCoordinate &center, qreal radius = -1.0) const;
+ Q_INVOKABLE QGeoPath path() const;
+
Q_INVOKABLE QGeoCircle shapeToCircle(const QGeoShape &shape) const;
Q_INVOKABLE QGeoRectangle shapeToRectangle(const QGeoShape &shape) const;
+ Q_INVOKABLE QGeoPath shapeToPath(const QGeoShape &shape) const;
};
#endif // LOCATIONSINGLETON_H
diff --git a/src/imports/positioning/positioning.cpp b/src/imports/positioning/positioning.cpp
index f8e1840f..f00a4ae6 100644
--- a/src/imports/positioning/positioning.cpp
+++ b/src/imports/positioning/positioning.cpp
@@ -40,7 +40,7 @@
#include <QtPositioning/private/qdeclarativegeoaddress_p.h>
#include <QtPositioning/private/qdeclarativegeolocation_p.h>
-#include <QtPositioning/private/qgeoprojection_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
#include "qdeclarativepositionsource_p.h"
#include "qdeclarativeposition_p.h"
@@ -55,6 +55,7 @@
#include <QtPositioning/QGeoRectangle>
#include <QtPositioning/QGeoCircle>
+#include <QtPositioning/QGeoPath>
#include <QtPositioning/QGeoLocation>
#include <QtCore/QDebug>
@@ -527,6 +528,8 @@ public:
QMetaType::registerEqualsComparator<QGeoRectangle>();
qRegisterMetaType<QGeoCircle>();
QMetaType::registerEqualsComparator<QGeoCircle>();
+ qRegisterMetaType<QGeoPath>();
+ QMetaType::registerEqualsComparator<QGeoPath>();
qRegisterMetaType<QGeoLocation>();
qRegisterMetaType<QGeoShape>();
QMetaType::registerEqualsComparator<QGeoShape>();
diff --git a/src/imports/positioning/qdeclarativepositionsource.cpp b/src/imports/positioning/qdeclarativepositionsource.cpp
index 35ff33b3..8be953f7 100644
--- a/src/imports/positioning/qdeclarativepositionsource.cpp
+++ b/src/imports/positioning/qdeclarativepositionsource.cpp
@@ -311,7 +311,7 @@ void QDeclarativePositionSource::setNmeaSource(const QUrl &nmeaSource)
QTimer::singleShot(0, this, SLOT(start()));
}
} else {
- qmlInfo(this) << QStringLiteral("Nmea file not found") << localFileName;
+ qmlWarning(this) << QStringLiteral("Nmea file not found") << localFileName;
#ifdef QDECLARATIVE_POSITION_DEBUG
qDebug() << "QDeclarativePositionSource NMEA File was not found: " << localFileName;
#endif
diff --git a/src/imports/positioning/qquickgeocoordinateanimation.cpp b/src/imports/positioning/qquickgeocoordinateanimation.cpp
index c386074a..41c1be1e 100644
--- a/src/imports/positioning/qquickgeocoordinateanimation.cpp
+++ b/src/imports/positioning/qquickgeocoordinateanimation.cpp
@@ -41,7 +41,7 @@
#include "qquickgeocoordinateanimation_p_p.h"
#include <QtQuick/private/qquickanimation_p_p.h>
#include <QtPositioning/private/qdoublevector2d_p.h>
-#include <QtPositioning/private/qgeoprojection_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
#include <QtPositioning/private/qgeocoordinate_p.h>
QT_BEGIN_NAMESPACE
@@ -80,7 +80,7 @@ QVariant q_coordinateInterpolator(const QGeoCoordinate &from, const QGeoCoordina
}
}
- QGeoCoordinate result = QGeoProjection::coordinateInterpolation(from, to, progress);
+ QGeoCoordinate result = QWebMercator::coordinateInterpolation(from, to, progress);
return QVariant::fromValue(result);
}
@@ -117,7 +117,7 @@ QVariant q_coordinateShortestInterpolator(const QGeoCoordinate &from, const QGeo
double y = fromY + (toY - fromY) * progress;
- QGeoCoordinate result = QGeoProjection::mercatorToCoord(QDoubleVector2D(x, y));
+ QGeoCoordinate result = QWebMercator::mercatorToCoord(QDoubleVector2D(x, y));
result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
return QVariant::fromValue(result);
}
@@ -146,7 +146,7 @@ QVariant q_coordinateWestInterpolator(const QGeoCoordinate &from, const QGeoCoor
while (x > 1.0)
x -= 1.0;
- QGeoCoordinate result = QGeoProjection::mercatorToCoord(QDoubleVector2D(x, y));
+ QGeoCoordinate result = QWebMercator::mercatorToCoord(QDoubleVector2D(x, y));
result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
return QVariant::fromValue(result);
@@ -176,7 +176,7 @@ QVariant q_coordinateEastInterpolator(const QGeoCoordinate &from, const QGeoCoor
while (x < 0.0)
x += 1.0;
- QGeoCoordinate result = QGeoProjection::mercatorToCoord(QDoubleVector2D(x, y));
+ QGeoCoordinate result = QWebMercator::mercatorToCoord(QDoubleVector2D(x, y));
result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
return QVariant::fromValue(result);
@@ -209,7 +209,7 @@ QGeoCoordinate QQuickGeoCoordinateAnimation::from() const
void QQuickGeoCoordinateAnimation::setFrom(const QGeoCoordinate &f)
{
QGeoMercatorCoordinatePrivate *mercator = new QGeoMercatorCoordinatePrivate();
- QDoubleVector2D fromVector = QGeoProjection::coordToMercator(f);
+ QDoubleVector2D fromVector = QWebMercator::coordToMercator(f);
mercator->lat = f.latitude();
mercator->lng = f.longitude();
mercator->alt = f.altitude();
@@ -232,7 +232,7 @@ QGeoCoordinate QQuickGeoCoordinateAnimation::to() const
void QQuickGeoCoordinateAnimation::setTo(const QGeoCoordinate &t)
{
QGeoMercatorCoordinatePrivate *mercator = new QGeoMercatorCoordinatePrivate();
- QDoubleVector2D toVector = QGeoProjection::coordToMercator(t);
+ QDoubleVector2D toVector = QWebMercator::coordToMercator(t);
mercator->lat = t.latitude();
mercator->lng = t.longitude();
mercator->alt = t.altitude();
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 6890703b..4cba1ab6 100644
--- a/src/imports/location/qdeclarativecirclemapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
@@ -37,19 +37,27 @@
#include "qdeclarativecirclemapitem_p.h"
#include "qdeclarativepolygonmapitem_p.h"
#include "qgeocameracapabilities_p.h"
-#include "qgeoprojection_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
@@ -121,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;
@@ -139,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.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.coordinateToItemPosition(mapCenter, false);
- QDoubleVector2D midPointPlusOne = QDoubleVector2D(midPoint.x() + 1.0, midPoint.y());
- QGeoCoordinate coord1 = map.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));
- }
- 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);
- }
+ /*
+ * 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;
}
- 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)
@@ -266,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
@@ -276,46 +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 = qgeocoordinate_radToDeg(resultLonRad);
- if (lon2 < -180.0) {
- lon2 += 360.0;
- } else if (lon2 > 180.0) {
- lon2 -= 360.0;
- }
+ 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);
@@ -323,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
@@ -376,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();
}
/*!
@@ -401,6 +407,7 @@ void QDeclarativeCircleMapItem::setColor(const QColor &color)
return;
color_ = color;
dirtyMaterial_ = true;
+ geoMaterialDirty_ = true;
update();
emit colorChanged(color_);
}
@@ -419,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();
}
/*!
@@ -471,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_);
@@ -479,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());
+ }
- setWidth(combined.width());
- setHeight(combined.height());
- } else {
- borderGeometry_.clear();
- setWidth(geometry_.screenBoundingBox().width());
- setHeight(geometry_.screenBoundingBox().height());
+ borderGeometry_.setPreserveGeometry(true, circle_.boundingGeoRectangle().topLeft()); // to set the geoLeftBound_
+ borderGeometry_.setPreserveGeometry(preserve, circle_.boundingGeoRectangle().topLeft());
+
+ // 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());
}
/*!
@@ -520,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();
}
/*!
@@ -560,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
*/
@@ -571,7 +588,7 @@ void QDeclarativeCircleMapItem::geometryChanged(const QRectF &newGeometry, const
}
QDoubleVector2D newPoint = QDoubleVector2D(x(),y()) + QDoubleVector2D(width(), height()) / 2;
- QGeoCoordinate newCoordinate = map()->itemPositionToCoordinate(newPoint, false);
+ QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(newPoint, false);
if (newCoordinate.isValid())
setCenter(newCoordinate);
@@ -591,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)
@@ -602,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()->coordinateToItemPosition(map()->cameraData().center(), false);
- QDoubleVector2D midPointPlusOne(midPoint.x() + 1.0, midPoint.y());
- QGeoCoordinate coord1 = map()->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()->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()->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 d8ff4e85..e92949ee 100644
--- a/src/imports/location/qdeclarativegeocodemodel.cpp
+++ b/src/location/declarativemaps/qdeclarativegeocodemodel.cpp
@@ -529,7 +529,7 @@ int QDeclarativeGeocodeModel::count() const
QDeclarativeGeoLocation *QDeclarativeGeocodeModel::get(int index)
{
if (index < 0 || index >= declarativeLocations_.count()) {
- qmlInfo(this) << QStringLiteral("Index '%1' out of range").arg(index);
+ qmlWarning(this) << QStringLiteral("Index '%1' out of range").arg(index);
return 0;
}
return declarativeLocations_.at(index);
@@ -679,12 +679,12 @@ void QDeclarativeGeocodeModel::setQuery(const QVariant &query)
connect(address_, SIGNAL(streetChanged()), this, SLOT(queryContentChanged()));
connect(address_, SIGNAL(postalCodeChanged()), this, SLOT(queryContentChanged()));
} else {
- qmlInfo(this) << QStringLiteral("Unsupported query type for geocode model ")
+ qmlWarning(this) << QStringLiteral("Unsupported query type for geocode model ")
<< QStringLiteral("(coordinate, string and Address supported).");
return;
}
} else {
- qmlInfo(this) << QStringLiteral("Unsupported query type for geocode model ")
+ qmlWarning(this) << QStringLiteral("Unsupported query type for geocode model ")
<< QStringLiteral("(coordinate, string and Address supported).");
return;
}
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 0450bf56..b7ec31ca 100644
--- a/src/imports/location/qdeclarativegeomap.cpp
+++ b/src/location/declarativemaps/qdeclarativegeomap.cpp
@@ -42,6 +42,7 @@
#include "qgeomappingmanager_p.h"
#include "qgeocameracapabilities_p.h"
#include "qgeomap_p.h"
+#include "qdeclarativegeomapparameter_p.h"
#include <QtPositioning/QGeoCircle>
#include <QtPositioning/QGeoRectangle>
#include <QtQuick/QQuickWindow>
@@ -50,6 +51,11 @@
#include <QtQml/qqmlinfo.h>
#include <cmath>
+#ifndef M_PI
+#define M_PI 3.141592653589793238463
+#endif
+
+
QT_BEGIN_NAMESPACE
/*!
@@ -158,7 +164,6 @@ static const qreal EARTH_MEAN_RADIUS = 6371007.2;
QDeclarativeGeoMap::QDeclarativeGeoMap(QQuickItem *parent)
: QQuickItem(parent),
m_plugin(0),
- m_serviceProvider(0),
m_mappingManager(0),
m_activeMapType(0),
m_gestureArea(new QQuickGeoMapGestureArea(this)),
@@ -169,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);
@@ -188,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
@@ -197,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();
}
@@ -234,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)));
@@ -303,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;
- setMinimumZoomLevel(m_map->minimumZoomAtViewportSize(width(), height()));
-
- // set latitude bundary check
- m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData.zoomLevel());
QGeoCoordinate center = m_cameraData.center();
+
+ setMinimumZoomLevel(m_map->minimumZoom());
+
+ 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()) {
@@ -324,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());
}
/*!
@@ -331,11 +416,11 @@ void QDeclarativeGeoMap::initialize()
*/
void QDeclarativeGeoMap::pluginReady()
{
- m_serviceProvider = m_plugin->sharedGeoServiceProvider();
- m_mappingManager = m_serviceProvider->mappingManager();
+ QGeoServiceProvider *provider = m_plugin->sharedGeoServiceProvider();
+ m_mappingManager = provider->mappingManager();
- if (m_serviceProvider->error() != QGeoServiceProvider::NoError) {
- setError(m_serviceProvider->error(), m_serviceProvider->errorString());
+ if (provider->error() != QGeoServiceProvider::NoError) {
+ setError(provider->error(), provider->errorString());
return;
}
@@ -360,6 +445,7 @@ void QDeclarativeGeoMap::pluginReady()
void QDeclarativeGeoMap::componentComplete()
{
m_componentCompleted = true;
+ populateParameters();
populateMap();
QQuickItem::componentComplete();
}
@@ -432,6 +518,8 @@ QQuickGeoMapGestureArea *QDeclarativeGeoMap::gesture()
/*!
\internal
+
+ This may happen before mappingManagerInitialized()
*/
void QDeclarativeGeoMap::populateMap()
{
@@ -451,10 +539,30 @@ 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;
}
}
}
+void QDeclarativeGeoMap::populateParameters()
+{
+ QObjectList kids = children();
+ QList<QQuickItem *> quickKids = childItems();
+ for (int i = 0; i < quickKids.count(); ++i)
+ kids.append(quickKids.at(i));
+ for (int i = 0; i < kids.size(); ++i) {
+ QDeclarativeGeoMapParameter *mapParameter = qobject_cast<QDeclarativeGeoMapParameter *>(kids.at(i));
+ if (mapParameter)
+ addMapParameter(mapParameter);
+ }
+}
+
/*!
\internal
*/
@@ -502,7 +610,7 @@ QSGNode *QDeclarativeGeoMap::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
void QDeclarativeGeoMap::setPlugin(QDeclarativeGeoServiceProvider *plugin)
{
if (m_plugin) {
- qmlInfo(this) << QStringLiteral("Plugin is a write-once property, and cannot be set again.");
+ qmlWarning(this) << QStringLiteral("Plugin is a write-once property, and cannot be set again.");
return;
}
m_plugin = plugin;
@@ -546,13 +654,12 @@ 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
+ //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_gestureArea->maximumZoomLevel() < 0
- || m_mappingManager->cameraCapabilities().maximumZoomLevel() < m_gestureArea->maximumZoomLevel())
- setMaximumZoomLevel(m_mappingManager->cameraCapabilities().maximumZoomLevel());
-
- if (m_mappingManager->cameraCapabilities().minimumZoomLevel() > m_gestureArea->minimumZoomLevel())
- setMinimumZoomLevel(m_mappingManager->cameraCapabilities().minimumZoomLevel());
+ if (m_mappingManager->cameraCapabilities().minimumZoomLevelAt256() > m_gestureArea->minimumZoomLevel())
+ setMinimumZoomLevel(m_mappingManager->cameraCapabilities().minimumZoomLevelAt256());
// Map tiles are built in this call. m_map->minimumZoom() becomes operational
@@ -564,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);
@@ -587,9 +701,27 @@ 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
+ // need to be added to m_map
+ for (QDeclarativeGeoMapParameter *p : m_mapParameters)
+ m_map->addParameter(p);
}
/*!
@@ -614,8 +746,8 @@ void QDeclarativeGeoMap::setMinimumZoomLevel(qreal minimumZoomLevel)
qreal oldMinimumZoomLevel = this->minimumZoomLevel();
if (m_map) {
- minimumZoomLevel = qBound(qreal(m_map->cameraCapabilities().minimumZoomLevel()), minimumZoomLevel, maximumZoomLevel());
- double minimumViewportZoomLevel = m_map->minimumZoomAtViewportSize(width(),height());
+ minimumZoomLevel = qBound(qreal(m_map->cameraCapabilities().minimumZoomLevelAt256()), minimumZoomLevel, maximumZoomLevel());
+ double minimumViewportZoomLevel = m_map->minimumZoom();
if (minimumZoomLevel < minimumViewportZoomLevel)
minimumZoomLevel = minimumViewportZoomLevel;
}
@@ -641,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().minimumZoomLevel();
- else
- return -1.0;
+ return m_gestureArea->minimumZoomLevel();
}
/*!
@@ -665,7 +792,7 @@ void QDeclarativeGeoMap::setMaximumZoomLevel(qreal maximumZoomLevel)
qreal oldMaximumZoomLevel = this->maximumZoomLevel();
if (m_map)
- maximumZoomLevel = qBound(minimumZoomLevel(), maximumZoomLevel, qreal(m_map->cameraCapabilities().maximumZoomLevel()));
+ maximumZoomLevel = qBound(minimumZoomLevel(), maximumZoomLevel, qreal(m_map->cameraCapabilities().maximumZoomLevelAt256()));
m_gestureArea->setMaximumZoomLevel(maximumZoomLevel);
@@ -683,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().maximumZoomLevel();
- else
- return -1.0;
+ return m_gestureArea->maximumZoomLevel();
}
/*!
@@ -709,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()) {
@@ -726,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());
@@ -739,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
@@ -763,7 +1064,6 @@ void QDeclarativeGeoMap::setCenter(const QGeoCoordinate &center)
m_cameraData.setCenter(center);
}
- m_validRegion = false;
emit centerChanged(m_cameraData.center());
}
@@ -793,17 +1093,20 @@ 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;
}
- if (!width() || !height()) {
+ if (!m_map || !width() || !height()) {
m_pendingFitViewport = true;
return;
}
@@ -814,10 +1117,10 @@ 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->itemPositionToCoordinate(QDoubleVector2D(0, 0));
- QGeoCoordinate br = m_map->itemPositionToCoordinate(QDoubleVector2D(width(), height()));
+ QGeoCoordinate tl = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(0, 0));
+ QGeoCoordinate br = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(width(), height()));
return QGeoRectangle(tl, br);
}
@@ -873,106 +1176,38 @@ 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)
+ const int margins = 10;
+ if (!m_map || !m_visibleRegion.isValid() || 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:
- return;
- }
-
- // adjust zoom, use reference world to keep things simple
- // otherwise we would need to do the error prone longitudes
- // wrapping
- QDoubleVector2D topLeftPoint =
- m_map->referenceCoordinateToItemPosition(topLeft);
- QDoubleVector2D bottomRightPoint =
- m_map->referenceCoordinateToItemPosition(bottomRight);
-
- double bboxWidth = bottomRightPoint.x() - topLeftPoint.x();
- double bboxHeight = bottomRightPoint.y() - topLeftPoint.y();
+ 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);
// find center of the bounding box
- QGeoCoordinate centerCoordinate =
- m_map->referenceItemPositionToCoordinate(
- (topLeftPoint + bottomRightPoint)/2);
+ QDoubleVector2D center = (topLeftPoint + bottomRightPoint) * 0.5;
+ center.setX(center.x() > 1.0 ? center.x() - 1.0 : center.x());
+ QGeoCoordinate centerCoordinate = m_map->geoProjection().mapProjectionToGeo(center);
// position camera to the center of bounding box
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;
}
@@ -999,7 +1234,7 @@ QQmlListProperty<QDeclarativeGeoMapType> QDeclarativeGeoMap::supportedMapTypes()
QGeoCoordinate QDeclarativeGeoMap::toCoordinate(const QPointF &position, bool clipToViewPort) const
{
if (m_map)
- return m_map->itemPositionToCoordinate(QDoubleVector2D(position), clipToViewPort);
+ return m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(position), clipToViewPort);
else
return QGeoCoordinate();
}
@@ -1015,7 +1250,7 @@ QGeoCoordinate QDeclarativeGeoMap::toCoordinate(const QPointF &position, bool cl
QPointF QDeclarativeGeoMap::fromCoordinate(const QGeoCoordinate &coordinate, bool clipToViewPort) const
{
if (m_map)
- return m_map->coordinateToItemPosition(coordinate, clipToViewPort).toPointF();
+ return m_map->geoProjection().coordinateToItemPosition(coordinate, clipToViewPort).toPointF();
else
return QPointF(qQNaN(), qQNaN());
}
@@ -1037,7 +1272,8 @@ void QDeclarativeGeoMap::pan(int dx, int dy)
return;
if (dx == 0 && dy == 0)
return;
- QGeoCoordinate coord = m_map->itemPositionToCoordinate(
+
+ QGeoCoordinate coord = m_map->geoProjection().itemPositionToCoordinate(
QDoubleVector2D(m_map->viewportWidth() / 2 + dx,
m_map->viewportHeight() / 2 + dy));
setCenter(coord);
@@ -1202,14 +1438,107 @@ 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();
}
/*!
+ \qmlmethod void QtLocation::Map::addMapParameter(MapParameter parameter)
+
+ Adds a MapParameter object to the map. The effect of this call is dependent
+ on the combination of the content of the MapParameter and the type of
+ underlying QGeoMap. If a MapParameter that is not supported by the underlying
+ QGeoMap gets added, the call has no effect.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, removeMapParameter, mapParameters, clearMapParameters
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::addMapParameter(QDeclarativeGeoMapParameter *parameter)
+{
+ if (!parameter->isComponentComplete()) {
+ connect(parameter, &QDeclarativeGeoMapParameter::completed, this, &QDeclarativeGeoMap::addMapParameter);
+ return;
+ }
+
+ disconnect(parameter);
+ if (m_mapParameters.contains(parameter))
+ return;
+ parameter->setParent(this);
+ m_mapParameters.insert(parameter); // parameter now owned by QDeclarativeGeoMap
+ if (m_map)
+ m_map->addParameter(parameter);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::removeMapParameter(MapParameter parameter)
+
+ Removes the given MapParameter object from the map.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, addMapParameter, mapParameters, clearMapParameters
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::removeMapParameter(QDeclarativeGeoMapParameter *parameter)
+{
+ if (!m_mapParameters.contains(parameter))
+ return;
+ if (m_map)
+ m_map->removeParameter(parameter);
+ m_mapParameters.remove(parameter);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::clearMapParameters()
+
+ Removes all map parameters from the map.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, mapParameters, addMapParameter, removeMapParameter, clearMapParameters
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::clearMapParameters()
+{
+ if (m_map)
+ m_map->clearParameters();
+ m_mapParameters.clear();
+}
+
+/*!
+ \qmlproperty list<MapParameters> QtLocation::Map::mapParameters
+
+ Returns the list of all map parameters in no particular order.
+ These items include map parameters that were declared statically as part of
+ the type declaration, as well as dynamical map parameters (\l addMapParameter).
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, addMapParameter, removeMapParameter, clearMapParameters
+
+ \since 5.9
+*/
+QList<QObject *> QDeclarativeGeoMap::mapParameters()
+{
+ QList<QObject *> ret;
+ for (QDeclarativeGeoMapParameter *p : m_mapParameters)
+ ret << p;
+ return ret;
+}
+
+/*!
\qmlproperty list<MapItem> QtLocation::Map::mapItems
Returns the list of all map items in no particular order.
@@ -1243,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();
@@ -1256,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}.
@@ -1312,10 +1704,25 @@ void QDeclarativeGeoMap::geometryChanged(const QRectF &newGeometry, const QRectF
m_map->setViewportSize(newGeometry.size().toSize());
- if (!m_initialized)
+ if (!m_initialized) {
initialize();
- else
- setMinimumZoomLevel(m_map->minimumZoomAtViewportSize(newGeometry.width(), newGeometry.height()));
+ } else {
+ setMinimumZoomLevel(m_map->minimumZoom());
+
+ // Update the center latitudinal threshold
+ double maximumCenterLatitudeAtZoom = m_map->maximumCenterLatitudeAtZoom(m_cameraData);
+ if (maximumCenterLatitudeAtZoom != m_maximumViewportLatitude) {
+ m_maximumViewportLatitude = maximumCenterLatitudeAtZoom;
+ QGeoCoordinate coord = m_cameraData.center();
+ coord.setLatitude(qBound(-m_maximumViewportLatitude, coord.latitude(), m_maximumViewportLatitude));
+
+ if (coord != m_cameraData.center()) {
+ m_cameraData.setCenter(coord);
+ m_map->setCameraData(m_cameraData);
+ emit centerChanged(m_cameraData.center());
+ }
+ }
+ }
/*!
The fitViewportTo*() functions depend on a valid map geometry.
@@ -1337,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;
@@ -1372,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
@@ -1386,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();
@@ -1410,7 +1836,7 @@ void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine)
if (itemCount == 0) {
if (haveQuickItem)
- fitViewportToMapItemsRefine(false);
+ fitViewportToMapItemsRefine(false, onlyVisible);
return;
}
double bboxWidth = maxX - minX;
@@ -1420,7 +1846,7 @@ void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine)
// position camera to the center of bounding box
QGeoCoordinate coordinate;
- coordinate = m_map->itemPositionToCoordinate(QDoubleVector2D(bboxCenterX, bboxCenterY), false);
+ coordinate = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(bboxCenterX, bboxCenterY), false);
setProperty("center", QVariant::fromValue(coordinate));
// adjust zoom
@@ -1440,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 262314ed..d7aee60f 100644
--- a/src/imports/location/qdeclarativegeomap_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomap_p.h
@@ -48,22 +48,27 @@
// 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
class QDeclarativeGeoServiceProvider;
class QDeclarativeGeoMapType;
class QDeclarativeGeoMapCopyrightNotice;
+class QDeclarativeGeoMapParameter;
-class QDeclarativeGeoMap : public QQuickItem
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMap : public QQuickItem
{
Q_OBJECT
Q_ENUMS(QGeoServiceProvider::Error)
@@ -72,10 +77,22 @@ 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)
Q_PROPERTY(QList<QObject *> mapItems READ mapItems NOTIFY mapItemsChanged)
+ Q_PROPERTY(QList<QObject *> mapParameters READ mapParameters)
Q_PROPERTY(QGeoServiceProvider::Error error READ error NOTIFY errorChanged)
Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
Q_PROPERTY(QGeoShape visibleRegion READ visibleRegion WRITE setVisibleRegion)
@@ -103,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;
@@ -119,15 +152,25 @@ 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();
+ Q_INVOKABLE void addMapParameter(QDeclarativeGeoMapParameter *parameter);
+ Q_INVOKABLE void removeMapParameter(QDeclarativeGeoMapParameter *parameter);
+ Q_INVOKABLE void clearMapParameters();
+ QList<QObject *> mapParameters();
+
Q_INVOKABLE QGeoCoordinate toCoordinate(const QPointF &position, bool clipToViewPort = true) const;
Q_INVOKABLE QPointF fromCoordinate(const QGeoCoordinate &coordinate, bool clipToViewPort = true) const;
QQuickGeoMapGestureArea *gesture();
Q_INVOKABLE void fitViewportToMapItems();
+ Q_INVOKABLE void fitViewportToVisibleMapItems();
Q_INVOKABLE void pan(int dx, int dy);
Q_INVOKABLE void prefetchData(); // optional hint for prefetch
Q_INVOKABLE void clearData();
@@ -148,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 ;
@@ -177,13 +231,13 @@ private Q_SLOTS:
private:
void setupMapView(QDeclarativeGeoMapItemView *view);
void populateMap();
- void fitViewportToMapItemsRefine(bool refine);
+ void populateParameters();
+ void fitViewportToMapItemsRefine(bool refine, bool onlyVisible);
void fitViewportToGeoShape();
bool isInteractive();
private:
QDeclarativeGeoServiceProvider *m_plugin;
- QGeoServiceProvider *m_serviceProvider;
QGeoMappingManager *m_mappingManager;
QDeclarativeGeoMapType *m_activeMapType;
QList<QDeclarativeGeoMapType *> m_supportedMapTypes;
@@ -192,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;
@@ -202,11 +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 1788f740..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()
@@ -102,11 +110,11 @@ void QDeclarativeGeoMapItemBase::afterChildrenChanged()
if (i->flags() & QQuickItem::ItemHasContents
&& !qobject_cast<QQuickMouseArea *>(i)) {
if (!printedWarning) {
- qmlInfo(this) << "Geographic map items do not support child items";
+ qmlWarning(this) << "Geographic map items do not support child items";
printedWarning = true;
}
- qmlInfo(i) << "deleting this child";
+ qmlWarning(i) << "deleting this child";
i->deleteLater();
}
}
@@ -177,20 +185,27 @@ void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate &coordina
if (!map_ || !quickMap_)
return;
- QPointF topLeft = map_->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 5a4e3b25..3ad3ceb4 100644
--- a/src/imports/location/qdeclarativegeomapitemview_p_p.h
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h
@@ -60,7 +60,9 @@ class MapItemViewDelegateIncubator;
class QDeclarativeGeoMapItemView;
class QDeclarativeGeoMapItemBase;
-struct QDeclarativeGeoMapItemViewItemData {
+class QDeclarativeGeoMapItemViewItemData
+{
+public:
QDeclarativeGeoMapItemViewItemData()
: incubator(0), item(0), context(0), modelData(0), modelDataMeta(0)
{
diff --git a/src/location/declarativemaps/qdeclarativegeomapparameter.cpp b/src/location/declarativemaps/qdeclarativegeomapparameter.cpp
new file mode 100644
index 00000000..a0e05436
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapparameter.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "qdeclarativegeomapparameter_p.h"
+
+#include <QByteArray>
+#include <QMetaObject>
+#include <QMetaProperty>
+#include <QSignalMapper>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapParameter
+ \instantiates QDeclarativeGeoMapParameter
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.9
+
+ \brief The MapParameter type represents a parameter for a Map element.
+ This type provides a mean to specify plugin-dependent optional parameters
+ for a map.
+
+ MapParameters by default contain only the \l type property, and
+ are highly plugin-dependent.
+ For this reason, additional properties have to be defined inside a
+ MapParameter at declaration time, using the QML syntax "property var foo".
+
+ What properties have to be put inside a particular MapParameter type for
+ a particular plugin can be found in the documentation of the plugin.
+ Note that MapProperties are \b optional.
+ By not specifying any of them, the Map will have the default behavior.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+*/
+
+/*!
+ \qmlproperty string QtLocation::MapParameter::type
+
+ Set-once property which holds a string defining the type of the MapParameter
+*/
+
+QDeclarativeGeoMapParameter::QDeclarativeGeoMapParameter(QObject *parent)
+: QGeoMapParameter(parent), m_initialPropertyCount(metaObject()->propertyCount()), m_complete(false)
+{
+
+}
+
+QDeclarativeGeoMapParameter::~QDeclarativeGeoMapParameter()
+{
+}
+
+bool QDeclarativeGeoMapParameter::isComponentComplete() const
+{
+ return m_complete;
+}
+
+int QDeclarativeGeoMapParameter::initialPropertyCount() const
+{
+ return m_initialPropertyCount;
+}
+
+void QDeclarativeGeoMapParameter::classBegin()
+{
+}
+
+void QDeclarativeGeoMapParameter::componentComplete()
+{
+ for (int i = m_initialPropertyCount; i < metaObject()->propertyCount(); ++i) {
+ QMetaProperty property = metaObject()->property(i);
+
+ if (!property.hasNotifySignal()) {
+ return;
+ }
+
+ QSignalMapper *mapper = new QSignalMapper(this);
+ mapper->setMapping(this, i);
+
+ const QByteArray signalName = '2' + property.notifySignal().methodSignature(); // TODO: explain why '2'
+ QObject::connect(this, signalName, mapper, SLOT(map()));
+ QObject::connect(mapper, SIGNAL(mapped(int)), this, SLOT(onPropertyUpdated(int)));
+ }
+ m_complete = true;
+ emit completed(this);
+}
+
+void QDeclarativeGeoMapParameter::onPropertyUpdated(int index)
+{
+ emit propertyUpdated(this, metaObject()->property(index).name());
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapparameter_p.h b/src/location/declarativemaps/qdeclarativegeomapparameter_p.h
new file mode 100644
index 00000000..0f54e1b7
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapparameter_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 QDECLARATIVEGEOMAPPARAMETER_P_H
+#define QDECLARATIVEGEOMAPPARAMETER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qgeomapparameter_p.h>
+#include <QQmlParserStatus>
+#include <qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapParameter : public QGeoMapParameter, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ explicit QDeclarativeGeoMapParameter(QObject *parent = 0);
+ virtual ~QDeclarativeGeoMapParameter();
+
+ bool isComponentComplete() const;
+
+Q_SIGNALS:
+ void completed(QDeclarativeGeoMapParameter *);
+
+protected:
+ int initialPropertyCount() const;
+ // QQmlParserStatus implementation
+ void classBegin() override;
+ void componentComplete() override;
+
+private slots:
+ void onPropertyUpdated(int index);
+
+private:
+ int m_initialPropertyCount;
+ bool m_complete;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapParameter)
+
+#endif // QDECLARATIVEGEOMAPPARAMETER_P_H
diff --git a/src/imports/location/qdeclarativegeomapquickitem.cpp b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp
index a66efb1d..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();
}
@@ -174,7 +178,7 @@ void QDeclarativeGeoMapQuickItem::geometryChanged(const QRectF &newGeometry, con
return;
}
- QGeoCoordinate newCoordinate = map()->itemPositionToCoordinate(QDoubleVector2D(x(), y()) + (scaleFactor() * QDoubleVector2D(anchorPoint_)), false);
+ QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(x(), y()) + (scaleFactor() * QDoubleVector2D(anchorPoint_)), false);
if (newCoordinate.isValid())
setCoordinate(newCoordinate);
@@ -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();
}
@@ -224,11 +228,11 @@ void QDeclarativeGeoMapQuickItem::afterChildrenChanged()
&& sourceItem_.data() != i
&& opacityContainer_ != i) {
if (!printedWarning) {
- qmlInfo(this) << "Use the sourceItem property for the contained item, direct children are not supported";
+ qmlWarning(this) << "Use the sourceItem property for the contained item, direct children are not supported";
printedWarning = true;
}
- qmlInfo(i) << "deleting this child";
+ qmlWarning(i) << "deleting this child";
i->deleteLater();
}
}
@@ -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 9fe29090..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>
@@ -189,7 +190,7 @@ void QDeclarativeGeoRoute::setPath(const QJSValue &value)
QGeoCoordinate c = parseCoordinate(value.property(i), &ok);
if (!ok || !c.isValid()) {
- qmlInfo(this) << "Unsupported path type";
+ qmlWarning(this) << "Unsupported path type";
return;
}
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 0c64c23a..90796412 100644
--- a/src/imports/location/qdeclarativegeoroutemodel.cpp
+++ b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
@@ -120,7 +120,6 @@ QDeclarativeGeoRouteModel::QDeclarativeGeoRouteModel(QObject *parent)
complete_(false),
plugin_(0),
routeQuery_(0),
- reply_(0),
autoUpdate_(false),
status_(QDeclarativeGeoRouteModel::Null),
error_(QDeclarativeGeoRouteModel::NoError)
@@ -133,7 +132,6 @@ QDeclarativeGeoRouteModel::~QDeclarativeGeoRouteModel()
qDeleteAll(routes_);
routes_.clear();
}
- delete reply_;
}
/*!
@@ -168,7 +166,7 @@ void QDeclarativeGeoRouteModel::reset()
endResetModel();
}
- abortRequest();
+ emit abortRequested();
setError(NoError, QString());
setStatus(QDeclarativeGeoRouteModel::Null);
}
@@ -181,25 +179,12 @@ void QDeclarativeGeoRouteModel::reset()
*/
void QDeclarativeGeoRouteModel::cancel()
{
- abortRequest();
+ emit abortRequested();
setError(NoError, QString());
setStatus(routes_.isEmpty() ? Null : Ready);
}
/*!
- \internal
-*/
-void QDeclarativeGeoRouteModel::abortRequest()
-{
- if (reply_) {
- reply_->abort();
- reply_->deleteLater();
- reply_ = 0;
- }
-}
-
-
-/*!
\qmlmethod void QtLocation::RouteModel::get(int)
Returns the Route at given index. Use \l count property to check the
@@ -212,7 +197,7 @@ void QDeclarativeGeoRouteModel::abortRequest()
QDeclarativeGeoRoute *QDeclarativeGeoRouteModel::get(int index)
{
if (index < 0 || index >= routes_.count()) {
- qmlInfo(this) << QStringLiteral("Index '%1' out of range").arg(index);
+ qmlWarning(this) << QStringLiteral("Index '%1' out of range").arg(index);
return 0;
}
return routes_.at(index);
@@ -244,12 +229,12 @@ int QDeclarativeGeoRouteModel::rowCount(const QModelIndex &parent) const
QVariant QDeclarativeGeoRouteModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
- qmlInfo(this) << QStringLiteral("Error in indexing route model's data (invalid index).");
+ qmlWarning(this) << QStringLiteral("Error in indexing route model's data (invalid index).");
return QVariant();
}
if (index.row() >= routes_.count()) {
- qmlInfo(this) << QStringLiteral("Fatal error in indexing route model's data (index overflow).");
+ qmlWarning(this) << QStringLiteral("Fatal error in indexing route model's data (index overflow).");
return QVariant();
}
@@ -589,7 +574,7 @@ void QDeclarativeGeoRouteModel::update()
setError(ParseError,"Cannot route, valid query not set.");
return;
}
- abortRequest(); // Clear previus requests
+ emit abortRequested(); // Clear previous requests
QGeoRouteRequest request = routeQuery_->routeRequest();
if (request.waypoints().count() < 2) {
setError(ParseError,tr("Not enough waypoints for routing."));
@@ -598,13 +583,15 @@ void QDeclarativeGeoRouteModel::update()
setError(NoError, QString());
- reply_ = routingManager->calculateRoute(request);
+ QGeoRouteReply *reply = routingManager->calculateRoute(request);
setStatus(QDeclarativeGeoRouteModel::Loading);
- if (reply_->isFinished()) {
- if (reply_->error() == QGeoRouteReply::NoError) {
- routingFinished(reply_);
+ if (!reply->isFinished()) {
+ connect(this, &QDeclarativeGeoRouteModel::abortRequested, reply, &QGeoRouteReply::abort);
+ } else {
+ if (reply->error() == QGeoRouteReply::NoError) {
+ routingFinished(reply);
} else {
- routingError(reply_, reply_->error(), reply_->errorString());
+ routingError(reply, reply->error(), reply->errorString());
}
}
}
@@ -614,7 +601,10 @@ void QDeclarativeGeoRouteModel::update()
*/
void QDeclarativeGeoRouteModel::routingFinished(QGeoRouteReply *reply)
{
- if (reply != reply_ || reply->error() != QGeoRouteReply::NoError)
+ if (!reply)
+ return;
+ reply->deleteLater();
+ if (reply->error() != QGeoRouteReply::NoError)
return;
beginResetModel();
@@ -632,9 +622,6 @@ void QDeclarativeGeoRouteModel::routingFinished(QGeoRouteReply *reply)
setError(NoError, QString());
setStatus(QDeclarativeGeoRouteModel::Ready);
- reply->deleteLater();
- reply_ = 0;
-
if (oldCount != 0 || routes_.count() != 0)
emit routesChanged();
if (oldCount != routes_.count())
@@ -648,12 +635,11 @@ void QDeclarativeGeoRouteModel::routingError(QGeoRouteReply *reply,
QGeoRouteReply::Error error,
const QString &errorString)
{
- if (reply != reply_)
+ if (!reply)
return;
+ reply->deleteLater();
setError(static_cast<QDeclarativeGeoRouteModel::RouteError>(error), errorString);
setStatus(QDeclarativeGeoRouteModel::Error);
- reply->deleteLater();
- reply_ = 0;
}
@@ -821,7 +807,7 @@ void QDeclarativeGeoRouteQuery::setWaypoints(const QJSValue &value)
QGeoCoordinate c = parseCoordinate(value.property(i), &ok);
if (!ok || !c.isValid()) {
- qmlInfo(this) << "Unsupported waypoint type";
+ qmlWarning(this) << "Unsupported waypoint type";
return;
}
@@ -877,7 +863,7 @@ void QDeclarativeGeoRouteQuery::setExcludedAreas(const QJSValue &value)
QGeoRectangle r = parseRectangle(value.property(i), &ok);
if (!ok || !r.isValid()) {
- qmlInfo(this) << "Unsupported area type";
+ qmlWarning(this) << "Unsupported area type";
return;
}
@@ -940,7 +926,7 @@ void QDeclarativeGeoRouteQuery::removeExcludedArea(const QGeoRectangle &area)
int index = excludedAreas.lastIndexOf(area);
if (index == -1) {
- qmlInfo(this) << QStringLiteral("Cannot remove nonexistent area.");
+ qmlWarning(this) << QStringLiteral("Cannot remove nonexistent area.");
return;
}
excludedAreas.removeAt(index);
@@ -980,7 +966,7 @@ void QDeclarativeGeoRouteQuery::clearExcludedAreas()
void QDeclarativeGeoRouteQuery::addWaypoint(const QGeoCoordinate &waypoint)
{
if (!waypoint.isValid()) {
- qmlInfo(this) << QStringLiteral("Not adding invalid waypoint.");
+ qmlWarning(this) << QStringLiteral("Not adding invalid waypoint.");
return;
}
@@ -1009,7 +995,7 @@ void QDeclarativeGeoRouteQuery::removeWaypoint(const QGeoCoordinate &waypoint)
int index = waypoints.lastIndexOf(waypoint);
if (index == -1) {
- qmlInfo(this) << QStringLiteral("Cannot remove nonexistent waypoint.");
+ qmlWarning(this) << QStringLiteral("Cannot remove nonexistent waypoint.");
return;
}
diff --git a/src/imports/location/qdeclarativegeoroutemodel_p.h b/src/location/declarativemaps/qdeclarativegeoroutemodel_p.h
index 66769ea7..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)
@@ -155,6 +156,7 @@ Q_SIGNALS:
void errorChanged(); //emitted also for errorString notification
void routesChanged();
void measurementSystemChanged();
+ void abortRequested();
public Q_SLOTS:
void update();
@@ -170,13 +172,11 @@ private Q_SLOTS:
private:
void setStatus(Status status);
void setError(RouteError error, const QString &errorString);
- void abortRequest();
bool complete_;
QDeclarativeGeoServiceProvider *plugin_;
QDeclarativeGeoRouteQuery *routeQuery_;
- QGeoRouteReply *reply_;
QList<QDeclarativeGeoRoute *> routes_;
bool autoUpdate_;
@@ -185,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 5b655f73..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
@@ -182,7 +181,7 @@ void QDeclarativeGeoServiceProvider::componentComplete()
}
}
- qmlInfo(this) << "Could not find a plugin with the required features to attach to";
+ qmlWarning(this) << "Could not find a plugin with the required features to attach to";
}
}
@@ -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 32dbb206..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,60 +147,102 @@ void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map,
if (!sourceDirty_)
return;
- double minX = -1.0;
-
- // 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.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.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;
- minX = point.x();
- srcOrigin_ = coord;
- srcPath_.moveTo(point.toPointF() - origin.toPointF());
- lastPoint = point;
- } else {
- if (point.x() <= minX)
- minX = point.x();
- 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();
sourceBounds_ = srcPath_.boundingRect();
- geoLeftBound_ = map.itemPositionToCoordinate(QDoubleVector2D(minX, 0), false);
}
/*!
@@ -219,7 +258,7 @@ void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map)
return;
}
- QDoubleVector2D origin = map.coordinateToItemPosition(srcOrigin_, false);
+ QDoubleVector2D origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false);
// Create the viewport rect in the same coordinate system
// as the actual points
@@ -229,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;
@@ -274,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();
@@ -320,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();
}
@@ -334,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()));
}
/*!
@@ -391,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);
@@ -419,23 +429,23 @@ void QDeclarativePolygonMapItem::setPath(const QJSValue &value)
QGeoCoordinate c = parseCoordinate(value.property(i), &ok);
if (!ok || !c.isValid()) {
- qmlInfo(this) << "Unsupported path type";
+ qmlWarning(this) << "Unsupported path type";
return;
}
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();
}
@@ -449,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();
}
@@ -471,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();
}
@@ -505,6 +512,7 @@ void QDeclarativePolygonMapItem::setColor(const QColor &color)
color_ = color;
dirtyMaterial_ = true;
+ geoMaterialDirty_ = true;
update();
emit colorChanged(color_);
}
@@ -537,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();
}
/*!
@@ -572,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();
}
@@ -608,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
*/
@@ -617,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()->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.
@@ -721,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 2153b036..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.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.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
*/
@@ -391,9 +464,9 @@ void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
if (!screenDirty_)
return;
- QPointF origin = map.coordinateToItemPosition(srcOrigin_, false).toPointF();
+ 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);
@@ -534,7 +603,7 @@ void QDeclarativePolylineMapItem::setPath(const QJSValue &value)
QGeoCoordinate c = parseCoordinate(value.property(i), &ok);
if (!ok || !c.isValid()) {
- qmlInfo(this) << "Unsupported path type";
+ qmlWarning(this) << "Unsupported path type";
return;
}
@@ -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()->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 f50d0340..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.coordinateToItemPosition(topLeft, false);
- QDoubleVector2D br = map.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.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()->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 a22be0af..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()));
@@ -125,14 +125,14 @@ double QGeoMapItemGeometry::geoDistanceToScreenWidth(const QGeoMap &map,
// Do not wrap around half the globe
Q_ASSERT(!qFuzzyCompare(fromCoord.longitude(), toCoord.longitude()));
- QGeoCoordinate mapMid = map.itemPositionToCoordinate(QDoubleVector2D(map.viewportWidth()/2.0, 0));
+ QGeoCoordinate mapMid = map.geoProjection().itemPositionToCoordinate(QDoubleVector2D(map.viewportWidth()/2.0, 0));
double halfGeoDist = toCoord.longitude() - fromCoord.longitude();
if (toCoord.longitude() < fromCoord.longitude())
halfGeoDist += 360;
halfGeoDist /= 2.0;
QGeoCoordinate geoDelta = QGeoCoordinate(0,
QLocationUtils::wrapLong(mapMid.longitude() + halfGeoDist));
- QDoubleVector2D halfScreenDist = map.coordinateToItemPosition(geoDelta, false)
+ QDoubleVector2D halfScreenDist = map.geoProjection().coordinateToItemPosition(geoDelta, false)
- QDoubleVector2D(map.viewportWidth()/2.0, 0);
return halfScreenDist.x() * 2.0;
}
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 0baaf98e..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/qgeoprojection_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->itemPositionToCoordinate(QDoubleVector2D(event->posF()), false);
- QPointF preZoomPoint = m_map->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->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->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->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->itemPositionToCoordinate(QDoubleVector2D(m_sceneCenter), false);
+ m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_touchPointsCentroid), false);
startOneTouchPoint();
m_touchPointState = touchPoints1;
}
@@ -847,7 +1072,7 @@ void QQuickGeoMapGestureArea::startOneTouchPoint()
m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
m_lastPos = m_sceneStartPoint1;
m_lastPosTime.start();
- QGeoCoordinate startCoord = m_map->itemPositionToCoordinate(QDoubleVector2D(m_sceneStartPoint1), false);
+ QGeoCoordinate startCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneStartPoint1), false);
// ensures a smooth transition for panning
m_startCoord.setLongitude(m_startCoord.longitude() + startCoord.longitude() -
m_touchCenterCoord.longitude());
@@ -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
*/
@@ -875,11 +1099,12 @@ void QQuickGeoMapGestureArea::startTwoTouchPoints()
QPointF startPos = (m_sceneStartPoint1 + m_sceneStartPoint2) * 0.5;
m_lastPos = startPos;
m_lastPosTime.start();
- QGeoCoordinate startCoord = m_map->itemPositionToCoordinate(QDoubleVector2D(startPos), false);
+ QGeoCoordinate startCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(startPos), false);
m_startCoord.setLongitude(m_startCoord.longitude() + startCoord.longitude() -
m_touchCenterCoord.longitude());
m_startCoord.setLatitude(m_startCoord.latitude() + startCoord.latitude() -
m_touchCenterCoord.latitude());
+ m_twoTouchAngleStart = touchAngle(m_sceneStartPoint1, m_sceneStartPoint2); // Initial angle used for calculating rotation
}
/*!
@@ -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 = QLineF(p1, p2).angle();
- if (m_twoTouchAngle > 180)
- m_twoTouchAngle -= 360;
+ 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;
+}
+
+/*!
+ \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);
@@ -1017,7 +1506,8 @@ void QQuickGeoMapGestureArea::updatePinch()
// Add to starting zoom level. Sign of (dist-pinchstartdist) takes care of zoom in / out
m_pinch.m_zoom.m_start;
}
- m_pinch.m_event.setCenter(mapFromScene(m_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());
@@ -1067,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->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);
@@ -1082,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();
}
@@ -1144,13 +1634,7 @@ bool QQuickGeoMapGestureArea::canStartPan()
*/
void QQuickGeoMapGestureArea::updatePan()
{
- QPointF startPoint = m_map->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->itemPositionToCoordinate(QDoubleVector2D(mapCenterPoint), false);
+ QGeoCoordinate animationStartCoordinate = anchorCoordinateToPoint(*m_map, m_startCoord, m_touchPointsCentroid);
m_declarativeMap->setCenter(animationStartCoordinate);
}
@@ -1172,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))
@@ -1180,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))
@@ -1213,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 69ded2d0..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
@@ -1182,7 +1182,7 @@ QPlaceManager *QDeclarativePlace::manager()
}
if (!m_plugin) {
- qmlInfo(this) << QStringLiteral("Plugin is not assigned to place.");
+ qmlWarning(this) << QStringLiteral("Plugin is not assigned to place.");
return 0;
}
@@ -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 d10b2b08..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
@@ -203,7 +203,7 @@ void QDeclarativePlaceIcon::pluginReady()
QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
QPlaceManager *placeManager = serviceProvider->placeManager();
if (!placeManager || serviceProvider->error() != QGeoServiceProvider::NoError) {
- qmlInfo(this) << QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
+ qmlWarning(this) << QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
.arg(m_plugin->name()).arg(serviceProvider->errorString());
return;
}
@@ -216,7 +216,7 @@ void QDeclarativePlaceIcon::pluginReady()
QPlaceManager *QDeclarativePlaceIcon::manager() const
{
if (!m_plugin) {
- qmlInfo(this) << QStringLiteral("Plugin is not assigned to place.");
+ qmlWarning(this) << QStringLiteral("Plugin is not assigned to place.");
return 0;
}
@@ -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/maps.pri b/src/location/maps/maps.pri
index 1ea54208..aaad5897 100644
--- a/src/location/maps/maps.pri
+++ b/src/location/maps/maps.pri
@@ -18,6 +18,7 @@ PUBLIC_HEADERS += \
maps/qgeoserviceprovider.h
PRIVATE_HEADERS += \
+ maps/qgeomapparameter_p.h \
maps/qgeocameracapabilities_p.h \
maps/qgeocameradata_p.h \
maps/qgeocameratiles_p.h \
@@ -58,6 +59,7 @@ PRIVATE_HEADERS += \
maps/qgeorouteparser_p_p.h \
maps/qgeorouteparserosrmv5_p.h \
maps/qgeorouteparserosrmv4_p.h \
+ maps/qgeoprojection_p.h \
maps/qcache3q_p.h
SOURCES += \
@@ -91,4 +93,6 @@ SOURCES += \
maps/qgeotiledmapscene.cpp \
maps/qgeorouteparser.cpp \
maps/qgeorouteparserosrmv5.cpp \
- maps/qgeorouteparserosrmv4.cpp
+ maps/qgeorouteparserosrmv4.cpp \
+ maps/qgeomapparameter.cpp \
+ maps/qgeoprojection.cpp
diff --git a/src/location/maps/qabstractgeotilecache_p.h b/src/location/maps/qabstractgeotilecache_p.h
index 484bb8a5..ba4c12de 100644
--- a/src/location/maps/qabstractgeotilecache_p.h
+++ b/src/location/maps/qabstractgeotilecache_p.h
@@ -57,13 +57,13 @@
#include <QTimer>
#include "qgeotilespec_p.h"
-#include "qgeotiledmappingmanagerengine_p.h"
#include <QImage>
QT_BEGIN_NAMESPACE
class QGeoMappingManager;
+class QGeoMappingManagerEngine;
class QGeoTile;
class QAbstractGeoTileCache;
@@ -91,6 +91,14 @@ public:
Unitary,
ByteSize
};
+
+ enum CacheArea {
+ DiskCache = 0x01,
+ MemoryCache = 0x02,
+ AllCaches = 0xFF
+ };
+ Q_DECLARE_FLAGS(CacheAreas, CacheArea)
+
virtual ~QAbstractGeoTileCache();
virtual void setMaxDiskUsage(int diskUsage);
@@ -119,20 +127,22 @@ public:
virtual void insert(const QGeoTileSpec &spec,
const QByteArray &bytes,
const QString &format,
- QGeoTiledMappingManagerEngine::CacheAreas areas = QGeoTiledMappingManagerEngine::AllCaches) = 0;
+ QAbstractGeoTileCache::CacheAreas areas = QAbstractGeoTileCache::AllCaches) = 0;
virtual void handleError(const QGeoTileSpec &spec, const QString &errorString);
+ virtual void init() = 0;
static QString baseCacheDirectory();
static QString baseLocationCacheDirectory();
protected:
QAbstractGeoTileCache(QObject *parent = 0);
- virtual void init() = 0;
virtual void printStats() = 0;
friend class QGeoTiledMappingManagerEngine;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractGeoTileCache::CacheAreas)
+
QT_END_NAMESPACE
#endif // QABSTRACTGEOTILECACHE_P_H
diff --git a/src/location/maps/qgeocameracapabilities.cpp b/src/location/maps/qgeocameracapabilities.cpp
index 7b4a014a..568476fd 100644
--- a/src/location/maps/qgeocameracapabilities.cpp
+++ b/src/location/maps/qgeocameracapabilities.cpp
@@ -37,6 +37,14 @@
#include "qgeocameracapabilities_p.h"
#include <QSharedData>
+#include <cmath>
+
+static const double invLog2 = 1.0 / std::log(2.0);
+
+static double zoomLevelTo256(double zoomLevelForTileSize, double tileSize)
+{
+ return std::log( std::pow(2.0, zoomLevelForTileSize) * tileSize / 256.0 ) * invLog2;
+}
QT_BEGIN_NAMESPACE
@@ -54,12 +62,16 @@ 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_;
double maxZoom_;
double minTilt_;
double maxTilt_;
+ int tileSize_;
+ double minimumFieldOfView_;
+ double maximumFieldOfView_;
};
QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate()
@@ -70,7 +82,10 @@ QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate()
minZoom_(0.0),
maxZoom_(0.0),
minTilt_(0.0),
- maxTilt_(0.0) {}
+ maxTilt_(0.0),
+ 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)
@@ -82,7 +97,11 @@ QGeoCameraCapabilitiesPrivate::QGeoCameraCapabilitiesPrivate(const QGeoCameraCap
minZoom_(other.minZoom_),
maxZoom_(other.maxZoom_),
minTilt_(other.minTilt_),
- maxTilt_(other.maxTilt_) {}
+ maxTilt_(other.maxTilt_),
+ tileSize_(other.tileSize_),
+ minimumFieldOfView_(other.minimumFieldOfView_),
+ maximumFieldOfView_(other.maximumFieldOfView_) {}
+
QGeoCameraCapabilitiesPrivate::~QGeoCameraCapabilitiesPrivate() {}
@@ -99,6 +118,9 @@ QGeoCameraCapabilitiesPrivate &QGeoCameraCapabilitiesPrivate::operator = (const
maxZoom_ = other.maxZoom_;
minTilt_ = other.minTilt_;
maxTilt_ = other.maxTilt_;
+ tileSize_ = other.tileSize_;
+ minimumFieldOfView_ = other.minimumFieldOfView_;
+ maximumFieldOfView_ = other.maximumFieldOfView_;
return *this;
}
@@ -149,6 +171,18 @@ QGeoCameraCapabilities &QGeoCameraCapabilities::operator = (const QGeoCameraCapa
return *this;
}
+void QGeoCameraCapabilities::setTileSize(int tileSize)
+{
+ if (tileSize < 1)
+ return;
+ d->tileSize_ = tileSize;
+}
+
+int QGeoCameraCapabilities::tileSize() const
+{
+ return d->tileSize_;
+}
+
/*!
Returns whether this instance of the class is considered "valid". To be
valid, the instance must have had at least one capability set (to either
@@ -183,6 +217,13 @@ double QGeoCameraCapabilities::minimumZoomLevel() const
return d->minZoom_;
}
+double QGeoCameraCapabilities::minimumZoomLevelAt256() const
+{
+ if (d->tileSize_ == 256)
+ return d->minZoom_;
+ return zoomLevelTo256(d->minZoom_, d->tileSize_);
+}
+
/*!
Sets the maximum zoom level supported by the associated plugin to \a maximumZoomLevel.
@@ -206,6 +247,13 @@ double QGeoCameraCapabilities::maximumZoomLevel() const
return d->maxZoom_;
}
+double QGeoCameraCapabilities::maximumZoomLevelAt256() const
+{
+ if (d->tileSize_ == 256)
+ return d->maxZoom_;
+ return zoomLevelTo256(d->maxZoom_, d->tileSize_);
+}
+
/*!
Sets whether the associated plugin can render a map when the camera
has an arbitrary bearing to \a supportsBearing.
@@ -309,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 4e498b1d..c9da53e9 100644
--- a/src/location/maps/qgeocameracapabilities_p.h
+++ b/src/location/maps/qgeocameracapabilities_p.h
@@ -65,11 +65,16 @@ public:
QGeoCameraCapabilities &operator = (const QGeoCameraCapabilities &other);
+ void setTileSize(int tileSize);
+ int tileSize() const;
+
void setMinimumZoomLevel(double minimumZoomLevel);
double minimumZoomLevel() const;
+ double minimumZoomLevelAt256() const;
void setMaximumZoomLevel(double maximumZoomLevel);
double maximumZoomLevel() const;
+ double maximumZoomLevelAt256() const;
void setSupportsBearing(bool supportsBearing);
bool supportsBearing() const;
@@ -86,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 23586082..ecf7d46a 100644
--- a/src/location/maps/qgeocameradata.cpp
+++ b/src/location/maps/qgeocameradata.cpp
@@ -35,6 +35,7 @@
****************************************************************************/
#include "qgeocameradata_p.h"
#include <QtPositioning/private/qgeocoordinate_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
#include <QtCore/QVariant>
#include <QtCore/QVariantAnimation>
@@ -54,6 +55,7 @@ public:
double m_bearing;
double m_tilt;
double m_roll;
+ double m_fieldOfView;
double m_zoomLevel;
};
@@ -63,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)
@@ -71,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)
@@ -82,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;
@@ -93,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));
}
@@ -112,7 +118,7 @@ QVariant cameraInterpolator(const QGeoCameraData &start,
}
}
else {
- QGeoCoordinate coordinateResult = QGeoProjection::coordinateInterpolation(from, to, progress);
+ QGeoCoordinate coordinateResult = QWebMercator::coordinateInterpolation(from, to, progress);
result.setCenter(coordinateResult);
}
@@ -122,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);
@@ -200,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 a1434fd8..4912ec3e 100644
--- a/src/location/maps/qgeocameradata_p.h
+++ b/src/location/maps/qgeocameradata_p.h
@@ -47,10 +47,8 @@
// We mean it.
//
-#include "qlocationglobal.h"
-#include "qgeocoordinate.h"
-
-#include <QtPositioning/private/qgeoprojection_p.h>
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtPositioning/qgeocoordinate.h>
#include <QMetaType>
@@ -60,7 +58,7 @@ QT_BEGIN_NAMESPACE
class QGeoCameraDataPrivate;
-class Q_LOCATION_EXPORT QGeoCameraData
+class Q_LOCATION_PRIVATE_EXPORT QGeoCameraData
{
public:
QGeoCameraData();
@@ -84,6 +82,11 @@ 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);
double zoomLevel() const;
diff --git a/src/location/maps/qgeocameratiles.cpp b/src/location/maps/qgeocameratiles.cpp
index f3a36adf..27044ee0 100644
--- a/src/location/maps/qgeocameratiles.cpp
+++ b/src/location/maps/qgeocameratiles.cpp
@@ -38,15 +38,28 @@
#include "qgeotilespec_p.h"
#include "qgeomaptype_p.h"
-#include <QtPositioning/private/qgeoprojection_p.h>
+#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
{
- QDoubleVector3D center = m_sideLength * QGeoProjection::coordToMercator(m_camera.center());
- center.setZ(0.0);
+ 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());
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/qgeocodereply.cpp b/src/location/maps/qgeocodereply.cpp
index 47018217..85e6e1f5 100644
--- a/src/location/maps/qgeocodereply.cpp
+++ b/src/location/maps/qgeocodereply.cpp
@@ -225,14 +225,26 @@ void QGeoCodeReply::setLocations(const QList<QGeoLocation> &locations)
}
/*!
+ \fn void QGeoCodeReply::aborted()
+ \since 5.9
+
+ This signal is emitted when the operation has been cancelled.
+
+ \sa abort()
+*/
+
+/*!
Cancels the operation immediately.
This will do nothing if the reply is finished.
+
+ \sa aborted()
*/
void QGeoCodeReply::abort()
{
if (!isFinished())
setFinished(true);
+ emit aborted();
}
/*!
diff --git a/src/location/maps/qgeocodereply.h b/src/location/maps/qgeocodereply.h
index 048493b4..c92bc606 100644
--- a/src/location/maps/qgeocodereply.h
+++ b/src/location/maps/qgeocodereply.h
@@ -80,6 +80,7 @@ public:
Q_SIGNALS:
void finished();
+ void aborted();
void error(QGeoCodeReply::Error error, const QString &errorString = QString());
protected:
diff --git a/src/location/maps/qgeofiletilecache.cpp b/src/location/maps/qgeofiletilecache.cpp
index 49e9dfff..f080c7f9 100644
--- a/src/location/maps/qgeofiletilecache.cpp
+++ b/src/location/maps/qgeofiletilecache.cpp
@@ -375,12 +375,12 @@ QSharedPointer<QGeoTileTexture> QGeoFileTileCache::get(const QGeoTileSpec &spec)
void QGeoFileTileCache::insert(const QGeoTileSpec &spec,
const QByteArray &bytes,
const QString &format,
- QGeoTiledMappingManagerEngine::CacheAreas areas)
+ QAbstractGeoTileCache::CacheAreas areas)
{
if (bytes.isEmpty())
return;
- if (areas & QGeoTiledMappingManagerEngine::DiskCache) {
+ if (areas & QAbstractGeoTileCache::DiskCache) {
QString filename = tileSpecToFilename(spec, format, directory_);
QFile file(filename);
file.open(QIODevice::WriteOnly);
@@ -390,7 +390,7 @@ void QGeoFileTileCache::insert(const QGeoTileSpec &spec,
addToDiskCache(spec, filename);
}
- if (areas & QGeoTiledMappingManagerEngine::MemoryCache) {
+ if (areas & QAbstractGeoTileCache::MemoryCache) {
addToMemoryCache(spec, bytes, format);
}
diff --git a/src/location/maps/qgeofiletilecache_p.h b/src/location/maps/qgeofiletilecache_p.h
index 7d6df9fd..7ca8cf33 100644
--- a/src/location/maps/qgeofiletilecache_p.h
+++ b/src/location/maps/qgeofiletilecache_p.h
@@ -135,7 +135,7 @@ public:
void insert(const QGeoTileSpec &spec,
const QByteArray &bytes,
const QString &format,
- QGeoTiledMappingManagerEngine::CacheAreas areas = QGeoTiledMappingManagerEngine::AllCaches) Q_DECL_OVERRIDE;
+ QAbstractGeoTileCache::CacheAreas areas = QAbstractGeoTileCache::AllCaches) Q_DECL_OVERRIDE;
protected:
void init() Q_DECL_OVERRIDE;
diff --git a/src/location/maps/qgeomap.cpp b/src/location/maps/qgeomap.cpp
index 0e0a2007..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)
@@ -57,6 +59,7 @@ void QGeoMap::setViewportSize(const QSize& size)
if (size == d->m_viewportSize)
return;
d->m_viewportSize = size;
+ d->m_geoProjection->setViewportSize(size);
d->changeViewportSize(size);
}
@@ -84,6 +87,7 @@ void QGeoMap::setCameraData(const QGeoCameraData &cameraData)
if (cameraData == d->m_cameraData)
return;
d->m_cameraData = cameraData;
+ d->m_geoProjection->setCameraData(cameraData);
d->changeCameraData(cameraData);
emit cameraDataChanged(d->m_cameraData);
}
@@ -110,6 +114,35 @@ const QGeoMapType QGeoMap::activeMapType() const
return d->m_activeMapType;
}
+double QGeoMap::minimumZoom() const
+{
+ Q_D(const QGeoMap);
+ return d->m_geoProjection->minimumZoom();
+}
+
+double QGeoMap::maximumCenterLatitudeAtZoom(const QGeoCameraData &cameraData) const
+{
+ Q_D(const QGeoMap);
+ return d->m_geoProjection->maximumCenterLatitudeAtZoom(cameraData);
+}
+
+double QGeoMap::mapWidth() const
+{
+ Q_D(const QGeoMap);
+ return d->m_geoProjection->mapWidth();
+}
+
+double QGeoMap::mapHeight() const
+{
+ Q_D(const QGeoMap);
+ return d->m_geoProjection->mapHeight();
+}
+
+const QGeoProjection &QGeoMap::geoProjection() const
+{
+ Q_D(const QGeoMap);
+ return *(d->m_geoProjection);
+}
QGeoCameraCapabilities QGeoMap::cameraCapabilities() const
{
@@ -130,8 +163,67 @@ void QGeoMap::clearData()
}
-QGeoMapPrivate::QGeoMapPrivate(QGeoMappingManagerEngine *engine)
+void QGeoMap::addParameter(QGeoMapParameter *param)
+{
+ Q_D(QGeoMap);
+ if (param && !d->m_mapParameters.contains(param)) {
+ d->m_mapParameters.insert(param);
+ d->addParameter(param);
+ }
+}
+
+void QGeoMap::removeParameter(QGeoMapParameter *param)
+{
+ Q_D(QGeoMap);
+ if (param && d->m_mapParameters.contains(param)) {
+ d->removeParameter(param);
+ d->m_mapParameters.remove(param);
+ }
+}
+
+void QGeoMap::clearParameters()
+{
+ Q_D(QGeoMap);
+ for (QGeoMapParameter *p : d->m_mapParameters)
+ d->removeParameter(p);
+ 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),
m_engine(engine),
m_activeMapType(QGeoMapType())
{
@@ -139,6 +231,33 @@ QGeoMapPrivate::QGeoMapPrivate(QGeoMappingManagerEngine *engine)
QGeoMapPrivate::~QGeoMapPrivate()
{
+ if (m_geoProjection)
+ delete m_geoProjection;
+}
+
+void QGeoMapPrivate::addParameter(QGeoMapParameter *param)
+{
+ Q_UNUSED(param)
+}
+
+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 ea4806c0..4838cb4e 100644
--- a/src/location/maps/qgeomap_p.h
+++ b/src/location/maps/qgeomap_p.h
@@ -49,18 +49,21 @@
#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>
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
{
@@ -68,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
@@ -83,17 +98,29 @@ public:
void setActiveMapType(const QGeoMapType mapType);
const QGeoMapType activeMapType() const;
- virtual QGeoCoordinate itemPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport = true) const = 0;
- virtual QDoubleVector2D coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport = true) const = 0;
- virtual double minimumZoomAtViewportSize(int viewportWidth, int viewportHeight) const = 0;
- virtual double maximumCenterLatitudeAtZoom(double zoomLevel) const = 0;
+ // returns the minimum zoom at the current viewport size
+ double minimumZoom() 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;
+ double mapHeight() const;
- virtual QDoubleVector2D referenceCoordinateToItemPosition(const QGeoCoordinate &coordinate) const = 0;
- virtual QGeoCoordinate referenceItemPositionToCoordinate(const QDoubleVector2D &pos) const = 0;
+ const QGeoProjection &geoProjection() const;
virtual void prefetchData();
virtual void clearData();
+ void addParameter(QGeoMapParameter *param);
+ 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);
@@ -108,10 +135,11 @@ Q_SIGNALS:
private:
Q_DISABLE_COPY(QGeoMap)
- friend class QGeoMapController; //setCameraData
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 b95c1dc7..ab603be7 100644
--- a/src/location/maps/qgeomap_p_p.h
+++ b/src/location/maps/qgeomap_p_p.h
@@ -50,8 +50,11 @@
#include <QtLocation/private/qlocationglobal_p.h>
#include <QtLocation/private/qgeocameradata_p.h>
#include <QtLocation/private/qgeomaptype_p.h>
+#include <QtLocation/private/qgeoprojection_p.h>
#include <QtCore/private/qobject_p.h>
#include <QtCore/QSize>
+#include <QtCore/QSet>
+#include "qgeomap_p.h"
QT_BEGIN_NAMESPACE
@@ -59,26 +62,38 @@ QT_BEGIN_NAMESPACE
class QGeoMappingManagerEngine;
class QGeoMap;
class QGeoMapController;
+class QGeoMapParameter;
+class QDeclarativeGeoMapItemBase;
class Q_LOCATION_PRIVATE_EXPORT QGeoMapPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QGeoMap)
public:
- QGeoMapPrivate(QGeoMappingManagerEngine *engine);
+ QGeoMapPrivate(QGeoMappingManagerEngine *engine, QGeoProjection *geoProjection);
virtual ~QGeoMapPrivate();
+ const QGeoProjection *geoProjection() const;
protected:
/* Hooks into the actual map implementations */
+ 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()
protected:
QSize m_viewportSize;
+ QGeoProjection *m_geoProjection;
QPointer<QGeoMappingManagerEngine> m_engine;
- QGeoMapController *m_controller;
QGeoCameraData m_cameraData;
QGeoMapType m_activeMapType;
+ QSet<QGeoMapParameter *> m_mapParameters;
+ QSet<QDeclarativeGeoMapItemBase *> m_mapItems;
};
QT_END_NAMESPACE
diff --git a/src/location/maps/qgeomapparameter.cpp b/src/location/maps/qgeomapparameter.cpp
new file mode 100644
index 00000000..b8f9561f
--- /dev/null
+++ b/src/location/maps/qgeomapparameter.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "qgeomapparameter_p.h"
+#include <QtCore/QVariant>
+
+QT_BEGIN_NAMESPACE
+
+QGeoMapParameter::QGeoMapParameter(QObject *parent) : QObject(parent)
+{
+
+}
+
+QGeoMapParameter::~QGeoMapParameter()
+{
+}
+
+QString QGeoMapParameter::type() const
+{
+ return m_type;
+}
+
+void QGeoMapParameter::setType(const QString &type)
+{
+ if (m_type.isEmpty())
+ m_type = type;
+}
+
+// DO NOT USE to set "type"
+void QGeoMapParameter::updateProperty(const char *propertyName, QVariant value)
+{
+ setProperty(propertyName, value);
+ // This should technically be emitted only for dynamically added properties.
+ // Since this object has only type defined as Q_PROPERTY() which is a set-once
+ // no check is really needed here.
+ emit propertyUpdated(this, propertyName);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/location/maps/qgeomapparameter_p.h b/src/location/maps/qgeomapparameter_p.h
new file mode 100644
index 00000000..c3bef4d8
--- /dev/null
+++ b/src/location/maps/qgeomapparameter_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 QGEOMAPPARAMETER_P_H
+#define QGEOMAPPARAMETER_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 <QObject>
+#include <QString>
+#include <QtLocation/qlocationglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_EXPORT QGeoMapParameter : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString type READ type WRITE setType)
+public:
+ explicit QGeoMapParameter(QObject *parent = 0);
+ virtual ~QGeoMapParameter();
+
+ QString type() const;
+ void setType(const QString &type);
+
+ void updateProperty(const char *propertyName, QVariant value);
+
+Q_SIGNALS:
+ void propertyUpdated(QGeoMapParameter *param, const char *propertyName);
+
+protected:
+ QString m_type;
+
+ Q_DISABLE_COPY(QGeoMapParameter)
+ friend class QGeoMap;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOMAPPARAMETER_P_H
diff --git a/src/location/maps/qgeoprojection.cpp b/src/location/maps/qgeoprojection.cpp
new file mode 100644
index 00000000..586dcb02
--- /dev/null
+++ b/src/location/maps/qgeoprojection.cpp
@@ -0,0 +1,498 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "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>
+
+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) };
+}
+
+QT_BEGIN_NAMESPACE
+
+QGeoProjection::QGeoProjection()
+{
+
+}
+
+QGeoProjection::~QGeoProjection()
+{
+
+}
+
+/*
+ * QGeoProjectionWebMercator implementation
+*/
+
+QGeoProjectionWebMercator::QGeoProjectionWebMercator()
+ : QGeoProjection(),
+ m_mapEdgeSize(256), // at zl 0
+ m_minimumZoom(0),
+ m_cameraCenterXMercator(0),
+ m_cameraCenterYMercator(0),
+ m_viewportWidth(1),
+ m_viewportHeight(1),
+ m_1_viewportWidth(0),
+ m_1_viewportHeight(0),
+ m_sideLength(256),
+ m_aperture(0.0),
+ m_nearPlane(0.0),
+ m_farPlane(0.0),
+ m_halfWidth(0.0),
+ m_halfHeight(0.0),
+ m_minimumUnprojectableY(0.0)
+{
+}
+
+QGeoProjectionWebMercator::~QGeoProjectionWebMercator()
+{
+
+}
+
+// This method returns the minimum zoom level that this specific qgeomap type allows
+// at the current viewport size and for the default tile size of 256^2.
+double QGeoProjectionWebMercator::minimumZoom() const
+{
+ return m_minimumZoom;
+}
+
+// This method recalculates the "no-trespassing" limits for the map center.
+// This has to be used when:
+// 1) the map is resized, because the meters per pixel remain the same, but
+// 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(const QGeoCameraData &cameraData) const
+{
+ double mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * defaultTileSize;
+
+ // At init time weird things happen
+ int clampedWindowHeight = (m_viewportHeight > mapEdgeSize) ? mapEdgeSize : m_viewportHeight;
+
+ // Use the window height divided by 2 as the topmost allowed center, with respect to the map size in pixels
+ double mercatorTopmost = (clampedWindowHeight * 0.5) / mapEdgeSize ;
+ QGeoCoordinate topMost = QWebMercator::mercatorToCoord(QDoubleVector2D(0.0, mercatorTopmost));
+
+ return topMost.latitude();
+}
+
+double QGeoProjectionWebMercator::mapWidth() const
+{
+ return m_mapEdgeSize;
+}
+
+double QGeoProjectionWebMercator::mapHeight() const
+{
+ return m_mapEdgeSize;
+}
+
+void QGeoProjectionWebMercator::setViewportSize(const QSize &size)
+{
+ m_viewportWidth = size.width();
+ m_viewportHeight = size.height();
+ m_1_viewportWidth = 1.0 / m_viewportWidth;
+ m_1_viewportHeight = 1.0 / m_viewportHeight;
+ m_minimumZoom = std::log(qMax(m_viewportWidth, m_viewportHeight) / defaultTileSize) / std::log(2.0);
+ setupCamera();
+}
+
+void QGeoProjectionWebMercator::setCameraData(const QGeoCameraData &cameraData)
+{
+ m_cameraData = cameraData;
+ m_mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * defaultTileSize;
+ setupCamera();
+}
+
+QDoubleVector2D QGeoProjectionWebMercator::geoToMapProjection(const QGeoCoordinate &coordinate) const
+{
+ return QWebMercator::coordToMercator(coordinate);
+}
+
+QGeoCoordinate QGeoProjectionWebMercator::mapProjectionToGeo(const QDoubleVector2D &projection) const
+{
+ return QWebMercator::mercatorToCoord(projection);
+}
+
+//wraps around center
+QDoubleVector2D QGeoProjectionWebMercator::wrapMapProjection(const QDoubleVector2D &projection) const
+{
+ double x = projection.x();
+ if (m_cameraCenterXMercator < 0.5) {
+ if (x - m_cameraCenterXMercator > 0.5 )
+ x -= 1.0;
+ } else if (m_cameraCenterXMercator > 0.5) {
+ if (x - m_cameraCenterXMercator < -0.5 )
+ x += 1.0;
+ }
+
+ return QDoubleVector2D(x, projection.y());
+}
+
+QDoubleVector2D QGeoProjectionWebMercator::unwrapMapProjection(const QDoubleVector2D &wrappedProjection) const
+{
+ double x = wrappedProjection.x();
+ if (x > 1.0)
+ return QDoubleVector2D(x - 1.0, wrappedProjection.y());
+ if (x <= 0.0)
+ return QDoubleVector2D(x + 1.0, wrappedProjection.y());
+ return wrappedProjection;
+}
+
+QDoubleVector2D QGeoProjectionWebMercator::wrappedMapProjectionToItemPosition(const QDoubleVector2D &wrappedProjection) const
+{
+ QDoubleVector3D pos = wrappedProjection * m_sideLength;
+ QDoubleVector2D res = (m_transformation * pos).toVector2D();
+ res += QDoubleVector2D(1.0,1.0);
+ res *= 0.5;
+ res *= QDoubleVector2D(m_viewportWidth, m_viewportHeight);
+ return res;
+}
+
+QDoubleVector2D QGeoProjectionWebMercator::itemPositionToWrappedMapProjection(const QDoubleVector2D &itemPosition) const
+{
+ QDoubleVector2D pos = itemPosition;
+ // when the camera is tilted, picking a point above the horizon returns a coordinate behind the camera
+ if (pos.y() < m_minimumUnprojectableY)
+ pos.setY(m_minimumUnprojectableY);
+ pos *= QDoubleVector2D(m_1_viewportWidth, m_1_viewportHeight);
+ pos *= 2.0;
+ pos -= QDoubleVector2D(1.0,1.0);
+
+ return viewportToWrappedMapProjection(pos);
+}
+
+/* Default implementations */
+QGeoCoordinate QGeoProjectionWebMercator::itemPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport) const
+{
+ if (clipToViewport) {
+ int w = m_viewportWidth;
+ int h = m_viewportHeight;
+
+ if ((pos.x() < 0) || (w < pos.x()) || (pos.y() < 0) || (h < pos.y()))
+ return QGeoCoordinate();
+ }
+
+ QDoubleVector2D wrappedMapProjection = itemPositionToWrappedMapProjection(pos);
+ // With rotation/tilting, a screen position might end up outside the projection space.
+ if (!isProjectable(wrappedMapProjection))
+ return QGeoCoordinate();
+ return mapProjectionToGeo(unwrapMapProjection(wrappedMapProjection));
+}
+
+QDoubleVector2D QGeoProjectionWebMercator::coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport) const
+{
+ QDoubleVector2D pos = wrappedMapProjectionToItemPosition(wrapMapProjection(geoToMapProjection(coordinate)));
+
+ if (clipToViewport) {
+ int w = m_viewportWidth;
+ int h = m_viewportHeight;
+ double x = pos.x();
+ double y = pos.y();
+ if ((x < -0.5) || (x > w + 0.5) || (y < -0.5) || (y > h + 0.5) || qIsNaN(x) || qIsNaN(y))
+ return QDoubleVector2D(qQNaN(), qQNaN());
+ }
+ 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
+{
+ if (m_cameraData.tilt() == 0.0)
+ return true;
+
+ 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 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()
+{
+ 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 = 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);
+ // 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
+ 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) {
+ 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) { // 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.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 = 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);
+
+ QDoubleMatrix4x4 projectionMatrix;
+ projectionMatrix.frustum(-m_halfWidth, m_halfWidth, -m_halfHeight, m_halfHeight, m_nearPlane, m_farPlane);
+
+ m_transformation = projectionMatrix * cameraMatrix;
+ 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
new file mode 100644
index 00000000..6ea8fd6e
--- /dev/null
+++ b/src/location/maps/qgeoprojection_p.h
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 QGEOPROJECTION_H
+#define QGEOPROJECTION_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/qgeocameradata_p.h>
+#include <QtPositioning/private/qdoublematrix4x4_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QGeoProjection
+{
+public:
+ QGeoProjection();
+ virtual ~QGeoProjection();
+
+ virtual void setViewportSize(const QSize &size) = 0;
+ virtual void setCameraData(const QGeoCameraData &cameraData) = 0;
+
+ // returns the minimum zoom at the current viewport size
+ virtual double minimumZoom() 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;
+ virtual QGeoCoordinate mapProjectionToGeo(const QDoubleVector2D &projection) const = 0;
+
+ virtual QDoubleVector2D wrapMapProjection(const QDoubleVector2D &projection) const = 0;
+ virtual QDoubleVector2D unwrapMapProjection(const QDoubleVector2D &wrappedProjection) const = 0;
+
+ virtual QDoubleVector2D wrappedMapProjectionToItemPosition(const QDoubleVector2D &wrappedProjection) const = 0;
+ virtual QDoubleVector2D itemPositionToWrappedMapProjection(const QDoubleVector2D &itemPosition) const = 0;
+
+ // Convenience methods to avoid the chain itemPositionToWrappedProjection(wrapProjection(geoToProjection()))
+ 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
+{
+public:
+ QGeoProjectionWebMercator();
+ ~QGeoProjectionWebMercator();
+
+ double minimumZoom() 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;
+ double mapHeight() const Q_DECL_OVERRIDE;
+
+ void setViewportSize(const QSize &size) Q_DECL_OVERRIDE;
+ void setCameraData(const QGeoCameraData &cameraData) Q_DECL_OVERRIDE;
+
+ QDoubleVector2D geoToMapProjection(const QGeoCoordinate &coordinate) const Q_DECL_OVERRIDE;
+ QGeoCoordinate mapProjectionToGeo(const QDoubleVector2D &projection) const Q_DECL_OVERRIDE;
+
+ QDoubleVector2D wrapMapProjection(const QDoubleVector2D &projection) const Q_DECL_OVERRIDE;
+ QDoubleVector2D unwrapMapProjection(const QDoubleVector2D &wrappedProjection) const Q_DECL_OVERRIDE;
+
+ QDoubleVector2D wrappedMapProjectionToItemPosition(const QDoubleVector2D &wrappedProjection) const Q_DECL_OVERRIDE;
+ QDoubleVector2D itemPositionToWrappedMapProjection(const QDoubleVector2D &itemPosition) const Q_DECL_OVERRIDE;
+
+ 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;
+
+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;
+ double m_minimumZoom;
+ // mercator to camera transform for coordinates (not tiles!)
+ double m_cameraCenterXMercator;
+ double m_cameraCenterYMercator;
+
+ // cameraToScreen transform
+ double m_viewportWidth; // in pixels
+ double m_viewportHeight; // in pixels
+ double m_1_viewportWidth;
+ double m_1_viewportHeight;
+
+ QDoubleMatrix4x4 m_transformation;
+ QDoubleVector3D m_eye;
+ QDoubleVector3D m_up;
+ QDoubleVector3D m_center;
+ QDoubleVector3D m_view;
+ QDoubleVector3D m_viewNormalized;
+ QDoubleVector3D m_side;
+ QDoubleVector3D m_centerNearPlane;
+ double m_sideLength; // map edge size at integer zoom level
+ double m_aperture;
+ double m_nearPlane;
+ double m_farPlane;
+ double m_halfWidth;
+ double m_halfHeight;
+ double m_minimumUnprojectableY;
+
+ // 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;
+
+ QList<QDoubleVector2D> m_visibleRegion;
+
+ Q_DISABLE_COPY(QGeoProjectionWebMercator)
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOPROJECTION_H
diff --git a/src/location/maps/qgeoroutereply.cpp b/src/location/maps/qgeoroutereply.cpp
index ab869d3c..6f7b3129 100644
--- a/src/location/maps/qgeoroutereply.cpp
+++ b/src/location/maps/qgeoroutereply.cpp
@@ -212,14 +212,22 @@ void QGeoRouteReply::addRoutes(const QList<QGeoRoute> &routes)
}
/*!
+ \fn void QGeoRouteReply::aborted()
+ \since 5.9
+
+ This signal is emitted when the operation has been cancelled.
+
+ \sa abort()
+*/
+
+/*!
Cancels the operation immediately.
This will do nothing if the reply is finished.
*/
void QGeoRouteReply::abort()
{
- if (!isFinished())
- setFinished(true);
+ emit aborted();
}
/*!
diff --git a/src/location/maps/qgeoroutereply.h b/src/location/maps/qgeoroutereply.h
index 318d85f8..c1d6e8d1 100644
--- a/src/location/maps/qgeoroutereply.h
+++ b/src/location/maps/qgeoroutereply.h
@@ -74,6 +74,7 @@ public:
Q_SIGNALS:
void finished();
+ void aborted();
void error(QGeoRouteReply::Error error, const QString &errorString = QString());
protected:
diff --git a/src/location/maps/qgeotiledmap.cpp b/src/location/maps/qgeotiledmap.cpp
index 04f9ad21..fc08fe62 100644
--- a/src/location/maps/qgeotiledmap.cpp
+++ b/src/location/maps/qgeotiledmap.cpp
@@ -35,10 +35,11 @@
****************************************************************************/
#include "qgeotiledmap_p.h"
#include "qgeotiledmap_p_p.h"
-
+#include <QtPositioning/private/qwebmercator_p.h>
#include "qgeotiledmappingmanagerengine_p.h"
#include "qabstractgeotilecache_p.h"
#include "qgeotilespec_p.h"
+#include "qgeoprojection_p.h"
#include "qgeocameratiles_p.h"
#include "qgeotilerequestmanager_p.h"
@@ -49,6 +50,13 @@
QT_BEGIN_NAMESPACE
#define PREFETCH_FRUSTUM_SCALE 2.0
+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;
+}
+
QGeoTiledMap::QGeoTiledMap(QGeoTiledMappingManagerEngine *engine, QObject *parent)
: QGeoMap(*new QGeoTiledMapPrivate(engine), parent)
{
@@ -60,6 +68,17 @@ QGeoTiledMap::QGeoTiledMap(QGeoTiledMappingManagerEngine *engine, QObject *paren
this,&QGeoTiledMap::handleTileVersionChanged);
}
+QGeoTiledMap::QGeoTiledMap(QGeoTiledMapPrivate &dd, QGeoTiledMappingManagerEngine *engine, QObject *parent)
+ : QGeoMap(dd, parent)
+{
+ Q_D(QGeoTiledMap);
+
+ d->m_tileRequests = new QGeoTileRequestManager(this, engine);
+
+ QObject::connect(engine,&QGeoTiledMappingManagerEngine::tileVersionChanged,
+ this,&QGeoTiledMap::handleTileVersionChanged);
+}
+
QGeoTiledMap::~QGeoTiledMap()
{
Q_D(QGeoTiledMap);
@@ -138,85 +157,8 @@ void QGeoTiledMap::evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles)
Q_UNUSED(visibleTiles);
}
-QGeoCoordinate QGeoTiledMap::itemPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport) const
-{
- Q_D(const QGeoTiledMap);
- if (clipToViewport) {
- int w = viewportWidth();
- int h = viewportHeight();
-
- if ((pos.x() < 0) || (w < pos.x()) || (pos.y() < 0) || (h < pos.y()))
- return QGeoCoordinate();
- }
-
- return d->itemPositionToCoordinate(pos);
-}
-
-QDoubleVector2D QGeoTiledMap::coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport) const
-{
- Q_D(const QGeoTiledMap);
- QDoubleVector2D pos = d->coordinateToItemPosition(coordinate);
-
- if (clipToViewport) {
- int w = viewportWidth();
- int h = viewportHeight();
- double x = pos.x();
- double y = pos.y();
- if ((x < 0.0) || (x > w) || (y < 0) || (y > h) || qIsNaN(x) || qIsNaN(y))
- return QDoubleVector2D(qQNaN(), qQNaN());
- }
-
- return pos;
-}
-
-// This method returns the minimum zoom level that this specific qgeomap type allows
-// at a given canvas size (width,height) and for a given tile size (usually 256).
-double QGeoTiledMap::minimumZoomAtViewportSize(int width, int height) const
-{
- Q_D(const QGeoTiledMap);
- double maxSize = qMax(width,height);
- double numTiles = maxSize / d->m_visibleTiles->tileSize();
- return std::log(numTiles) / std::log(2.0);
-}
-
-// This method recalculates the "no-trespassing" limits for the map center.
-// This has to be done when:
-// 1) the map is resized, because the meters per pixel remain the same, but
-// 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 QGeoTiledMap::maximumCenterLatitudeAtZoom(double zoomLevel) const
-{
- Q_D(const QGeoTiledMap);
- double mapEdgeSize = std::pow(2.0,zoomLevel);
- mapEdgeSize *= d->m_visibleTiles->tileSize();
-
- // At init time weird things happen
- int clampedWindowHeight = (viewportHeight() > mapEdgeSize) ? mapEdgeSize : viewportHeight();
-
- // Use the window height divided by 2 as the topmost allowed center, with respect to the map size in pixels
- double mercatorTopmost = (clampedWindowHeight * 0.5) / mapEdgeSize ;
- QGeoCoordinate topMost = QGeoProjection::mercatorToCoord(QDoubleVector2D(0.0,mercatorTopmost));
-
- return topMost.latitude();
-}
-
-QDoubleVector2D QGeoTiledMap::referenceCoordinateToItemPosition(const QGeoCoordinate &coordinate) const
-{
- Q_D(const QGeoTiledMap);
- QDoubleVector2D point = QGeoProjection::coordToMercator(coordinate);
- return point * std::pow(2.0, d->m_cameraData.zoomLevel()) * d->m_visibleTiles->tileSize();
-}
-
-QGeoCoordinate QGeoTiledMap::referenceItemPositionToCoordinate(const QDoubleVector2D &pos) const
-{
- Q_D(const QGeoTiledMap);
- QDoubleVector2D point = pos / (std::pow(2.0, d->m_cameraData.zoomLevel()) * d->m_visibleTiles->tileSize());
- return QGeoProjection::mercatorToCoord(point);
-}
-
QGeoTiledMapPrivate::QGeoTiledMapPrivate(QGeoTiledMappingManagerEngine *engine)
- : QGeoMapPrivate(engine),
+ : QGeoMapPrivate(engine, new QGeoProjectionWebMercator),
m_cache(engine->tileCache()),
m_visibleTiles(new QGeoCameraTiles()),
m_prefetchTiles(new QGeoCameraTiles()),
@@ -309,10 +251,18 @@ void QGeoTiledMapPrivate::changeCameraData(const QGeoCameraData &cameraData)
{
Q_Q(QGeoTiledMap);
+ QGeoCameraData cam = cameraData;
+
+ // The incoming zoom level is intended for a tileSize of 256.
+ // Adapt it to the current tileSize
+ double zoomLevel = cameraData.zoomLevel();
+ if (m_visibleTiles->tileSize() != 256)
+ zoomLevel = zoomLevelFrom256(zoomLevel, m_visibleTiles->tileSize());
+ cam.setZoomLevel(zoomLevel);
+
// For zoomlevel, "snap" 0.01 either side of a whole number.
// This is so that when we turn off bilinear scaling, we're
// snapped to the exact pixel size of the tiles
- QGeoCameraData cam = cameraData;
int izl = static_cast<int>(std::floor(cam.zoomLevel()));
float delta = cam.zoomLevel() - izl;
@@ -320,6 +270,8 @@ void QGeoTiledMapPrivate::changeCameraData(const QGeoCameraData &cameraData)
izl++;
delta -= 1.0;
}
+
+ // TODO: Don't do this if there's tilt or bearing.
if (qAbs(delta) < 0.01) {
cam.setZoomLevel(izl);
}
@@ -420,14 +372,4 @@ QSGNode *QGeoTiledMapPrivate::updateSceneGraph(QSGNode *oldNode, QQuickWindow *w
return m_mapScene->updateSceneGraph(oldNode, window);
}
-QGeoCoordinate QGeoTiledMapPrivate::itemPositionToCoordinate(const QDoubleVector2D &pos) const
-{
- return QGeoProjection::mercatorToCoord(m_mapScene->itemPositionToMercator(pos));
-}
-
-QDoubleVector2D QGeoTiledMapPrivate::coordinateToItemPosition(const QGeoCoordinate &coordinate) const
-{
- return m_mapScene->mercatorToItemPosition(QGeoProjection::coordToMercator(coordinate));
-}
-
QT_END_NAMESPACE
diff --git a/src/location/maps/qgeotiledmap_p.h b/src/location/maps/qgeotiledmap_p.h
index d00a1ed9..9c9b819f 100644
--- a/src/location/maps/qgeotiledmap_p.h
+++ b/src/location/maps/qgeotiledmap_p.h
@@ -49,10 +49,10 @@
#include <QObject>
#include <QString>
-
-#include "qgeomap_p.h"
-#include "qgeocameradata_p.h"
-#include "qgeomaptype_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qgeomap_p.h>
+#include <QtLocation/private/qgeocameradata_p.h>
+#include <QtLocation/private/qgeomaptype_p.h>
#include <QtPositioning/private/qdoublevector2d_p.h>
@@ -70,7 +70,7 @@ class QSGNode;
class QPointF;
-class Q_LOCATION_EXPORT QGeoTiledMap : public QGeoMap
+class Q_LOCATION_PRIVATE_EXPORT QGeoTiledMap : public QGeoMap
{
Q_OBJECT
Q_DECLARE_PRIVATE(QGeoTiledMap)
@@ -84,15 +84,6 @@ public:
void updateTile(const QGeoTileSpec &spec);
void setPrefetchStyle(PrefetchStyle style);
- QGeoCoordinate itemPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport = true) const Q_DECL_OVERRIDE;
- QDoubleVector2D coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport = true) const Q_DECL_OVERRIDE;
- double minimumZoomAtViewportSize(int viewportWidth, int viewportHeight) const Q_DECL_OVERRIDE;
- double maximumCenterLatitudeAtZoom(double zoomLevel) const Q_DECL_OVERRIDE;
-
-
- QDoubleVector2D referenceCoordinateToItemPosition(const QGeoCoordinate &coordinate) const Q_DECL_OVERRIDE;
- QGeoCoordinate referenceItemPositionToCoordinate(const QDoubleVector2D &pos) const Q_DECL_OVERRIDE;
-
void prefetchData() Q_DECL_OVERRIDE;
void clearData() Q_DECL_OVERRIDE;
@@ -103,6 +94,8 @@ protected:
QSGNode *updateSceneGraph(QSGNode *, QQuickWindow *window) Q_DECL_OVERRIDE;
virtual void evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles);
+ QGeoTiledMap(QGeoTiledMapPrivate &dd, QGeoTiledMappingManagerEngine *engine, QObject *parent);
+
private Q_SLOTS:
void handleTileVersionChanged();
diff --git a/src/location/maps/qgeotiledmap_p_p.h b/src/location/maps/qgeotiledmap_p_p.h
index 01646d66..7106adf3 100644
--- a/src/location/maps/qgeotiledmap_p_p.h
+++ b/src/location/maps/qgeotiledmap_p_p.h
@@ -47,9 +47,10 @@
// We mean it.
//
-#include "qgeomap_p_p.h"
-#include "qgeocameradata_p.h"
-#include "qgeomaptype_p.h"
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qgeomap_p_p.h>
+#include <QtLocation/private/qgeocameradata_p.h>
+#include <QtLocation/private/qgeomaptype_p.h>
#include <QtPositioning/private/qdoublevector3d_p.h>
#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QtCore/QPointer>
@@ -66,7 +67,7 @@ class QGeoTileSpec;
class QSGNode;
class QQuickWindow;
-class QGeoTiledMapPrivate : public QGeoMapPrivate
+class Q_LOCATION_PRIVATE_EXPORT QGeoTiledMapPrivate : public QGeoMapPrivate
{
Q_DECLARE_PUBLIC(QGeoTiledMap)
public:
@@ -75,9 +76,6 @@ public:
QSGNode *updateSceneGraph(QSGNode *node, QQuickWindow *window);
- QGeoCoordinate itemPositionToCoordinate(const QDoubleVector2D &pos) const;
- QDoubleVector2D coordinateToItemPosition(const QGeoCoordinate &coordinate) const;
-
void updateTile(const QGeoTileSpec &spec);
void prefetchTiles();
QGeoMapType activeMapType();
@@ -89,10 +87,9 @@ protected:
void changeTileVersion(int version);
void clearScene();
-private:
void updateScene();
-private:
+protected:
QAbstractGeoTileCache *m_cache;
QGeoCameraTiles *m_visibleTiles;
QGeoCameraTiles *m_prefetchTiles;
@@ -101,7 +98,6 @@ private:
int m_maxZoomLevel;
int m_minZoomLevel;
QGeoTiledMap::PrefetchStyle m_prefetchStyle;
- bool m_geomoteryUpdated;
Q_DISABLE_COPY(QGeoTiledMapPrivate)
};
diff --git a/src/location/maps/qgeotiledmappingmanagerengine.cpp b/src/location/maps/qgeotiledmappingmanagerengine.cpp
index 0ad37a1d..3d15ee99 100644
--- a/src/location/maps/qgeotiledmappingmanagerengine.cpp
+++ b/src/location/maps/qgeotiledmappingmanagerengine.cpp
@@ -268,13 +268,13 @@ int QGeoTiledMappingManagerEngine::tileVersion() const
return d->m_tileVersion;
}
-QGeoTiledMappingManagerEngine::CacheAreas QGeoTiledMappingManagerEngine::cacheHint() const
+QAbstractGeoTileCache::CacheAreas QGeoTiledMappingManagerEngine::cacheHint() const
{
Q_D(const QGeoTiledMappingManagerEngine);
return d->cacheHint_;
}
-void QGeoTiledMappingManagerEngine::setCacheHint(QGeoTiledMappingManagerEngine::CacheAreas cacheHint)
+void QGeoTiledMappingManagerEngine::setCacheHint(QAbstractGeoTileCache::CacheAreas cacheHint)
{
Q_D(QGeoTiledMappingManagerEngine);
d->cacheHint_ = cacheHint;
@@ -315,7 +315,7 @@ QSharedPointer<QGeoTileTexture> QGeoTiledMappingManagerEngine::getTileTexture(co
QGeoTiledMappingManagerEnginePrivate::QGeoTiledMappingManagerEnginePrivate()
: m_tileVersion(-1),
- cacheHint_(QGeoTiledMappingManagerEngine::AllCaches),
+ cacheHint_(QAbstractGeoTileCache::AllCaches),
tileCache_(0),
fetcher_(0)
{
diff --git a/src/location/maps/qgeotiledmappingmanagerengine_p.h b/src/location/maps/qgeotiledmappingmanagerengine_p.h
index 86c5b63c..78461f40 100644
--- a/src/location/maps/qgeotiledmappingmanagerengine_p.h
+++ b/src/location/maps/qgeotiledmappingmanagerengine_p.h
@@ -52,32 +52,24 @@
#include <QSize>
#include <QPair>
#include <QtLocation/qlocationglobal.h>
-#include "qgeomaptype_p.h"
-#include "qgeomappingmanagerengine_p.h"
+#include <QtLocation/private/qabstractgeotilecache_p.h>
+#include <QtLocation/private/qgeomaptype_p.h>
+#include <QtLocation/private/qgeomappingmanagerengine_p.h>
+
QT_BEGIN_NAMESPACE
class QGeoTiledMappingManagerEnginePrivate;
-class QGeoMapRequestOptions;
class QGeoTileFetcher;
class QGeoTileTexture;
-
class QGeoTileSpec;
class QGeoTiledMap;
-class QAbstractGeoTileCache;
class Q_LOCATION_EXPORT QGeoTiledMappingManagerEngine : public QGeoMappingManagerEngine
{
Q_OBJECT
public:
- enum CacheArea {
- DiskCache = 0x01,
- MemoryCache = 0x02,
- AllCaches = 0xFF
- };
- Q_DECLARE_FLAGS(CacheAreas, CacheArea)
-
explicit QGeoTiledMappingManagerEngine(QObject *parent = 0);
virtual ~QGeoTiledMappingManagerEngine();
@@ -97,7 +89,7 @@ public:
QSharedPointer<QGeoTileTexture> getTileTexture(const QGeoTileSpec &spec);
- QGeoTiledMappingManagerEngine::CacheAreas cacheHint() const;
+ QAbstractGeoTileCache::CacheAreas cacheHint() const;
private Q_SLOTS:
void engineTileFinished(const QGeoTileSpec &spec, const QByteArray &bytes, const QString &format);
@@ -111,7 +103,7 @@ protected:
void setTileFetcher(QGeoTileFetcher *fetcher);
void setTileSize(const QSize &tileSize);
void setTileVersion(int version);
- void setCacheHint(QGeoTiledMappingManagerEngine::CacheAreas cacheHint);
+ void setCacheHint(QAbstractGeoTileCache::CacheAreas cacheHint);
void setTileCache(QAbstractGeoTileCache *cache);
private:
@@ -123,8 +115,6 @@ private:
friend class QGeoTileFetcher;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QGeoTiledMappingManagerEngine::CacheAreas)
-
QT_END_NAMESPACE
#endif
diff --git a/src/location/maps/qgeotiledmappingmanagerengine_p_p.h b/src/location/maps/qgeotiledmappingmanagerengine_p_p.h
index 86ad0f08..5ef5b372 100644
--- a/src/location/maps/qgeotiledmappingmanagerengine_p_p.h
+++ b/src/location/maps/qgeotiledmappingmanagerengine_p_p.h
@@ -71,7 +71,7 @@ public:
int m_tileVersion;
QHash<QGeoTiledMap *, QSet<QGeoTileSpec> > mapHash_;
QHash<QGeoTileSpec, QSet<QGeoTiledMap *> > tileHash_;
- QGeoTiledMappingManagerEngine::CacheAreas cacheHint_;
+ QAbstractGeoTileCache::CacheAreas cacheHint_;
QAbstractGeoTileCache *tileCache_;
QGeoTileFetcher *fetcher_;
diff --git a/src/location/maps/qgeotiledmapreply.cpp b/src/location/maps/qgeotiledmapreply.cpp
index f2dfd9eb..34ca041f 100644
--- a/src/location/maps/qgeotiledmapreply.cpp
+++ b/src/location/maps/qgeotiledmapreply.cpp
@@ -242,6 +242,7 @@ void QGeoTiledMapReply::abort()
{
if (!isFinished())
setFinished(true);
+ emit aborted();
}
/*
diff --git a/src/location/maps/qgeotiledmapreply_p.h b/src/location/maps/qgeotiledmapreply_p.h
index 91852cc3..fc991bb7 100644
--- a/src/location/maps/qgeotiledmapreply_p.h
+++ b/src/location/maps/qgeotiledmapreply_p.h
@@ -88,6 +88,7 @@ public:
Q_SIGNALS:
void finished();
+ void aborted();
void error(QGeoTiledMapReply::Error error, const QString &errorString = QString());
protected:
diff --git a/src/location/maps/qgeotiledmapscene.cpp b/src/location/maps/qgeotiledmapscene.cpp
index d859c2af..fbd05645 100644
--- a/src/location/maps/qgeotiledmapscene.cpp
+++ b/src/location/maps/qgeotiledmapscene.cpp
@@ -39,10 +39,20 @@
#include "qabstractgeotilecache_p.h"
#include "qgeotilespec_p.h"
#include <QtPositioning/private/qdoublevector3d_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
#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
@@ -74,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;
@@ -84,35 +95,18 @@ public:
int m_maxTileY;
int m_tileXWrapsBelow; // the wrap point as a tile index
- // cameraToGrid transform
- double m_mercatorCenterX; // center of camera in grid space (0 to sideLength)
- double m_mercatorCenterY;
- double m_mercatorWidth; // width of camera in grid space (0 to sideLength)
- double m_mercatorHeight;
-
- // screenToWindow transform
- double m_screenOffsetX; // in pixels
- double m_screenOffsetY; // in pixels
- // cameraToScreen transform
- double m_screenWidth; // in pixels
- double m_screenHeight; // in pixels
-
- bool m_useVerticalLock;
- bool m_verticalLock;
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;
-
- 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)
@@ -124,12 +118,6 @@ QGeoTiledMapScene::~QGeoTiledMapScene()
{
}
-void QGeoTiledMapScene::setUseVerticalLock(bool lock)
-{
- Q_D(QGeoTiledMapScene);
- d->m_useVerticalLock = lock;
-}
-
void QGeoTiledMapScene::setScreenSize(const QSize &size)
{
Q_D(QGeoTiledMapScene);
@@ -148,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)
@@ -170,24 +159,6 @@ void QGeoTiledMapScene::addTile(const QGeoTileSpec &spec, QSharedPointer<QGeoTil
d->addTile(spec, texture);
}
-QDoubleVector2D QGeoTiledMapScene::itemPositionToMercator(const QDoubleVector2D &pos) const
-{
- Q_D(const QGeoTiledMapScene);
- return d->itemPositionToMercator(pos);
-}
-
-QDoubleVector2D QGeoTiledMapScene::mercatorToItemPosition(const QDoubleVector2D &mercator) const
-{
- Q_D(const QGeoTiledMapScene);
- return d->mercatorToItemPosition(mercator);
-}
-
-bool QGeoTiledMapScene::verticalLock() const
-{
- Q_D(const QGeoTiledMapScene);
- return d->m_verticalLock;
-}
-
QSet<QGeoTileSpec> QGeoTiledMapScene::texturedTiles()
{
Q_D(QGeoTiledMapScene);
@@ -216,16 +187,6 @@ QGeoTiledMapScenePrivate::QGeoTiledMapScenePrivate()
m_maxTileX(-1),
m_maxTileY(-1),
m_tileXWrapsBelow(0),
- m_mercatorCenterX(0.0),
- m_mercatorCenterY(0.0),
- m_mercatorWidth(0.0),
- m_mercatorHeight(0.0),
- m_screenOffsetX(0.0),
- m_screenOffsetY(0.0),
- m_screenWidth(0.0),
- m_screenHeight(0.0),
- m_useVerticalLock(false),
- m_verticalLock(false),
m_linearScaling(false),
m_dropTextures(false)
{
@@ -235,67 +196,6 @@ QGeoTiledMapScenePrivate::~QGeoTiledMapScenePrivate()
{
}
-QDoubleVector2D QGeoTiledMapScenePrivate::itemPositionToMercator(const QDoubleVector2D &pos) const
-{
- double x = m_mercatorWidth * (((pos.x() - m_screenOffsetX) / m_screenWidth) - 0.5);
- x += m_mercatorCenterX;
-
- if (x > 1.0 * m_sideLength)
- x -= 1.0 * m_sideLength;
- if (x < 0.0)
- x += 1.0 * m_sideLength;
-
- x /= 1.0 * m_sideLength;
-
- double y = m_mercatorHeight * (((pos.y() - m_screenOffsetY) / m_screenHeight) - 0.5);
- y += m_mercatorCenterY;
- y /= 1.0 * m_sideLength;
-
- return QDoubleVector2D(x, y);
-}
-
-QDoubleVector2D QGeoTiledMapScenePrivate::mercatorToItemPosition(const QDoubleVector2D &mercator) const
-{
- double mx = m_sideLength * mercator.x();
-
- double lb = m_mercatorCenterX - m_mercatorWidth / 2.0;
- if (lb < 0.0)
- lb += m_sideLength;
- double ub = m_mercatorCenterX + m_mercatorWidth / 2.0;
- if (m_sideLength < ub)
- ub -= m_sideLength;
-
- double m = (mx - m_mercatorCenterX) / m_mercatorWidth;
-
- double mWrapLower = (mx - m_mercatorCenterX - m_sideLength) / m_mercatorWidth;
- double mWrapUpper = (mx - m_mercatorCenterX + m_sideLength) / m_mercatorWidth;
-
- // correct for crossing dateline
- if (qFuzzyCompare(ub - lb + 1.0, 1.0) || (ub < lb) ) {
- if (m_mercatorCenterX < ub) {
- if (lb < mx) {
- m = mWrapLower;
- }
- } else if (lb < m_mercatorCenterX) {
- if (mx <= ub) {
- m = mWrapUpper;
- }
- }
- }
-
- // apply wrapping if necessary so we don't return unreasonably large pos/neg screen positions
- // also allows map items to be drawn properly if some of their coords are out of the screen
- if ( qAbs(mWrapLower) < qAbs(m) )
- m = mWrapLower;
- if ( qAbs(mWrapUpper) < qAbs(m) )
- m = mWrapUpper;
-
- double x = m_screenWidth * (0.5 + m);
- double y = m_screenHeight * (0.5 + (m_sideLength * mercator.y() - m_mercatorCenterY) / m_mercatorHeight);
-
- return QDoubleVector2D(x + m_screenOffsetX, y + m_screenOffsetY);
-}
-
bool QGeoTiledMapScenePrivate::buildGeometry(const QGeoTileSpec &spec, QSGImageNode *imageNode)
{
int x = spec.x();
@@ -339,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)
@@ -366,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;
@@ -448,70 +348,42 @@ 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;
- // calculate altitdue that allows the visible map tiles
+ // calculate altitude that allows the visible map tiles
// 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) ;
-
- // mercatorWidth_ and mercatorHeight_ define the ratio for
- // mercator and screen coordinate conversion,
- // see mercatorToItemPosition() and itemPositionToMercator()
- m_mercatorHeight = m_screenSize.height() / z;
- m_mercatorWidth = m_screenSize.width() / z;
+ 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)
- QDoubleVector3D center = (m_sideLength * QGeoProjection::coordToMercator(m_cameraData.center()));
+ QDoubleVector2D camCenterMercator = QWebMercator::coordToMercator(m_cameraData.center());
+ QDoubleVector3D center = (m_sideLength * camCenterMercator);
// wrap the center if necessary (due to dateline crossing)
if (center.x() < m_tileXWrapsBelow)
center.setX(center.x() + 1.0 * m_sideLength);
- m_mercatorCenterX = center.x();
- m_mercatorCenterY = center.y();
-
// work out where the camera center is w.r.t minimum tile bounds
center.setX(center.x() - 1.0 * m_minTileX);
center.setY(1.0 * m_minTileY - center.y());
- // letter box vertically
- if (m_useVerticalLock && (m_mercatorHeight > 1.0 * m_sideLength)) {
- center.setY(-1.0 * m_sideLength / 2.0);
- m_mercatorCenterY = m_sideLength / 2.0;
- m_screenOffsetY = m_screenSize.height() * (0.5 - m_sideLength / (2 * m_mercatorHeight));
- m_screenHeight = m_screenSize.height() - 2 * m_screenOffsetY;
- m_mercatorHeight = 1.0 * m_sideLength;
- m_verticalLock = true;
- } else {
- m_screenOffsetY = 0.0;
- m_screenHeight = m_screenSize.height();
- m_verticalLock = false;
- }
-
- if (m_mercatorWidth > 1.0 * m_sideLength) {
- m_screenOffsetX = m_screenSize.width() * (0.5 - (m_sideLength / (2 * m_mercatorWidth)));
- m_screenWidth = m_screenSize.width() - 2 * m_screenOffsetX;
- m_mercatorWidth = 1.0 * m_sideLength;
- } else {
- m_screenOffsetX = 0.0;
- 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
@@ -519,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);
@@ -540,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) {
@@ -622,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,
@@ -652,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;
@@ -686,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);
@@ -714,7 +617,8 @@ QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *win
if (!mapRoot)
mapRoot = new QGeoTiledMapRootNode();
- mapRoot->setClipRect(QRect(d->m_screenOffsetX, d->m_screenOffsetY, d->m_screenWidth, d->m_screenHeight));
+ // Setting clip rect to fullscreen, as now the map can never be smaller than the viewport.
+ mapRoot->setClipRect(QRect(0, 0, w, h));
QMatrix4x4 itemSpaceMatrix;
itemSpaceMatrix.scale(w / 2, h / 2);
diff --git a/src/location/maps/qgeotiledmapscene_p.h b/src/location/maps/qgeotiledmapscene_p.h
index 1e3a9bc7..da7829a3 100644
--- a/src/location/maps/qgeotiledmapscene_p.h
+++ b/src/location/maps/qgeotiledmapscene_p.h
@@ -49,6 +49,7 @@
#include <QObject>
#include <QtLocation/qlocationglobal.h>
+#include <QtPositioning/QGeoCoordinate>
QT_BEGIN_NAMESPACE
@@ -75,16 +76,10 @@ public:
void setVisibleTiles(const QSet<QGeoTileSpec> &tiles);
const QSet<QGeoTileSpec> &visibleTiles() const;
- void setUseVerticalLock(bool lock);
-
void addTile(const QGeoTileSpec &spec, QSharedPointer<QGeoTileTexture> texture);
- QDoubleVector2D itemPositionToMercator(const QDoubleVector2D &pos) const;
- QDoubleVector2D mercatorToItemPosition(const QDoubleVector2D &mercator) const;
-
QSGNode *updateSceneGraph(QSGNode *oldNode, QQuickWindow *window);
- bool verticalLock() const;
QSet<QGeoTileSpec> texturedTiles();
void clearTexturedTiles();
diff --git a/src/location/maps/qgeotilefetcher_p.h b/src/location/maps/qgeotilefetcher_p.h
index e3621d3d..007a919a 100644
--- a/src/location/maps/qgeotilefetcher_p.h
+++ b/src/location/maps/qgeotilefetcher_p.h
@@ -87,7 +87,7 @@ protected:
QGeoTileFetcher(QGeoTileFetcherPrivate &dd, QObject *parent = 0);
void timerEvent(QTimerEvent *event);
- QGeoTiledMappingManagerEngine::CacheAreas cacheHint() const;
+ QAbstractGeoTileCache::CacheAreas cacheHint() const;
virtual bool initialized() const;
private:
diff --git a/src/location/places/qplacereply.cpp b/src/location/places/qplacereply.cpp
index 0590871d..55e67e43 100644
--- a/src/location/places/qplacereply.cpp
+++ b/src/location/places/qplacereply.cpp
@@ -195,10 +195,22 @@ QPlaceReply::Error QPlaceReply::error() const
}
/*!
- Aborts the operation.
+ \fn void QPlaceReply::aborted()
+ \since 5.9
+
+ This signal is emitted when the operation has been cancelled.
+
+ \sa abort()
+*/
+
+/*!
+ Cancels the operation immediately.
+
+ \sa aborted()
*/
void QPlaceReply::abort()
{
+ emit aborted();
}
/*!
diff --git a/src/location/places/qplacereply.h b/src/location/places/qplacereply.h
index 374c68b3..3eb3d6cc 100644
--- a/src/location/places/qplacereply.h
+++ b/src/location/places/qplacereply.h
@@ -86,6 +86,7 @@ public Q_SLOTS:
Q_SIGNALS:
void finished();
+ void aborted();
void error(QPlaceReply::Error error, const QString &errorString = QString());
protected:
diff --git a/src/plugins/geoservices/esri/geocodereply_esri.cpp b/src/plugins/geoservices/esri/geocodereply_esri.cpp
index a7ad9368..f1dac184 100644
--- a/src/plugins/geoservices/esri/geocodereply_esri.cpp
+++ b/src/plugins/geoservices/esri/geocodereply_esri.cpp
@@ -51,11 +51,17 @@ QT_BEGIN_NAMESPACE
GeoCodeReplyEsri::GeoCodeReplyEsri(QNetworkReply *reply, OperationType operationType,
QObject *parent) :
- QGeoCodeReply(parent), m_reply(reply), m_operationType(operationType)
+ QGeoCodeReply(parent), m_operationType(operationType)
{
- connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
+ connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
+ connect(this, &QGeoCodeReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
setLimit(1);
setOffset(0);
@@ -63,49 +69,25 @@ GeoCodeReplyEsri::GeoCodeReplyEsri(QNetworkReply *reply, OperationType operation
GeoCodeReplyEsri::~GeoCodeReplyEsri()
{
- if (m_reply)
- m_reply->deleteLater();
-}
-
-void GeoCodeReplyEsri::abort()
-{
- if (!m_reply)
- return;
-
- m_reply->abort();
- QGeoCodeReply::abort();
-
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
}
void GeoCodeReplyEsri::networkReplyError(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
-
- if (!m_reply)
- return;
-
- setError(QGeoCodeReply::CommunicationError, m_reply->errorString());
-
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ setError(QGeoCodeReply::CommunicationError, reply->errorString());
}
void GeoCodeReplyEsri::networkReplyFinished()
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (m_reply->error() != QNetworkReply::NoError)
- {
- setError(QGeoCodeReply::CommunicationError, m_reply->errorString());
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
+ if (reply->error() != QNetworkReply::NoError)
return;
- }
- QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll());
+ QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
if (document.isObject()) {
QJsonObject object = document.object();
@@ -148,9 +130,6 @@ void GeoCodeReplyEsri::networkReplyFinished()
} else {
setError(QGeoCodeReply::CommunicationError, QStringLiteral("Unknown document"));
}
-
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
}
QGeoLocation GeoCodeReplyEsri::parseAddress(const QJsonObject& object)
diff --git a/src/plugins/geoservices/esri/geocodereply_esri.h b/src/plugins/geoservices/esri/geocodereply_esri.h
index 4434b7dc..a857599b 100644
--- a/src/plugins/geoservices/esri/geocodereply_esri.h
+++ b/src/plugins/geoservices/esri/geocodereply_esri.h
@@ -58,9 +58,7 @@ public:
public:
GeoCodeReplyEsri(QNetworkReply *reply, OperationType operationType, QObject *parent = Q_NULLPTR);
- virtual ~GeoCodeReplyEsri();
-
- void abort() Q_DECL_OVERRIDE;
+ ~GeoCodeReplyEsri();
inline OperationType operationType() const;
@@ -72,7 +70,6 @@ private Q_SLOTS:
QGeoLocation parseCandidate(const QJsonObject &candidate);
private:
- QNetworkReply *m_reply;
OperationType m_operationType;
};
diff --git a/src/plugins/geoservices/esri/georoutereply_esri.cpp b/src/plugins/geoservices/esri/georoutereply_esri.cpp
index 4a7d5c67..811ffd0d 100644
--- a/src/plugins/geoservices/esri/georoutereply_esri.cpp
+++ b/src/plugins/geoservices/esri/georoutereply_esri.cpp
@@ -48,43 +48,32 @@ QT_BEGIN_NAMESPACE
GeoRouteReplyEsri::GeoRouteReplyEsri(QNetworkReply *reply, const QGeoRouteRequest &request,
QObject *parent) :
- QGeoRouteReply(request, parent), m_reply(reply)
+ QGeoRouteReply(request, parent)
{
- connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
+ connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
+ connect(this, &QGeoRouteReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
GeoRouteReplyEsri::~GeoRouteReplyEsri()
{
- if (m_reply)
- m_reply->deleteLater();
-}
-
-void GeoRouteReplyEsri::abort()
-{
- if (!m_reply)
- return;
-
- m_reply->abort();
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
}
void GeoRouteReplyEsri::networkReplyFinished()
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (m_reply->error() != QNetworkReply::NoError)
- {
- setError(QGeoRouteReply::CommunicationError, m_reply->errorString());
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
+ if (reply->error() != QNetworkReply::NoError)
return;
- }
- QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll());
+ QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
GeoRouteJsonParserEsri parser(document);
if (parser.isValid())
@@ -94,21 +83,14 @@ void GeoRouteReplyEsri::networkReplyFinished()
} else {
setError(QGeoRouteReply::ParseError, parser.errorString());
}
-
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
}
void GeoRouteReplyEsri::networkReplyError(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
-
- if (!m_reply)
- return;
-
- setError(QGeoRouteReply::CommunicationError, m_reply->errorString());
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ setError(QGeoRouteReply::CommunicationError, reply->errorString());
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/esri/georoutereply_esri.h b/src/plugins/geoservices/esri/georoutereply_esri.h
index 6e97ee9f..049dc3ba 100644
--- a/src/plugins/geoservices/esri/georoutereply_esri.h
+++ b/src/plugins/geoservices/esri/georoutereply_esri.h
@@ -51,16 +51,11 @@ class GeoRouteReplyEsri : public QGeoRouteReply
public:
GeoRouteReplyEsri(QNetworkReply *reply, const QGeoRouteRequest &request, QObject *parent = Q_NULLPTR);
- virtual ~GeoRouteReplyEsri();
-
- void abort() Q_DECL_OVERRIDE;
+ ~GeoRouteReplyEsri();
private Q_SLOTS:
void networkReplyFinished();
void networkReplyError(QNetworkReply::NetworkError error);
-
-private:
- QNetworkReply *m_reply;
};
QT_END_NAMESPACE
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/esri/geotiledmapreply_esri.cpp b/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp
index e0816c15..f4431bf0 100644
--- a/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp
+++ b/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp
@@ -49,50 +49,32 @@ static const unsigned char gifSignature[] = {0x47, 0x49, 0x46, 0x38, 0x00};
GeoTiledMapReplyEsri::GeoTiledMapReplyEsri(QNetworkReply *reply, const QGeoTileSpec &spec,
QObject *parent) :
- QGeoTiledMapReply(spec, parent), m_reply(reply)
+ QGeoTiledMapReply(spec, parent)
{
- connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
+ connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
- connect(m_reply, SIGNAL(destroyed()), this, SLOT(replyDestroyed()));
+ connect(this, &QGeoTiledMapReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
GeoTiledMapReplyEsri::~GeoTiledMapReplyEsri()
{
- if (m_reply) {
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
- }
-}
-
-void GeoTiledMapReplyEsri::abort()
-{
- if (!m_reply)
- return;
-
- m_reply->abort();
- QGeoTiledMapReply::abort();
-}
-
-void GeoTiledMapReplyEsri::replyDestroyed()
-{
- m_reply = Q_NULLPTR;
}
void GeoTiledMapReplyEsri::networkReplyFinished()
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (m_reply->error() != QNetworkReply::NoError)
- {
- setError(QGeoTiledMapReply::CommunicationError, m_reply->errorString());
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
+ if (reply->error() != QNetworkReply::NoError)
return;
- }
- QByteArray const& imageData = m_reply->readAll();
+ QByteArray const& imageData = reply->readAll();
bool validFormat = true;
if (imageData.startsWith(reinterpret_cast<const char*>(pngSignature)))
@@ -108,22 +90,16 @@ void GeoTiledMapReplyEsri::networkReplyFinished()
setMapImageData(imageData);
setFinished(true);
-
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
}
void GeoTiledMapReplyEsri::networkReplyError(QNetworkReply::NetworkError error)
{
- if (!m_reply)
- return;
-
- if (error != QNetworkReply::OperationCanceledError)
- setError(QGeoTiledMapReply::CommunicationError, m_reply->errorString());
-
- setFinished(true);
- m_reply->deleteLater();
- m_reply = Q_NULLPTR;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ if (error == QNetworkReply::OperationCanceledError)
+ setFinished(true);
+ else
+ setError(QGeoTiledMapReply::CommunicationError, reply->errorString());
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/esri/geotiledmapreply_esri.h b/src/plugins/geoservices/esri/geotiledmapreply_esri.h
index 32a35698..b459e943 100644
--- a/src/plugins/geoservices/esri/geotiledmapreply_esri.h
+++ b/src/plugins/geoservices/esri/geotiledmapreply_esri.h
@@ -52,17 +52,11 @@ class GeoTiledMapReplyEsri : public QGeoTiledMapReply
public:
GeoTiledMapReplyEsri(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent = Q_NULLPTR);
- virtual ~GeoTiledMapReplyEsri();
-
- void abort() Q_DECL_OVERRIDE;
+ ~GeoTiledMapReplyEsri();
private Q_SLOTS:
- void replyDestroyed();
void networkReplyFinished();
void networkReplyError(QNetworkReply::NetworkError error);
-
-private:
- QNetworkReply *m_reply;
};
QT_END_NAMESPACE
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/qgeomapreplymapbox.cpp b/src/plugins/geoservices/mapbox/qgeomapreplymapbox.cpp
index 5fe9caa8..4b60231d 100644
--- a/src/plugins/geoservices/mapbox/qgeomapreplymapbox.cpp
+++ b/src/plugins/geoservices/mapbox/qgeomapreplymapbox.cpp
@@ -39,59 +39,42 @@
#include <QtLocation/private/qgeotilespec_p.h>
QGeoMapReplyMapbox::QGeoMapReplyMapbox(QNetworkReply *reply, const QGeoTileSpec &spec, const QString &format, QObject *parent)
-: QGeoTiledMapReply(spec, parent), m_reply(reply), m_format (format)
+: QGeoTiledMapReply(spec, parent), m_format (format)
{
- connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
+ connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
+ connect(this, &QGeoTiledMapReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
QGeoMapReplyMapbox::~QGeoMapReplyMapbox()
{
- if (m_reply) {
- m_reply->deleteLater();
- m_reply = 0;
- }
-}
-
-void QGeoMapReplyMapbox::abort()
-{
- if (!m_reply)
- return;
-
- m_reply->abort();
-}
-
-QNetworkReply *QGeoMapReplyMapbox::networkReply() const
-{
- return m_reply;
}
void QGeoMapReplyMapbox::networkReplyFinished()
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (m_reply->error() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
- setMapImageData(m_reply->readAll());
+ setMapImageData(reply->readAll());
setMapImageFormat(m_format);
setFinished(true);
-
- m_reply->deleteLater();
- m_reply = 0;
}
void QGeoMapReplyMapbox::networkReplyError(QNetworkReply::NetworkError error)
{
- if (!m_reply)
- return;
-
- if (error != QNetworkReply::OperationCanceledError)
- setError(QGeoTiledMapReply::CommunicationError, m_reply->errorString());
-
- setFinished(true);
- m_reply->deleteLater();
- m_reply = 0;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ if (error == QNetworkReply::OperationCanceledError)
+ setFinished(true);
+ else
+ setError(QGeoTiledMapReply::CommunicationError, reply->errorString());
}
diff --git a/src/plugins/geoservices/mapbox/qgeomapreplymapbox.h b/src/plugins/geoservices/mapbox/qgeomapreplymapbox.h
index 67ad61ad..c4a1dd82 100644
--- a/src/plugins/geoservices/mapbox/qgeomapreplymapbox.h
+++ b/src/plugins/geoservices/mapbox/qgeomapreplymapbox.h
@@ -51,16 +51,11 @@ public:
explicit QGeoMapReplyMapbox(QNetworkReply *reply, const QGeoTileSpec &spec, const QString &format, QObject *parent = 0);
~QGeoMapReplyMapbox();
- void abort();
-
- QNetworkReply *networkReply() const;
-
private Q_SLOTS:
void networkReplyFinished();
void networkReplyError(QNetworkReply::NetworkError error);
private:
- QPointer<QNetworkReply> m_reply;
QString m_format;
};
diff --git a/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp b/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp
index 4c98412b..8fc3386a 100644
--- a/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp
+++ b/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp
@@ -84,28 +84,21 @@ static QList<QGeoCoordinate> parseGeometry(const QJsonValue &geometry)
QGeoRouteReplyMapbox::QGeoRouteReplyMapbox(QNetworkReply *reply, const QGeoRouteRequest &request,
QObject *parent)
-: QGeoRouteReply(request, parent), m_reply(reply)
+: QGeoRouteReply(request, parent)
{
- connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
+ connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
+ connect(this, &QGeoRouteReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
QGeoRouteReplyMapbox::~QGeoRouteReplyMapbox()
{
- if (m_reply)
- m_reply->deleteLater();
-}
-
-void QGeoRouteReplyMapbox::abort()
-{
- if (!m_reply)
- return;
-
- m_reply->abort();
-
- m_reply->deleteLater();
- m_reply = 0;
}
static QGeoRoute constructRoute(const QJsonObject &obj)
@@ -177,25 +170,19 @@ static QGeoRoute constructRoute(const QJsonObject &obj)
void QGeoRouteReplyMapbox::networkReplyFinished()
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (m_reply->error() != QNetworkReply::NoError) {
- setError(QGeoRouteReply::CommunicationError, m_reply->errorString());
- m_reply->deleteLater();
- m_reply = 0;
+ if (reply->error() != QNetworkReply::NoError)
return;
- }
- QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll());
+ QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
if (document.isObject()) {
QJsonObject object = document.object();
QString status = object.value(QStringLiteral("code")).toString();
if (status != QStringLiteral("Ok")) {
setError(QGeoRouteReply::UnknownError, object.value(QStringLiteral("message")).toString());
- m_reply->deleteLater();
- m_reply = 0;
return;
}
@@ -210,22 +197,14 @@ void QGeoRouteReplyMapbox::networkReplyFinished()
} else {
setError(QGeoRouteReply::ParseError, QStringLiteral("Couldn't parse json."));
}
-
- m_reply->deleteLater();
- m_reply = 0;
}
void QGeoRouteReplyMapbox::networkReplyError(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
-
- if (!m_reply)
- return;
-
- setError(QGeoRouteReply::CommunicationError, m_reply->errorString());
-
- m_reply->deleteLater();
- m_reply = 0;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ setError(QGeoRouteReply::CommunicationError, reply->errorString());
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.h b/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.h
index 9df45ac4..f19faee7 100644
--- a/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.h
+++ b/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.h
@@ -55,14 +55,9 @@ public:
QGeoRouteReplyMapbox(QNetworkReply *reply, const QGeoRouteRequest &request, QObject *parent = 0);
~QGeoRouteReplyMapbox();
- void abort() Q_DECL_OVERRIDE;
-
private Q_SLOTS:
void networkReplyFinished();
void networkReplyError(QNetworkReply::NetworkError error);
-
-private:
- QNetworkReply *m_reply;
};
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/mapbox/qgeoroutingmanagerenginemapbox.cpp b/src/plugins/geoservices/mapbox/qgeoroutingmanagerenginemapbox.cpp
index d6ef8f0a..f5776852 100644
--- a/src/plugins/geoservices/mapbox/qgeoroutingmanagerenginemapbox.cpp
+++ b/src/plugins/geoservices/mapbox/qgeoroutingmanagerenginemapbox.cpp
@@ -89,10 +89,19 @@ QGeoRouteReply* QGeoRoutingManagerEngineMapbox::calculateRoute(const QGeoRouteRe
foreach (const QGeoCoordinate &c, request.waypoints()) {
url += QString("%1,%2;").arg(c.longitude()).arg(c.latitude());
}
- if (url.right(1) == ";") url.chop(1);
- url += QString("?steps=true&overview=full&geometries=geojson&access_token=%1").arg(m_accessToken);
-
- networkRequest.setUrl(QUrl(url));
+ if (url.right(1) == ";")
+ url.chop(1);
+
+ QUrlQuery query;
+ query.addQueryItem(QStringLiteral("steps"), QStringLiteral("true"));
+ query.addQueryItem(QStringLiteral("alternatives"), QStringLiteral("true"));
+ query.addQueryItem(QStringLiteral("overview"), QStringLiteral("full"));
+ query.addQueryItem(QStringLiteral("geometries"), QStringLiteral("geojson"));
+ query.addQueryItem(QStringLiteral("access_token"), m_accessToken);
+
+ QUrl u(url);
+ u.setQuery(query);
+ networkRequest.setUrl(u);
QNetworkReply *reply = m_networkManager->get(networkRequest);
QGeoRouteReplyMapbox *routeReply = new QGeoRouteReplyMapbox(reply, request, this);
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/placesv2/qplacecontentreplyimpl.cpp b/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.cpp
index 9a5cbf48..f67fa5bb 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.cpp
+++ b/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.cpp
@@ -48,30 +48,26 @@ QT_BEGIN_NAMESPACE
QPlaceContentReplyImpl::QPlaceContentReplyImpl(const QPlaceContentRequest &request,
QNetworkReply *reply,
QPlaceManagerEngineNokiaV2 *engine)
- : QPlaceContentReply(engine), m_reply(reply), m_engine(engine)
+ : QPlaceContentReply(engine), m_engine(engine)
{
Q_ASSERT(engine);
- setRequest(request);
-
- if (!m_reply)
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
return;
+ }
+ setRequest(request);
- m_reply->setParent(this);
- connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(replyError(QNetworkReply::NetworkError)));
+ connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
QPlaceContentReplyImpl::~QPlaceContentReplyImpl()
{
}
-void QPlaceContentReplyImpl::abort()
-{
- if (m_reply)
- m_reply->abort();
-}
-
void QPlaceContentReplyImpl::setError(QPlaceReply::Error error_, const QString &errorString)
{
QPlaceContentReply::setError(error_, errorString);
@@ -82,31 +78,32 @@ void QPlaceContentReplyImpl::setError(QPlaceReply::Error error_, const QString &
void QPlaceContentReplyImpl::replyFinished()
{
- if (m_reply->isOpen()) {
- QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll());
- if (!document.isObject()) {
- setError(ParseError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, PARSE_ERROR));
- return;
- }
-
- QJsonObject object = document.object();
-
- QPlaceContent::Collection collection;
- int totalCount;
- QPlaceContentRequest previous;
- QPlaceContentRequest next;
-
- parseCollection(request().contentType(), object, &collection, &totalCount,
- &previous, &next, m_engine);
-
- setTotalCount(totalCount);
- setContent(collection);
- setPreviousPageRequest(previous);
- setNextPageRequest(next);
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+
+ if (reply->error() != QNetworkReply::NoError)
+ return;
+
+ QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
+ if (!document.isObject()) {
+ setError(ParseError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, PARSE_ERROR));
+ return;
}
- m_reply->deleteLater();
- m_reply = 0;
+ QJsonObject object = document.object();
+
+ QPlaceContent::Collection collection;
+ int totalCount;
+ QPlaceContentRequest previous;
+ QPlaceContentRequest next;
+
+ parseCollection(request().contentType(), object, &collection, &totalCount,
+ &previous, &next, m_engine);
+
+ setTotalCount(totalCount);
+ setContent(collection);
+ setPreviousPageRequest(previous);
+ setNextPageRequest(next);
setFinished(true);
emit finished();
@@ -114,13 +111,12 @@ void QPlaceContentReplyImpl::replyFinished()
void QPlaceContentReplyImpl::replyError(QNetworkReply::NetworkError error)
{
- switch (error) {
- case QNetworkReply::OperationCanceledError:
- setError(CancelError, "Request canceled.");
- break;
- default:
- setError(CommunicationError, "Network error.");
- }
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ if (error == QNetworkReply::OperationCanceledError)
+ setError(QPlaceReply::CancelError, QStringLiteral("Request cancelled"));
+ else
+ setError(QPlaceReply::CommunicationError, reply->errorString());
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.h b/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.h
index c7ef7ee4..596b9a4c 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.h
+++ b/src/plugins/geoservices/nokia/placesv2/qplacecontentreplyimpl.h
@@ -54,15 +54,12 @@ public:
QPlaceManagerEngineNokiaV2 *engine);
~QPlaceContentReplyImpl();
- void abort();
-
private slots:
void setError(QPlaceReply::Error error_, const QString &errorString);
void replyFinished();
void replyError(QNetworkReply::NetworkError error);
private:
- QNetworkReply *m_reply;
QPlaceManagerEngineNokiaV2 *m_engine;
};
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.cpp b/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.cpp
index e85b9cc7..1e7f2d2f 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.cpp
+++ b/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.cpp
@@ -88,27 +88,23 @@ static bool countryTableContains(const QString &countryCode)
QPlaceDetailsReplyImpl::QPlaceDetailsReplyImpl(QNetworkReply *reply,
QPlaceManagerEngineNokiaV2 *parent)
- : QPlaceDetailsReply(parent), m_reply(reply), m_engine(parent)
+: QPlaceDetailsReply(parent), m_engine(parent)
{
- Q_ASSERT(parent);
-
- if (!m_reply)
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
return;
-
- m_reply->setParent(this);
- connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ }
+ connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(replyError(QNetworkReply::NetworkError)));
+ connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
QPlaceDetailsReplyImpl::~QPlaceDetailsReplyImpl()
{
}
-void QPlaceDetailsReplyImpl::abort()
-{
- if (m_reply)
- m_reply->abort();
-}
-
void QPlaceDetailsReplyImpl::setError(QPlaceReply::Error error_, const QString &errorString)
{
QPlaceReply::setError(error_, errorString);
@@ -119,23 +115,13 @@ void QPlaceDetailsReplyImpl::setError(QPlaceReply::Error error_, const QString &
void QPlaceDetailsReplyImpl::replyFinished()
{
- if (m_reply->error() != QNetworkReply::NoError) {
- switch (m_reply->error()) {
- case QNetworkReply::OperationCanceledError:
- setError(CancelError, "Request canceled.");
- break;
- case QNetworkReply::ContentNotFoundError:
- setError(PlaceDoesNotExistError,
- QString::fromLatin1("The id, %1, does not reference an existing place")
- .arg(m_placeId));
- break;
- default:
- setError(CommunicationError, "Network error.");
- }
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+
+ if (reply->error() != QNetworkReply::NoError)
return;
- }
- QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll());
+ QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
if (!document.isObject()) {
setError(ParseError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, PARSE_ERROR));
return;
@@ -337,11 +323,23 @@ void QPlaceDetailsReplyImpl::replyFinished()
place.setDetailsFetched(true);
setPlace(place);
- m_reply->deleteLater();
- m_reply = 0;
-
setFinished(true);
emit finished();
}
+void QPlaceDetailsReplyImpl::replyError(QNetworkReply::NetworkError error)
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ if (error == QNetworkReply::OperationCanceledError) {
+ setError(QPlaceReply::CancelError, QStringLiteral("Request cancelled"));
+ } else if (error == QNetworkReply::ContentNotFoundError) {
+ setError(QPlaceReply::PlaceDoesNotExistError,
+ QString::fromLatin1("The id, %1, does not reference an existing place")
+ .arg(m_placeId));
+ } else {
+ setError(QPlaceReply::CommunicationError, reply->errorString());
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.h b/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.h
index 2524d04a..dc537c80 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.h
+++ b/src/plugins/geoservices/nokia/placesv2/qplacedetailsreplyimpl.h
@@ -53,15 +53,14 @@ public:
QPlaceDetailsReplyImpl(QNetworkReply *reply, QPlaceManagerEngineNokiaV2 *parent);
~QPlaceDetailsReplyImpl();
- void abort();
void setPlaceId(const QString &placeId) { m_placeId = placeId; }
private slots:
void setError(QPlaceReply::Error error_, const QString &errorString);
void replyFinished();
+ void replyError(QNetworkReply::NetworkError error);
private:
- QNetworkReply *m_reply;
QPlaceManagerEngineNokiaV2 *m_engine;
QString m_placeId;
};
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp b/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp
index 3a56c927..9808b539 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp
+++ b/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp
@@ -54,29 +54,25 @@ QT_BEGIN_NAMESPACE
QPlaceSearchReplyHere::QPlaceSearchReplyHere(const QPlaceSearchRequest &request,
QNetworkReply *reply,
QPlaceManagerEngineNokiaV2 *parent)
- : QPlaceSearchReply(parent), m_reply(reply), m_engine(parent)
+ : QPlaceSearchReply(parent), m_engine(parent)
{
- Q_ASSERT(parent);
-
- setRequest(request);
-
- if (!m_reply)
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
return;
+ }
+ setRequest(request);
- m_reply->setParent(this);
- connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(replyError(QNetworkReply::NetworkError)));
+ connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
QPlaceSearchReplyHere::~QPlaceSearchReplyHere()
{
}
-void QPlaceSearchReplyHere::abort()
-{
- if (m_reply)
- m_reply->abort();
-}
-
void QPlaceSearchReplyHere::setError(QPlaceReply::Error error_, const QString &errorString)
{
QPlaceReply::setError(error_, errorString);
@@ -87,23 +83,13 @@ void QPlaceSearchReplyHere::setError(QPlaceReply::Error error_, const QString &e
void QPlaceSearchReplyHere::replyFinished()
{
- if (m_reply->error() != QNetworkReply::NoError) {
- switch (m_reply->error()) {
- case QNetworkReply::OperationCanceledError:
- setError(CancelError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, CANCEL_ERROR));
- break;
- case QNetworkReply::ContentNotFoundError:
- setError(PlaceDoesNotExistError,
- QString::fromLatin1("The id, %1, does not reference an existing place")
- .arg(request().recommendationId()));
- break;
- default:
- setError(CommunicationError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, NETWORK_ERROR));
- }
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+
+ if (reply->error() != QNetworkReply::NoError)
return;
- }
- QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll());
+ QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
if (!document.isObject()) {
setError(ParseError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, PARSE_ERROR));
return;
@@ -141,9 +127,6 @@ void QPlaceSearchReplyHere::replyFinished()
setResults(results);
- m_reply->deleteLater();
- m_reply = 0;
-
setFinished(true);
emit finished();
}
@@ -227,4 +210,19 @@ QPlaceProposedSearchResult QPlaceSearchReplyHere::parseSearchResult(const QJsonO
return result;
}
+void QPlaceSearchReplyHere::replyError(QNetworkReply::NetworkError error)
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ if (error == QNetworkReply::OperationCanceledError) {
+ setError(QPlaceReply::CancelError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, CANCEL_ERROR));
+ } else if (error == QNetworkReply::ContentNotFoundError) {
+ setError(QPlaceReply::PlaceDoesNotExistError,
+ QString::fromLatin1("The id, %1, does not reference an existing place")
+ .arg(request().recommendationId()));
+ } else {
+ setError(QPlaceReply::CommunicationError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, NETWORK_ERROR));
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.h b/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.h
index a712ab84..b3d97a3d 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.h
+++ b/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.h
@@ -56,17 +56,15 @@ public:
QPlaceManagerEngineNokiaV2 *parent);
~QPlaceSearchReplyHere();
- void abort();
-
private slots:
void setError(QPlaceReply::Error error_, const QString &errorString);
void replyFinished();
+ void replyError(QNetworkReply::NetworkError error);
private:
QPlaceResult parsePlaceResult(const QJsonObject &item) const;
QPlaceProposedSearchResult parseSearchResult(const QJsonObject &item) const;
- QNetworkReply *m_reply;
QPlaceManagerEngineNokiaV2 *m_engine;
};
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.cpp b/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.cpp
index 6ed8b5a2..9882545d 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.cpp
+++ b/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.cpp
@@ -46,25 +46,23 @@ QT_BEGIN_NAMESPACE
QPlaceSearchSuggestionReplyImpl::QPlaceSearchSuggestionReplyImpl(QNetworkReply *reply,
QObject *parent)
-: QPlaceSearchSuggestionReply(parent), m_reply(reply)
+: QPlaceSearchSuggestionReply(parent)
{
- if (!m_reply)
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
return;
-
- m_reply->setParent(this);
- connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ }
+ connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(replyError(QNetworkReply::NetworkError)));
+ connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
QPlaceSearchSuggestionReplyImpl::~QPlaceSearchSuggestionReplyImpl()
{
}
-void QPlaceSearchSuggestionReplyImpl::abort()
-{
- if (m_reply)
- m_reply->abort();
-}
-
void QPlaceSearchSuggestionReplyImpl::setError(QPlaceReply::Error error_,
const QString &errorString)
{
@@ -76,18 +74,13 @@ void QPlaceSearchSuggestionReplyImpl::setError(QPlaceReply::Error error_,
void QPlaceSearchSuggestionReplyImpl::replyFinished()
{
- if (m_reply->error() != QNetworkReply::NoError) {
- switch (m_reply->error()) {
- case QNetworkReply::OperationCanceledError:
- setError(CancelError, "Request canceled.");
- break;
- default:
- setError(CommunicationError, "Network error.");
- }
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+
+ if (reply->error() != QNetworkReply::NoError)
return;
- }
- QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll());
+ QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
if (!document.isObject()) {
setError(ParseError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, PARSE_ERROR));
emit error(error(), errorString());
@@ -107,11 +100,18 @@ void QPlaceSearchSuggestionReplyImpl::replyFinished()
setSuggestions(s);
- m_reply->deleteLater();
- m_reply = 0;
-
setFinished(true);
emit finished();
}
+void QPlaceSearchSuggestionReplyImpl::replyError(QNetworkReply::NetworkError error)
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ if (error == QNetworkReply::OperationCanceledError)
+ setError(QPlaceReply::CancelError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, CANCEL_ERROR));
+ else
+ setError(QPlaceReply::CommunicationError, QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, NETWORK_ERROR));
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.h b/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.h
index dbcba3ab..97ae3e1e 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.h
+++ b/src/plugins/geoservices/nokia/placesv2/qplacesearchsuggestionreplyimpl.h
@@ -50,14 +50,10 @@ public:
explicit QPlaceSearchSuggestionReplyImpl(QNetworkReply *reply, QObject *parent = 0);
~QPlaceSearchSuggestionReplyImpl();
- void abort();
-
private slots:
void setError(QPlaceReply::Error error_, const QString &errorString);
void replyFinished();
-
-private:
- QNetworkReply *m_reply;
+ void replyError(QNetworkReply::NetworkError error);
};
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp b/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp
index e99b9815..0fb6eb2a 100644
--- a/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeocodereply_nokia.cpp
@@ -53,13 +53,21 @@ QT_BEGIN_NAMESPACE
QGeoCodeReplyNokia::QGeoCodeReplyNokia(QNetworkReply *reply, int limit, int offset,
const QGeoShape &viewport, bool manualBoundsRequired,
QObject *parent)
-: QGeoCodeReply(parent), m_reply(reply), m_parsing(false), m_manualBoundsRequired(manualBoundsRequired)
+: QGeoCodeReply(parent), m_parsing(false), m_manualBoundsRequired(manualBoundsRequired)
{
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
qRegisterMetaType<QList<QGeoLocation> >();
- connect(m_reply, SIGNAL(finished()), this, SLOT(networkFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ connect(reply, SIGNAL(finished()), this, SLOT(networkFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkError(QNetworkReply::NetworkError)));
+ connect(this, &QGeoCodeReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QGeoCodeReply::aborted, [this](){ m_parsing = false; });
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
+
setLimit(limit);
setOffset(offset);
@@ -68,29 +76,14 @@ QGeoCodeReplyNokia::QGeoCodeReplyNokia(QNetworkReply *reply, int limit, int offs
QGeoCodeReplyNokia::~QGeoCodeReplyNokia()
{
- abort();
-}
-
-void QGeoCodeReplyNokia::abort()
-{
- if (!m_reply) {
- m_parsing = false;
- return;
- }
-
- m_reply->abort();
-
- m_reply->deleteLater();
- m_reply = 0;
- m_parsing = false;
}
void QGeoCodeReplyNokia::networkFinished()
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (m_reply->error() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QGeoCodeJsonParser *parser = new QGeoCodeJsonParser; // QRunnable, autoDelete = true.
@@ -101,23 +94,16 @@ void QGeoCodeReplyNokia::networkFinished()
connect(parser, SIGNAL(error(QString)), this, SLOT(parseError(QString)));
m_parsing = true;
- parser->parse(m_reply->readAll());
-
- m_reply->deleteLater();
- m_reply = 0;
+ parser->parse(reply->readAll());
}
void QGeoCodeReplyNokia::networkError(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
- if (!m_reply)
- return;
-
- setError(QGeoCodeReply::CommunicationError, m_reply->errorString());
-
- m_reply->deleteLater();
- m_reply = 0;
+ QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ setError(QGeoCodeReply::CommunicationError, reply->errorString());
}
void QGeoCodeReplyNokia::appendResults(const QList<QGeoLocation> &locations)
@@ -136,7 +122,6 @@ void QGeoCodeReplyNokia::parseError(const QString &errorString)
setError(QGeoCodeReply::ParseError,
QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, RESPONSE_NOT_RECOGNIZABLE));
- abort();
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/qgeocodereply_nokia.h b/src/plugins/geoservices/nokia/qgeocodereply_nokia.h
index 0d0c47d1..90443ebc 100644
--- a/src/plugins/geoservices/nokia/qgeocodereply_nokia.h
+++ b/src/plugins/geoservices/nokia/qgeocodereply_nokia.h
@@ -49,8 +49,6 @@ public:
QGeoCodeReplyNokia(QNetworkReply *reply, int limit, int offset, const QGeoShape &viewport, bool manualBoundsRequired, QObject *parent = 0);
~QGeoCodeReplyNokia();
- void abort();
-
private Q_SLOTS:
void networkFinished();
void networkError(QNetworkReply::NetworkError error);
@@ -58,7 +56,6 @@ private Q_SLOTS:
void parseError(const QString &errorString);
private:
- QNetworkReply *m_reply;
bool m_parsing;
bool m_manualBoundsRequired;
};
diff --git a/src/plugins/geoservices/nokia/qgeomapreply_nokia.cpp b/src/plugins/geoservices/nokia/qgeomapreply_nokia.cpp
index c95f8de3..6e1a1e85 100644
--- a/src/plugins/geoservices/nokia/qgeomapreply_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeomapreply_nokia.cpp
@@ -42,63 +42,50 @@
QT_BEGIN_NAMESPACE
QGeoMapReplyNokia::QGeoMapReplyNokia(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent)
- : QGeoTiledMapReply(spec, parent),
- m_reply(reply)
+ : QGeoTiledMapReply(spec, parent)
{
- connect(m_reply,
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
+ connect(reply,
SIGNAL(finished()),
this,
SLOT(networkFinished()));
- connect(m_reply,
+ connect(reply,
SIGNAL(error(QNetworkReply::NetworkError)),
this,
SLOT(networkError(QNetworkReply::NetworkError)));
+ connect(this, &QGeoTiledMapReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
QGeoMapReplyNokia::~QGeoMapReplyNokia()
{
}
-QNetworkReply *QGeoMapReplyNokia::networkReply() const
-{
- return m_reply;
-}
-
-void QGeoMapReplyNokia::abort()
-{
- if (!m_reply)
- return;
-
- m_reply->abort();
-}
-
void QGeoMapReplyNokia::networkFinished()
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (m_reply->error() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
- setMapImageData(m_reply->readAll());
+ setMapImageData(reply->readAll());
setMapImageFormat("png");
setFinished(true);
-
- m_reply->deleteLater();
- m_reply = 0;
}
void QGeoMapReplyNokia::networkError(QNetworkReply::NetworkError error)
{
- if (!m_reply)
- return;
-
- if (error != QNetworkReply::OperationCanceledError)
- setError(QGeoTiledMapReply::CommunicationError, m_reply->errorString());
- setFinished(true);
- m_reply->deleteLater();
- m_reply = 0;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ if (error == QNetworkReply::OperationCanceledError)
+ setFinished(true);
+ else
+ setError(QGeoTiledMapReply::CommunicationError, reply->errorString());
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/qgeomapreply_nokia.h b/src/plugins/geoservices/nokia/qgeomapreply_nokia.h
index 55759914..d835757c 100644
--- a/src/plugins/geoservices/nokia/qgeomapreply_nokia.h
+++ b/src/plugins/geoservices/nokia/qgeomapreply_nokia.h
@@ -52,16 +52,9 @@ public:
QGeoMapReplyNokia(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent = 0);
~QGeoMapReplyNokia();
- void abort();
-
- QNetworkReply *networkReply() const;
-
private Q_SLOTS:
void networkFinished();
void networkError(QNetworkReply::NetworkError error);
-
-private:
- QPointer<QNetworkReply> m_reply;
};
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp b/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp
index 45ea071f..b5fdfee1 100644
--- a/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp
@@ -49,43 +49,41 @@ QT_BEGIN_NAMESPACE
QGeoRouteReplyNokia::QGeoRouteReplyNokia(const QGeoRouteRequest &request,
const QList<QNetworkReply *> &replies,
QObject *parent)
-: QGeoRouteReply(request, parent), m_replies(replies), m_parsers(0)
+: QGeoRouteReply(request, parent), m_parsers(0)
{
qRegisterMetaType<QList<QGeoRoute> >();
- foreach (QNetworkReply *reply, m_replies) {
+ bool failure = false;
+ foreach (QNetworkReply *reply, replies) {
+ if (!reply) {
+ failure = true;
+ continue;
+ }
connect(reply, SIGNAL(finished()), this, SLOT(networkFinished()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkError(QNetworkReply::NetworkError)));
+ connect(this, &QGeoRouteReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
+ if (failure)
+ setError(UnknownError, QStringLiteral("Null reply"));
+ else
+ connect(this, &QGeoRouteReply::aborted, [this](){ m_parsers = 0; });
}
QGeoRouteReplyNokia::~QGeoRouteReplyNokia()
{
- abort();
-}
-
-void QGeoRouteReplyNokia::abort()
-{
- if (m_replies.isEmpty() && !m_parsers)
- return;
-
- foreach (QNetworkReply *reply, m_replies) {
- reply->abort();
- reply->deleteLater();
- }
- m_replies.clear();
- m_parsers = 0;
}
void QGeoRouteReplyNokia::networkFinished()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
- if (!reply)
- return;
+ reply->deleteLater();
- if (reply->error() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError
+ && reply->error() != QNetworkReply::UnknownContentError) {
return;
+ }
QGeoRouteXmlParser *parser = new QGeoRouteXmlParser(request());
connect(parser, SIGNAL(results(QList<QGeoRoute>)),
@@ -94,32 +92,17 @@ void QGeoRouteReplyNokia::networkFinished()
++m_parsers;
parser->parse(reply->readAll());
-
- m_replies.removeOne(reply);
- reply->deleteLater();
}
void QGeoRouteReplyNokia::networkError(QNetworkReply::NetworkError error)
{
- QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
- if (!reply)
+ if (error == QNetworkReply::UnknownContentError)
return;
-
- if (error == QNetworkReply::UnknownContentError) {
- QGeoRouteXmlParser *parser = new QGeoRouteXmlParser(request());
- connect(parser, SIGNAL(results(QList<QGeoRoute>)),
- this, SLOT(appendResults(QList<QGeoRoute>)));
- connect(parser, SIGNAL(error(QString)), this, SLOT(parserError(QString)));
-
- ++m_parsers;
- parser->parse(reply->readAll());
-
- m_replies.removeOne(reply);
- reply->deleteLater();
- } else {
- setError(QGeoRouteReply::CommunicationError, reply->errorString());
- abort();
- }
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ setError(QGeoRouteReply::CommunicationError, reply->errorString());
+ if (error != QNetworkReply::OperationCanceledError) // Any error not caused by abort()
+ emit aborted(); // aborts all unfinished replies and sets m_parsers to 0
}
void QGeoRouteReplyNokia::appendResults(const QList<QGeoRoute> &routes)
@@ -130,19 +113,16 @@ void QGeoRouteReplyNokia::appendResults(const QList<QGeoRoute> &routes)
--m_parsers;
addRoutes(routes);
- if (!m_parsers && m_replies.isEmpty())
+ if (!m_parsers)
setFinished(true);
}
void QGeoRouteReplyNokia::parserError(const QString &errorString)
{
Q_UNUSED(errorString)
-
- --m_parsers;
-
+ emit aborted();
setError(QGeoRouteReply::ParseError,
QCoreApplication::translate(NOKIA_PLUGIN_CONTEXT_NAME, RESPONSE_NOT_RECOGNIZABLE));
- abort();
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/qgeoroutereply_nokia.h b/src/plugins/geoservices/nokia/qgeoroutereply_nokia.h
index 9d32bdb3..d38262a5 100644
--- a/src/plugins/geoservices/nokia/qgeoroutereply_nokia.h
+++ b/src/plugins/geoservices/nokia/qgeoroutereply_nokia.h
@@ -51,8 +51,6 @@ public:
QGeoRouteReplyNokia(const QGeoRouteRequest &request, const QList<QNetworkReply*> &replies, QObject *parent = 0);
~QGeoRouteReplyNokia();
- void abort();
-
private Q_SLOTS:
void networkFinished();
void networkError(QNetworkReply::NetworkError error);
@@ -60,7 +58,6 @@ private Q_SLOTS:
void parserError(const QString &errorString);
private:
- QList<QNetworkReply *> m_replies;
int m_parsers;
};
diff --git a/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp b/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp
index 6548aa2b..e5809018 100644
--- a/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp
@@ -34,6 +34,7 @@
**
****************************************************************************/
+#include <QtPositioning/private/qwebmercator_p.h>
#include "qgeocameracapabilities_p.h"
#include "qgeotiledmappingmanagerengine_nokia.h"
#include "qgeotiledmap_nokia.h"
@@ -66,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));
@@ -378,10 +384,10 @@ QString QGeoTiledMappingManagerEngineNokia::evaluateCopyrightsText(const QGeoMap
pt.setX(viewX0 / divFactor);
pt.setY(viewY0 / divFactor);
- viewport.setTopLeft(QGeoProjection::mercatorToCoord(pt));
+ viewport.setTopLeft(QWebMercator::mercatorToCoord(pt));
pt.setX(viewX1 / divFactor);
pt.setY(viewY1 / divFactor);
- viewport.setBottomRight(QGeoProjection::mercatorToCoord(pt));
+ viewport.setBottomRight(QWebMercator::mercatorToCoord(pt));
}
// TODO: the following invalidation detection algorithm may be improved later.
diff --git a/src/plugins/geoservices/osm/qgeocodereplyosm.cpp b/src/plugins/geoservices/osm/qgeocodereplyosm.cpp
index 15b1724e..a30601d0 100644
--- a/src/plugins/geoservices/osm/qgeocodereplyosm.cpp
+++ b/src/plugins/geoservices/osm/qgeocodereplyosm.cpp
@@ -50,31 +50,23 @@
QT_BEGIN_NAMESPACE
QGeoCodeReplyOsm::QGeoCodeReplyOsm(QNetworkReply *reply, QObject *parent)
-: QGeoCodeReply(parent), m_reply(reply)
+: QGeoCodeReply(parent)
{
- connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
+ connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
-
+ connect(this, &QGeoCodeReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
setLimit(1);
setOffset(0);
}
QGeoCodeReplyOsm::~QGeoCodeReplyOsm()
{
- if (m_reply)
- m_reply->deleteLater();
-}
-
-void QGeoCodeReplyOsm::abort()
-{
- if (!m_reply)
- return;
-
- m_reply->abort();
-
- m_reply->deleteLater();
- m_reply = 0;
}
static QGeoAddress parseAddressObject(const QJsonObject &object)
@@ -108,14 +100,14 @@ static QGeoAddress parseAddressObject(const QJsonObject &object)
void QGeoCodeReplyOsm::networkReplyFinished()
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (m_reply->error() != QNetworkReply::NoError)
+ if (reply->error() != QNetworkReply::NoError)
return;
QList<QGeoLocation> locations;
- QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll());
+ QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
if (document.isObject()) {
QJsonObject object = document.object();
@@ -169,22 +161,14 @@ void QGeoCodeReplyOsm::networkReplyFinished()
setLocations(locations);
setFinished(true);
-
- m_reply->deleteLater();
- m_reply = 0;
}
void QGeoCodeReplyOsm::networkReplyError(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
-
- if (!m_reply)
- return;
-
- setError(QGeoCodeReply::CommunicationError, m_reply->errorString());
-
- m_reply->deleteLater();
- m_reply = 0;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ setError(QGeoCodeReply::CommunicationError, reply->errorString());
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeocodereplyosm.h b/src/plugins/geoservices/osm/qgeocodereplyosm.h
index 2772910e..0847f58c 100644
--- a/src/plugins/geoservices/osm/qgeocodereplyosm.h
+++ b/src/plugins/geoservices/osm/qgeocodereplyosm.h
@@ -53,14 +53,9 @@ public:
explicit QGeoCodeReplyOsm(QNetworkReply *reply, QObject *parent = 0);
~QGeoCodeReplyOsm();
- void abort();
-
private Q_SLOTS:
void networkReplyFinished();
void networkReplyError(QNetworkReply::NetworkError error);
-
-private:
- QNetworkReply *m_reply;
};
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeomapreplyosm.cpp b/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
index 052ed351..a06f91f3 100644
--- a/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
+++ b/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
@@ -45,64 +45,45 @@ QGeoMapReplyOsm::QGeoMapReplyOsm(QNetworkReply *reply,
const QGeoTileSpec &spec,
const QString &imageFormat,
QObject *parent)
-: QGeoTiledMapReply(spec, parent), m_reply(reply)
+: QGeoTiledMapReply(spec, parent)
{
- connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
+ connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
+ connect(this, &QGeoTiledMapReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
setMapImageFormat(imageFormat);
}
QGeoMapReplyOsm::~QGeoMapReplyOsm()
{
- if (m_reply) {
- m_reply->deleteLater();
- m_reply = 0;
- }
-}
-
-void QGeoMapReplyOsm::abort()
-{
- if (!m_reply)
- return;
-
- m_reply->abort();
-}
-
-QNetworkReply *QGeoMapReplyOsm::networkReply() const
-{
- return m_reply;
}
void QGeoMapReplyOsm::networkReplyFinished()
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (m_reply->error() != QNetworkReply::NoError) {
- m_reply->deleteLater();
- m_reply = 0;
+ if (reply->error() != QNetworkReply::NoError) // Already handled in networkReplyError
return;
- }
- QByteArray a = m_reply->readAll();
+ QByteArray a = reply->readAll();
setMapImageData(a);
setFinished(true);
-
- m_reply->deleteLater();
- m_reply = 0;
}
void QGeoMapReplyOsm::networkReplyError(QNetworkReply::NetworkError error)
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ if (error == QNetworkReply::OperationCanceledError)
+ setFinished(true);
+ else
+ setError(QGeoTiledMapReply::CommunicationError, reply->errorString());
- if (error != QNetworkReply::OperationCanceledError)
- setError(QGeoTiledMapReply::CommunicationError, m_reply->errorString());
-
- setFinished(true);
- m_reply->deleteLater();
- m_reply = 0;
}
diff --git a/src/plugins/geoservices/osm/qgeomapreplyosm.h b/src/plugins/geoservices/osm/qgeomapreplyosm.h
index 804a0a24..ef0cbb15 100644
--- a/src/plugins/geoservices/osm/qgeomapreplyosm.h
+++ b/src/plugins/geoservices/osm/qgeomapreplyosm.h
@@ -40,12 +40,8 @@
#ifndef QGEOMAPREPLYOSM_H
#define QGEOMAPREPLYOSM_H
-#include "qgeotilefetcherosm.h"
-#include "qgeotileproviderosm.h"
-
#include <QtNetwork/QNetworkReply>
#include <QtLocation/private/qgeotiledmapreply_p.h>
-#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -57,16 +53,9 @@ public:
QGeoMapReplyOsm(QNetworkReply *reply, const QGeoTileSpec &spec, const QString &imageFormat, QObject *parent = 0);
~QGeoMapReplyOsm();
- void abort();
-
- QNetworkReply *networkReply() const;
-
private Q_SLOTS:
void networkReplyFinished();
void networkReplyError(QNetworkReply::NetworkError error);
-
-private:
- QPointer<QNetworkReply> m_reply;
};
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
index c640e595..6924fda7 100644
--- a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
+++ b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
@@ -44,48 +44,37 @@ QT_BEGIN_NAMESPACE
QGeoRouteReplyOsm::QGeoRouteReplyOsm(QNetworkReply *reply, const QGeoRouteRequest &request,
QObject *parent)
-: QGeoRouteReply(request, parent), m_reply(reply)
+: QGeoRouteReply(request, parent)
{
- connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
+ connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
+ connect(this, &QGeoRouteReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
QGeoRouteReplyOsm::~QGeoRouteReplyOsm()
{
- if (m_reply)
- m_reply->deleteLater();
-}
-
-void QGeoRouteReplyOsm::abort()
-{
- if (!m_reply)
- return;
-
- m_reply->abort();
-
- m_reply->deleteLater();
- m_reply = 0;
}
void QGeoRouteReplyOsm::networkReplyFinished()
{
- if (!m_reply)
- return;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (m_reply->error() != QNetworkReply::NoError) {
- setError(QGeoRouteReply::CommunicationError, m_reply->errorString());
- m_reply->deleteLater();
- m_reply = 0;
+ if (reply->error() != QNetworkReply::NoError)
return;
- }
QGeoRoutingManagerEngineOsm *engine = qobject_cast<QGeoRoutingManagerEngineOsm *>(parent());
const QGeoRouteParser *parser = engine->routeParser();
QList<QGeoRoute> routes;
QString errorString;
- QGeoRouteReply::Error error = parser->parseReply(routes, errorString, m_reply->readAll());
+ QGeoRouteReply::Error error = parser->parseReply(routes, errorString, reply->readAll());
if (error == QGeoRouteReply::NoError) {
setRoutes(routes.mid(0,1)); // TODO QTBUG-56426
@@ -94,22 +83,14 @@ void QGeoRouteReplyOsm::networkReplyFinished()
} else {
setError(error, errorString);
}
-
- m_reply->deleteLater();
- m_reply = 0;
}
void QGeoRouteReplyOsm::networkReplyError(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
-
- if (!m_reply)
- return;
-
- setError(QGeoRouteReply::CommunicationError, m_reply->errorString());
-
- m_reply->deleteLater();
- m_reply = 0;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ setError(QGeoRouteReply::CommunicationError, reply->errorString());
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeoroutereplyosm.h b/src/plugins/geoservices/osm/qgeoroutereplyosm.h
index 8733c154..feaae59c 100644
--- a/src/plugins/geoservices/osm/qgeoroutereplyosm.h
+++ b/src/plugins/geoservices/osm/qgeoroutereplyosm.h
@@ -54,14 +54,9 @@ public:
QGeoRouteReplyOsm(QNetworkReply *reply, const QGeoRouteRequest &request, QObject *parent = 0);
~QGeoRouteReplyOsm();
- void abort() Q_DECL_OVERRIDE;
-
private Q_SLOTS:
void networkReplyFinished();
void networkReplyError(QNetworkReply::NetworkError error);
-
-private:
- QNetworkReply *m_reply;
};
QT_END_NAMESPACE
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/plugins/geoservices/osm/qplacemanagerengineosm.cpp b/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp
index 719769f0..dcf02b13 100644
--- a/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp
+++ b/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp
@@ -260,9 +260,6 @@ void QPlaceManagerEngineOsm::setLocales(const QList<QLocale> &locales)
void QPlaceManagerEngineOsm::categoryReplyFinished()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
- if (!reply)
- return;
-
reply->deleteLater();
QXmlStreamReader parser(reply);
diff --git a/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp b/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp
index 3cb0ab60..35b05d4d 100644
--- a/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp
+++ b/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp
@@ -53,32 +53,28 @@ QT_BEGIN_NAMESPACE
QPlaceSearchReplyOsm::QPlaceSearchReplyOsm(const QPlaceSearchRequest &request,
QNetworkReply *reply, QPlaceManagerEngineOsm *parent)
-: QPlaceSearchReply(parent), m_reply(reply)
+: QPlaceSearchReply(parent)
{
Q_ASSERT(parent);
-
- setRequest(request);
-
- if (!m_reply)
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
return;
+ }
+ setRequest(request);
- m_reply->setParent(this);
- connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkError(QNetworkReply::NetworkError)));
+ connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
}
QPlaceSearchReplyOsm::~QPlaceSearchReplyOsm()
{
}
-void QPlaceSearchReplyOsm::abort()
-{
- if (m_reply)
- m_reply->abort();
-}
-
void QPlaceSearchReplyOsm::setError(QPlaceReply::Error errorCode, const QString &errorString)
{
- QPlaceReply::setError(errorCode, errorString);
+ setError(errorCode, errorString);
emit error(errorCode, errorString);
setFinished(true);
emit finished();
@@ -99,14 +95,11 @@ static QGeoRectangle parseBoundingBox(const QJsonArray &coordinates)
void QPlaceSearchReplyOsm::replyFinished()
{
- QNetworkReply *reply = m_reply;
- m_reply->deleteLater();
- m_reply = 0;
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
- if (reply->error() != QNetworkReply::NoError) {
- setError(CommunicationError, tr("Communication error"));
+ if (reply->error() != QNetworkReply::NoError)
return;
- }
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
if (!document.isArray()) {
@@ -163,6 +156,14 @@ void QPlaceSearchReplyOsm::replyFinished()
emit finished();
}
+void QPlaceSearchReplyOsm::networkError(QNetworkReply::NetworkError error)
+{
+ Q_UNUSED(error)
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ setError(QPlaceReply::CommunicationError, reply->errorString());
+}
+
QPlaceResult QPlaceSearchReplyOsm::parsePlaceResult(const QJsonObject &item) const
{
QPlace place;
diff --git a/src/plugins/geoservices/osm/qplacesearchreplyosm.h b/src/plugins/geoservices/osm/qplacesearchreplyosm.h
index e495d4fa..223e5f0c 100644
--- a/src/plugins/geoservices/osm/qplacesearchreplyosm.h
+++ b/src/plugins/geoservices/osm/qplacesearchreplyosm.h
@@ -41,6 +41,7 @@
#define QPLACESEARCHREPLYOSM_H
#include <QtLocation/QPlaceSearchReply>
+#include <QNetworkReply>
QT_BEGIN_NAMESPACE
@@ -57,16 +58,13 @@ public:
QPlaceManagerEngineOsm *parent);
~QPlaceSearchReplyOsm();
- void abort();
-
private slots:
void setError(QPlaceReply::Error errorCode, const QString &errorString);
void replyFinished();
+ void networkError(QNetworkReply::NetworkError error);
private:
QPlaceResult parsePlaceResult(const QJsonObject &item) const;
-
- QNetworkReply *m_reply;
};
QT_END_NAMESPACE
diff --git a/src/plugins/position/corelocation/corelocation.pro b/src/plugins/position/corelocation/corelocation.pro
index dbb5b6b3..947a1d0c 100644
--- a/src/plugins/position/corelocation/corelocation.pro
+++ b/src/plugins/position/corelocation/corelocation.pro
@@ -13,9 +13,7 @@ HEADERS += \
OTHER_FILES += \
plugin.json
-osx: LIBS += -framework Foundation
-else: ios|tvos: LIBS += -framework CoreFoundation
-LIBS += -framework CoreLocation
+LIBS += -framework Foundation -framework CoreLocation
PLUGIN_TYPE = position
PLUGIN_CLASS_NAME = QGeoPositionInfoSourceFactoryCL
diff --git a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp
index a8e5e201..32a20a16 100644
--- a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp
+++ b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp
@@ -58,9 +58,7 @@ using namespace ABI::Windows::Foundation::Collections;
typedef ITypedEventHandler<Geolocator *, PositionChangedEventArgs *> GeoLocatorPositionHandler;
typedef ITypedEventHandler<Geolocator *, StatusChangedEventArgs *> GeoLocatorStatusHandler;
typedef IAsyncOperationCompletedHandler<Geoposition*> PositionHandler;
-#if _MSC_VER >= 1900
typedef IAsyncOperationCompletedHandler<GeolocationAccessStatus> AccessHandler;
-#endif
Q_DECLARE_METATYPE(QGeoPositionInfo)
@@ -106,13 +104,10 @@ QGeoPositionInfoSourceWinRT::QGeoPositionInfoSourceWinRT(QObject *parent)
&d->locator);
RETURN_HR_IF_FAILED("Could not initialize native location services.");
- // StatusChanged throws an exception on Windows 8.1
-#if _MSC_VER >= 1900
hr = d->locator->add_StatusChanged(Callback<GeoLocatorStatusHandler>(this,
&QGeoPositionInfoSourceWinRT::onStatusChanged).Get(),
&d->statusToken);
RETURN_HR_IF_FAILED("Could not add status callback.");
-#endif
hr = d->locator->put_ReportInterval(1000);
RETURN_HR_IF_FAILED("Could not initialize report interval.");
@@ -531,7 +526,7 @@ HRESULT QGeoPositionInfoSourceWinRT::onStatusChanged(IGeolocator*, IStatusChange
bool QGeoPositionInfoSourceWinRT::requestAccess() const
{
-#if _MSC_VER >= 1900 && defined(Q_OS_WINRT)
+#ifdef Q_OS_WINRT
static GeolocationAccessStatus accessStatus = GeolocationAccessStatus_Unspecified;
static ComPtr<IGeolocatorStatics> statics;
@@ -556,9 +551,9 @@ bool QGeoPositionInfoSourceWinRT::requestAccess() const
// We cannot wait inside the XamlThread as that would deadlock
QWinRTFunctions::await(op, &accessStatus);
return accessStatus == GeolocationAccessStatus_Allowed;
-#else // _MSC_VER < 1900
+#else // Q_OS_WINRT
return true;
-#endif // _MSC_VER < 1900
+#endif // Q_OS_WINRT
}
QT_END_NAMESPACE
diff --git a/src/positioning/positioning.pro b/src/positioning/positioning.pro
index 3cc059c0..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
@@ -32,7 +36,8 @@ PUBLIC_HEADERS += \
qgeosatelliteinfosource.h \
qnmeapositioninfosource.h \
qgeopositioninfosourcefactory.h \
- qpositioningglobal.h
+ qpositioningglobal.h \
+ qgeopath.h \
PRIVATE_HEADERS += \
qgeoaddress_p.h \
@@ -48,9 +53,12 @@ PRIVATE_HEADERS += \
qdeclarativegeolocation_p.h \
qdoublevector2d_p.h \
qdoublevector3d_p.h \
- qgeoprojection_p.h \
+ qwebmercator_p.h \
qpositioningglobal_p.h \
- qlocationdata_simulator_p.h
+ qlocationdata_simulator_p.h \
+ qdoublematrix4x4_p.h \
+ qgeopath_p.h \
+ qclipperutils_p.h
SOURCES += \
qgeoaddress.cpp \
@@ -72,10 +80,15 @@ SOURCES += \
qdeclarativegeolocation.cpp \
qdoublevector2d.cpp \
qdoublevector3d.cpp \
- qgeoprojection.cpp \
- qlocationdata_simulator.cpp
+ qgeopath.cpp \
+ qlocationdata_simulator.cpp \
+ qwebmercator.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/qdoublematrix4x4.cpp b/src/positioning/qdoublematrix4x4.cpp
new file mode 100644
index 00000000..bca38075
--- /dev/null
+++ b/src/positioning/qdoublematrix4x4.cpp
@@ -0,0 +1,1111 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui 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 "qdoublematrix4x4_p.h"
+#include <QtCore/qmath.h>
+//#include <QtCore/qvariant.h>
+#include <cmath>
+
+QT_BEGIN_NAMESPACE
+
+static const double inv_dist_to_plane = 1.0 / 1024.0;
+
+QDoubleMatrix4x4::QDoubleMatrix4x4(const double *values)
+{
+ for (int row = 0; row < 4; ++row)
+ for (int col = 0; col < 4; ++col)
+ m[col][row] = values[row * 4 + col];
+ flagBits = General;
+}
+
+QDoubleMatrix4x4::QDoubleMatrix4x4(const double *values, int cols, int rows)
+{
+ for (int col = 0; col < 4; ++col) {
+ for (int row = 0; row < 4; ++row) {
+ if (col < cols && row < rows)
+ m[col][row] = values[col * rows + row];
+ else if (col == row)
+ m[col][row] = 1.0;
+ else
+ m[col][row] = 0.0;
+ }
+ }
+ flagBits = General;
+}
+
+static inline double matrixDet2(const double m[4][4], int col0, int col1, int row0, int row1)
+{
+ return m[col0][row0] * m[col1][row1] - m[col0][row1] * m[col1][row0];
+}
+
+static inline double matrixDet3
+ (const double m[4][4], int col0, int col1, int col2,
+ int row0, int row1, int row2)
+{
+ return m[col0][row0] * matrixDet2(m, col1, col2, row1, row2)
+ - m[col1][row0] * matrixDet2(m, col0, col2, row1, row2)
+ + m[col2][row0] * matrixDet2(m, col0, col1, row1, row2);
+}
+
+static inline double matrixDet4(const double m[4][4])
+{
+ double det;
+ det = m[0][0] * matrixDet3(m, 1, 2, 3, 1, 2, 3);
+ det -= m[1][0] * matrixDet3(m, 0, 2, 3, 1, 2, 3);
+ det += m[2][0] * matrixDet3(m, 0, 1, 3, 1, 2, 3);
+ det -= m[3][0] * matrixDet3(m, 0, 1, 2, 1, 2, 3);
+ return det;
+}
+
+double QDoubleMatrix4x4::determinant() const
+{
+ if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity)
+ return 1.0;
+
+ if (flagBits < Rotation2D)
+ return m[0][0] * m[1][1] * m[2][2]; // Translation | Scale
+ if (flagBits < Perspective)
+ return matrixDet3(m, 0, 1, 2, 0, 1, 2);
+ return matrixDet4(m);
+}
+
+QDoubleMatrix4x4 QDoubleMatrix4x4::inverted(bool *invertible) const
+{
+ // Handle some of the easy cases first.
+ if (flagBits == Identity) {
+ if (invertible)
+ *invertible = true;
+ return QDoubleMatrix4x4();
+ } else if (flagBits == Translation) {
+ QDoubleMatrix4x4 inv;
+ inv.m[3][0] = -m[3][0];
+ inv.m[3][1] = -m[3][1];
+ inv.m[3][2] = -m[3][2];
+ inv.flagBits = Translation;
+ if (invertible)
+ *invertible = true;
+ return inv;
+ } else if (flagBits < Rotation2D) {
+ // Translation | Scale
+ if (m[0][0] == 0 || m[1][1] == 0 || m[2][2] == 0) {
+ if (invertible)
+ *invertible = false;
+ return QDoubleMatrix4x4();
+ }
+ QDoubleMatrix4x4 inv;
+ inv.m[0][0] = 1.0 / m[0][0];
+ inv.m[1][1] = 1.0 / m[1][1];
+ inv.m[2][2] = 1.0 / m[2][2];
+ inv.m[3][0] = -m[3][0] * inv.m[0][0];
+ inv.m[3][1] = -m[3][1] * inv.m[1][1];
+ inv.m[3][2] = -m[3][2] * inv.m[2][2];
+ inv.flagBits = flagBits;
+
+ if (invertible)
+ *invertible = true;
+ return inv;
+ } else if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) {
+ if (invertible)
+ *invertible = true;
+ return orthonormalInverse();
+ } else if (flagBits < Perspective) {
+ QDoubleMatrix4x4 inv(1); // The "1" says to not load the identity.
+
+ double det = matrixDet3(m, 0, 1, 2, 0, 1, 2);
+ if (det == 0.0) {
+ if (invertible)
+ *invertible = false;
+ return QDoubleMatrix4x4();
+ }
+ det = 1.0 / det;
+
+ inv.m[0][0] = matrixDet2(m, 1, 2, 1, 2) * det;
+ inv.m[0][1] = -matrixDet2(m, 0, 2, 1, 2) * det;
+ inv.m[0][2] = matrixDet2(m, 0, 1, 1, 2) * det;
+ inv.m[0][3] = 0;
+ inv.m[1][0] = -matrixDet2(m, 1, 2, 0, 2) * det;
+ inv.m[1][1] = matrixDet2(m, 0, 2, 0, 2) * det;
+ inv.m[1][2] = -matrixDet2(m, 0, 1, 0, 2) * det;
+ inv.m[1][3] = 0;
+ inv.m[2][0] = matrixDet2(m, 1, 2, 0, 1) * det;
+ inv.m[2][1] = -matrixDet2(m, 0, 2, 0, 1) * det;
+ inv.m[2][2] = matrixDet2(m, 0, 1, 0, 1) * det;
+ inv.m[2][3] = 0;
+ inv.m[3][0] = -inv.m[0][0] * m[3][0] - inv.m[1][0] * m[3][1] - inv.m[2][0] * m[3][2];
+ inv.m[3][1] = -inv.m[0][1] * m[3][0] - inv.m[1][1] * m[3][1] - inv.m[2][1] * m[3][2];
+ inv.m[3][2] = -inv.m[0][2] * m[3][0] - inv.m[1][2] * m[3][1] - inv.m[2][2] * m[3][2];
+ inv.m[3][3] = 1;
+ inv.flagBits = flagBits;
+
+ if (invertible)
+ *invertible = true;
+ return inv;
+ }
+
+ QDoubleMatrix4x4 inv(1); // The "1" says to not load the identity.
+
+ double det = matrixDet4(m);
+ if (det == 0.0) {
+ if (invertible)
+ *invertible = false;
+ return QDoubleMatrix4x4();
+ }
+ det = 1.0 / det;
+
+ inv.m[0][0] = matrixDet3(m, 1, 2, 3, 1, 2, 3) * det;
+ inv.m[0][1] = -matrixDet3(m, 0, 2, 3, 1, 2, 3) * det;
+ inv.m[0][2] = matrixDet3(m, 0, 1, 3, 1, 2, 3) * det;
+ inv.m[0][3] = -matrixDet3(m, 0, 1, 2, 1, 2, 3) * det;
+ inv.m[1][0] = -matrixDet3(m, 1, 2, 3, 0, 2, 3) * det;
+ inv.m[1][1] = matrixDet3(m, 0, 2, 3, 0, 2, 3) * det;
+ inv.m[1][2] = -matrixDet3(m, 0, 1, 3, 0, 2, 3) * det;
+ inv.m[1][3] = matrixDet3(m, 0, 1, 2, 0, 2, 3) * det;
+ inv.m[2][0] = matrixDet3(m, 1, 2, 3, 0, 1, 3) * det;
+ inv.m[2][1] = -matrixDet3(m, 0, 2, 3, 0, 1, 3) * det;
+ inv.m[2][2] = matrixDet3(m, 0, 1, 3, 0, 1, 3) * det;
+ inv.m[2][3] = -matrixDet3(m, 0, 1, 2, 0, 1, 3) * det;
+ inv.m[3][0] = -matrixDet3(m, 1, 2, 3, 0, 1, 2) * det;
+ inv.m[3][1] = matrixDet3(m, 0, 2, 3, 0, 1, 2) * det;
+ inv.m[3][2] = -matrixDet3(m, 0, 1, 3, 0, 1, 2) * det;
+ inv.m[3][3] = matrixDet3(m, 0, 1, 2, 0, 1, 2) * det;
+ inv.flagBits = flagBits;
+
+ if (invertible)
+ *invertible = true;
+ return inv;
+}
+
+QDoubleMatrix4x4 QDoubleMatrix4x4::transposed() const
+{
+ QDoubleMatrix4x4 result(1); // The "1" says to not load the identity.
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ result.m[col][row] = m[row][col];
+ }
+ }
+ // When a translation is transposed, it becomes a perspective transformation.
+ result.flagBits = (flagBits & Translation ? General : flagBits);
+ return result;
+}
+
+QDoubleMatrix4x4& QDoubleMatrix4x4::operator/=(double divisor)
+{
+ m[0][0] /= divisor;
+ m[0][1] /= divisor;
+ m[0][2] /= divisor;
+ m[0][3] /= divisor;
+ m[1][0] /= divisor;
+ m[1][1] /= divisor;
+ m[1][2] /= divisor;
+ m[1][3] /= divisor;
+ m[2][0] /= divisor;
+ m[2][1] /= divisor;
+ m[2][2] /= divisor;
+ m[2][3] /= divisor;
+ m[3][0] /= divisor;
+ m[3][1] /= divisor;
+ m[3][2] /= divisor;
+ m[3][3] /= divisor;
+ flagBits = General;
+ return *this;
+}
+
+QDoubleMatrix4x4 operator/(const QDoubleMatrix4x4& matrix, double divisor)
+{
+ QDoubleMatrix4x4 m(1); // The "1" says to not load the identity.
+ m.m[0][0] = matrix.m[0][0] / divisor;
+ m.m[0][1] = matrix.m[0][1] / divisor;
+ m.m[0][2] = matrix.m[0][2] / divisor;
+ m.m[0][3] = matrix.m[0][3] / divisor;
+ m.m[1][0] = matrix.m[1][0] / divisor;
+ m.m[1][1] = matrix.m[1][1] / divisor;
+ m.m[1][2] = matrix.m[1][2] / divisor;
+ m.m[1][3] = matrix.m[1][3] / divisor;
+ m.m[2][0] = matrix.m[2][0] / divisor;
+ m.m[2][1] = matrix.m[2][1] / divisor;
+ m.m[2][2] = matrix.m[2][2] / divisor;
+ m.m[2][3] = matrix.m[2][3] / divisor;
+ m.m[3][0] = matrix.m[3][0] / divisor;
+ m.m[3][1] = matrix.m[3][1] / divisor;
+ m.m[3][2] = matrix.m[3][2] / divisor;
+ m.m[3][3] = matrix.m[3][3] / divisor;
+ m.flagBits = QDoubleMatrix4x4::General;
+ return m;
+}
+
+void QDoubleMatrix4x4::scale(const QDoubleVector3D& vector)
+{
+ double vx = vector.x();
+ double vy = vector.y();
+ double vz = vector.z();
+ if (flagBits < Scale) {
+ m[0][0] = vx;
+ m[1][1] = vy;
+ m[2][2] = vz;
+ } else if (flagBits < Rotation2D) {
+ m[0][0] *= vx;
+ m[1][1] *= vy;
+ m[2][2] *= vz;
+ } else if (flagBits < Rotation) {
+ m[0][0] *= vx;
+ m[0][1] *= vx;
+ m[1][0] *= vy;
+ m[1][1] *= vy;
+ m[2][2] *= vz;
+ } else {
+ m[0][0] *= vx;
+ m[0][1] *= vx;
+ m[0][2] *= vx;
+ m[0][3] *= vx;
+ m[1][0] *= vy;
+ m[1][1] *= vy;
+ m[1][2] *= vy;
+ m[1][3] *= vy;
+ m[2][0] *= vz;
+ m[2][1] *= vz;
+ m[2][2] *= vz;
+ m[2][3] *= vz;
+ }
+ flagBits |= Scale;
+}
+
+void QDoubleMatrix4x4::scale(double x, double y)
+{
+ if (flagBits < Scale) {
+ m[0][0] = x;
+ m[1][1] = y;
+ } else if (flagBits < Rotation2D) {
+ m[0][0] *= x;
+ m[1][1] *= y;
+ } else if (flagBits < Rotation) {
+ m[0][0] *= x;
+ m[0][1] *= x;
+ m[1][0] *= y;
+ m[1][1] *= y;
+ } else {
+ m[0][0] *= x;
+ m[0][1] *= x;
+ m[0][2] *= x;
+ m[0][3] *= x;
+ m[1][0] *= y;
+ m[1][1] *= y;
+ m[1][2] *= y;
+ m[1][3] *= y;
+ }
+ flagBits |= Scale;
+}
+
+void QDoubleMatrix4x4::scale(double x, double y, double z)
+{
+ if (flagBits < Scale) {
+ m[0][0] = x;
+ m[1][1] = y;
+ m[2][2] = z;
+ } else if (flagBits < Rotation2D) {
+ m[0][0] *= x;
+ m[1][1] *= y;
+ m[2][2] *= z;
+ } else if (flagBits < Rotation) {
+ m[0][0] *= x;
+ m[0][1] *= x;
+ m[1][0] *= y;
+ m[1][1] *= y;
+ m[2][2] *= z;
+ } else {
+ m[0][0] *= x;
+ m[0][1] *= x;
+ m[0][2] *= x;
+ m[0][3] *= x;
+ m[1][0] *= y;
+ m[1][1] *= y;
+ m[1][2] *= y;
+ m[1][3] *= y;
+ m[2][0] *= z;
+ m[2][1] *= z;
+ m[2][2] *= z;
+ m[2][3] *= z;
+ }
+ flagBits |= Scale;
+}
+
+void QDoubleMatrix4x4::scale(double factor)
+{
+ if (flagBits < Scale) {
+ m[0][0] = factor;
+ m[1][1] = factor;
+ m[2][2] = factor;
+ } else if (flagBits < Rotation2D) {
+ m[0][0] *= factor;
+ m[1][1] *= factor;
+ m[2][2] *= factor;
+ } else if (flagBits < Rotation) {
+ m[0][0] *= factor;
+ m[0][1] *= factor;
+ m[1][0] *= factor;
+ m[1][1] *= factor;
+ m[2][2] *= factor;
+ } else {
+ m[0][0] *= factor;
+ m[0][1] *= factor;
+ m[0][2] *= factor;
+ m[0][3] *= factor;
+ m[1][0] *= factor;
+ m[1][1] *= factor;
+ m[1][2] *= factor;
+ m[1][3] *= factor;
+ m[2][0] *= factor;
+ m[2][1] *= factor;
+ m[2][2] *= factor;
+ m[2][3] *= factor;
+ }
+ flagBits |= Scale;
+}
+
+void QDoubleMatrix4x4::translate(const QDoubleVector3D& vector)
+{
+ double vx = vector.x();
+ double vy = vector.y();
+ double vz = vector.z();
+ if (flagBits == Identity) {
+ m[3][0] = vx;
+ m[3][1] = vy;
+ m[3][2] = vz;
+ } else if (flagBits == Translation) {
+ m[3][0] += vx;
+ m[3][1] += vy;
+ m[3][2] += vz;
+ } else if (flagBits == Scale) {
+ m[3][0] = m[0][0] * vx;
+ m[3][1] = m[1][1] * vy;
+ m[3][2] = m[2][2] * vz;
+ } else if (flagBits == (Translation | Scale)) {
+ m[3][0] += m[0][0] * vx;
+ m[3][1] += m[1][1] * vy;
+ m[3][2] += m[2][2] * vz;
+ } else if (flagBits < Rotation) {
+ m[3][0] += m[0][0] * vx + m[1][0] * vy;
+ m[3][1] += m[0][1] * vx + m[1][1] * vy;
+ m[3][2] += m[2][2] * vz;
+ } else {
+ m[3][0] += m[0][0] * vx + m[1][0] * vy + m[2][0] * vz;
+ m[3][1] += m[0][1] * vx + m[1][1] * vy + m[2][1] * vz;
+ m[3][2] += m[0][2] * vx + m[1][2] * vy + m[2][2] * vz;
+ m[3][3] += m[0][3] * vx + m[1][3] * vy + m[2][3] * vz;
+ }
+ flagBits |= Translation;
+}
+
+void QDoubleMatrix4x4::translate(double x, double y)
+{
+ if (flagBits == Identity) {
+ m[3][0] = x;
+ m[3][1] = y;
+ } else if (flagBits == Translation) {
+ m[3][0] += x;
+ m[3][1] += y;
+ } else if (flagBits == Scale) {
+ m[3][0] = m[0][0] * x;
+ m[3][1] = m[1][1] * y;
+ } else if (flagBits == (Translation | Scale)) {
+ m[3][0] += m[0][0] * x;
+ m[3][1] += m[1][1] * y;
+ } else if (flagBits < Rotation) {
+ m[3][0] += m[0][0] * x + m[1][0] * y;
+ m[3][1] += m[0][1] * x + m[1][1] * y;
+ } else {
+ m[3][0] += m[0][0] * x + m[1][0] * y;
+ m[3][1] += m[0][1] * x + m[1][1] * y;
+ m[3][2] += m[0][2] * x + m[1][2] * y;
+ m[3][3] += m[0][3] * x + m[1][3] * y;
+ }
+ flagBits |= Translation;
+}
+
+void QDoubleMatrix4x4::translate(double x, double y, double z)
+{
+ if (flagBits == Identity) {
+ m[3][0] = x;
+ m[3][1] = y;
+ m[3][2] = z;
+ } else if (flagBits == Translation) {
+ m[3][0] += x;
+ m[3][1] += y;
+ m[3][2] += z;
+ } else if (flagBits == Scale) {
+ m[3][0] = m[0][0] * x;
+ m[3][1] = m[1][1] * y;
+ m[3][2] = m[2][2] * z;
+ } else if (flagBits == (Translation | Scale)) {
+ m[3][0] += m[0][0] * x;
+ m[3][1] += m[1][1] * y;
+ m[3][2] += m[2][2] * z;
+ } else if (flagBits < Rotation) {
+ m[3][0] += m[0][0] * x + m[1][0] * y;
+ m[3][1] += m[0][1] * x + m[1][1] * y;
+ m[3][2] += m[2][2] * z;
+ } else {
+ m[3][0] += m[0][0] * x + m[1][0] * y + m[2][0] * z;
+ m[3][1] += m[0][1] * x + m[1][1] * y + m[2][1] * z;
+ m[3][2] += m[0][2] * x + m[1][2] * y + m[2][2] * z;
+ m[3][3] += m[0][3] * x + m[1][3] * y + m[2][3] * z;
+ }
+ flagBits |= Translation;
+}
+
+void QDoubleMatrix4x4::rotate(double angle, const QDoubleVector3D& vector)
+{
+ rotate(angle, vector.x(), vector.y(), vector.z());
+}
+
+void QDoubleMatrix4x4::rotate(double angle, double x, double y, double z)
+{
+ if (angle == 0.0)
+ return;
+ double c, s;
+ if (angle == 90.0 || angle == -270.0) {
+ s = 1.0;
+ c = 0.0;
+ } else if (angle == -90.0 || angle == 270.0) {
+ s = -1.0;
+ c = 0.0;
+ } else if (angle == 180.0 || angle == -180.0) {
+ s = 0.0;
+ c = -1.0;
+ } else {
+ double a = angle * M_PI / 180.0;
+ c = std::cos(a);
+ s = std::sin(a);
+ }
+ if (x == 0.0) {
+ if (y == 0.0) {
+ if (z != 0.0) {
+ // Rotate around the Z axis.
+ if (z < 0)
+ s = -s;
+ double tmp;
+ m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s;
+ m[1][0] = m[1][0] * c - tmp * s;
+ m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s;
+ m[1][1] = m[1][1] * c - tmp * s;
+ m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s;
+ m[1][2] = m[1][2] * c - tmp * s;
+ m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
+ m[1][3] = m[1][3] * c - tmp * s;
+
+ flagBits |= Rotation2D;
+ return;
+ }
+ } else if (z == 0.0) {
+ // Rotate around the Y axis.
+ if (y < 0)
+ s = -s;
+ double tmp;
+ m[2][0] = (tmp = m[2][0]) * c + m[0][0] * s;
+ m[0][0] = m[0][0] * c - tmp * s;
+ m[2][1] = (tmp = m[2][1]) * c + m[0][1] * s;
+ m[0][1] = m[0][1] * c - tmp * s;
+ m[2][2] = (tmp = m[2][2]) * c + m[0][2] * s;
+ m[0][2] = m[0][2] * c - tmp * s;
+ m[2][3] = (tmp = m[2][3]) * c + m[0][3] * s;
+ m[0][3] = m[0][3] * c - tmp * s;
+
+ flagBits |= Rotation;
+ return;
+ }
+ } else if (y == 0.0 && z == 0.0) {
+ // Rotate around the X axis.
+ if (x < 0)
+ s = -s;
+ double tmp;
+ m[1][0] = (tmp = m[1][0]) * c + m[2][0] * s;
+ m[2][0] = m[2][0] * c - tmp * s;
+ m[1][1] = (tmp = m[1][1]) * c + m[2][1] * s;
+ m[2][1] = m[2][1] * c - tmp * s;
+ m[1][2] = (tmp = m[1][2]) * c + m[2][2] * s;
+ m[2][2] = m[2][2] * c - tmp * s;
+ m[1][3] = (tmp = m[1][3]) * c + m[2][3] * s;
+ m[2][3] = m[2][3] * c - tmp * s;
+
+ flagBits |= Rotation;
+ return;
+ }
+
+ double len = double(x) * double(x) +
+ double(y) * double(y) +
+ double(z) * double(z);
+ if (!qFuzzyCompare(len, 1.0) && !qFuzzyIsNull(len)) {
+ len = std::sqrt(len);
+ x = double(double(x) / len);
+ y = double(double(y) / len);
+ z = double(double(z) / len);
+ }
+ double ic = 1.0 - c;
+ QDoubleMatrix4x4 rot(1); // The "1" says to not load the identity.
+ rot.m[0][0] = x * x * ic + c;
+ rot.m[1][0] = x * y * ic - z * s;
+ rot.m[2][0] = x * z * ic + y * s;
+ rot.m[3][0] = 0.0;
+ rot.m[0][1] = y * x * ic + z * s;
+ rot.m[1][1] = y * y * ic + c;
+ rot.m[2][1] = y * z * ic - x * s;
+ rot.m[3][1] = 0.0;
+ rot.m[0][2] = x * z * ic - y * s;
+ rot.m[1][2] = y * z * ic + x * s;
+ rot.m[2][2] = z * z * ic + c;
+ rot.m[3][2] = 0.0;
+ rot.m[0][3] = 0.0;
+ rot.m[1][3] = 0.0;
+ rot.m[2][3] = 0.0;
+ rot.m[3][3] = 1.0;
+ rot.flagBits = Rotation;
+ *this *= rot;
+}
+
+void QDoubleMatrix4x4::projectedRotate(double angle, double x, double y, double z)
+{
+ // Used by QGraphicsRotation::applyTo() to perform a rotation
+ // and projection back to 2D in a single step.
+ if (angle == 0.0)
+ return;
+ double c, s;
+ if (angle == 90.0 || angle == -270.0) {
+ s = 1.0;
+ c = 0.0;
+ } else if (angle == -90.0 || angle == 270.0) {
+ s = -1.0;
+ c = 0.0;
+ } else if (angle == 180.0 || angle == -180.0) {
+ s = 0.0;
+ c = -1.0;
+ } else {
+ double a = angle * M_PI / 180.0;
+ c = std::cos(a);
+ s = std::sin(a);
+ }
+ if (x == 0.0) {
+ if (y == 0.0) {
+ if (z != 0.0) {
+ // Rotate around the Z axis.
+ if (z < 0)
+ s = -s;
+ double tmp;
+ m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s;
+ m[1][0] = m[1][0] * c - tmp * s;
+ m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s;
+ m[1][1] = m[1][1] * c - tmp * s;
+ m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s;
+ m[1][2] = m[1][2] * c - tmp * s;
+ m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
+ m[1][3] = m[1][3] * c - tmp * s;
+
+ flagBits |= Rotation2D;
+ return;
+ }
+ } else if (z == 0.0) {
+ // Rotate around the Y axis.
+ if (y < 0)
+ s = -s;
+ m[0][0] = m[0][0] * c + m[3][0] * s * inv_dist_to_plane;
+ m[0][1] = m[0][1] * c + m[3][1] * s * inv_dist_to_plane;
+ m[0][2] = m[0][2] * c + m[3][2] * s * inv_dist_to_plane;
+ m[0][3] = m[0][3] * c + m[3][3] * s * inv_dist_to_plane;
+ flagBits = General;
+ return;
+ }
+ } else if (y == 0.0 && z == 0.0) {
+ // Rotate around the X axis.
+ if (x < 0)
+ s = -s;
+ m[1][0] = m[1][0] * c - m[3][0] * s * inv_dist_to_plane;
+ m[1][1] = m[1][1] * c - m[3][1] * s * inv_dist_to_plane;
+ m[1][2] = m[1][2] * c - m[3][2] * s * inv_dist_to_plane;
+ m[1][3] = m[1][3] * c - m[3][3] * s * inv_dist_to_plane;
+ flagBits = General;
+ return;
+ }
+ double len = double(x) * double(x) +
+ double(y) * double(y) +
+ double(z) * double(z);
+ if (!qFuzzyCompare(len, 1.0) && !qFuzzyIsNull(len)) {
+ len = std::sqrt(len);
+ x = double(double(x) / len);
+ y = double(double(y) / len);
+ z = double(double(z) / len);
+ }
+ double ic = 1.0 - c;
+ QDoubleMatrix4x4 rot(1); // The "1" says to not load the identity.
+ rot.m[0][0] = x * x * ic + c;
+ rot.m[1][0] = x * y * ic - z * s;
+ rot.m[2][0] = 0.0;
+ rot.m[3][0] = 0.0;
+ rot.m[0][1] = y * x * ic + z * s;
+ rot.m[1][1] = y * y * ic + c;
+ rot.m[2][1] = 0.0;
+ rot.m[3][1] = 0.0;
+ rot.m[0][2] = 0.0;
+ rot.m[1][2] = 0.0;
+ rot.m[2][2] = 1.0;
+ rot.m[3][2] = 0.0;
+ rot.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane;
+ rot.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane;
+ rot.m[2][3] = 0.0;
+ rot.m[3][3] = 1.0;
+ rot.flagBits = General;
+ *this *= rot;
+}
+
+void QDoubleMatrix4x4::ortho(const QRect& rect)
+{
+ // Note: rect.right() and rect.bottom() subtract 1 in QRect,
+ // which gives the location of a pixel within the rectangle,
+ // instead of the extent of the rectangle. We want the extent.
+ // QRectF expresses the extent properly.
+ ortho(rect.x(), rect.x() + rect.width(), rect.y() + rect.height(), rect.y(), -1.0, 1.0);
+}
+
+void QDoubleMatrix4x4::ortho(const QRectF& rect)
+{
+ ortho(rect.left(), rect.right(), rect.bottom(), rect.top(), -1.0, 1.0);
+}
+
+void QDoubleMatrix4x4::ortho(double left, double right, double bottom, double top, double nearPlane, double farPlane)
+{
+ // Bail out if the projection volume is zero-sized.
+ if (left == right || bottom == top || nearPlane == farPlane)
+ return;
+
+ // Construct the projection.
+ double width = right - left;
+ double invheight = top - bottom;
+ double clip = farPlane - nearPlane;
+ QDoubleMatrix4x4 m(1);
+ m.m[0][0] = 2.0 / width;
+ m.m[1][0] = 0.0;
+ m.m[2][0] = 0.0;
+ m.m[3][0] = -(left + right) / width;
+ m.m[0][1] = 0.0;
+ m.m[1][1] = 2.0 / invheight;
+ m.m[2][1] = 0.0;
+ m.m[3][1] = -(top + bottom) / invheight;
+ m.m[0][2] = 0.0;
+ m.m[1][2] = 0.0;
+ m.m[2][2] = -2.0 / clip;
+ m.m[3][2] = -(nearPlane + farPlane) / clip;
+ m.m[0][3] = 0.0;
+ m.m[1][3] = 0.0;
+ m.m[2][3] = 0.0;
+ m.m[3][3] = 1.0;
+ m.flagBits = Translation | Scale;
+
+ // Apply the projection.
+ *this *= m;
+}
+
+void QDoubleMatrix4x4::frustum(double left, double right, double bottom, double top, double nearPlane, double farPlane)
+{
+ // Bail out if the projection volume is zero-sized.
+ if (left == right || bottom == top || nearPlane == farPlane)
+ return;
+
+ // Construct the projection.
+ QDoubleMatrix4x4 m(1);
+ double width = right - left;
+ double invheight = top - bottom;
+ double clip = farPlane - nearPlane;
+ m.m[0][0] = 2.0 * nearPlane / width;
+ m.m[1][0] = 0.0;
+ m.m[2][0] = (left + right) / width;
+ m.m[3][0] = 0.0;
+ m.m[0][1] = 0.0;
+ m.m[1][1] = 2.0 * nearPlane / invheight;
+ m.m[2][1] = (top + bottom) / invheight;
+ m.m[3][1] = 0.0;
+ m.m[0][2] = 0.0;
+ m.m[1][2] = 0.0;
+ m.m[2][2] = -(nearPlane + farPlane) / clip;
+ m.m[3][2] = -2.0 * nearPlane * farPlane / clip;
+ m.m[0][3] = 0.0;
+ m.m[1][3] = 0.0;
+ m.m[2][3] = -1.0;
+ m.m[3][3] = 0.0;
+ m.flagBits = General;
+
+ // Apply the projection.
+ *this *= m;
+}
+
+void QDoubleMatrix4x4::perspective(double verticalAngle, double aspectRatio, double nearPlane, double farPlane)
+{
+ // Bail out if the projection volume is zero-sized.
+ if (nearPlane == farPlane || aspectRatio == 0.0)
+ return;
+
+ // Construct the projection.
+ QDoubleMatrix4x4 m(1);
+ double radians = (verticalAngle / 2.0) * M_PI / 180.0;
+ double sine = std::sin(radians);
+ if (sine == 0.0)
+ return;
+ double cotan = std::cos(radians) / sine;
+ double clip = farPlane - nearPlane;
+ m.m[0][0] = cotan / aspectRatio;
+ m.m[1][0] = 0.0;
+ m.m[2][0] = 0.0;
+ m.m[3][0] = 0.0;
+ m.m[0][1] = 0.0;
+ m.m[1][1] = cotan;
+ m.m[2][1] = 0.0;
+ m.m[3][1] = 0.0;
+ m.m[0][2] = 0.0;
+ m.m[1][2] = 0.0;
+ m.m[2][2] = -(nearPlane + farPlane) / clip;
+ m.m[3][2] = -(2.0 * nearPlane * farPlane) / clip;
+ m.m[0][3] = 0.0;
+ m.m[1][3] = 0.0;
+ m.m[2][3] = -1.0;
+ m.m[3][3] = 0.0;
+ m.flagBits = General;
+
+ // Apply the projection.
+ *this *= m;
+}
+
+void QDoubleMatrix4x4::lookAt(const QDoubleVector3D& eye, const QDoubleVector3D& center, const QDoubleVector3D& up)
+{
+ QDoubleVector3D forward = center - eye;
+ if (qFuzzyIsNull(forward.x()) && qFuzzyIsNull(forward.y()) && qFuzzyIsNull(forward.z()))
+ return;
+
+ forward.normalize();
+ QDoubleVector3D side = QDoubleVector3D::crossProduct(forward, up).normalized();
+ QDoubleVector3D upVector = QDoubleVector3D::crossProduct(side, forward);
+
+ QDoubleMatrix4x4 m(1);
+ m.m[0][0] = side.x();
+ m.m[1][0] = side.y();
+ m.m[2][0] = side.z();
+ m.m[3][0] = 0.0;
+ m.m[0][1] = upVector.x();
+ m.m[1][1] = upVector.y();
+ m.m[2][1] = upVector.z();
+ m.m[3][1] = 0.0;
+ m.m[0][2] = -forward.x();
+ m.m[1][2] = -forward.y();
+ m.m[2][2] = -forward.z();
+ m.m[3][2] = 0.0;
+ m.m[0][3] = 0.0;
+ m.m[1][3] = 0.0;
+ m.m[2][3] = 0.0;
+ m.m[3][3] = 1.0;
+ m.flagBits = Rotation;
+
+ *this *= m;
+ translate(-eye);
+}
+
+void QDoubleMatrix4x4::viewport(double left, double bottom, double width, double height, double nearPlane, double farPlane)
+{
+ const double w2 = width / 2.0;
+ const double h2 = height / 2.0;
+
+ QDoubleMatrix4x4 m(1);
+ m.m[0][0] = w2;
+ m.m[1][0] = 0.0;
+ m.m[2][0] = 0.0;
+ m.m[3][0] = left + w2;
+ m.m[0][1] = 0.0;
+ m.m[1][1] = h2;
+ m.m[2][1] = 0.0;
+ m.m[3][1] = bottom + h2;
+ m.m[0][2] = 0.0;
+ m.m[1][2] = 0.0;
+ m.m[2][2] = (farPlane - nearPlane) / 2.0;
+ m.m[3][2] = (nearPlane + farPlane) / 2.0;
+ m.m[0][3] = 0.0;
+ m.m[1][3] = 0.0;
+ m.m[2][3] = 0.0;
+ m.m[3][3] = 1.0;
+ m.flagBits = General;
+
+ *this *= m;
+}
+
+void QDoubleMatrix4x4::flipCoordinates()
+{
+ // Multiplying the y and z coordinates with -1 does NOT flip between right-handed and
+ // left-handed coordinate systems, it just rotates 180 degrees around the x axis, so
+ // I'm deprecating this function.
+ if (flagBits < Rotation2D) {
+ // Translation | Scale
+ m[1][1] = -m[1][1];
+ m[2][2] = -m[2][2];
+ } else {
+ m[1][0] = -m[1][0];
+ m[1][1] = -m[1][1];
+ m[1][2] = -m[1][2];
+ m[1][3] = -m[1][3];
+ m[2][0] = -m[2][0];
+ m[2][1] = -m[2][1];
+ m[2][2] = -m[2][2];
+ m[2][3] = -m[2][3];
+ }
+ flagBits |= Scale;
+}
+
+void QDoubleMatrix4x4::copyDataTo(double *values) const
+{
+ for (int row = 0; row < 4; ++row)
+ for (int col = 0; col < 4; ++col)
+ values[row * 4 + col] = double(m[col][row]);
+}
+
+QRect QDoubleMatrix4x4::mapRect(const QRect& rect) const
+{
+ if (flagBits < Scale) {
+ // Translation
+ return QRect(qRound(rect.x() + m[3][0]),
+ qRound(rect.y() + m[3][1]),
+ rect.width(), rect.height());
+ } else if (flagBits < Rotation2D) {
+ // Translation | Scale
+ double x = rect.x() * m[0][0] + m[3][0];
+ double y = rect.y() * m[1][1] + m[3][1];
+ double w = rect.width() * m[0][0];
+ double h = rect.height() * m[1][1];
+ if (w < 0) {
+ w = -w;
+ x -= w;
+ }
+ if (h < 0) {
+ h = -h;
+ y -= h;
+ }
+ return QRect(qRound(x), qRound(y), qRound(w), qRound(h));
+ }
+
+ QPoint tl = map(rect.topLeft());
+ QPoint tr = map(QPoint(rect.x() + rect.width(), rect.y()));
+ QPoint bl = map(QPoint(rect.x(), rect.y() + rect.height()));
+ QPoint br = map(QPoint(rect.x() + rect.width(),
+ rect.y() + rect.height()));
+
+ int xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x()));
+ int xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x()));
+ int ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y()));
+ int ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y()));
+
+ return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
+}
+
+QRectF QDoubleMatrix4x4::mapRect(const QRectF& rect) const
+{
+ if (flagBits < Scale) {
+ // Translation
+ return rect.translated(m[3][0], m[3][1]);
+ } else if (flagBits < Rotation2D) {
+ // Translation | Scale
+ double x = rect.x() * m[0][0] + m[3][0];
+ double y = rect.y() * m[1][1] + m[3][1];
+ double w = rect.width() * m[0][0];
+ double h = rect.height() * m[1][1];
+ if (w < 0) {
+ w = -w;
+ x -= w;
+ }
+ if (h < 0) {
+ h = -h;
+ y -= h;
+ }
+ return QRectF(x, y, w, h);
+ }
+
+ QPointF tl = map(rect.topLeft()); QPointF tr = map(rect.topRight());
+ QPointF bl = map(rect.bottomLeft()); QPointF br = map(rect.bottomRight());
+
+ double xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x()));
+ double xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x()));
+ double ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y()));
+ double ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y()));
+
+ return QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
+}
+
+QDoubleMatrix4x4 QDoubleMatrix4x4::orthonormalInverse() const
+{
+ QDoubleMatrix4x4 result(1); // The '1' says not to load identity
+
+ result.m[0][0] = m[0][0];
+ result.m[1][0] = m[0][1];
+ result.m[2][0] = m[0][2];
+
+ result.m[0][1] = m[1][0];
+ result.m[1][1] = m[1][1];
+ result.m[2][1] = m[1][2];
+
+ result.m[0][2] = m[2][0];
+ result.m[1][2] = m[2][1];
+ result.m[2][2] = m[2][2];
+
+ result.m[0][3] = 0.0;
+ result.m[1][3] = 0.0;
+ result.m[2][3] = 0.0;
+
+ result.m[3][0] = -(result.m[0][0] * m[3][0] + result.m[1][0] * m[3][1] + result.m[2][0] * m[3][2]);
+ result.m[3][1] = -(result.m[0][1] * m[3][0] + result.m[1][1] * m[3][1] + result.m[2][1] * m[3][2]);
+ result.m[3][2] = -(result.m[0][2] * m[3][0] + result.m[1][2] * m[3][1] + result.m[2][2] * m[3][2]);
+ result.m[3][3] = 1.0;
+
+ result.flagBits = flagBits;
+
+ return result;
+}
+
+void QDoubleMatrix4x4::optimize()
+{
+ // If the last row is not (0, 0, 0, 1), the matrix is not a special type.
+ flagBits = General;
+ if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0 || m[3][3] != 1)
+ return;
+
+ flagBits &= ~Perspective;
+
+ // If the last column is (0, 0, 0, 1), then there is no translation.
+ if (m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0)
+ flagBits &= ~Translation;
+
+ // If the two first elements of row 3 and column 3 are 0, then any rotation must be about Z.
+ if (!m[0][2] && !m[1][2] && !m[2][0] && !m[2][1]) {
+ flagBits &= ~Rotation;
+ // If the six non-diagonal elements in the top left 3x3 matrix are 0, there is no rotation.
+ if (!m[0][1] && !m[1][0]) {
+ flagBits &= ~Rotation2D;
+ // Check for identity.
+ if (m[0][0] == 1 && m[1][1] == 1 && m[2][2] == 1)
+ flagBits &= ~Scale;
+ } else {
+ // If the columns are orthonormal and form a right-handed system, then there is no scale.
+ double det = matrixDet2(m, 0, 1, 0, 1);
+ double lenX = m[0][0] * m[0][0] + m[0][1] * m[0][1];
+ double lenY = m[1][0] * m[1][0] + m[1][1] * m[1][1];
+ double lenZ = m[2][2];
+ if (qFuzzyCompare(det, 1.0) && qFuzzyCompare(lenX, 1.0)
+ && qFuzzyCompare(lenY, 1.0) && qFuzzyCompare(lenZ, 1.0))
+ {
+ flagBits &= ~Scale;
+ }
+ }
+ } else {
+ // If the columns are orthonormal and form a right-handed system, then there is no scale.
+ double det = matrixDet3(m, 0, 1, 2, 0, 1, 2);
+ double lenX = m[0][0] * m[0][0] + m[0][1] * m[0][1] + m[0][2] * m[0][2];
+ double lenY = m[1][0] * m[1][0] + m[1][1] * m[1][1] + m[1][2] * m[1][2];
+ double lenZ = m[2][0] * m[2][0] + m[2][1] * m[2][1] + m[2][2] * m[2][2];
+ if (qFuzzyCompare(det, 1.0) && qFuzzyCompare(lenX, 1.0)
+ && qFuzzyCompare(lenY, 1.0) && qFuzzyCompare(lenZ, 1.0))
+ {
+ flagBits &= ~Scale;
+ }
+ }
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QDoubleMatrix4x4 &m)
+{
+ QDebugStateSaver saver(dbg);
+ // Create a string that represents the matrix type.
+ QByteArray bits;
+ if (m.flagBits == QDoubleMatrix4x4::Identity) {
+ bits = "Identity";
+ } else if (m.flagBits == QDoubleMatrix4x4::General) {
+ bits = "General";
+ } else {
+ if ((m.flagBits & QDoubleMatrix4x4::Translation) != 0)
+ bits += "Translation,";
+ if ((m.flagBits & QDoubleMatrix4x4::Scale) != 0)
+ bits += "Scale,";
+ if ((m.flagBits & QDoubleMatrix4x4::Rotation2D) != 0)
+ bits += "Rotation2D,";
+ if ((m.flagBits & QDoubleMatrix4x4::Rotation) != 0)
+ bits += "Rotation,";
+ if ((m.flagBits & QDoubleMatrix4x4::Perspective) != 0)
+ bits += "Perspective,";
+ if (bits.size() > 0)
+ bits = bits.left(bits.size() - 1);
+ }
+
+ // Output in row-major order because it is more human-readable.
+ dbg.nospace() << "QDoubleMatrix4x4(type:" << bits.constData() << endl
+ << qSetFieldWidth(10)
+ << m(0, 0) << m(0, 1) << m(0, 2) << m(0, 3) << endl
+ << m(1, 0) << m(1, 1) << m(1, 2) << m(1, 3) << endl
+ << m(2, 0) << m(2, 1) << m(2, 2) << m(2, 3) << endl
+ << m(3, 0) << m(3, 1) << m(3, 2) << m(3, 3) << endl
+ << qSetFieldWidth(0) << ')';
+ return dbg;
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+QDataStream &operator<<(QDataStream &stream, const QDoubleMatrix4x4 &matrix)
+{
+ for (int row = 0; row < 4; ++row)
+ for (int col = 0; col < 4; ++col)
+ stream << matrix(row, col);
+ return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QDoubleMatrix4x4 &matrix)
+{
+ double x;
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ stream >> x;
+ matrix(row, col) = x;
+ }
+ }
+ matrix.optimize();
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+QT_END_NAMESPACE
diff --git a/src/positioning/qdoublematrix4x4_p.h b/src/positioning/qdoublematrix4x4_p.h
new file mode 100644
index 00000000..3ce7b312
--- /dev/null
+++ b/src/positioning/qdoublematrix4x4_p.h
@@ -0,0 +1,946 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui 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 QDOUBLEMATRIX4X4_H
+#define QDOUBLEMATRIX4X4_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtPositioning/private/qpositioningglobal_p.h>
+#include <QtPositioning/private/qdoublevector3d_p.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/QRectF>
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ * This class is a copy/paste/replace of QMatrix4x4
+ * No algorithm has been changed.
+ * Some methods have been removed.
+ */
+
+class Q_POSITIONING_PRIVATE_EXPORT QDoubleMatrix4x4
+{
+public:
+ inline QDoubleMatrix4x4() { setToIdentity(); }
+ explicit QDoubleMatrix4x4(Qt::Initialization) : flagBits(General) {}
+ explicit QDoubleMatrix4x4(const double *values);
+ inline QDoubleMatrix4x4(double m11, double m12, double m13, double m14,
+ double m21, double m22, double m23, double m24,
+ double m31, double m32, double m33, double m34,
+ double m41, double m42, double m43, double m44);
+
+ QDoubleMatrix4x4(const double *values, int cols, int rows);
+
+ inline const double& operator()(int row, int column) const;
+ inline double& operator()(int row, int column);
+
+ inline bool isAffine() const;
+
+ inline bool isIdentity() const;
+ inline void setToIdentity();
+
+ inline void fill(double value);
+
+ double determinant() const;
+ QDoubleMatrix4x4 inverted(bool *invertible = Q_NULLPTR) const;
+ QDoubleMatrix4x4 transposed() const;
+
+ inline QDoubleMatrix4x4& operator+=(const QDoubleMatrix4x4& other);
+ inline QDoubleMatrix4x4& operator-=(const QDoubleMatrix4x4& other);
+ inline QDoubleMatrix4x4& operator*=(const QDoubleMatrix4x4& other);
+ inline QDoubleMatrix4x4& operator*=(double factor);
+ QDoubleMatrix4x4& operator/=(double divisor);
+ inline bool operator==(const QDoubleMatrix4x4& other) const;
+ inline bool operator!=(const QDoubleMatrix4x4& other) const;
+
+ friend QDoubleMatrix4x4 operator+(const QDoubleMatrix4x4& m1, const QDoubleMatrix4x4& m2);
+ friend QDoubleMatrix4x4 operator-(const QDoubleMatrix4x4& m1, const QDoubleMatrix4x4& m2);
+ friend QDoubleMatrix4x4 operator*(const QDoubleMatrix4x4& m1, const QDoubleMatrix4x4& m2);
+
+ friend QDoubleVector3D operator*(const QDoubleMatrix4x4& matrix, const QDoubleVector3D& vector);
+ friend QDoubleVector3D operator*(const QDoubleVector3D& vector, const QDoubleMatrix4x4& matrix);
+
+ friend QPoint operator*(const QPoint& point, const QDoubleMatrix4x4& matrix);
+ friend QPointF operator*(const QPointF& point, const QDoubleMatrix4x4& matrix);
+ friend QDoubleMatrix4x4 operator-(const QDoubleMatrix4x4& matrix);
+ friend QPoint operator*(const QDoubleMatrix4x4& matrix, const QPoint& point);
+ friend QPointF operator*(const QDoubleMatrix4x4& matrix, const QPointF& point);
+ friend QDoubleMatrix4x4 operator*(double factor, const QDoubleMatrix4x4& matrix);
+ friend QDoubleMatrix4x4 operator*(const QDoubleMatrix4x4& matrix, double factor);
+ friend Q_POSITIONING_PRIVATE_EXPORT QDoubleMatrix4x4 operator/(const QDoubleMatrix4x4& matrix, double divisor);
+
+ friend inline bool qFuzzyCompare(const QDoubleMatrix4x4& m1, const QDoubleMatrix4x4& m2);
+
+
+ void scale(const QDoubleVector3D& vector);
+ void translate(const QDoubleVector3D& vector);
+ void rotate(double angle, const QDoubleVector3D& vector);
+
+ void scale(double x, double y);
+ void scale(double x, double y, double z);
+ void scale(double factor);
+ void translate(double x, double y);
+ void translate(double x, double y, double z);
+ void rotate(double angle, double x, double y, double z = 0.0f);
+
+ void ortho(const QRect& rect);
+ void ortho(const QRectF& rect);
+ void ortho(double left, double right, double bottom, double top, double nearPlane, double farPlane);
+ void frustum(double left, double right, double bottom, double top, double nearPlane, double farPlane);
+ void perspective(double verticalAngle, double aspectRatio, double nearPlane, double farPlane);
+
+ void lookAt(const QDoubleVector3D& eye, const QDoubleVector3D& center, const QDoubleVector3D& up);
+
+ void viewport(const QRectF &rect);
+ void viewport(double left, double bottom, double width, double height, double nearPlane = 0.0f, double farPlane = 1.0f);
+ void flipCoordinates();
+
+ void copyDataTo(double *values) const;
+
+ QPoint map(const QPoint& point) const;
+ QPointF map(const QPointF& point) const;
+
+ QDoubleVector3D map(const QDoubleVector3D& point) const;
+ QDoubleVector3D mapVector(const QDoubleVector3D& vector) const;
+
+ QRect mapRect(const QRect& rect) const;
+ QRectF mapRect(const QRectF& rect) const;
+
+ inline double *data();
+ inline const double *data() const { return *m; }
+ inline const double *constData() const { return *m; }
+
+ void optimize();
+
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_POSITIONING_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QDoubleMatrix4x4 &m);
+#endif
+
+private:
+ double m[4][4]; // Column-major order to match OpenGL.
+ int flagBits; // Flag bits from the enum below.
+
+ // When matrices are multiplied, the flag bits are or-ed together.
+ enum {
+ Identity = 0x0000, // Identity matrix
+ Translation = 0x0001, // Contains a translation
+ Scale = 0x0002, // Contains a scale
+ Rotation2D = 0x0004, // Contains a rotation about the Z axis
+ Rotation = 0x0008, // Contains an arbitrary rotation
+ Perspective = 0x0010, // Last row is different from (0, 0, 0, 1)
+ General = 0x001f // General matrix, unknown contents
+ };
+
+ // Construct without initializing identity matrix.
+ explicit QDoubleMatrix4x4(int) { }
+
+ QDoubleMatrix4x4 orthonormalInverse() const;
+
+ void projectedRotate(double angle, double x, double y, double z);
+};
+
+Q_DECLARE_TYPEINFO(QDoubleMatrix4x4, Q_MOVABLE_TYPE);
+
+inline QDoubleMatrix4x4::QDoubleMatrix4x4
+ (double m11, double m12, double m13, double m14,
+ double m21, double m22, double m23, double m24,
+ double m31, double m32, double m33, double m34,
+ double m41, double m42, double m43, double m44)
+{
+ m[0][0] = m11; m[0][1] = m21; m[0][2] = m31; m[0][3] = m41;
+ m[1][0] = m12; m[1][1] = m22; m[1][2] = m32; m[1][3] = m42;
+ m[2][0] = m13; m[2][1] = m23; m[2][2] = m33; m[2][3] = m43;
+ m[3][0] = m14; m[3][1] = m24; m[3][2] = m34; m[3][3] = m44;
+ flagBits = General;
+}
+
+inline const double& QDoubleMatrix4x4::operator()(int aRow, int aColumn) const
+{
+ Q_ASSERT(aRow >= 0 && aRow < 4 && aColumn >= 0 && aColumn < 4);
+ return m[aColumn][aRow];
+}
+
+inline double& QDoubleMatrix4x4::operator()(int aRow, int aColumn)
+{
+ Q_ASSERT(aRow >= 0 && aRow < 4 && aColumn >= 0 && aColumn < 4);
+ flagBits = General;
+ return m[aColumn][aRow];
+}
+
+Q_POSITIONING_PRIVATE_EXPORT QDoubleMatrix4x4 operator/(const QDoubleMatrix4x4& matrix, double divisor);
+
+inline bool QDoubleMatrix4x4::isAffine() const
+{
+ return m[0][3] == 0.0f && m[1][3] == 0.0f && m[2][3] == 0.0f && m[3][3] == 1.0f;
+}
+
+inline bool QDoubleMatrix4x4::isIdentity() const
+{
+ if (flagBits == Identity)
+ return true;
+ if (m[0][0] != 1.0f || m[0][1] != 0.0f || m[0][2] != 0.0f)
+ return false;
+ if (m[0][3] != 0.0f || m[1][0] != 0.0f || m[1][1] != 1.0f)
+ return false;
+ if (m[1][2] != 0.0f || m[1][3] != 0.0f || m[2][0] != 0.0f)
+ return false;
+ if (m[2][1] != 0.0f || m[2][2] != 1.0f || m[2][3] != 0.0f)
+ return false;
+ if (m[3][0] != 0.0f || m[3][1] != 0.0f || m[3][2] != 0.0f)
+ return false;
+ return (m[3][3] == 1.0f);
+}
+
+inline void QDoubleMatrix4x4::setToIdentity()
+{
+ m[0][0] = 1.0f;
+ m[0][1] = 0.0f;
+ m[0][2] = 0.0f;
+ m[0][3] = 0.0f;
+ m[1][0] = 0.0f;
+ m[1][1] = 1.0f;
+ m[1][2] = 0.0f;
+ m[1][3] = 0.0f;
+ m[2][0] = 0.0f;
+ m[2][1] = 0.0f;
+ m[2][2] = 1.0f;
+ m[2][3] = 0.0f;
+ m[3][0] = 0.0f;
+ m[3][1] = 0.0f;
+ m[3][2] = 0.0f;
+ m[3][3] = 1.0f;
+ flagBits = Identity;
+}
+
+inline void QDoubleMatrix4x4::fill(double value)
+{
+ m[0][0] = value;
+ m[0][1] = value;
+ m[0][2] = value;
+ m[0][3] = value;
+ m[1][0] = value;
+ m[1][1] = value;
+ m[1][2] = value;
+ m[1][3] = value;
+ m[2][0] = value;
+ m[2][1] = value;
+ m[2][2] = value;
+ m[2][3] = value;
+ m[3][0] = value;
+ m[3][1] = value;
+ m[3][2] = value;
+ m[3][3] = value;
+ flagBits = General;
+}
+
+inline QDoubleMatrix4x4& QDoubleMatrix4x4::operator+=(const QDoubleMatrix4x4& other)
+{
+ m[0][0] += other.m[0][0];
+ m[0][1] += other.m[0][1];
+ m[0][2] += other.m[0][2];
+ m[0][3] += other.m[0][3];
+ m[1][0] += other.m[1][0];
+ m[1][1] += other.m[1][1];
+ m[1][2] += other.m[1][2];
+ m[1][3] += other.m[1][3];
+ m[2][0] += other.m[2][0];
+ m[2][1] += other.m[2][1];
+ m[2][2] += other.m[2][2];
+ m[2][3] += other.m[2][3];
+ m[3][0] += other.m[3][0];
+ m[3][1] += other.m[3][1];
+ m[3][2] += other.m[3][2];
+ m[3][3] += other.m[3][3];
+ flagBits = General;
+ return *this;
+}
+
+inline QDoubleMatrix4x4& QDoubleMatrix4x4::operator-=(const QDoubleMatrix4x4& other)
+{
+ m[0][0] -= other.m[0][0];
+ m[0][1] -= other.m[0][1];
+ m[0][2] -= other.m[0][2];
+ m[0][3] -= other.m[0][3];
+ m[1][0] -= other.m[1][0];
+ m[1][1] -= other.m[1][1];
+ m[1][2] -= other.m[1][2];
+ m[1][3] -= other.m[1][3];
+ m[2][0] -= other.m[2][0];
+ m[2][1] -= other.m[2][1];
+ m[2][2] -= other.m[2][2];
+ m[2][3] -= other.m[2][3];
+ m[3][0] -= other.m[3][0];
+ m[3][1] -= other.m[3][1];
+ m[3][2] -= other.m[3][2];
+ m[3][3] -= other.m[3][3];
+ flagBits = General;
+ return *this;
+}
+
+inline QDoubleMatrix4x4& QDoubleMatrix4x4::operator*=(const QDoubleMatrix4x4& other)
+{
+ flagBits |= other.flagBits;
+
+ if (flagBits < Rotation2D) {
+ m[3][0] += m[0][0] * other.m[3][0];
+ m[3][1] += m[1][1] * other.m[3][1];
+ m[3][2] += m[2][2] * other.m[3][2];
+
+ m[0][0] *= other.m[0][0];
+ m[1][1] *= other.m[1][1];
+ m[2][2] *= other.m[2][2];
+ return *this;
+ }
+
+ double m0, m1, m2;
+ m0 = m[0][0] * other.m[0][0]
+ + m[1][0] * other.m[0][1]
+ + m[2][0] * other.m[0][2]
+ + m[3][0] * other.m[0][3];
+ m1 = m[0][0] * other.m[1][0]
+ + m[1][0] * other.m[1][1]
+ + m[2][0] * other.m[1][2]
+ + m[3][0] * other.m[1][3];
+ m2 = m[0][0] * other.m[2][0]
+ + m[1][0] * other.m[2][1]
+ + m[2][0] * other.m[2][2]
+ + m[3][0] * other.m[2][3];
+ m[3][0] = m[0][0] * other.m[3][0]
+ + m[1][0] * other.m[3][1]
+ + m[2][0] * other.m[3][2]
+ + m[3][0] * other.m[3][3];
+ m[0][0] = m0;
+ m[1][0] = m1;
+ m[2][0] = m2;
+
+ m0 = m[0][1] * other.m[0][0]
+ + m[1][1] * other.m[0][1]
+ + m[2][1] * other.m[0][2]
+ + m[3][1] * other.m[0][3];
+ m1 = m[0][1] * other.m[1][0]
+ + m[1][1] * other.m[1][1]
+ + m[2][1] * other.m[1][2]
+ + m[3][1] * other.m[1][3];
+ m2 = m[0][1] * other.m[2][0]
+ + m[1][1] * other.m[2][1]
+ + m[2][1] * other.m[2][2]
+ + m[3][1] * other.m[2][3];
+ m[3][1] = m[0][1] * other.m[3][0]
+ + m[1][1] * other.m[3][1]
+ + m[2][1] * other.m[3][2]
+ + m[3][1] * other.m[3][3];
+ m[0][1] = m0;
+ m[1][1] = m1;
+ m[2][1] = m2;
+
+ m0 = m[0][2] * other.m[0][0]
+ + m[1][2] * other.m[0][1]
+ + m[2][2] * other.m[0][2]
+ + m[3][2] * other.m[0][3];
+ m1 = m[0][2] * other.m[1][0]
+ + m[1][2] * other.m[1][1]
+ + m[2][2] * other.m[1][2]
+ + m[3][2] * other.m[1][3];
+ m2 = m[0][2] * other.m[2][0]
+ + m[1][2] * other.m[2][1]
+ + m[2][2] * other.m[2][2]
+ + m[3][2] * other.m[2][3];
+ m[3][2] = m[0][2] * other.m[3][0]
+ + m[1][2] * other.m[3][1]
+ + m[2][2] * other.m[3][2]
+ + m[3][2] * other.m[3][3];
+ m[0][2] = m0;
+ m[1][2] = m1;
+ m[2][2] = m2;
+
+ m0 = m[0][3] * other.m[0][0]
+ + m[1][3] * other.m[0][1]
+ + m[2][3] * other.m[0][2]
+ + m[3][3] * other.m[0][3];
+ m1 = m[0][3] * other.m[1][0]
+ + m[1][3] * other.m[1][1]
+ + m[2][3] * other.m[1][2]
+ + m[3][3] * other.m[1][3];
+ m2 = m[0][3] * other.m[2][0]
+ + m[1][3] * other.m[2][1]
+ + m[2][3] * other.m[2][2]
+ + m[3][3] * other.m[2][3];
+ m[3][3] = m[0][3] * other.m[3][0]
+ + m[1][3] * other.m[3][1]
+ + m[2][3] * other.m[3][2]
+ + m[3][3] * other.m[3][3];
+ m[0][3] = m0;
+ m[1][3] = m1;
+ m[2][3] = m2;
+ return *this;
+}
+
+inline QDoubleMatrix4x4& QDoubleMatrix4x4::operator*=(double factor)
+{
+ m[0][0] *= factor;
+ m[0][1] *= factor;
+ m[0][2] *= factor;
+ m[0][3] *= factor;
+ m[1][0] *= factor;
+ m[1][1] *= factor;
+ m[1][2] *= factor;
+ m[1][3] *= factor;
+ m[2][0] *= factor;
+ m[2][1] *= factor;
+ m[2][2] *= factor;
+ m[2][3] *= factor;
+ m[3][0] *= factor;
+ m[3][1] *= factor;
+ m[3][2] *= factor;
+ m[3][3] *= factor;
+ flagBits = General;
+ return *this;
+}
+
+inline bool QDoubleMatrix4x4::operator==(const QDoubleMatrix4x4& other) const
+{
+ return m[0][0] == other.m[0][0] &&
+ m[0][1] == other.m[0][1] &&
+ m[0][2] == other.m[0][2] &&
+ m[0][3] == other.m[0][3] &&
+ m[1][0] == other.m[1][0] &&
+ m[1][1] == other.m[1][1] &&
+ m[1][2] == other.m[1][2] &&
+ m[1][3] == other.m[1][3] &&
+ m[2][0] == other.m[2][0] &&
+ m[2][1] == other.m[2][1] &&
+ m[2][2] == other.m[2][2] &&
+ m[2][3] == other.m[2][3] &&
+ m[3][0] == other.m[3][0] &&
+ m[3][1] == other.m[3][1] &&
+ m[3][2] == other.m[3][2] &&
+ m[3][3] == other.m[3][3];
+}
+
+inline bool QDoubleMatrix4x4::operator!=(const QDoubleMatrix4x4& other) const
+{
+ return m[0][0] != other.m[0][0] ||
+ m[0][1] != other.m[0][1] ||
+ m[0][2] != other.m[0][2] ||
+ m[0][3] != other.m[0][3] ||
+ m[1][0] != other.m[1][0] ||
+ m[1][1] != other.m[1][1] ||
+ m[1][2] != other.m[1][2] ||
+ m[1][3] != other.m[1][3] ||
+ m[2][0] != other.m[2][0] ||
+ m[2][1] != other.m[2][1] ||
+ m[2][2] != other.m[2][2] ||
+ m[2][3] != other.m[2][3] ||
+ m[3][0] != other.m[3][0] ||
+ m[3][1] != other.m[3][1] ||
+ m[3][2] != other.m[3][2] ||
+ m[3][3] != other.m[3][3];
+}
+
+inline QDoubleMatrix4x4 operator+(const QDoubleMatrix4x4& m1, const QDoubleMatrix4x4& m2)
+{
+ QDoubleMatrix4x4 m(1);
+ m.m[0][0] = m1.m[0][0] + m2.m[0][0];
+ m.m[0][1] = m1.m[0][1] + m2.m[0][1];
+ m.m[0][2] = m1.m[0][2] + m2.m[0][2];
+ m.m[0][3] = m1.m[0][3] + m2.m[0][3];
+ m.m[1][0] = m1.m[1][0] + m2.m[1][0];
+ m.m[1][1] = m1.m[1][1] + m2.m[1][1];
+ m.m[1][2] = m1.m[1][2] + m2.m[1][2];
+ m.m[1][3] = m1.m[1][3] + m2.m[1][3];
+ m.m[2][0] = m1.m[2][0] + m2.m[2][0];
+ m.m[2][1] = m1.m[2][1] + m2.m[2][1];
+ m.m[2][2] = m1.m[2][2] + m2.m[2][2];
+ m.m[2][3] = m1.m[2][3] + m2.m[2][3];
+ m.m[3][0] = m1.m[3][0] + m2.m[3][0];
+ m.m[3][1] = m1.m[3][1] + m2.m[3][1];
+ m.m[3][2] = m1.m[3][2] + m2.m[3][2];
+ m.m[3][3] = m1.m[3][3] + m2.m[3][3];
+ m.flagBits = QDoubleMatrix4x4::General;
+ return m;
+}
+
+inline QDoubleMatrix4x4 operator-(const QDoubleMatrix4x4& m1, const QDoubleMatrix4x4& m2)
+{
+ QDoubleMatrix4x4 m(1);
+ m.m[0][0] = m1.m[0][0] - m2.m[0][0];
+ m.m[0][1] = m1.m[0][1] - m2.m[0][1];
+ m.m[0][2] = m1.m[0][2] - m2.m[0][2];
+ m.m[0][3] = m1.m[0][3] - m2.m[0][3];
+ m.m[1][0] = m1.m[1][0] - m2.m[1][0];
+ m.m[1][1] = m1.m[1][1] - m2.m[1][1];
+ m.m[1][2] = m1.m[1][2] - m2.m[1][2];
+ m.m[1][3] = m1.m[1][3] - m2.m[1][3];
+ m.m[2][0] = m1.m[2][0] - m2.m[2][0];
+ m.m[2][1] = m1.m[2][1] - m2.m[2][1];
+ m.m[2][2] = m1.m[2][2] - m2.m[2][2];
+ m.m[2][3] = m1.m[2][3] - m2.m[2][3];
+ m.m[3][0] = m1.m[3][0] - m2.m[3][0];
+ m.m[3][1] = m1.m[3][1] - m2.m[3][1];
+ m.m[3][2] = m1.m[3][2] - m2.m[3][2];
+ m.m[3][3] = m1.m[3][3] - m2.m[3][3];
+ m.flagBits = QDoubleMatrix4x4::General;
+ return m;
+}
+
+inline QDoubleMatrix4x4 operator*(const QDoubleMatrix4x4& m1, const QDoubleMatrix4x4& m2)
+{
+ int flagBits = m1.flagBits | m2.flagBits;
+ if (flagBits < QDoubleMatrix4x4::Rotation2D) {
+ QDoubleMatrix4x4 m = m1;
+ m.m[3][0] += m.m[0][0] * m2.m[3][0];
+ m.m[3][1] += m.m[1][1] * m2.m[3][1];
+ m.m[3][2] += m.m[2][2] * m2.m[3][2];
+
+ m.m[0][0] *= m2.m[0][0];
+ m.m[1][1] *= m2.m[1][1];
+ m.m[2][2] *= m2.m[2][2];
+ m.flagBits = flagBits;
+ return m;
+ }
+
+ QDoubleMatrix4x4 m(1);
+ m.m[0][0] = m1.m[0][0] * m2.m[0][0]
+ + m1.m[1][0] * m2.m[0][1]
+ + m1.m[2][0] * m2.m[0][2]
+ + m1.m[3][0] * m2.m[0][3];
+ m.m[0][1] = m1.m[0][1] * m2.m[0][0]
+ + m1.m[1][1] * m2.m[0][1]
+ + m1.m[2][1] * m2.m[0][2]
+ + m1.m[3][1] * m2.m[0][3];
+ m.m[0][2] = m1.m[0][2] * m2.m[0][0]
+ + m1.m[1][2] * m2.m[0][1]
+ + m1.m[2][2] * m2.m[0][2]
+ + m1.m[3][2] * m2.m[0][3];
+ m.m[0][3] = m1.m[0][3] * m2.m[0][0]
+ + m1.m[1][3] * m2.m[0][1]
+ + m1.m[2][3] * m2.m[0][2]
+ + m1.m[3][3] * m2.m[0][3];
+
+ m.m[1][0] = m1.m[0][0] * m2.m[1][0]
+ + m1.m[1][0] * m2.m[1][1]
+ + m1.m[2][0] * m2.m[1][2]
+ + m1.m[3][0] * m2.m[1][3];
+ m.m[1][1] = m1.m[0][1] * m2.m[1][0]
+ + m1.m[1][1] * m2.m[1][1]
+ + m1.m[2][1] * m2.m[1][2]
+ + m1.m[3][1] * m2.m[1][3];
+ m.m[1][2] = m1.m[0][2] * m2.m[1][0]
+ + m1.m[1][2] * m2.m[1][1]
+ + m1.m[2][2] * m2.m[1][2]
+ + m1.m[3][2] * m2.m[1][3];
+ m.m[1][3] = m1.m[0][3] * m2.m[1][0]
+ + m1.m[1][3] * m2.m[1][1]
+ + m1.m[2][3] * m2.m[1][2]
+ + m1.m[3][3] * m2.m[1][3];
+
+ m.m[2][0] = m1.m[0][0] * m2.m[2][0]
+ + m1.m[1][0] * m2.m[2][1]
+ + m1.m[2][0] * m2.m[2][2]
+ + m1.m[3][0] * m2.m[2][3];
+ m.m[2][1] = m1.m[0][1] * m2.m[2][0]
+ + m1.m[1][1] * m2.m[2][1]
+ + m1.m[2][1] * m2.m[2][2]
+ + m1.m[3][1] * m2.m[2][3];
+ m.m[2][2] = m1.m[0][2] * m2.m[2][0]
+ + m1.m[1][2] * m2.m[2][1]
+ + m1.m[2][2] * m2.m[2][2]
+ + m1.m[3][2] * m2.m[2][3];
+ m.m[2][3] = m1.m[0][3] * m2.m[2][0]
+ + m1.m[1][3] * m2.m[2][1]
+ + m1.m[2][3] * m2.m[2][2]
+ + m1.m[3][3] * m2.m[2][3];
+
+ m.m[3][0] = m1.m[0][0] * m2.m[3][0]
+ + m1.m[1][0] * m2.m[3][1]
+ + m1.m[2][0] * m2.m[3][2]
+ + m1.m[3][0] * m2.m[3][3];
+ m.m[3][1] = m1.m[0][1] * m2.m[3][0]
+ + m1.m[1][1] * m2.m[3][1]
+ + m1.m[2][1] * m2.m[3][2]
+ + m1.m[3][1] * m2.m[3][3];
+ m.m[3][2] = m1.m[0][2] * m2.m[3][0]
+ + m1.m[1][2] * m2.m[3][1]
+ + m1.m[2][2] * m2.m[3][2]
+ + m1.m[3][2] * m2.m[3][3];
+ m.m[3][3] = m1.m[0][3] * m2.m[3][0]
+ + m1.m[1][3] * m2.m[3][1]
+ + m1.m[2][3] * m2.m[3][2]
+ + m1.m[3][3] * m2.m[3][3];
+ m.flagBits = flagBits;
+ return m;
+}
+
+inline QDoubleVector3D operator*(const QDoubleVector3D& vector, const QDoubleMatrix4x4& matrix)
+{
+ double x, y, z, w;
+ x = vector.x() * matrix.m[0][0] +
+ vector.y() * matrix.m[0][1] +
+ vector.z() * matrix.m[0][2] +
+ matrix.m[0][3];
+ y = vector.x() * matrix.m[1][0] +
+ vector.y() * matrix.m[1][1] +
+ vector.z() * matrix.m[1][2] +
+ matrix.m[1][3];
+ z = vector.x() * matrix.m[2][0] +
+ vector.y() * matrix.m[2][1] +
+ vector.z() * matrix.m[2][2] +
+ matrix.m[2][3];
+ w = vector.x() * matrix.m[3][0] +
+ vector.y() * matrix.m[3][1] +
+ vector.z() * matrix.m[3][2] +
+ matrix.m[3][3];
+ if (w == 1.0f)
+ return QDoubleVector3D(x, y, z);
+ else
+ return QDoubleVector3D(x / w, y / w, z / w);
+}
+
+inline QDoubleVector3D operator*(const QDoubleMatrix4x4& matrix, const QDoubleVector3D& vector)
+{
+ double x, y, z, w;
+ if (matrix.flagBits == QDoubleMatrix4x4::Identity) {
+ return vector;
+ } else if (matrix.flagBits < QDoubleMatrix4x4::Rotation2D) {
+ // Translation | Scale
+ return QDoubleVector3D(vector.x() * matrix.m[0][0] + matrix.m[3][0],
+ vector.y() * matrix.m[1][1] + matrix.m[3][1],
+ vector.z() * matrix.m[2][2] + matrix.m[3][2]);
+ } else if (matrix.flagBits < QDoubleMatrix4x4::Rotation) {
+ // Translation | Scale | Rotation2D
+ return QDoubleVector3D(vector.x() * matrix.m[0][0] + vector.y() * matrix.m[1][0] + matrix.m[3][0],
+ vector.x() * matrix.m[0][1] + vector.y() * matrix.m[1][1] + matrix.m[3][1],
+ vector.z() * matrix.m[2][2] + matrix.m[3][2]);
+ } else {
+ x = vector.x() * matrix.m[0][0] +
+ vector.y() * matrix.m[1][0] +
+ vector.z() * matrix.m[2][0] +
+ matrix.m[3][0];
+ y = vector.x() * matrix.m[0][1] +
+ vector.y() * matrix.m[1][1] +
+ vector.z() * matrix.m[2][1] +
+ matrix.m[3][1];
+ z = vector.x() * matrix.m[0][2] +
+ vector.y() * matrix.m[1][2] +
+ vector.z() * matrix.m[2][2] +
+ matrix.m[3][2];
+ w = vector.x() * matrix.m[0][3] +
+ vector.y() * matrix.m[1][3] +
+ vector.z() * matrix.m[2][3] +
+ matrix.m[3][3];
+ if (w == 1.0f)
+ return QDoubleVector3D(x, y, z);
+ else
+ return QDoubleVector3D(x / w, y / w, z / w);
+ }
+}
+
+inline QPoint operator*(const QPoint& point, const QDoubleMatrix4x4& matrix)
+{
+ double xin, yin;
+ double x, y, w;
+ xin = point.x();
+ yin = point.y();
+ x = xin * matrix.m[0][0] +
+ yin * matrix.m[0][1] +
+ matrix.m[0][3];
+ y = xin * matrix.m[1][0] +
+ yin * matrix.m[1][1] +
+ matrix.m[1][3];
+ w = xin * matrix.m[3][0] +
+ yin * matrix.m[3][1] +
+ matrix.m[3][3];
+ if (w == 1.0f)
+ return QPoint(qRound(x), qRound(y));
+ else
+ return QPoint(qRound(x / w), qRound(y / w));
+}
+
+inline QPointF operator*(const QPointF& point, const QDoubleMatrix4x4& matrix)
+{
+ double xin, yin;
+ double x, y, w;
+ xin = point.x();
+ yin = point.y();
+ x = xin * matrix.m[0][0] +
+ yin * matrix.m[0][1] +
+ matrix.m[0][3];
+ y = xin * matrix.m[1][0] +
+ yin * matrix.m[1][1] +
+ matrix.m[1][3];
+ w = xin * matrix.m[3][0] +
+ yin * matrix.m[3][1] +
+ matrix.m[3][3];
+ if (w == 1.0f) {
+ return QPointF(double(x), double(y));
+ } else {
+ return QPointF(double(x / w), double(y / w));
+ }
+}
+
+inline QPoint operator*(const QDoubleMatrix4x4& matrix, const QPoint& point)
+{
+ double xin, yin;
+ double x, y, w;
+ xin = point.x();
+ yin = point.y();
+ if (matrix.flagBits == QDoubleMatrix4x4::Identity) {
+ return point;
+ } else if (matrix.flagBits < QDoubleMatrix4x4::Rotation2D) {
+ // Translation | Scale
+ return QPoint(qRound(xin * matrix.m[0][0] + matrix.m[3][0]),
+ qRound(yin * matrix.m[1][1] + matrix.m[3][1]));
+ } else if (matrix.flagBits < QDoubleMatrix4x4::Perspective) {
+ return QPoint(qRound(xin * matrix.m[0][0] + yin * matrix.m[1][0] + matrix.m[3][0]),
+ qRound(xin * matrix.m[0][1] + yin * matrix.m[1][1] + matrix.m[3][1]));
+ } else {
+ x = xin * matrix.m[0][0] +
+ yin * matrix.m[1][0] +
+ matrix.m[3][0];
+ y = xin * matrix.m[0][1] +
+ yin * matrix.m[1][1] +
+ matrix.m[3][1];
+ w = xin * matrix.m[0][3] +
+ yin * matrix.m[1][3] +
+ matrix.m[3][3];
+ if (w == 1.0f)
+ return QPoint(qRound(x), qRound(y));
+ else
+ return QPoint(qRound(x / w), qRound(y / w));
+ }
+}
+
+inline QPointF operator*(const QDoubleMatrix4x4& matrix, const QPointF& point)
+{
+ double xin, yin;
+ double x, y, w;
+ xin = point.x();
+ yin = point.y();
+ if (matrix.flagBits == QDoubleMatrix4x4::Identity) {
+ return point;
+ } else if (matrix.flagBits < QDoubleMatrix4x4::Rotation2D) {
+ // Translation | Scale
+ return QPointF(xin * matrix.m[0][0] + matrix.m[3][0],
+ yin * matrix.m[1][1] + matrix.m[3][1]);
+ } else if (matrix.flagBits < QDoubleMatrix4x4::Perspective) {
+ return QPointF(xin * matrix.m[0][0] + yin * matrix.m[1][0] + matrix.m[3][0],
+ xin * matrix.m[0][1] + yin * matrix.m[1][1] + matrix.m[3][1]);
+ } else {
+ x = xin * matrix.m[0][0] +
+ yin * matrix.m[1][0] +
+ matrix.m[3][0];
+ y = xin * matrix.m[0][1] +
+ yin * matrix.m[1][1] +
+ matrix.m[3][1];
+ w = xin * matrix.m[0][3] +
+ yin * matrix.m[1][3] +
+ matrix.m[3][3];
+ if (w == 1.0f) {
+ return QPointF(double(x), double(y));
+ } else {
+ return QPointF(double(x / w), double(y / w));
+ }
+ }
+}
+
+inline QDoubleMatrix4x4 operator-(const QDoubleMatrix4x4& matrix)
+{
+ QDoubleMatrix4x4 m(1);
+ m.m[0][0] = -matrix.m[0][0];
+ m.m[0][1] = -matrix.m[0][1];
+ m.m[0][2] = -matrix.m[0][2];
+ m.m[0][3] = -matrix.m[0][3];
+ m.m[1][0] = -matrix.m[1][0];
+ m.m[1][1] = -matrix.m[1][1];
+ m.m[1][2] = -matrix.m[1][2];
+ m.m[1][3] = -matrix.m[1][3];
+ m.m[2][0] = -matrix.m[2][0];
+ m.m[2][1] = -matrix.m[2][1];
+ m.m[2][2] = -matrix.m[2][2];
+ m.m[2][3] = -matrix.m[2][3];
+ m.m[3][0] = -matrix.m[3][0];
+ m.m[3][1] = -matrix.m[3][1];
+ m.m[3][2] = -matrix.m[3][2];
+ m.m[3][3] = -matrix.m[3][3];
+ m.flagBits = QDoubleMatrix4x4::General;
+ return m;
+}
+
+inline QDoubleMatrix4x4 operator*(double factor, const QDoubleMatrix4x4& matrix)
+{
+ QDoubleMatrix4x4 m(1);
+ m.m[0][0] = matrix.m[0][0] * factor;
+ m.m[0][1] = matrix.m[0][1] * factor;
+ m.m[0][2] = matrix.m[0][2] * factor;
+ m.m[0][3] = matrix.m[0][3] * factor;
+ m.m[1][0] = matrix.m[1][0] * factor;
+ m.m[1][1] = matrix.m[1][1] * factor;
+ m.m[1][2] = matrix.m[1][2] * factor;
+ m.m[1][3] = matrix.m[1][3] * factor;
+ m.m[2][0] = matrix.m[2][0] * factor;
+ m.m[2][1] = matrix.m[2][1] * factor;
+ m.m[2][2] = matrix.m[2][2] * factor;
+ m.m[2][3] = matrix.m[2][3] * factor;
+ m.m[3][0] = matrix.m[3][0] * factor;
+ m.m[3][1] = matrix.m[3][1] * factor;
+ m.m[3][2] = matrix.m[3][2] * factor;
+ m.m[3][3] = matrix.m[3][3] * factor;
+ m.flagBits = QDoubleMatrix4x4::General;
+ return m;
+}
+
+inline QDoubleMatrix4x4 operator*(const QDoubleMatrix4x4& matrix, double factor)
+{
+ QDoubleMatrix4x4 m(1);
+ m.m[0][0] = matrix.m[0][0] * factor;
+ m.m[0][1] = matrix.m[0][1] * factor;
+ m.m[0][2] = matrix.m[0][2] * factor;
+ m.m[0][3] = matrix.m[0][3] * factor;
+ m.m[1][0] = matrix.m[1][0] * factor;
+ m.m[1][1] = matrix.m[1][1] * factor;
+ m.m[1][2] = matrix.m[1][2] * factor;
+ m.m[1][3] = matrix.m[1][3] * factor;
+ m.m[2][0] = matrix.m[2][0] * factor;
+ m.m[2][1] = matrix.m[2][1] * factor;
+ m.m[2][2] = matrix.m[2][2] * factor;
+ m.m[2][3] = matrix.m[2][3] * factor;
+ m.m[3][0] = matrix.m[3][0] * factor;
+ m.m[3][1] = matrix.m[3][1] * factor;
+ m.m[3][2] = matrix.m[3][2] * factor;
+ m.m[3][3] = matrix.m[3][3] * factor;
+ m.flagBits = QDoubleMatrix4x4::General;
+ return m;
+}
+
+inline bool qFuzzyCompare(const QDoubleMatrix4x4& m1, const QDoubleMatrix4x4& m2)
+{
+ return qFuzzyCompare(m1.m[0][0], m2.m[0][0]) &&
+ qFuzzyCompare(m1.m[0][1], m2.m[0][1]) &&
+ qFuzzyCompare(m1.m[0][2], m2.m[0][2]) &&
+ qFuzzyCompare(m1.m[0][3], m2.m[0][3]) &&
+ qFuzzyCompare(m1.m[1][0], m2.m[1][0]) &&
+ qFuzzyCompare(m1.m[1][1], m2.m[1][1]) &&
+ qFuzzyCompare(m1.m[1][2], m2.m[1][2]) &&
+ qFuzzyCompare(m1.m[1][3], m2.m[1][3]) &&
+ qFuzzyCompare(m1.m[2][0], m2.m[2][0]) &&
+ qFuzzyCompare(m1.m[2][1], m2.m[2][1]) &&
+ qFuzzyCompare(m1.m[2][2], m2.m[2][2]) &&
+ qFuzzyCompare(m1.m[2][3], m2.m[2][3]) &&
+ qFuzzyCompare(m1.m[3][0], m2.m[3][0]) &&
+ qFuzzyCompare(m1.m[3][1], m2.m[3][1]) &&
+ qFuzzyCompare(m1.m[3][2], m2.m[3][2]) &&
+ qFuzzyCompare(m1.m[3][3], m2.m[3][3]);
+}
+
+inline QPoint QDoubleMatrix4x4::map(const QPoint& point) const
+{
+ return *this * point;
+}
+
+inline QPointF QDoubleMatrix4x4::map(const QPointF& point) const
+{
+ return *this * point;
+}
+
+inline QDoubleVector3D QDoubleMatrix4x4::map(const QDoubleVector3D& point) const
+{
+ return *this * point;
+}
+
+inline QDoubleVector3D QDoubleMatrix4x4::mapVector(const QDoubleVector3D& vector) const
+{
+ if (flagBits < Scale) {
+ // Translation
+ return vector;
+ } else if (flagBits < Rotation2D) {
+ // Translation | Scale
+ return QDoubleVector3D(vector.x() * m[0][0],
+ vector.y() * m[1][1],
+ vector.z() * m[2][2]);
+ } else {
+ return QDoubleVector3D(vector.x() * m[0][0] +
+ vector.y() * m[1][0] +
+ vector.z() * m[2][0],
+ vector.x() * m[0][1] +
+ vector.y() * m[1][1] +
+ vector.z() * m[2][1],
+ vector.x() * m[0][2] +
+ vector.y() * m[1][2] +
+ vector.z() * m[2][2]);
+ }
+}
+
+inline double *QDoubleMatrix4x4::data()
+{
+ // We have to assume that the caller will modify the matrix elements,
+ // so we flip it over to "General" mode.
+ flagBits = General;
+ return *m;
+}
+
+inline void QDoubleMatrix4x4::viewport(const QRectF &rect)
+{
+ viewport(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_POSITIONING_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QDoubleMatrix4x4 &m);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_POSITIONING_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QDoubleMatrix4x4 &);
+Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QDoubleMatrix4x4 &);
+#endif
+
+
+QT_END_NAMESPACE
+
+
+#endif // QDOUBLEMATRIX4X4_H
diff --git a/src/positioning/qdoublevector2d_p.h b/src/positioning/qdoublevector2d_p.h
index c35899e4..69348ee1 100644
--- a/src/positioning/qdoublevector2d_p.h
+++ b/src/positioning/qdoublevector2d_p.h
@@ -91,6 +91,7 @@ public:
inline QDoubleVector2D &operator*=(double factor);
inline QDoubleVector2D &operator*=(const QDoubleVector2D &vector);
inline QDoubleVector2D &operator/=(double divisor);
+ inline QDoubleVector2D &operator/=(const QDoubleVector2D &vector);
Q_DECL_CONSTEXPR static inline double dotProduct(const QDoubleVector2D &v1, const QDoubleVector2D &v2)
{ return v1.xp * v2.xp + v1.yp * v2.yp; }
@@ -179,6 +180,13 @@ inline QDoubleVector2D &QDoubleVector2D::operator/=(double divisor)
return *this;
}
+inline QDoubleVector2D &QDoubleVector2D::operator/=(const QDoubleVector2D &vector)
+{
+ xp /= vector.xp;
+ yp /= vector.yp;
+ return *this;
+}
+
Q_DECL_CONSTEXPR inline bool operator==(const QDoubleVector2D &v1, const QDoubleVector2D &v2)
{
return v1.xp == v2.xp && v1.yp == v2.yp;
diff --git a/src/positioning/qgeocircle.cpp b/src/positioning/qgeocircle.cpp
index 3f2707a4..6fccb8af 100644
--- a/src/positioning/qgeocircle.cpp
+++ b/src/positioning/qgeocircle.cpp
@@ -42,9 +42,11 @@
#include "qgeocoordinate.h"
#include "qnumeric.h"
+#include "qlocationutils_p.h"
#include "qdoublevector2d_p.h"
#include "qdoublevector3d_p.h"
+#include <cmath>
QT_BEGIN_NAMESPACE
/*!
@@ -191,12 +193,12 @@ bool QGeoCircle::operator!=(const QGeoCircle &other) const
bool QGeoCirclePrivate::isValid() const
{
- return m_center.isValid() && !qIsNaN(radius) && radius >= -1e-7;
+ return m_center.isValid() && !qIsNaN(m_radius) && m_radius >= -1e-7;
}
bool QGeoCirclePrivate::isEmpty() const
{
- return !isValid() || radius <= 1e-7;
+ return !isValid() || m_radius <= 1e-7;
}
/*!
@@ -206,7 +208,7 @@ void QGeoCircle::setCenter(const QGeoCoordinate &center)
{
Q_D(QGeoCircle);
- d->m_center = center;
+ d->setCenter(center);
}
/*!
@@ -226,7 +228,7 @@ void QGeoCircle::setRadius(qreal radius)
{
Q_D(QGeoCircle);
- d->radius = radius;
+ d->setRadius(radius);
}
/*!
@@ -236,7 +238,7 @@ qreal QGeoCircle::radius() const
{
Q_D(const QGeoCircle);
- return d->radius;
+ return d->m_radius;
}
bool QGeoCirclePrivate::contains(const QGeoCoordinate &coordinate) const
@@ -246,7 +248,7 @@ bool QGeoCirclePrivate::contains(const QGeoCoordinate &coordinate) const
// see QTBUG-41447 for details
qreal distance = m_center.distanceTo(coordinate);
- if (qFuzzyCompare(distance, radius) || distance <= radius)
+ if (qFuzzyCompare(distance, m_radius) || distance <= m_radius)
return true;
return false;
@@ -257,6 +259,103 @@ QGeoCoordinate QGeoCirclePrivate::center() const
return m_center;
}
+QGeoRectangle QGeoCirclePrivate::boundingGeoRectangle() const
+{
+ return m_bbox;
+}
+
+void QGeoCirclePrivate::updateBoundingBox()
+{
+ if (isEmpty()) {
+ if (m_center.isValid()) {
+ m_bbox.setTopLeft(m_center);
+ m_bbox.setBottomRight(m_center);
+ }
+ return;
+ }
+
+ bool crossNorth = crossNorthPole();
+ bool crossSouth = crossSouthPole();
+
+ if (crossNorth && crossSouth) {
+ // Circle crossing both poles fills the whole map
+ m_bbox = QGeoRectangle(QGeoCoordinate(90.0, -180.0), QGeoCoordinate(-90.0, 180.0));
+ } else if (crossNorth) {
+ // Circle crossing one pole fills the map in the longitudinal direction
+ m_bbox = QGeoRectangle(QGeoCoordinate(90.0, -180.0), QGeoCoordinate(m_center.atDistanceAndAzimuth(m_radius, 180.0).latitude(), 180.0));
+ } else if (crossSouth) {
+ m_bbox = QGeoRectangle(QGeoCoordinate(m_center.atDistanceAndAzimuth(m_radius, 0.0).latitude(), -180.0), QGeoCoordinate(-90, 180.0));
+ } else {
+ // Regular circle not crossing anything
+
+ // Calculate geo bounding box of the circle
+ //
+ // A circle tangential point with a meridian, together with pole and
+ // the circle center create a spherical triangle.
+ // Finding the tangential point with the spherical law of sines:
+ //
+ // * lon_delta_in_rad : delta between the circle center and a tangential
+ // point (absolute value).
+ // * r_in_rad : angular radius of the circle
+ // * lat_in_rad : latitude of the circle center
+ // * alpha_in_rad : angle between meridian and radius of the circle.
+ // At the tangential point, sin(alpha_in_rad) == 1.
+ // * lat_delta_in_rad - absolute delta of latitudes between the circle center and
+ // any of the two points where the great circle going through the circle
+ // center and the pole crosses the circle. In other words, the points
+ // on the circle with azimuth 0 or 180.
+ //
+ // Using:
+ // sin(lon_delta_in_rad)/sin(r_in_rad) = sin(alpha_in_rad)/sin(pi/2 - lat_in_rad)
+
+ double r_in_rad = m_radius / QLocationUtils::earthMeanRadius(); // angular r
+ double lat_delta_in_deg = QLocationUtils::degrees(r_in_rad);
+ double lon_delta_in_deg = QLocationUtils::degrees(std::asin(
+ std::sin(r_in_rad) /
+ std::cos(QLocationUtils::radians(m_center.latitude()))
+ ));
+
+ QGeoCoordinate topLeft;
+ 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(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);
+ }
+}
+
+void QGeoCirclePrivate::setCenter(const QGeoCoordinate &c)
+{
+ m_center = c;
+ updateBoundingBox();
+}
+
+void QGeoCirclePrivate::setRadius(const qreal r)
+{
+ m_radius = r;
+ updateBoundingBox();
+}
+
+bool QGeoCirclePrivate::crossNorthPole() const
+{
+ const QGeoCoordinate northPole(90.0, m_center.longitude());
+ qreal distanceToPole = m_center.distanceTo(northPole);
+ if (distanceToPole < m_radius)
+ return true;
+ return false;
+}
+
+bool QGeoCirclePrivate::crossSouthPole() const
+{
+ const QGeoCoordinate southPole(-90.0, m_center.longitude());
+ qreal distanceToPole = m_center.distanceTo(southPole);
+ if (distanceToPole < m_radius)
+ return true;
+ return false;
+}
+
/*!
Extends the circle to include \a coordinate
*/
@@ -265,7 +364,7 @@ void QGeoCirclePrivate::extendShape(const QGeoCoordinate &coordinate)
if (!isValid() || !coordinate.isValid() || contains(coordinate))
return;
- radius = m_center.distanceTo(coordinate);
+ setRadius(m_center.distanceTo(coordinate));
}
/*!
@@ -285,12 +384,9 @@ void QGeoCircle::translate(double degreesLatitude, double degreesLongitude)
lat += degreesLatitude;
lon += degreesLongitude;
+ lon = QLocationUtils::wrapLong(lon);
- if (lon < -180.0)
- lon += 360.0;
- if (lon > 180.0)
- lon -= 360.0;
-
+ // TODO: remove this and simply clip latitude.
if (lat > 90.0) {
lat = 180.0 - lat;
if (lon < 0.0)
@@ -307,7 +403,7 @@ void QGeoCircle::translate(double degreesLatitude, double degreesLongitude)
lon -= 180;
}
- d->m_center = QGeoCoordinate(lat, lon);
+ d->setCenter(QGeoCoordinate(lat, lon));
}
/*!
@@ -327,6 +423,17 @@ QGeoCircle QGeoCircle::translated(double degreesLatitude, double degreesLongitud
}
/*!
+ Extends the geo circle to also cover the coordinate \a coordinate
+
+ \since 5.9
+*/
+void QGeoCircle::extendCircle(const QGeoCoordinate &coordinate)
+{
+ Q_D(QGeoCircle);
+ d->extendShape(coordinate);
+}
+
+/*!
Returns the geo circle properties as a string.
\since 5.5
@@ -349,18 +456,19 @@ QString QGeoCircle::toString() const
*******************************************************************************/
QGeoCirclePrivate::QGeoCirclePrivate()
-: QGeoShapePrivate(QGeoShape::CircleType), radius(-1.0)
+: QGeoShapePrivate(QGeoShape::CircleType), m_radius(-1.0)
{
}
QGeoCirclePrivate::QGeoCirclePrivate(const QGeoCoordinate &center, qreal radius)
-: QGeoShapePrivate(QGeoShape::CircleType), m_center(center), radius(radius)
+: QGeoShapePrivate(QGeoShape::CircleType), m_center(center), m_radius(radius)
{
+ updateBoundingBox();
}
QGeoCirclePrivate::QGeoCirclePrivate(const QGeoCirclePrivate &other)
: QGeoShapePrivate(QGeoShape::CircleType), m_center(other.m_center),
- radius(other.radius)
+ m_radius(other.m_radius), m_bbox(other.m_bbox)
{
}
@@ -378,8 +486,7 @@ bool QGeoCirclePrivate::operator==(const QGeoShapePrivate &other) const
const QGeoCirclePrivate &otherCircle = static_cast<const QGeoCirclePrivate &>(other);
- return radius == otherCircle.radius && m_center == otherCircle.m_center;
+ return m_radius == otherCircle.m_radius && m_center == otherCircle.m_center;
}
QT_END_NAMESPACE
-
diff --git a/src/positioning/qgeocircle.h b/src/positioning/qgeocircle.h
index b4b6c45e..dc10ccf9 100644
--- a/src/positioning/qgeocircle.h
+++ b/src/positioning/qgeocircle.h
@@ -75,8 +75,9 @@ public:
void setRadius(qreal radius);
qreal radius() const;
- void translate(double degreesLatitude, double degreesLongitude);
- QGeoCircle translated(double degreesLatitude, double degreesLongitude) const;
+ Q_INVOKABLE void translate(double degreesLatitude, double degreesLongitude);
+ Q_INVOKABLE QGeoCircle translated(double degreesLatitude, double degreesLongitude) const;
+ Q_INVOKABLE void extendCircle(const QGeoCoordinate &coordinate);
Q_INVOKABLE QString toString() const;
diff --git a/src/positioning/qgeocircle_p.h b/src/positioning/qgeocircle_p.h
index 311aba8b..07d79db4 100644
--- a/src/positioning/qgeocircle_p.h
+++ b/src/positioning/qgeocircle_p.h
@@ -70,6 +70,14 @@ public:
QGeoCoordinate center() const Q_DECL_OVERRIDE;
+ QGeoRectangle boundingGeoRectangle() const Q_DECL_OVERRIDE;
+
+ bool crossNorthPole() const;
+ bool crossSouthPole() const;
+ void updateBoundingBox();
+ void setCenter(const QGeoCoordinate &c);
+ void setRadius(const qreal r);
+
void extendShape(const QGeoCoordinate &coordinate) Q_DECL_OVERRIDE;
QGeoShapePrivate *clone() const Q_DECL_OVERRIDE;
@@ -77,7 +85,8 @@ public:
bool operator==(const QGeoShapePrivate &other) const Q_DECL_OVERRIDE;
QGeoCoordinate m_center;
- qreal radius;
+ qreal m_radius;
+ QGeoRectangle m_bbox;
};
QT_END_NAMESPACE
diff --git a/src/positioning/qgeocoordinate.cpp b/src/positioning/qgeocoordinate.cpp
index 0386e859..8d39a62e 100644
--- a/src/positioning/qgeocoordinate.cpp
+++ b/src/positioning/qgeocoordinate.cpp
@@ -517,14 +517,8 @@ QGeoCoordinate QGeoCoordinate::atDistanceAndAzimuth(qreal distance, qreal azimut
double resultLon, resultLat;
QGeoCoordinatePrivate::atDistanceAndAzimuth(*this, distance, azimuth,
&resultLon, &resultLat);
-
- if (resultLon > 180.0)
- resultLon -= 360.0;
- else if (resultLon < -180.0)
- resultLon += 360.0;
-
double resultAlt = d->alt + distanceUp;
- return QGeoCoordinate(resultLat, resultLon, resultAlt);
+ return QGeoCoordinate(resultLat, QLocationUtils::wrapLong(resultLon), resultAlt);
}
/*!
diff --git a/src/positioning/qgeopath.cpp b/src/positioning/qgeopath.cpp
new file mode 100644
index 00000000..87f4a9d4
--- /dev/null
+++ b/src/positioning/qgeopath.cpp
@@ -0,0 +1,679 @@
+/****************************************************************************
+**
+** 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 "qgeopath.h"
+#include "qgeopath_p.h"
+
+#include "qgeocoordinate.h"
+#include "qnumeric.h"
+#include "qlocationutils_p.h"
+#include "qwebmercator_p.h"
+
+#include "qdoublevector2d_p.h"
+#include "qdoublevector3d_p.h"
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGeoPath
+ \inmodule QtPositioning
+ \ingroup QtPositioning-positioning
+ \since 5.9
+
+ \brief The QGeoPath class defines a geographic path.
+
+ The path is defined by an ordered list of QGeoCoordinates.
+
+ Each two adjacent elements in the path are intended to be connected
+ together by the shortest line segment of constant bearing passing
+ through both elements.
+ This type of connection can cross the dateline in the longitudinal direction,
+ but never crosses the poles.
+
+ This is relevant for the calculation of the bounding box returned by
+ \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.
+
+ This class is a \l Q_GADGET.
+ It can be \l{Cpp_value_integration_positioning}{directly used from C++ and QML}.
+*/
+
+/*!
+ \property QGeoPath::path
+ \brief This property holds the list of coordinates for the geo path.
+
+ The path is both invalid and empty if it contains no coordinate.
+
+ A default constructed QGeoPath is therefore invalid.
+*/
+
+inline QGeoPathPrivate *QGeoPath::d_func()
+{
+ return static_cast<QGeoPathPrivate *>(d_ptr.data());
+}
+
+inline const QGeoPathPrivate *QGeoPath::d_func() const
+{
+ return static_cast<const QGeoPathPrivate *>(d_ptr.constData());
+}
+
+struct PathVariantConversions
+{
+ PathVariantConversions()
+ {
+ QMetaType::registerConverter<QGeoShape, QGeoPath>();
+ QMetaType::registerConverter<QGeoPath, QGeoShape>();
+ }
+};
+
+Q_GLOBAL_STATIC(PathVariantConversions, initPathConversions)
+
+/*!
+ Constructs a new, empty geo path.
+*/
+QGeoPath::QGeoPath()
+: QGeoShape(new QGeoPathPrivate)
+{
+ initPathConversions();
+}
+
+/*!
+ Constructs a new geo path from a list of coordinates.
+*/
+QGeoPath::QGeoPath(const QList<QGeoCoordinate> &path, const qreal &width)
+: QGeoShape(new QGeoPathPrivate(path, width))
+{
+ initPathConversions();
+}
+
+/*!
+ Constructs a new geo path from the contents of \a other.
+*/
+QGeoPath::QGeoPath(const QGeoPath &other)
+: QGeoShape(other)
+{
+ initPathConversions();
+}
+
+/*!
+ Constructs a new geo path from the contents of \a other.
+*/
+QGeoPath::QGeoPath(const QGeoShape &other)
+: QGeoShape(other)
+{
+ initPathConversions();
+ if (type() != QGeoShape::PathType)
+ d_ptr = new QGeoPathPrivate;
+}
+
+/*!
+ Destroys this path.
+*/
+QGeoPath::~QGeoPath() {}
+
+/*!
+ Assigns \a other to this geo path and returns a reference to this geo path.
+*/
+QGeoPath &QGeoPath::operator=(const QGeoPath &other)
+{
+ QGeoShape::operator=(other);
+ return *this;
+}
+
+/*!
+ Returns whether this geo path is equal to \a other.
+*/
+bool QGeoPath::operator==(const QGeoPath &other) const
+{
+ Q_D(const QGeoPath);
+ return *d == *other.d_func();
+}
+
+/*!
+ Returns whether this geo path is not equal to \a other.
+*/
+bool QGeoPath::operator!=(const QGeoPath &other) const
+{
+ Q_D(const QGeoPath);
+ return !(*d == *other.d_func());
+}
+
+void QGeoPath::setPath(const QList<QGeoCoordinate> &path)
+{
+ Q_D(QGeoPath);
+ return d->setPath(path);
+}
+
+/*!
+ Returns all the elements. Equivalent to QGeoShape::center().
+ The center coordinate, in case of a QGeoPath, is the center of its bounding box.
+*/
+const QList<QGeoCoordinate> &QGeoPath::path() const
+{
+ Q_D(const QGeoPath);
+ return d->path();
+}
+
+void QGeoPath::setWidth(const qreal &width)
+{
+ Q_D(QGeoPath);
+ d->setWidth(width);
+}
+
+/*!
+ Returns the width of the path, in meters. This information is used in the \l contains method
+ The default value is 0.
+*/
+qreal QGeoPath::width() const
+{
+ Q_D(const QGeoPath);
+ return d->width();
+}
+
+/*!
+ Translates this geo path by \a degreesLatitude northwards and \a degreesLongitude eastwards.
+
+ Negative values of \a degreesLatitude and \a degreesLongitude correspond to
+ southward and westward translation respectively.
+*/
+void QGeoPath::translate(double degreesLatitude, double degreesLongitude)
+{
+ Q_D(QGeoPath);
+ d->translate(degreesLatitude, degreesLongitude);
+}
+
+/*!
+ Returns a copy of this geo path translated by \a degreesLatitude northwards and
+ \a degreesLongitude eastwards.
+
+ Negative values of \a degreesLatitude and \a degreesLongitude correspond to
+ southward and westward translation respectively.
+
+ \sa translate()
+*/
+QGeoPath QGeoPath::translated(double degreesLatitude, double degreesLongitude) const
+{
+ QGeoPath result(*this);
+ result.translate(degreesLatitude, degreesLongitude);
+ return result;
+}
+
+/*!
+ Returns the length of the path, in meters, from the element \a indexFrom to the element \a indexTo.
+ The length is intended to be the sum of the shortest distances for each pair of adjacent points.
+*/
+double QGeoPath::length(int indexFrom, int indexTo) const
+{
+ Q_D(const QGeoPath);
+ return d->length(indexFrom, indexTo);
+}
+
+/*!
+ Appends \a coordinate to the path.
+*/
+void QGeoPath::addCoordinate(const QGeoCoordinate &coordinate)
+{
+ Q_D(QGeoPath);
+ d->addCoordinate(coordinate);
+}
+
+/*!
+ Inserts \a coordinate at the specified \a index.
+*/
+void QGeoPath::insertCoordinate(int index, const QGeoCoordinate &coordinate)
+{
+ Q_D(QGeoPath);
+ d->insertCoordinate(index, coordinate);
+}
+
+/*!
+ Replaces the path element at the specified \a index with \a coordinate.
+*/
+void QGeoPath::replaceCoordinate(int index, const QGeoCoordinate &coordinate)
+{
+ Q_D(QGeoPath);
+ d->replaceCoordinate(index, coordinate);
+}
+
+/*!
+ Returns the coordinate at \a index .
+*/
+QGeoCoordinate QGeoPath::coordinateAt(int index) const
+{
+ Q_D(const QGeoPath);
+ return d->coordinateAt(index);
+}
+
+/*!
+ Returns true if the path contains \a coordinate as one of the elements.
+*/
+bool QGeoPath::containsCoordinate(const QGeoCoordinate &coordinate) const
+{
+ Q_D(const QGeoPath);
+ return d->containsCoordinate(coordinate);
+}
+
+/*!
+ Removes the last occurrence of \a coordinate from the path.
+*/
+void QGeoPath::removeCoordinate(const QGeoCoordinate &coordinate)
+{
+ Q_D(QGeoPath);
+ d->removeCoordinate(coordinate);
+}
+
+/*!
+ Removes element at position \a index from the path.
+*/
+void QGeoPath::removeCoordinate(int index)
+{
+ Q_D(QGeoPath);
+ d->removeCoordinate(index);
+}
+
+/*!
+ Returns the geo path properties as a string.
+*/
+QString QGeoPath::toString() const
+{
+ if (type() != QGeoShape::PathType) {
+ qWarning("Not a path");
+ return QStringLiteral("QGeoPath(not a path)");
+ }
+
+ QString pathString;
+ for (const auto &p : path())
+ pathString += p.toString() + QLatin1Char(',');
+
+ return QStringLiteral("QGeoPath([ %1 ])").arg(pathString);
+}
+
+/*******************************************************************************
+ * QGeoPathPrivate
+*******************************************************************************/
+
+QGeoPathPrivate::QGeoPathPrivate()
+: QGeoShapePrivate(QGeoShape::PathType), m_width(0)
+{
+}
+
+QGeoPathPrivate::QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width)
+: QGeoShapePrivate(QGeoShape::PathType), m_width(0)
+{
+ setPath(path);
+ setWidth(width);
+}
+
+QGeoPathPrivate::QGeoPathPrivate(const QGeoPathPrivate &other)
+: QGeoShapePrivate(QGeoShape::PathType), m_path(other.m_path),
+ m_deltaXs(other.m_deltaXs), m_minX(other.m_minX), m_maxX(other.m_maxX), m_minLati(other.m_minLati),
+ m_maxLati(other.m_maxLati), m_bbox(other.m_bbox), m_width(other.m_width)
+{
+}
+
+QGeoPathPrivate::~QGeoPathPrivate() {}
+
+QGeoShapePrivate *QGeoPathPrivate::clone() const
+{
+ return new QGeoPathPrivate(*this);
+}
+
+bool QGeoPathPrivate::operator==(const QGeoShapePrivate &other) const
+{
+ if (!QGeoShapePrivate::operator==(other))
+ return false;
+
+ const QGeoPathPrivate &otherPath = static_cast<const QGeoPathPrivate &>(other);
+ if (m_path.size() != otherPath.m_path.size())
+ return false;
+ return m_width == otherPath.m_width && m_path == otherPath.m_path;
+}
+
+bool QGeoPathPrivate::isValid() const
+{
+ return !isEmpty();
+}
+
+bool QGeoPathPrivate::isEmpty() const
+{
+ return m_path.isEmpty();
+}
+
+const QList<QGeoCoordinate> &QGeoPathPrivate::path() const
+{
+ return m_path;
+}
+
+void QGeoPathPrivate::setPath(const QList<QGeoCoordinate> &path)
+{
+ for (const QGeoCoordinate &c: path)
+ if (!c.isValid())
+ return;
+ m_path = path;
+ computeBoundingBox();
+}
+
+qreal QGeoPathPrivate::width() const
+{
+ return m_width;
+}
+
+void QGeoPathPrivate::setWidth(const qreal &width)
+{
+ if (qIsNaN(width) || width < 0.0)
+ return;
+ m_width = width;
+}
+
+double QGeoPathPrivate::length(int indexFrom, int indexTo) const
+{
+ if (indexTo < 0 || indexTo >= path().size())
+ indexTo = path().size() - 1;
+ double len = 0.0;
+ // TODO: consider calculating the length of the actual rhumb line segments
+ // instead of the shortest path from A to B.
+ for (int i = indexFrom; i < indexTo; i++)
+ len += m_path[i].distanceTo(m_path[i+1]);
+ return len;
+}
+
+/*!
+ Returns true if coordinate is present in m_path.
+*/
+bool QGeoPathPrivate::contains(const QGeoCoordinate &coordinate) const
+{
+ // Unoptimized approach:
+ // - consider each segment of the path
+ // - project it into mercator space (rhumb lines are straight in mercator space)
+ // - find closest point to coordinate
+ // - unproject the closest point
+ // - calculate coordinate to closest point distance with distanceTo()
+ // - if not within lineRadius, advance
+ //
+ // To keep wrapping into the equation:
+ // If the mercator x value of a coordinate of the line, or the coordinate parameter, is less
+ // than mercator(m_bbox).x, add that to the conversion.
+
+ double lineRadius = qMax(width() * 0.5, 0.2); // minimum radius: 20cm
+
+ if (!m_path.size())
+ return false;
+ else if (m_path.size() == 1)
+ return (m_path[0].distanceTo(coordinate) <= lineRadius);
+
+ double leftBoundMercator = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
+
+ QDoubleVector2D p = QWebMercator::coordToMercator(coordinate);
+ if (p.x() < leftBoundMercator)
+ p.setX(p.x() + leftBoundMercator); // unwrap X
+
+ QDoubleVector2D a;
+ QDoubleVector2D b;
+ if (m_path.size()) {
+ a = QWebMercator::coordToMercator(m_path[0]);
+ if (a.x() < leftBoundMercator)
+ a.setX(a.x() + leftBoundMercator); // unwrap X
+ }
+ for (int i = 1; i < m_path.size(); i++) {
+ b = QWebMercator::coordToMercator(m_path[i]);
+ if (b.x() < leftBoundMercator)
+ b.setX(b.x() + leftBoundMercator); // unwrap X
+ if (b == a)
+ continue;
+
+ double u = ((p.x() - a.x()) * (b.x() - a.x()) + (p.y() - a.y()) * (b.y() - a.y()) ) / (b - a).lengthSquared();
+ QDoubleVector2D intersection(a.x() + u * (b.x() - a.x()) , a.y() + u * (b.y() - a.y()) );
+
+ QDoubleVector2D candidate = ( (p-a).length() < (p-b).length() ) ? a : b;
+
+ if (u < (b - a).length()
+ && (p-intersection).length() < (p-candidate).length() ) // And it falls in the segment
+ candidate = intersection;
+
+
+ if (candidate.x() > 1.0)
+ candidate.setX(candidate.x() - leftBoundMercator); // wrap X
+
+ QGeoCoordinate closest = QWebMercator::mercatorToCoord(candidate);
+
+ double distanceMeters = coordinate.distanceTo(closest);
+ if (distanceMeters <= lineRadius)
+ return true;
+
+ // swap
+ a = b;
+ }
+
+ // Last check if the coordinate is on the left of leftBoundMercator, but close enough to
+ // m_path[0]
+ return (m_path[0].distanceTo(coordinate) <= lineRadius);
+}
+
+QGeoCoordinate QGeoPathPrivate::center() const
+{
+ return boundingGeoRectangle().center();
+}
+
+QGeoRectangle QGeoPathPrivate::boundingGeoRectangle() const
+{
+ return m_bbox;
+}
+
+void QGeoPathPrivate::extendShape(const QGeoCoordinate &coordinate)
+{
+ if (!coordinate.isValid() || contains(coordinate))
+ return;
+ addCoordinate(coordinate);
+}
+
+void QGeoPathPrivate::translate(double degreesLatitude, double degreesLongitude)
+{
+ if (degreesLatitude > 0.0)
+ degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati);
+ else
+ degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati);
+ for (QGeoCoordinate &p: m_path) {
+ p.setLatitude(p.latitude() + degreesLatitude);
+ p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude));
+ }
+ m_bbox.translate(degreesLatitude, degreesLongitude);
+ m_minLati += degreesLatitude;
+ m_maxLati += degreesLatitude;
+}
+
+void QGeoPathPrivate::addCoordinate(const QGeoCoordinate &coordinate)
+{
+ if (!coordinate.isValid())
+ return;
+ m_path.append(coordinate);
+ updateBoundingBox();
+}
+
+void QGeoPathPrivate::insertCoordinate(int index, const QGeoCoordinate &coordinate)
+{
+ if (index < 0 || index > m_path.size() || !coordinate.isValid())
+ return;
+
+ m_path.insert(index, coordinate);
+ computeBoundingBox();
+}
+
+void QGeoPathPrivate::replaceCoordinate(int index, const QGeoCoordinate &coordinate)
+{
+ if (index < 0 || index >= m_path.size() || !coordinate.isValid())
+ return;
+
+ m_path[index] = coordinate;
+ computeBoundingBox();
+}
+
+QGeoCoordinate QGeoPathPrivate::coordinateAt(int index) const
+{
+ if (index < 0 || index >= m_path.size())
+ return QGeoCoordinate();
+
+ return m_path.at(index);
+}
+
+bool QGeoPathPrivate::containsCoordinate(const QGeoCoordinate &coordinate) const
+{
+ return m_path.indexOf(coordinate) > -1;
+}
+
+void QGeoPathPrivate::removeCoordinate(const QGeoCoordinate &coordinate)
+{
+ int index = m_path.lastIndexOf(coordinate);
+ removeCoordinate(index);
+}
+
+void QGeoPathPrivate::removeCoordinate(int index)
+{
+ if (index < 0 || index >= m_path.size())
+ return;
+
+ m_path.removeAt(index);
+ computeBoundingBox();
+}
+
+void QGeoPathPrivate::computeBoundingBox()
+{
+ if (m_path.isEmpty()) {
+ m_deltaXs.clear();
+ m_minX = qInf();
+ m_maxX = -qInf();
+ m_minLati = qInf();
+ m_maxLati = -qInf();
+ m_bbox = QGeoRectangle();
+ return;
+ }
+
+ m_minLati = m_maxLati = m_path.at(0).latitude();
+ int minId = 0;
+ int maxId = 0;
+ m_deltaXs.resize(m_path.size());
+ m_deltaXs[0] = m_minX = m_maxX = 0.0;
+
+ for (int i = 1; i < m_path.size(); i++) {
+ const QGeoCoordinate &geoFrom = m_path.at(i-1);
+ const QGeoCoordinate &geoTo = m_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;
+ }
+ m_deltaXs[i] = m_deltaXs[i-1] + deltaLongi;
+ if (m_deltaXs[i] < m_minX) {
+ m_minX = m_deltaXs[i];
+ minId = i;
+ }
+ if (m_deltaXs[i] > m_maxX) {
+ m_maxX = m_deltaXs[i];
+ maxId = i;
+ }
+ if (geoTo.latitude() > m_maxLati)
+ m_maxLati = geoTo.latitude();
+ if (geoTo.latitude() < m_minLati)
+ m_minLati = geoTo.latitude();
+ }
+
+ m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(minId).longitude()),
+ QGeoCoordinate(m_minLati, m_path.at(maxId).longitude()));
+}
+
+void QGeoPathPrivate::updateBoundingBox()
+{
+ if (m_path.isEmpty()) {
+ m_deltaXs.clear();
+ m_minX = qInf();
+ m_maxX = -qInf();
+ m_minLati = qInf();
+ m_maxLati = -qInf();
+ m_bbox = QGeoRectangle();
+ return;
+ } else if (m_path.size() == 1) { // was 0 now is 1
+ m_deltaXs.resize(1);
+ m_deltaXs[0] = m_minX = m_maxX = 0.0;
+ m_minLati = m_maxLati = m_path.at(0).latitude();
+ m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(0).longitude()),
+ QGeoCoordinate(m_minLati, m_path.at(0).longitude()));
+ return;
+ } else if ( m_path.size() != m_deltaXs.size() + 1 ) { // this case should not happen
+ computeBoundingBox(); // something went wrong
+ return;
+ }
+
+ const QGeoCoordinate &geoFrom = m_path.at(m_path.size()-2);
+ const QGeoCoordinate &geoTo = m_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;
+ }
+
+ m_deltaXs.push_back(m_deltaXs.last() + deltaLongi);
+ double currentMinLongi = m_bbox.topLeft().longitude();
+ double currentMaxLongi = m_bbox.bottomRight().longitude();
+ if (m_deltaXs.last() < m_minX) {
+ m_minX = m_deltaXs.last();
+ currentMinLongi = geoTo.longitude();
+ }
+ if (m_deltaXs.last() > m_maxX) {
+ m_maxX = m_deltaXs.last();
+ currentMaxLongi = geoTo.longitude();
+ }
+ if (geoTo.latitude() > m_maxLati)
+ m_maxLati = geoTo.latitude();
+ if (geoTo.latitude() < m_minLati)
+ m_minLati = geoTo.latitude();
+ m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, currentMinLongi),
+ QGeoCoordinate(m_minLati, currentMaxLongi));
+}
+
+QT_END_NAMESPACE
diff --git a/src/positioning/qgeopath.h b/src/positioning/qgeopath.h
new file mode 100644
index 00000000..09a53a49
--- /dev/null
+++ b/src/positioning/qgeopath.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** 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 QGEOPATH_H
+#define QGEOPATH_H
+
+#include <QtPositioning/QGeoShape>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoCoordinate;
+class QGeoPathPrivate;
+
+class Q_POSITIONING_EXPORT QGeoPath : public QGeoShape
+{
+ Q_GADGET
+ Q_PROPERTY(QList<QGeoCoordinate> path READ path WRITE setPath)
+ Q_PROPERTY(qreal width READ width WRITE setWidth)
+
+public:
+ QGeoPath();
+ QGeoPath(const QList<QGeoCoordinate> &path, const qreal &width = 0.0);
+ QGeoPath(const QGeoPath &other);
+ QGeoPath(const QGeoShape &other);
+
+ ~QGeoPath();
+
+ QGeoPath &operator=(const QGeoPath &other);
+
+ using QGeoShape::operator==;
+ bool operator==(const QGeoPath &other) const;
+
+ using QGeoShape::operator!=;
+ bool operator!=(const QGeoPath &other) const;
+
+ void setPath(const QList<QGeoCoordinate> &path);
+ const QList<QGeoCoordinate> &path() const;
+
+ void setWidth(const qreal &width);
+ qreal width() const;
+
+ Q_INVOKABLE void translate(double degreesLatitude, double degreesLongitude);
+ Q_INVOKABLE QGeoPath translated(double degreesLatitude, double degreesLongitude) const;
+ Q_INVOKABLE double length(int indexFrom = 0, int indexTo = -1) const;
+ Q_INVOKABLE void addCoordinate(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void insertCoordinate(int index, const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void replaceCoordinate(int index, const QGeoCoordinate &coordinate);
+ Q_INVOKABLE QGeoCoordinate coordinateAt(int index) const;
+ Q_INVOKABLE bool containsCoordinate(const QGeoCoordinate &coordinate) const;
+ Q_INVOKABLE void removeCoordinate(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void removeCoordinate(int index);
+
+ Q_INVOKABLE QString toString() const;
+
+private:
+ inline QGeoPathPrivate *d_func();
+ inline const QGeoPathPrivate *d_func() const;
+};
+
+Q_DECLARE_TYPEINFO(QGeoPath, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QGeoPath)
+
+#endif // QGEOPATH_H
diff --git a/src/positioning/qgeopath_p.h b/src/positioning/qgeopath_p.h
new file mode 100644
index 00000000..2256796d
--- /dev/null
+++ b/src/positioning/qgeopath_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** 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 QGEOPATH_P_H
+#define QGEOPATH_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 "qgeoshape_p.h"
+#include "qgeocoordinate.h"
+#include "qlocationutils_p.h"
+
+#include <QtCore/QVector>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoPathPrivate : public QGeoShapePrivate
+{
+public:
+ QGeoPathPrivate();
+ QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width = 0.0);
+ QGeoPathPrivate(const QGeoPathPrivate &other);
+ ~QGeoPathPrivate();
+
+ bool isValid() const Q_DECL_OVERRIDE;
+ bool isEmpty() const Q_DECL_OVERRIDE;
+ bool contains(const QGeoCoordinate &coordinate) const Q_DECL_OVERRIDE;
+
+ QGeoCoordinate center() const Q_DECL_OVERRIDE;
+ QGeoRectangle boundingGeoRectangle() const Q_DECL_OVERRIDE;
+ void extendShape(const QGeoCoordinate &coordinate) Q_DECL_OVERRIDE;
+ void translate(double degreesLatitude, double degreesLongitude);
+
+ QGeoShapePrivate *clone() const Q_DECL_OVERRIDE;
+
+ bool operator==(const QGeoShapePrivate &other) const Q_DECL_OVERRIDE;
+
+ const QList<QGeoCoordinate> &path() const;
+ void setPath(const QList<QGeoCoordinate> &path);
+ qreal width() const;
+ void setWidth(const qreal &width);
+ double length(int indexFrom, int indexTo) const;
+ void addCoordinate(const QGeoCoordinate &coordinate);
+ void insertCoordinate(int index, const QGeoCoordinate &coordinate);
+ void replaceCoordinate(int index, const QGeoCoordinate &coordinate);
+ QGeoCoordinate coordinateAt(int index) const;
+ bool containsCoordinate(const QGeoCoordinate &coordinate) const;
+ void removeCoordinate(const QGeoCoordinate &coordinate);
+ void removeCoordinate(int index);
+ void computeBoundingBox();
+ void updateBoundingBox();
+
+
+ QList<QGeoCoordinate> m_path;
+ QVector<double> m_deltaXs; // longitude deltas from m_path[0]
+ double m_minX; // minimum value inside deltaXs
+ double m_maxX; // maximum value inside deltaXs
+ double m_minLati; // minimum latitude. paths do not wrap around through the poles
+ double m_maxLati; // minimum latitude. paths do not wrap around through the poles
+ QGeoRectangle m_bbox;
+ qreal m_width;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOPATH_P_H
diff --git a/src/positioning/qgeorectangle.cpp b/src/positioning/qgeorectangle.cpp
index bbcafd6b..337b4c76 100644
--- a/src/positioning/qgeorectangle.cpp
+++ b/src/positioning/qgeorectangle.cpp
@@ -40,8 +40,11 @@
#include "qgeorectangle.h"
#include "qgeorectangle_p.h"
+#include "qwebmercator_p.h"
+#include "qdoublevector2d_p.h"
#include "qgeocoordinate.h"
#include "qnumeric.h"
+#include "qlocationutils_p.h"
#include <QList>
QT_BEGIN_NAMESPACE
@@ -440,16 +443,8 @@ void QGeoRectangle::setCenter(const QGeoCoordinate &center)
double tlLon = center.longitude() - width / 2.0;
double brLat = center.latitude() - height / 2.0;
double brLon = center.longitude() + width / 2.0;
-
- if (tlLon < -180.0)
- tlLon += 360.0;
- if (tlLon > 180.0)
- tlLon -= 360.0;
-
- if (brLon < -180.0)
- brLon += 360.0;
- if (brLon > 180.0)
- brLon -= 360.0;
+ tlLon = QLocationUtils::wrapLong(tlLon);
+ brLon = QLocationUtils::wrapLong(brLon);
if (tlLat > 90.0) {
brLat = 2 * center.latitude() - 90.0;
@@ -515,18 +510,10 @@ void QGeoRectangle::setWidth(double degreesWidth)
QGeoCoordinate c = center();
double tlLon = c.longitude() - degreesWidth / 2.0;
-
- if (tlLon < -180.0)
- tlLon += 360.0;
- if (tlLon > 180.0)
- tlLon -= 360.0;
+ tlLon = QLocationUtils::wrapLong(tlLon);
double brLon = c.longitude() + degreesWidth / 2.0;
-
- if (brLon < -180.0)
- brLon += 360.0;
- if (brLon > 180.0)
- brLon -= 360.0;
+ brLon = QLocationUtils::wrapLong(brLon);
d->topLeft = QGeoCoordinate(tlLat, tlLon);
d->bottomRight = QGeoCoordinate(brLat, brLon);
@@ -614,10 +601,7 @@ double QGeoRectangle::height() const
Q_D(const QGeoRectangle);
- double result = d->topLeft.latitude() - d->bottomRight.latitude();
- if (result < 0.0)
- result = qQNaN();
- return result;
+ return d->topLeft.latitude() - d->bottomRight.latitude();
}
bool QGeoRectanglePrivate::contains(const QGeoCoordinate &coordinate) const
@@ -666,14 +650,15 @@ QGeoCoordinate QGeoRectanglePrivate::center() const
if (topLeft.longitude() > bottomRight.longitude())
cLon = cLon - 180.0;
- if (cLon < -180.0)
- cLon += 360.0;
- if (cLon > 180.0)
- cLon -= 360.0;
-
+ cLon = QLocationUtils::wrapLong(cLon);
return QGeoCoordinate(cLat, cLon);
}
+QGeoRectangle QGeoRectanglePrivate::boundingGeoRectangle() const
+{
+ return QGeoRectangle(topLeft, bottomRight);
+}
+
/*!
Returns whether the geo rectangle \a rectangle is contained within this
geo rectangle.
@@ -763,37 +748,18 @@ void QGeoRectangle::translate(double degreesLatitude, double degreesLongitude)
double brLat = d->bottomRight.latitude();
double brLon = d->bottomRight.longitude();
- if ((tlLat != 90.0) || (brLat != -90.0)) {
- tlLat += degreesLatitude;
- brLat += degreesLatitude;
- }
+ if (degreesLatitude >= 0.0)
+ degreesLatitude = qMin(degreesLatitude, 90.0 - tlLat);
+ else
+ degreesLatitude = qMax(degreesLatitude, -90.0 - brLat);
if ( (tlLon != -180.0) || (brLon != 180.0) ) {
- tlLon += degreesLongitude;
- brLon += degreesLongitude;
+ tlLon = QLocationUtils::wrapLong(tlLon + degreesLongitude);
+ brLon = QLocationUtils::wrapLong(brLon + degreesLongitude);
}
- if (tlLon < -180.0)
- tlLon += 360.0;
- if (tlLon > 180.0)
- tlLon -= 360.0;
-
- if (brLon < -180.0)
- brLon += 360.0;
- if (brLon > 180.0)
- brLon -= 360.0;
-
- if (tlLat > 90.0)
- tlLat = 90.0;
-
- if (tlLat < -90.0)
- tlLat = -90.0;
-
- if (brLat > 90.0)
- brLat = 90.0;
-
- if (brLat < -90.0)
- brLat = -90.0;
+ tlLat += degreesLatitude;
+ brLat += degreesLatitude;
d->topLeft = QGeoCoordinate(tlLat, tlLon);
d->bottomRight = QGeoCoordinate(brLat, brLon);
@@ -816,6 +782,17 @@ QGeoRectangle QGeoRectangle::translated(double degreesLatitude, double degreesLo
}
/*!
+ Extends the geo rectangle to also cover the coordinate \a coordinate
+
+ \since 5.9
+*/
+void QGeoRectangle::extendRectangle(const QGeoCoordinate &coordinate)
+{
+ Q_D(QGeoRectangle);
+ d->extendShape(coordinate);
+}
+
+/*!
Returns the smallest geo rectangle which contains both this geo rectangle and \a rectangle.
If the centers of the two geo rectangles are separated by exactly 180.0 degrees then the
diff --git a/src/positioning/qgeorectangle.h b/src/positioning/qgeorectangle.h
index 7e921730..9e9acf91 100644
--- a/src/positioning/qgeorectangle.h
+++ b/src/positioning/qgeorectangle.h
@@ -42,89 +42,7 @@
#include <QtPositioning/QGeoShape>
-QT_BEGIN_NAMESPACE
-
-class QGeoCoordinate;
-class QGeoRectanglePrivate;
-
-class Q_POSITIONING_EXPORT QGeoRectangle : public QGeoShape
-{
- Q_GADGET
- Q_PROPERTY(QGeoCoordinate bottomLeft READ bottomLeft WRITE setBottomLeft)
- Q_PROPERTY(QGeoCoordinate bottomRight READ bottomRight WRITE setBottomRight)
- Q_PROPERTY(QGeoCoordinate topLeft READ topLeft WRITE setTopLeft)
- Q_PROPERTY(QGeoCoordinate topRight READ topRight WRITE setTopRight)
- Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter)
- Q_PROPERTY(double height READ height WRITE setHeight)
- Q_PROPERTY(double width READ width WRITE setWidth)
-
-public:
- QGeoRectangle();
- QGeoRectangle(const QGeoCoordinate &center, double degreesWidth, double degreesHeight);
- QGeoRectangle(const QGeoCoordinate &topLeft, const QGeoCoordinate &bottomRight);
- QGeoRectangle(const QList<QGeoCoordinate> &coordinates);
- QGeoRectangle(const QGeoRectangle &other);
- QGeoRectangle(const QGeoShape &other);
-
- ~QGeoRectangle();
-
- QGeoRectangle &operator=(const QGeoRectangle &other);
-
- using QGeoShape::operator==;
- bool operator==(const QGeoRectangle &other) const;
-
- using QGeoShape::operator!=;
- bool operator!=(const QGeoRectangle &other) const;
-
- void setTopLeft(const QGeoCoordinate &topLeft);
- QGeoCoordinate topLeft() const;
-
- void setTopRight(const QGeoCoordinate &topRight);
- QGeoCoordinate topRight() const;
-
- void setBottomLeft(const QGeoCoordinate &bottomLeft);
- QGeoCoordinate bottomLeft() const;
-
- void setBottomRight(const QGeoCoordinate &bottomRight);
- QGeoCoordinate bottomRight() const;
-
- void setCenter(const QGeoCoordinate &center);
- QGeoCoordinate center() const;
-
- void setWidth(double degreesWidth);
- double width() const;
-
- void setHeight(double degreesHeight);
- double height() const;
-
- using QGeoShape::contains;
- bool contains(const QGeoRectangle &rectangle) const;
- bool intersects(const QGeoRectangle &rectangle) const;
-
- void translate(double degreesLatitude, double degreesLongitude);
- QGeoRectangle translated(double degreesLatitude, double degreesLongitude) const;
-
- QGeoRectangle united(const QGeoRectangle &rectangle) const;
- QGeoRectangle operator|(const QGeoRectangle &rectangle) const;
- QGeoRectangle &operator|=(const QGeoRectangle &rectangle);
-
- Q_INVOKABLE QString toString() const;
-
-private:
- inline QGeoRectanglePrivate *d_func();
- inline const QGeoRectanglePrivate *d_func() const;
-};
-
-Q_DECLARE_TYPEINFO(QGeoRectangle, Q_MOVABLE_TYPE);
-
-inline QGeoRectangle QGeoRectangle::operator|(const QGeoRectangle &rectangle) const
-{
- return united(rectangle);
-}
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QGeoRectangle)
+// QGeoRectangle declaration now in qgeoshape.h.
+// This file remains for compatibility.
#endif
-
diff --git a/src/positioning/qgeorectangle_p.h b/src/positioning/qgeorectangle_p.h
index 188e5548..ee1b1732 100644
--- a/src/positioning/qgeorectangle_p.h
+++ b/src/positioning/qgeorectangle_p.h
@@ -70,6 +70,8 @@ public:
QGeoCoordinate center() const Q_DECL_OVERRIDE;
+ QGeoRectangle boundingGeoRectangle() const Q_DECL_OVERRIDE;
+
void extendShape(const QGeoCoordinate &coordinate) Q_DECL_OVERRIDE;
QGeoShapePrivate *clone() const Q_DECL_OVERRIDE;
diff --git a/src/positioning/qgeoshape.cpp b/src/positioning/qgeoshape.cpp
index bac37605..60ef18a4 100644
--- a/src/positioning/qgeoshape.cpp
+++ b/src/positioning/qgeoshape.cpp
@@ -41,6 +41,8 @@
#include "qgeoshape_p.h"
#include "qgeorectangle.h"
#include "qgeocircle.h"
+#include "qgeopath.h"
+
#ifndef QT_NO_DEBUG_STREAM
#include <QtCore/QDebug>
@@ -227,6 +229,22 @@ bool QGeoShape::contains(const QGeoCoordinate &coordinate) const
}
/*!
+ Returns a \a QGeoRectangle representing the geographical bounding rectangle of the
+ geo shape, that defines the latitudinal/longitudinal bounds of the geo shape.
+
+ \since 5.9
+*/
+QGeoRectangle QGeoShape::boundingGeoRectangle() const
+{
+ Q_D(const QGeoShape);
+
+ if (d)
+ return d->boundingGeoRectangle();
+ else
+ return QGeoRectangle();
+}
+
+/*!
Returns the coordinate located at the geometric center of the geo shape.
\since 5.5
@@ -242,7 +260,17 @@ QGeoCoordinate QGeoShape::center() const
}
/*!
- Extends the geo shape to also cover the coordinate \a coordinate
+ \deprecated
+
+ This method used to extend the geo shape to also cover the coordinate \a coordinate.
+
+ It currently only works for \l QGeoCircle and \l QGeoRectangle, on which the functionality remains,
+ now also accessible through QGeoCircle::extendCircle and QGeoRectangle::extendRectangle.
+
+ This method should therefore not be called on a generic QGeoShape any longer, as the behavior for
+ other shape types is undefined.
+
+ \sa QGeoRectangle::extendRectangle, QGeoCircle::extendCircle
*/
void QGeoShape::extendShape(const QGeoCoordinate &coordinate)
{
@@ -313,6 +341,9 @@ QDebug operator<<(QDebug dbg, const QGeoShape &shape)
case QGeoShape::RectangleType:
dbg << "Rectangle";
break;
+ case QGeoShape::PathType:
+ dbg << "Path";
+ break;
case QGeoShape::CircleType:
dbg << "Circle";
}
@@ -340,6 +371,13 @@ QDataStream &operator<<(QDataStream &stream, const QGeoShape &shape)
stream << c.center() << c.radius();
break;
}
+ case QGeoShape::PathType: {
+ QGeoPath p = shape;
+ stream << p.path().size();
+ for (const auto &c: p.path())
+ stream << c;
+ break;
+ }
}
return stream;
@@ -368,6 +406,18 @@ QDataStream &operator>>(QDataStream &stream, QGeoShape &shape)
shape = QGeoCircle(c, r);
break;
}
+ case QGeoShape::PathType: {
+ QList<QGeoCoordinate> l;
+ QGeoCoordinate c;
+ int sz;
+ stream >> sz;
+ for (int i = 0; i < sz; i++) {
+ stream >> c;
+ l.append(c);
+ }
+ shape = QGeoPath(l);
+ break;
+ }
}
return stream;
diff --git a/src/positioning/qgeoshape.h b/src/positioning/qgeoshape.h
index f8a30358..441c9ebb 100644
--- a/src/positioning/qgeoshape.h
+++ b/src/positioning/qgeoshape.h
@@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE
class QDebug;
class QGeoShapePrivate;
+class QGeoRectangle;
class Q_POSITIONING_EXPORT QGeoShape
{
@@ -64,7 +65,8 @@ public:
enum ShapeType {
UnknownType,
RectangleType,
- CircleType
+ CircleType,
+ PathType
};
ShapeType type() const;
@@ -72,10 +74,10 @@ public:
bool isValid() const;
bool isEmpty() const;
Q_INVOKABLE bool contains(const QGeoCoordinate &coordinate) const;
+ Q_INVOKABLE QGeoRectangle boundingGeoRectangle() const;
+ Q_INVOKABLE QGeoCoordinate center() const;
- QGeoCoordinate center() const;
-
- void extendShape(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void extendShape(const QGeoCoordinate &coordinate);
bool operator==(const QGeoShape &other) const;
bool operator!=(const QGeoShape &other) const;
@@ -104,9 +106,90 @@ Q_POSITIONING_EXPORT QDataStream &operator<<(QDataStream &stream, const QGeoShap
Q_POSITIONING_EXPORT QDataStream &operator>>(QDataStream &stream, QGeoShape &shape);
#endif
+
+
+// QGeoRectangle is declared here because of QGeoShape::boundingGeoRectangle
+class QGeoRectanglePrivate;
+
+class Q_POSITIONING_EXPORT QGeoRectangle : public QGeoShape
+{
+ Q_GADGET
+ Q_PROPERTY(QGeoCoordinate bottomLeft READ bottomLeft WRITE setBottomLeft)
+ Q_PROPERTY(QGeoCoordinate bottomRight READ bottomRight WRITE setBottomRight)
+ Q_PROPERTY(QGeoCoordinate topLeft READ topLeft WRITE setTopLeft)
+ Q_PROPERTY(QGeoCoordinate topRight READ topRight WRITE setTopRight)
+ Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter)
+ Q_PROPERTY(double height READ height WRITE setHeight)
+ Q_PROPERTY(double width READ width WRITE setWidth)
+
+public:
+ QGeoRectangle();
+ QGeoRectangle(const QGeoCoordinate &center, double degreesWidth, double degreesHeight);
+ QGeoRectangle(const QGeoCoordinate &topLeft, const QGeoCoordinate &bottomRight);
+ QGeoRectangle(const QList<QGeoCoordinate> &coordinates);
+ QGeoRectangle(const QGeoRectangle &other);
+ QGeoRectangle(const QGeoShape &other);
+
+ ~QGeoRectangle();
+
+ QGeoRectangle &operator=(const QGeoRectangle &other);
+
+ using QGeoShape::operator==;
+ bool operator==(const QGeoRectangle &other) const;
+
+ using QGeoShape::operator!=;
+ bool operator!=(const QGeoRectangle &other) const;
+
+ void setTopLeft(const QGeoCoordinate &topLeft);
+ QGeoCoordinate topLeft() const;
+
+ void setTopRight(const QGeoCoordinate &topRight);
+ QGeoCoordinate topRight() const;
+
+ void setBottomLeft(const QGeoCoordinate &bottomLeft);
+ QGeoCoordinate bottomLeft() const;
+
+ void setBottomRight(const QGeoCoordinate &bottomRight);
+ QGeoCoordinate bottomRight() const;
+
+ void setCenter(const QGeoCoordinate &center);
+ QGeoCoordinate center() const;
+
+ void setWidth(double degreesWidth);
+ double width() const;
+
+ void setHeight(double degreesHeight);
+ double height() const;
+
+ using QGeoShape::contains;
+ bool contains(const QGeoRectangle &rectangle) const;
+ Q_INVOKABLE bool intersects(const QGeoRectangle &rectangle) const;
+
+ Q_INVOKABLE void translate(double degreesLatitude, double degreesLongitude);
+ Q_INVOKABLE QGeoRectangle translated(double degreesLatitude, double degreesLongitude) const;
+ Q_INVOKABLE void extendRectangle(const QGeoCoordinate &coordinate);
+
+ Q_INVOKABLE QGeoRectangle united(const QGeoRectangle &rectangle) const;
+ QGeoRectangle operator|(const QGeoRectangle &rectangle) const;
+ QGeoRectangle &operator|=(const QGeoRectangle &rectangle);
+
+ Q_INVOKABLE QString toString() const;
+
+private:
+ inline QGeoRectanglePrivate *d_func();
+ inline const QGeoRectanglePrivate *d_func() const;
+};
+
+Q_DECLARE_TYPEINFO(QGeoRectangle, Q_MOVABLE_TYPE);
+
+inline QGeoRectangle QGeoRectangle::operator|(const QGeoRectangle &rectangle) const
+{
+ return united(rectangle);
+}
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QGeoShape)
+Q_DECLARE_METATYPE(QGeoRectangle)
#endif
-
diff --git a/src/positioning/qgeoshape_p.h b/src/positioning/qgeoshape_p.h
index 275886ff..251e872c 100644
--- a/src/positioning/qgeoshape_p.h
+++ b/src/positioning/qgeoshape_p.h
@@ -69,6 +69,8 @@ public:
virtual QGeoCoordinate center() const = 0;
+ virtual QGeoRectangle boundingGeoRectangle() const = 0;
+
virtual void extendShape(const QGeoCoordinate &coordinate) = 0;
virtual QGeoShapePrivate *clone() const = 0;
@@ -89,4 +91,3 @@ Q_INLINE_TEMPLATE QGeoShapePrivate *QSharedDataPointer<QGeoShapePrivate>::clone(
QT_END_NAMESPACE
#endif
-
diff --git a/src/positioning/qlocationutils_p.h b/src/positioning/qlocationutils_p.h
index 00c4d3e3..f66179e1 100644
--- a/src/positioning/qlocationutils_p.h
+++ b/src/positioning/qlocationutils_p.h
@@ -52,6 +52,16 @@
#include <QtCore/QtGlobal>
#include <math.h>
+#include <QtPositioning/QGeoCoordinate>
+
+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;
@@ -81,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;
}
@@ -176,6 +186,69 @@ public:
return CardinalNNW;
}
+ // For values exceeding +- 720.0
+ inline static double wrapLongExt(double lng) {
+ double remainder = fmod(lng + 180.0, 360.0);
+ return fmod(remainder + 360.0, 360.0) - 180.0;
+ }
+
+ // Mirrors the azimuth against the X axis. Azimuth assumed to be in [0,360[
+ inline static double mirrorAzimuthX(double azimuth) {
+ if (azimuth <= 90.0)
+ return 180.0 - azimuth;
+ else
+ return 180.0 + (360.0 - azimuth);
+ }
+
+ // Mirrors the azimuth against the Y axis. Azimuth assumed to be in [0,360[
+ inline static double mirrorAzimuthY(double azimuth) {
+ if (azimuth == 0.0)
+ return 0.0;
+ return 360.0 - azimuth;
+ }
+
+ inline static double radians(double degrees)
+ {
+ return degrees * M_PI_180D;
+ }
+
+ inline static double degrees(double radians)
+ {
+ return radians * M_180_PID;
+ }
+
+ inline static double earthMeanRadius()
+ {
+ 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/qgeoprojection.cpp b/src/positioning/qwebmercator.cpp
index 507f0805..da35c7d7 100644
--- a/src/positioning/qgeoprojection.cpp
+++ b/src/positioning/qwebmercator.cpp
@@ -36,7 +36,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include "qgeoprojection_p.h"
+#include "qwebmercator_p.h"
#include "qgeocoordinate.h"
@@ -49,7 +49,7 @@
QT_BEGIN_NAMESPACE
-QDoubleVector2D QGeoProjection::coordToMercator(const QGeoCoordinate &coord)
+QDoubleVector2D QWebMercator::coordToMercator(const QGeoCoordinate &coord)
{
const double pi = M_PI;
@@ -62,13 +62,13 @@ QDoubleVector2D QGeoProjection::coordToMercator(const QGeoCoordinate &coord)
return QDoubleVector2D(lon, lat);
}
-double QGeoProjection::realmod(const double a, const double b)
+double QWebMercator::realmod(const double a, const double b)
{
quint64 div = static_cast<quint64>(a / b);
return a - static_cast<double>(div) * b;
}
-QGeoCoordinate QGeoProjection::mercatorToCoord(const QDoubleVector2D &mercator)
+QGeoCoordinate QWebMercator::mercatorToCoord(const QDoubleVector2D &mercator)
{
const double pi = M_PI;
@@ -101,10 +101,34 @@ QGeoCoordinate QGeoProjection::mercatorToCoord(const QDoubleVector2D &mercator)
return QGeoCoordinate(lat, lng, 0.0);
}
-QGeoCoordinate QGeoProjection::coordinateInterpolation(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
+QGeoCoordinate QWebMercator::mercatorToCoordClamped(const QDoubleVector2D &mercator)
{
- QDoubleVector2D s = QGeoProjection::coordToMercator(from);
- QDoubleVector2D e = QGeoProjection::coordToMercator(to);
+ 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);
+ QDoubleVector2D e = QWebMercator::coordToMercator(to);
double x = s.x();
@@ -128,7 +152,7 @@ QGeoCoordinate QGeoProjection::coordinateInterpolation(const QGeoCoordinate &fro
double y = (1.0 - progress) * s.y() + progress * e.y();
- QGeoCoordinate result = QGeoProjection::mercatorToCoord(QDoubleVector2D(x, y));
+ QGeoCoordinate result = QWebMercator::mercatorToCoord(QDoubleVector2D(x, y));
result.setAltitude((1.0 - progress) * from.altitude() + progress * to.altitude());
return result;
diff --git a/src/positioning/qgeoprojection_p.h b/src/positioning/qwebmercator_p.h
index b80678b7..2b8e9564 100644
--- a/src/positioning/qgeoprojection_p.h
+++ b/src/positioning/qwebmercator_p.h
@@ -36,8 +36,8 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef QGEOPROJECTION_P_H
-#define QGEOPROJECTION_P_H
+#ifndef QWEBMERCATOR_P_H
+#define QWEBMERCATOR_P_H
//
// W A R N I N G
@@ -50,24 +50,22 @@
// We mean it.
//
-#ifndef M_PI
-#define M_PI (3.14159265358979323846)
-#endif
-
#include <qglobal.h>
#include <QtCore/qvariant.h>
-#include "qpositioningglobal.h"
+#include <math.h>
+#include "qpositioningglobal_p.h"
QT_BEGIN_NAMESPACE
class QGeoCoordinate;
class QDoubleVector2D;
-class Q_POSITIONING_EXPORT QGeoProjection
+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:
@@ -76,4 +74,4 @@ private:
QT_END_NAMESPACE
-#endif // QGEOPROJECTION_P_H
+#endif // QWEBMERCATOR_P_H
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
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index e3236deb..ba7dc523 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -74,6 +74,7 @@ SUBDIRS += \
qgeoshape \
qgeorectangle \
qgeocircle \
+ qgeopath \
qgeocoordinate \
qgeolocation \
qgeopositioninfo \
diff --git a/tests/auto/declarative_ui/ItemGroup.qml b/tests/auto/declarative_ui/ItemGroup.qml
new file mode 100644
index 00000000..57108ec7
--- /dev/null
+++ b/tests/auto/declarative_ui/ItemGroup.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtPositioning 5.6
+import QtLocation 5.9
+import QtLocation.Test 5.6
+
+MapItemGroup {
+ id: itemGroup
+ property double latitude : (mainRectangle.topLeft.latitude + mainRectangle.bottomRight.latitude) / 2.0
+ property double longitude: (mainRectangle.topLeft.longitude + mainRectangle.bottomRight.longitude) / 2.0
+ property double radius: 100 * 1000
+
+ MapRectangle {
+ id: mainRectangle
+ topLeft: QtPositioning.coordinate(43, -3)
+ bottomRight: QtPositioning.coordinate(37, 3)
+ opacity: 0.05
+ visible: true
+ color: 'blue'
+ }
+
+ MapCircle {
+ id: groupCircle
+ center: QtPositioning.coordinate(parent.latitude, parent.longitude)
+ radius: parent.radius
+ color: 'crimson'
+ }
+
+ MapRectangle {
+ id: groupRectangle
+ topLeft: QtPositioning.coordinate(parent.latitude + 5, parent.longitude - 5)
+ bottomRight: QtPositioning.coordinate(parent.latitude, parent.longitude )
+ color: 'yellow'
+ }
+}
diff --git a/tests/auto/declarative_ui/declarative_ui.pro b/tests/auto/declarative_ui/declarative_ui.pro
index d3a2f08e..6734b1f9 100644
--- a/tests/auto/declarative_ui/declarative_ui.pro
+++ b/tests/auto/declarative_ui/declarative_ui.pro
@@ -16,3 +16,6 @@ TESTDATA = $$OTHER_FILES
# Import path used by 'make check' since CI doesn't install test imports
IMPORTPATH = $$OUT_PWD/../../../qml
+
+DISTFILES += \
+ ItemGroup.qml
diff --git a/tests/auto/declarative_ui/tst_map.qml b/tests/auto/declarative_ui/tst_map.qml
index 5f02962d..ab1ddd8c 100644
--- a/tests/auto/declarative_ui/tst_map.qml
+++ b/tests/auto/declarative_ui/tst_map.qml
@@ -28,8 +28,8 @@
import QtQuick 2.0
import QtTest 1.0
-import QtLocation 5.6
import QtPositioning 5.5
+import QtLocation 5.9
Item {
width:100
@@ -79,10 +79,22 @@ Item {
Map {id: map; plugin: testPlugin; center: coordinate1; width: 100; height: 100}
SignalSpy {id: mapCenterSpy; target: map; signalName: 'centerChanged'}
+ Map {id: mapPar; plugin: testPlugin; center: coordinate1; width: 512; height: 512}
+
Map {id: coordinateMap; plugin: herePlugin; center: coordinate3;
width: 1000; height: 1000; zoomLevel: 15 }
+ Map {id: mapTiltBearing; plugin: testPlugin; center: coordinate1;
+ width: 1000; height: 1000; zoomLevel: 4; bearing: 45.0; tilt: 25.0 }
+
+ Map {id: mapTiltBearingHere; plugin: herePlugin; center: coordinate1;
+ width: 1000; height: 1000; zoomLevel: 4; bearing: 45.0; tilt: 25.0 }
+ MapParameter {
+ id: testParameter
+ type: "cameraCenter_test"
+ property var center: QtPositioning.coordinate(-33.0, -47.0)
+ }
TestCase {
@@ -128,6 +140,51 @@ Item {
compare(map.center.latitude, 12)
}
+ function test_map_parameters()
+ {
+ // coordinate is set at map element declaration
+ var center = mapPar.toCoordinate(Qt.point((mapPar.width - 1) / 2.0, (mapPar.height - 1) / 2.0))
+ fuzzyCompare(center.latitude, 10, 0.1)
+ fuzzyCompare(center.longitude, 11, 0.1)
+
+ compare(mapPar.mapParameters.length, 0)
+
+ mapPar.addMapParameter(testParameter)
+
+ compare(mapPar.mapParameters.length, 1)
+
+ center = mapPar.toCoordinate(Qt.point((mapPar.width - 1) / 2.0, (mapPar.height - 1) / 2.0))
+ fuzzyCompare(center.latitude, -33, 0.1)
+ fuzzyCompare(center.longitude, -47, 0.1)
+
+ mapPar.addMapParameter(testParameter)
+ compare(mapPar.mapParameters.length, 1)
+
+ mapPar.removeMapParameter(testParameter)
+ compare(mapPar.mapParameters.length, 0)
+
+ center = mapPar.toCoordinate(Qt.point((mapPar.width - 1) / 2.0, (mapPar.height - 1) / 2.0))
+ fuzzyCompare(center.latitude, -33, 0.1)
+ fuzzyCompare(center.longitude, -47, 0.1)
+
+ testParameter.center = mapPar.center // map.center has not been affected as it lives in the Declarative Map
+ mapPar.addMapParameter(testParameter)
+ compare(mapPar.mapParameters.length, 1)
+
+ center = mapPar.toCoordinate(Qt.point((mapPar.width - 1) / 2.0, (mapPar.height - 1) / 2.0))
+ fuzzyCompare(center.latitude, 10, 0.1)
+ fuzzyCompare(center.longitude, 11, 0.1)
+
+ testParameter.center = QtPositioning.coordinate(-33.0, -47.0)
+
+ center = mapPar.toCoordinate(Qt.point((mapPar.width - 1) / 2.0, (mapPar.height - 1) / 2.0))
+ fuzzyCompare(center.latitude, -33, 0.1)
+ fuzzyCompare(center.longitude, -47, 0.1)
+
+ mapPar.removeMapParameter(testParameter)
+ compare(mapPar.mapParameters.length, 0)
+ }
+
function test_map_clamp()
{
//valid
@@ -298,6 +355,44 @@ Item {
mapCenterSpy.clear()
}
+ function test_map_tilt_bearing()
+ {
+ compare(map.bearing, 0.0)
+ compare(map.tilt, 0.0)
+ compare(mapTiltBearing.bearing, 45.0)
+ compare(mapTiltBearing.tilt, 25.0)
+ compare(mapTiltBearingHere.bearing, 45.0)
+ compare(mapTiltBearingHere.tilt, 25.0)
+
+ mapTiltBearing.bearing = 0.0
+ mapTiltBearing.tilt = 0.0
+ compare(mapTiltBearing.bearing, 0.0)
+ compare(mapTiltBearing.tilt, 0.0)
+
+ mapTiltBearing.bearing = 480.0
+ mapTiltBearing.tilt = 140.0
+ compare(mapTiltBearing.bearing, 120.0)
+ compare(mapTiltBearing.tilt, 60.0)
+
+ mapTiltBearing.tilt = -140.0
+ compare(mapTiltBearing.tilt, 0.0)
+
+ mapTiltBearingHere.bearing = 45.0
+ mapTiltBearingHere.tilt = 25.0
+ compare(mapTiltBearingHere.bearing, 45.0)
+ compare(mapTiltBearingHere.tilt, 25.0)
+ mapTiltBearingHere.bearing = 0.0
+ mapTiltBearingHere.tilt = 0.0
+ compare(mapTiltBearingHere.bearing, 0.0)
+ compare(mapTiltBearingHere.tilt, 0.0)
+
+ mapTiltBearing.bearing = 45.0
+ mapTiltBearing.tilt = 25.0
+ mapTiltBearing.zoomLevel = 8.0
+ compare(mapTiltBearing.bearing, 45.0)
+ compare(mapTiltBearing.tilt, 25.0)
+ }
+
function test_coordinate_conversion()
{
wait(1000)
diff --git a/tests/auto/declarative_ui/tst_map_error.qml b/tests/auto/declarative_ui/tst_map_error.qml
index c978e0cf..35613f63 100644
--- a/tests/auto/declarative_ui/tst_map_error.qml
+++ b/tests/auto/declarative_ui/tst_map_error.qml
@@ -192,10 +192,16 @@ Item {
{
map_no_plugin.visibleRegion = QtPositioning.circle(coordinate,1000)
verify(map_no_plugin.center != coordinate)
- verify(map_no_plugin.visibleRegion == QtPositioning.circle(coordinate,1000))
+ verify(map_no_plugin.visibleRegion.contains(coordinate.atDistanceAndAzimuth(1000,0)) == true)
+ verify(map_no_plugin.visibleRegion.contains(coordinate.atDistanceAndAzimuth(1000,90)) == true)
+ verify(map_no_plugin.visibleRegion.contains(coordinate.atDistanceAndAzimuth(1000,180)) == true)
+ verify(map_no_plugin.visibleRegion.contains(coordinate.atDistanceAndAzimuth(1000,270)) == true)
map_error_plugin.visibleRegion = QtPositioning.circle(coordinate,1000)
verify(map_error_plugin.center != coordinate)
- verify(map_no_plugin.visibleRegion == QtPositioning.circle(coordinate,1000))
+ verify(map_error_plugin.visibleRegion.contains(coordinate.atDistanceAndAzimuth(1000,0)) == true)
+ verify(map_error_plugin.visibleRegion.contains(coordinate.atDistanceAndAzimuth(1000,90)) == true)
+ verify(map_error_plugin.visibleRegion.contains(coordinate.atDistanceAndAzimuth(1000,180)) == true)
+ verify(map_error_plugin.visibleRegion.contains(coordinate.atDistanceAndAzimuth(1000,270)) == true)
}
function test_map_activeMapType()
diff --git a/tests/auto/declarative_ui/tst_map_item.qml b/tests/auto/declarative_ui/tst_map_item.qml
index 8ede357f..b75daf38 100644
--- a/tests/auto/declarative_ui/tst_map_item.qml
+++ b/tests/auto/declarative_ui/tst_map_item.qml
@@ -28,7 +28,7 @@
import QtQuick 2.0
import QtTest 1.0
-import QtLocation 5.6
+import QtLocation 5.9
import QtPositioning 5.5
import QtLocation.Test 5.6
@@ -75,6 +75,10 @@ Item {
}
Item { id: someItem }
+ ItemGroup {
+ id: itemGroup1
+ }
+
MapCircle {
id: extMapCircle
center {
@@ -403,6 +407,10 @@ Item {
mouseClick(map, map.width + 5, point.y + 5)
tryCompare(extMapQuickItemClicked, "count", 1)
map.removeMapItem(extMapQuickItem)
+
+ var numItemsOnMap = map.mapItems.length
+ map.addMapItemGroup( itemGroup1 )
+ compare(map.mapItems.length, numItemsOnMap + 3)
}
function test_drag()
diff --git a/tests/auto/geotestplugin/geotestplugin.pro b/tests/auto/geotestplugin/geotestplugin.pro
index fb3f1b39..f4fe25b3 100644
--- a/tests/auto/geotestplugin/geotestplugin.pro
+++ b/tests/auto/geotestplugin/geotestplugin.pro
@@ -14,7 +14,8 @@ HEADERS += qgeocodingmanagerengine_test.h \
qgeotiledmap_test.h \
qgeotilefetcher_test.h
-SOURCES += qgeoserviceproviderplugin_test.cpp
+SOURCES += qgeoserviceproviderplugin_test.cpp \
+ qgeotiledmap_test.cpp
OTHER_FILES += \
geotestplugin.json \
diff --git a/tests/auto/geotestplugin/qgeocodingmanagerengine_test.h b/tests/auto/geotestplugin/qgeocodingmanagerengine_test.h
index 1d9f0792..ecbb60d1 100644
--- a/tests/auto/geotestplugin/qgeocodingmanagerengine_test.h
+++ b/tests/auto/geotestplugin/qgeocodingmanagerengine_test.h
@@ -57,11 +57,6 @@ public:
void callSetOffset ( int offset ) {setOffset(offset);}
void callSetLocations ( const QList<QGeoLocation> & locations ) {setLocations(locations);}
void callSetViewport ( const QGeoShape &viewport ) {setViewport(viewport);}
- void abort() {
- emit aborted();
- }
-Q_SIGNALS:
- void aborted();
};
class QGeoCodingManagerEngineTest: public QGeoCodingManagerEngine
diff --git a/tests/auto/geotestplugin/qgeoroutingmanagerengine_test.h b/tests/auto/geotestplugin/qgeoroutingmanagerengine_test.h
index 8ae58042..0a1e7ce6 100644
--- a/tests/auto/geotestplugin/qgeoroutingmanagerengine_test.h
+++ b/tests/auto/geotestplugin/qgeoroutingmanagerengine_test.h
@@ -52,12 +52,6 @@ public:
void callSetError ( Error error, const QString & errorString ) {setError(error, errorString);}
void callSetFinished ( bool finished ) {setFinished(finished);}
void callSetRoutes(const QList<QGeoRoute> &routes) {setRoutes(routes);}
-
- void abort() {
- emit aborted();
- }
-Q_SIGNALS:
- void aborted();
};
class QGeoRoutingManagerEngineTest: public QGeoRoutingManagerEngine
diff --git a/tests/auto/geotestplugin/qgeotiledmap_test.cpp b/tests/auto/geotestplugin/qgeotiledmap_test.cpp
new file mode 100644
index 00000000..ef2af7db
--- /dev/null
+++ b/tests/auto/geotestplugin/qgeotiledmap_test.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeotiledmap_test.h"
+#include <QtLocation/private/qgeotiledmap_p_p.h>
+#include <QtLocation/private/qgeomapparameter_p.h>
+
+QT_USE_NAMESPACE
+
+class QGeoTiledMapTestPrivate: public QGeoTiledMapPrivate
+{
+ Q_DECLARE_PUBLIC(QGeoTiledMapTest)
+public:
+ QGeoTiledMapTestPrivate(QGeoTiledMappingManagerEngine *engine)
+ : QGeoTiledMapPrivate(engine)
+ {
+
+ }
+
+ ~QGeoTiledMapTestPrivate()
+ {
+
+ }
+
+ void addParameter(QGeoMapParameter *param) override
+ {
+ Q_Q(QGeoTiledMapTest);
+ if (param->type() == QStringLiteral("cameraCenter_test")) {
+ // We assume that cameraCenter_test parameters have a QGeoCoordinate property named "center"
+ // Handle the parameter
+ QGeoCameraData cameraData = m_cameraData;
+ QGeoCoordinate newCenter = param->property("center").value<QGeoCoordinate>();
+ cameraData.setCenter(newCenter);
+ q->setCameraData(cameraData);
+ // Connect for further changes handling
+ q->connect(param, SIGNAL(propertyUpdated(QGeoMapParameter *, const char *)),
+ q, SLOT(onCameraCenter_testChanged(QGeoMapParameter*, const char*)));
+
+ }
+ }
+ void removeParameter(QGeoMapParameter *param) override
+ {
+ Q_Q(QGeoTiledMapTest);
+ param->disconnect(q);
+ }
+};
+
+QGeoTiledMapTest::QGeoTiledMapTest(QGeoTiledMappingManagerEngine *engine, QObject *parent)
+: QGeoTiledMap(*new QGeoTiledMapTestPrivate(engine), engine, parent), m_engine(engine)
+{
+}
+
+void QGeoTiledMapTest::onCameraCenter_testChanged(QGeoMapParameter *param, const char *propertyName)
+{
+ Q_D(QGeoTiledMapTest);
+ if (strcmp(propertyName, "center") == 0) {
+ QGeoCameraData cameraData = d->m_cameraData;
+ // Not testing for propertyName as this param has only one allowed property
+ QGeoCoordinate newCenter = param->property(propertyName).value<QGeoCoordinate>();
+ cameraData.setCenter(newCenter);
+ setCameraData(cameraData);
+ }
+}
diff --git a/tests/auto/geotestplugin/qgeotiledmap_test.h b/tests/auto/geotestplugin/qgeotiledmap_test.h
index 27ff7164..19c7620e 100644
--- a/tests/auto/geotestplugin/qgeotiledmap_test.h
+++ b/tests/auto/geotestplugin/qgeotiledmap_test.h
@@ -33,17 +33,25 @@
#include <QtLocation/private/qgeotiledmap_p.h>
QT_USE_NAMESPACE
+
class QGeoTiledMappingManagerEngineTest;
+class QGeoTiledMapTestPrivate;
+
class QGeoTiledMapTest: public QGeoTiledMap
{
Q_OBJECT
+ Q_DECLARE_PRIVATE(QGeoTiledMapTest)
public:
- QGeoTiledMapTest(QGeoTiledMappingManagerEngine *engine, QObject *parent = 0):
- QGeoTiledMap(engine, parent),
- m_engine(engine){}
+ QGeoTiledMapTest(QGeoTiledMappingManagerEngine *engine, QObject *parent = 0);
+
+protected slots:
+ void onCameraCenter_testChanged(QGeoMapParameter *param, const char *propertyName);
+
public:
using QGeoTiledMap::setCameraData;
QGeoTiledMappingManagerEngine *m_engine;
};
#endif
+
+
diff --git a/tests/auto/geotestplugin/qgeotiledmappingmanagerengine_test.h b/tests/auto/geotestplugin/qgeotiledmappingmanagerengine_test.h
index 2765c268..015a203a 100644
--- a/tests/auto/geotestplugin/qgeotiledmappingmanagerengine_test.h
+++ b/tests/auto/geotestplugin/qgeotiledmappingmanagerengine_test.h
@@ -57,6 +57,9 @@ public:
capabilities.setMinimumZoomLevel(0.0);
capabilities.setMaximumZoomLevel(20.0);
capabilities.setSupportsBearing(true);
+ capabilities.setSupportsTilting(true);
+ capabilities.setMinimumTilt(0);
+ capabilities.setMaximumTilt(60);
setTileSize(QSize(256, 256));
QList<QGeoMapType> mapTypes;
diff --git a/tests/auto/qgeocameracapabilities/tst_qgeocameracapabilities.cpp b/tests/auto/qgeocameracapabilities/tst_qgeocameracapabilities.cpp
index 54755421..09d7293b 100644
--- a/tests/auto/qgeocameracapabilities/tst_qgeocameracapabilities.cpp
+++ b/tests/auto/qgeocameracapabilities/tst_qgeocameracapabilities.cpp
@@ -29,8 +29,8 @@
#include <QtCore/QString>
#include <QtTest/QtTest>
-#include "qgeocameracapabilities_p.h"
-#include "qgeotiledmap_p.h"
+#include <QtLocation/private/qgeocameracapabilities_p.h>
+#include <QtLocation/private/qgeotiledmap_p.h>
QT_USE_NAMESPACE
diff --git a/tests/auto/qgeocameradata/qgeocameradata.pro b/tests/auto/qgeocameradata/qgeocameradata.pro
index f2d6d5d8..80069ea1 100644
--- a/tests/auto/qgeocameradata/qgeocameradata.pro
+++ b/tests/auto/qgeocameradata/qgeocameradata.pro
@@ -6,4 +6,4 @@ INCLUDEPATH += ../../../src/location/maps
SOURCES += tst_qgeocameradata.cpp
-QT += location positioning-private testlib
+QT += location-private positioning-private testlib
diff --git a/tests/auto/qgeocameratiles/qgeocameratiles.pro b/tests/auto/qgeocameratiles/qgeocameratiles.pro
index 816e4240..63ab2771 100644
--- a/tests/auto/qgeocameratiles/qgeocameratiles.pro
+++ b/tests/auto/qgeocameratiles/qgeocameratiles.pro
@@ -5,4 +5,4 @@ INCLUDEPATH += ../../../src/location/maps
SOURCES += tst_qgeocameratiles.cpp
-QT += location positioning-private testlib
+QT += location-private positioning-private testlib
diff --git a/tests/auto/qgeocameratiles/tst_qgeocameratiles.cpp b/tests/auto/qgeocameratiles/tst_qgeocameratiles.cpp
index 8d9cec3a..33ebda67 100644
--- a/tests/auto/qgeocameratiles/tst_qgeocameratiles.cpp
+++ b/tests/auto/qgeocameratiles/tst_qgeocameratiles.cpp
@@ -28,12 +28,12 @@
//TESTED_COMPONENT=src/location/maps
-#include "qgeotilespec_p.h"
-#include "qgeocameratiles_p.h"
-#include "qgeocameradata_p.h"
-#include "qgeomaptype_p.h"
+#include <QtLocation/private/qgeotilespec_p.h>
+#include <QtLocation/private/qgeocameratiles_p.h>
+#include <QtLocation/private/qgeocameradata_p.h>
+#include <QtLocation/private/qgeomaptype_p.h>
-#include <QtPositioning/private/qgeoprojection_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QtTest/QtTest>
#include <QtCore/QList>
@@ -226,7 +226,7 @@ void tst_QGeoCameraTiles::tilesPositions()
QGeoCameraData camera;
camera.setZoomLevel(zoom);
- camera.setCenter(QGeoProjection::mercatorToCoord(QDoubleVector2D(mercatorX, mercatorY)));
+ camera.setCenter(QWebMercator::mercatorToCoord(QDoubleVector2D(mercatorX, mercatorY)));
QGeoCameraTiles ct;
ct.setTileSize(16);
diff --git a/tests/auto/qgeocircle/tst_qgeocircle.cpp b/tests/auto/qgeocircle/tst_qgeocircle.cpp
index 01fbed6b..8777e7d9 100644
--- a/tests/auto/qgeocircle/tst_qgeocircle.cpp
+++ b/tests/auto/qgeocircle/tst_qgeocircle.cpp
@@ -60,8 +60,11 @@ private slots:
void contains_data();
void contains();
- void extendShape();
- void extendShape_data();
+ void boundingGeoRectangle_data();
+ void boundingGeoRectangle();
+
+ void extendCircle();
+ void extendCircle_data();
void areaComparison();
void areaComparison_data();
@@ -243,7 +246,7 @@ void tst_QGeoCircle::valid()
QCOMPARE(c.isValid(), valid);
QGeoShape area = c;
- QCOMPARE(c.isValid(), valid);
+ QCOMPARE(area.isValid(), valid);
}
void tst_QGeoCircle::empty_data()
@@ -281,7 +284,7 @@ void tst_QGeoCircle::contains_data()
QTest::addColumn<QGeoCoordinate>("probe");
QTest::addColumn<bool>("result");
- QTest::newRow("own centre") << QGeoCoordinate(1,1) << qreal(100.0) <<
+ QTest::newRow("own center") << QGeoCoordinate(1,1) << qreal(100.0) <<
QGeoCoordinate(1,1) << true;
QTest::newRow("over the hills") << QGeoCoordinate(1,1) << qreal(100.0) <<
QGeoCoordinate(30, 40) << false;
@@ -291,6 +294,7 @@ void tst_QGeoCircle::contains_data()
QGeoCoordinate(1.00077538, 0.99955527) << true;
QTest::newRow("at 1.01*radius") << QGeoCoordinate(1,1) << qreal(100.0) <<
QGeoCoordinate(1.00071413, 0.99943423) << false;
+ // TODO: add tests for edge circle cases: cross 1 pole, cross both poles
}
void tst_QGeoCircle::contains()
@@ -307,7 +311,39 @@ void tst_QGeoCircle::contains()
QCOMPARE(area.contains(probe), result);
}
-void tst_QGeoCircle::extendShape()
+void tst_QGeoCircle::boundingGeoRectangle_data()
+{
+ QTest::addColumn<QGeoCoordinate>("center");
+ QTest::addColumn<qreal>("radius");
+ QTest::addColumn<QGeoCoordinate>("probe");
+ QTest::addColumn<bool>("result");
+
+ QTest::newRow("own center") << QGeoCoordinate(1,1) << qreal(100.0) <<
+ QGeoCoordinate(1,1) << true;
+ QTest::newRow("over the hills") << QGeoCoordinate(1,1) << qreal(100.0) <<
+ QGeoCoordinate(30, 40) << false;
+ QTest::newRow("at 0.5*radius") << QGeoCoordinate(1,1) << qreal(100.0) <<
+ QGeoCoordinate(1.00015374,1.00015274) << true;
+ QTest::newRow("at 0.99*radius") << QGeoCoordinate(1,1) << qreal(100.0) <<
+ QGeoCoordinate(1.00077538, 0.99955527) << true;
+ QTest::newRow("Outside the box") << QGeoCoordinate(1,1) << qreal(100.0) <<
+ QGeoCoordinate(1.00071413, 0.99903423) << false;
+ // TODO: add tests for edge circle cases: cross 1 pole, cross both poles
+}
+
+void tst_QGeoCircle::boundingGeoRectangle()
+{
+ QFETCH(QGeoCoordinate, center);
+ QFETCH(qreal, radius);
+ QFETCH(QGeoCoordinate, probe);
+ QFETCH(bool, result);
+
+ QGeoCircle c(center, radius);
+ QGeoRectangle box = c.boundingGeoRectangle();
+ QCOMPARE(box.contains(probe), result);
+}
+
+void tst_QGeoCircle::extendCircle()
{
QFETCH(QGeoCircle, circle);
QFETCH(QGeoCoordinate, coord);
@@ -315,12 +351,12 @@ void tst_QGeoCircle::extendShape()
QFETCH(bool, containsExtended);
QCOMPARE(circle.contains(coord), containsFirst);
- circle.extendShape(coord);
+ circle.extendCircle(coord);
QCOMPARE(circle.contains(coord), containsExtended);
}
-void tst_QGeoCircle::extendShape_data()
+void tst_QGeoCircle::extendCircle_data()
{
QTest::addColumn<QGeoCircle>("circle");
QTest::addColumn<QGeoCoordinate>("coord");
diff --git a/tests/auto/qgeopath/qgeopath.pro b/tests/auto/qgeopath/qgeopath.pro
new file mode 100644
index 00000000..eec05974
--- /dev/null
+++ b/tests/auto/qgeopath/qgeopath.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+CONFIG += testcase
+TARGET = tst_qgeopath
+
+SOURCES += \
+ tst_qgeopath.cpp
+
+QT += positioning testlib
diff --git a/tests/auto/qgeopath/tst_qgeopath.cpp b/tests/auto/qgeopath/tst_qgeopath.cpp
new file mode 100644
index 00000000..8c4ac767
--- /dev/null
+++ b/tests/auto/qgeopath/tst_qgeopath.cpp
@@ -0,0 +1,385 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtPositioning/QGeoCoordinate>
+#include <QtPositioning/QGeoRectangle>
+#include <QtPositioning/QGeoPath>
+
+QT_USE_NAMESPACE
+
+class tst_QGeoPath : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void defaultConstructor();
+ void listConstructor();
+ void assignment();
+
+ void comparison();
+ void type();
+
+ void path();
+ void width();
+
+ void translate_data();
+ void translate();
+
+ void valid_data();
+ void valid();
+
+ void contains_data();
+ void contains();
+
+ void boundingGeoRectangle_data();
+ void boundingGeoRectangle();
+
+ void extendShape();
+ void extendShape_data();
+};
+
+void tst_QGeoPath::defaultConstructor()
+{
+ QGeoPath p;
+ QVERIFY(!p.path().size());
+ QCOMPARE(p.width(), qreal(0.0));
+}
+
+void tst_QGeoPath::listConstructor()
+{
+ QList<QGeoCoordinate> coords;
+ coords.append(QGeoCoordinate(1,1));
+ coords.append(QGeoCoordinate(2,2));
+ coords.append(QGeoCoordinate(3,0));
+
+ QGeoPath p(coords, 1.0);
+ QCOMPARE(p.width(), qreal(1.0));
+ QCOMPARE(p.path().size(), 3);
+
+ for (const QGeoCoordinate &c : coords) {
+ QCOMPARE(p.path().contains(c), true);
+ }
+}
+
+void tst_QGeoPath::assignment()
+{
+ QGeoPath p1;
+ QList<QGeoCoordinate> coords;
+ coords.append(QGeoCoordinate(1,1));
+ coords.append(QGeoCoordinate(2,2));
+ coords.append(QGeoCoordinate(3,0));
+ QGeoPath p2(coords, 1.0);
+
+ QVERIFY(p1 != p2);
+
+ p1 = p2;
+ QCOMPARE(p1.path(), coords);
+ QCOMPARE(p1.width(), 1.0);
+ QCOMPARE(p1, p2);
+
+ // Assign c1 to an area
+ QGeoShape area = p1;
+ QCOMPARE(area.type(), p1.type());
+ QVERIFY(area == p1);
+
+ // Assign the area back to a bounding circle
+ QGeoPath p3 = area;
+ QCOMPARE(p3.path(), coords);
+ QCOMPARE(p3.width(), 1.0);
+
+ // Check that the copy is not modified when modifying the original.
+ p1.setWidth(2.0);
+ QVERIFY(p3.width() != p1.width());
+ QVERIFY(p3 != p1);
+}
+
+void tst_QGeoPath::comparison()
+{
+ QList<QGeoCoordinate> coords;
+ coords.append(QGeoCoordinate(1,1));
+ coords.append(QGeoCoordinate(2,2));
+ coords.append(QGeoCoordinate(3,0));
+ QList<QGeoCoordinate> coords2;
+ coords2.append(QGeoCoordinate(3,1));
+ coords2.append(QGeoCoordinate(4,2));
+ coords2.append(QGeoCoordinate(3,0));
+ QGeoPath c1(coords, qreal(50.0));
+ QGeoPath c2(coords, qreal(50.0));
+ QGeoPath c3(coords, qreal(35.0));
+ QGeoPath c4(coords2, qreal(50.0));
+
+ QVERIFY(c1 == c2);
+ QVERIFY(!(c1 != c2));
+
+ QVERIFY(!(c1 == c3));
+ QVERIFY(c1 != c3);
+
+ QVERIFY(!(c1 == c4));
+ QVERIFY(c1 != c4);
+
+ QVERIFY(!(c2 == c3));
+ QVERIFY(c2 != c3);
+
+ QGeoRectangle b1(QGeoCoordinate(20,20),QGeoCoordinate(10,30));
+ QVERIFY(!(c1 == b1));
+ QVERIFY(c1 != b1);
+
+ QGeoShape *c2Ptr = &c2;
+ QVERIFY(c1 == *c2Ptr);
+ QVERIFY(!(c1 != *c2Ptr));
+
+ QGeoShape *c3Ptr = &c3;
+ QVERIFY(!(c1 == *c3Ptr));
+ QVERIFY(c1 != *c3Ptr);
+}
+
+void tst_QGeoPath::type()
+{
+ QGeoPath c;
+ QCOMPARE(c.type(), QGeoShape::PathType);
+}
+
+void tst_QGeoPath::path()
+{
+ QList<QGeoCoordinate> coords;
+ coords.append(QGeoCoordinate(1,1));
+ coords.append(QGeoCoordinate(2,2));
+ coords.append(QGeoCoordinate(3,0));
+
+ QGeoPath p;
+ p.setPath(coords);
+ QCOMPARE(p.path().size(), 3);
+
+ for (const QGeoCoordinate &c : coords) {
+ QCOMPARE(p.path().contains(c), true);
+ }
+}
+
+void tst_QGeoPath::width()
+{
+ QGeoPath p;
+ p.setWidth(10.0);
+ QCOMPARE(p.width(), qreal(10.0));
+}
+
+void tst_QGeoPath::translate_data()
+{
+ QTest::addColumn<QGeoCoordinate>("c1");
+ QTest::addColumn<QGeoCoordinate>("c2");
+ QTest::addColumn<QGeoCoordinate>("c3");
+ QTest::addColumn<double>("lat");
+ QTest::addColumn<double>("lon");
+
+ QTest::newRow("Simple") << QGeoCoordinate(1,1) << QGeoCoordinate(2,2) <<
+ QGeoCoordinate(3,0) << 5.0 << 4.0;
+ QTest::newRow("Backward") << QGeoCoordinate(1,1) << QGeoCoordinate(2,2) <<
+ QGeoCoordinate(3,0) << -5.0 << -4.0;
+}
+
+void tst_QGeoPath::translate()
+{
+ QFETCH(QGeoCoordinate, c1);
+ QFETCH(QGeoCoordinate, c2);
+ QFETCH(QGeoCoordinate, c3);
+ QFETCH(double, lat);
+ QFETCH(double, lon);
+
+ QList<QGeoCoordinate> coords;
+ coords.append(c1);
+ coords.append(c2);
+ coords.append(c3);
+ QGeoPath p(coords);
+
+ p.translate(lat, lon);
+
+ for (int i = 0; i < p.path().size(); i++) {
+ QCOMPARE(coords[i].latitude(), p.path()[i].latitude() - lat );
+ QCOMPARE(coords[i].longitude(), p.path()[i].longitude() - lon );
+ }
+}
+
+void tst_QGeoPath::valid_data()
+{
+ QTest::addColumn<QGeoCoordinate>("c1");
+ QTest::addColumn<QGeoCoordinate>("c2");
+ QTest::addColumn<QGeoCoordinate>("c3");
+ QTest::addColumn<qreal>("width");
+ QTest::addColumn<bool>("valid");
+
+ QTest::newRow("empty coords") << QGeoCoordinate() << QGeoCoordinate() << QGeoCoordinate() << qreal(5.0) << false;
+ QTest::newRow("invalid coord") << QGeoCoordinate(50, 50) << QGeoCoordinate(60, 60) << QGeoCoordinate(700, 700) << qreal(5.0) << false;
+ QTest::newRow("bad width") << QGeoCoordinate(10, 10) << QGeoCoordinate(11, 11) << QGeoCoordinate(10, 12) << qreal(-5.0) << true;
+ QTest::newRow("NaN width") << QGeoCoordinate(10, 10) << QGeoCoordinate(11, 11) << QGeoCoordinate(10, 12) << qreal(qQNaN()) << true;
+ QTest::newRow("zero width") << QGeoCoordinate(10, 10) << QGeoCoordinate(11, 11) << QGeoCoordinate(10, 12) << qreal(0) << true;
+ QTest::newRow("good") << QGeoCoordinate(10, 10) << QGeoCoordinate(11, 11) << QGeoCoordinate(10, 12) << qreal(5) << true;
+}
+
+void tst_QGeoPath::valid()
+{
+ QFETCH(QGeoCoordinate, c1);
+ QFETCH(QGeoCoordinate, c2);
+ QFETCH(QGeoCoordinate, c3);
+ QFETCH(qreal, width);
+ QFETCH(bool, valid);
+
+ QList<QGeoCoordinate> coords;
+ coords.append(c1);
+ coords.append(c2);
+ coords.append(c3);
+ QGeoPath p(coords, width);
+
+ QCOMPARE(p.isValid(), valid);
+
+ QGeoShape area = p;
+ QCOMPARE(area.isValid(), valid);
+}
+
+void tst_QGeoPath::contains_data()
+{
+ QTest::addColumn<QGeoCoordinate>("c1");
+ QTest::addColumn<QGeoCoordinate>("c2");
+ QTest::addColumn<QGeoCoordinate>("c3");
+ QTest::addColumn<qreal>("width");
+ QTest::addColumn<QGeoCoordinate>("probe");
+ QTest::addColumn<bool>("result");
+
+ QList<QGeoCoordinate> c;
+ c.append(QGeoCoordinate(1,1));
+ c.append(QGeoCoordinate(2,2));
+ c.append(QGeoCoordinate(3,0));
+
+ QTest::newRow("One of the points") << c[0] << c[1] << c[2] << 0.0 << QGeoCoordinate(2, 2) << true;
+ QTest::newRow("Not so far away") << c[0] << c[1] << c[2] << 0.0 << QGeoCoordinate(0, 0) << false;
+ QTest::newRow("Not so far away and large line") << c[0] << c[1] << c[2] << 100000.0 << QGeoCoordinate(0, 0) << true;
+}
+
+void tst_QGeoPath::contains()
+{
+ QFETCH(QGeoCoordinate, c1);
+ QFETCH(QGeoCoordinate, c2);
+ QFETCH(QGeoCoordinate, c3);
+ QFETCH(qreal, width);
+ QFETCH(QGeoCoordinate, probe);
+ QFETCH(bool, result);
+
+ QList<QGeoCoordinate> coords;
+ coords.append(c1);
+ coords.append(c2);
+ coords.append(c3);
+ QGeoPath p(coords, width);
+
+ QCOMPARE(p.contains(probe), result);
+
+ QGeoShape area = p;
+ QCOMPARE(area.contains(probe), result);
+}
+
+void tst_QGeoPath::boundingGeoRectangle_data()
+{
+ QTest::addColumn<QGeoCoordinate>("c1");
+ QTest::addColumn<QGeoCoordinate>("c2");
+ QTest::addColumn<QGeoCoordinate>("c3");
+ QTest::addColumn<qreal>("width");
+ QTest::addColumn<QGeoCoordinate>("probe");
+ QTest::addColumn<bool>("result");
+
+ QList<QGeoCoordinate> c;
+ c.append(QGeoCoordinate(1,1));
+ c.append(QGeoCoordinate(2,2));
+ c.append(QGeoCoordinate(3,0));
+
+ QTest::newRow("One of the points") << c[0] << c[1] << c[2] << 0.0 << QGeoCoordinate(2, 2) << true;
+ QTest::newRow("Not so far away") << c[0] << c[1] << c[2] << 0.0 << QGeoCoordinate(0, 0) << false;
+ QTest::newRow("Inside the bounds") << c[0] << c[1] << c[2] << 100.0 << QGeoCoordinate(1, 0) << true;
+ QTest::newRow("Inside the bounds") << c[0] << c[1] << c[2] << 100.0 << QGeoCoordinate(1.1, 0.1) << true;
+}
+
+void tst_QGeoPath::boundingGeoRectangle()
+{
+ QFETCH(QGeoCoordinate, c1);
+ QFETCH(QGeoCoordinate, c2);
+ QFETCH(QGeoCoordinate, c3);
+ QFETCH(qreal, width);
+ QFETCH(QGeoCoordinate, probe);
+ QFETCH(bool, result);
+
+ QList<QGeoCoordinate> coords;
+ coords.append(c1);
+ coords.append(c2);
+ coords.append(c3);
+ QGeoPath p(coords, width);
+
+ QGeoRectangle box = p.boundingGeoRectangle();
+ QCOMPARE(box.contains(probe), result);
+}
+
+void tst_QGeoPath::extendShape()
+{
+ QFETCH(QGeoCoordinate, c1);
+ QFETCH(QGeoCoordinate, c2);
+ QFETCH(QGeoCoordinate, c3);
+ QFETCH(qreal, width);
+ QFETCH(QGeoCoordinate, probe);
+ QFETCH(bool, before);
+ QFETCH(bool, after);
+
+ QList<QGeoCoordinate> coords;
+ coords.append(c1);
+ coords.append(c2);
+ coords.append(c3);
+ QGeoPath p(coords, width);
+
+
+ QCOMPARE(p.contains(probe), before);
+ p.extendShape(probe);
+ QCOMPARE(p.contains(probe), after);
+}
+
+void tst_QGeoPath::extendShape_data()
+{
+ QTest::addColumn<QGeoCoordinate>("c1");
+ QTest::addColumn<QGeoCoordinate>("c2");
+ QTest::addColumn<QGeoCoordinate>("c3");
+ QTest::addColumn<qreal>("width");
+ QTest::addColumn<QGeoCoordinate>("probe");
+ QTest::addColumn<bool>("before");
+ QTest::addColumn<bool>("after");
+
+ QList<QGeoCoordinate> c;
+ c.append(QGeoCoordinate(1,1));
+ c.append(QGeoCoordinate(2,2));
+ c.append(QGeoCoordinate(3,0));
+
+ QTest::newRow("One of the points") << c[0] << c[1] << c[2] << 0.0 << QGeoCoordinate(2, 2) << true << true;
+ QTest::newRow("Not so far away") << c[0] << c[1] << c[2] << 0.0 << QGeoCoordinate(0, 0) << false << true;
+ QTest::newRow("Not so far away and large line") << c[0] << c[1] << c[2] << 100000.0 << QGeoCoordinate(0, 0) << true << true;
+}
+
+QTEST_MAIN(tst_QGeoPath)
+#include "tst_qgeopath.moc"
diff --git a/tests/auto/qgeorectangle/tst_qgeorectangle.cpp b/tests/auto/qgeorectangle/tst_qgeorectangle.cpp
index 71a3765a..01f0104b 100644
--- a/tests/auto/qgeorectangle/tst_qgeorectangle.cpp
+++ b/tests/auto/qgeorectangle/tst_qgeorectangle.cpp
@@ -71,6 +71,9 @@ private slots:
void center();
void center_data();
+ void boundingGeoRectangle();
+ void boundingGeoRectangle_data();
+
void containsCoord();
void containsCoord_data();
@@ -83,8 +86,8 @@ private slots:
void unite();
void unite_data();
- void extendShape();
- void extendShape_data();
+ void extendRectangle();
+ void extendRectangle_data();
void areaComparison();
void areaComparison_data();
@@ -957,6 +960,28 @@ void tst_QGeoRectangle::center_data()
QGeoCoordinate(-90.0, -170.0));
}
+void tst_QGeoRectangle::boundingGeoRectangle_data()
+{
+ QTest::addColumn<QGeoRectangle>("rectangle");
+
+ QGeoRectangle b1(QGeoCoordinate(70, 30), QGeoCoordinate(30, 70));
+ QGeoRectangle b2(QGeoCoordinate(70, 150), QGeoCoordinate(30, -170));
+ QGeoRectangle b3(QGeoCoordinate(90, 30), QGeoCoordinate(50, 70));
+ QGeoRectangle b4(QGeoCoordinate(-50, 30), QGeoCoordinate(-90, 70));
+
+ QTest::newRow("Box 1") << b1;
+ QTest::newRow("Box 2") << b2;
+ QTest::newRow("Box 3") << b3;
+ QTest::newRow("Box 4") << b4;
+}
+
+void tst_QGeoRectangle::boundingGeoRectangle()
+{
+ QFETCH(QGeoRectangle, rectangle);
+
+ QGeoRectangle box = rectangle.boundingGeoRectangle();
+ QCOMPARE(box, rectangle);
+}
void tst_QGeoRectangle::containsCoord()
{
@@ -1769,14 +1794,14 @@ void tst_QGeoRectangle::translate_data()
<< 20.0
<< 20.0
<< QGeoRectangle(QGeoCoordinate(90.0, -10.0),
- QGeoCoordinate(40.0, 50.0));
+ QGeoCoordinate(30.0, 50.0));
QTest::newRow("non wrapping -> south clip")
<< QGeoRectangle(QGeoCoordinate(-20.0, -30.0),
QGeoCoordinate(-80.0, 30.0))
<< -20.0
<< 20.0
- << QGeoRectangle(QGeoCoordinate(-40.0, -10.0),
+ << QGeoRectangle(QGeoCoordinate(-30.0, -10.0),
QGeoCoordinate(-90.0, 50.0));
QTest::newRow("wrapping -> non wrapping")
@@ -1801,14 +1826,14 @@ void tst_QGeoRectangle::translate_data()
<< 20.0
<< 20.0
<< QGeoRectangle(QGeoCoordinate(90.0, 150.0),
- QGeoCoordinate(40.0, -150.0));
+ QGeoCoordinate(30.0, -150.0));
QTest::newRow("wrapping -> south clip")
<< QGeoRectangle(QGeoCoordinate(-20.0, 130.0),
QGeoCoordinate(-80.0, -170.0))
<< -20.0
<< 20.0
- << QGeoRectangle(QGeoCoordinate(-40.0, 150.0),
+ << QGeoRectangle(QGeoCoordinate(-30.0, 150.0),
QGeoCoordinate(-90.0, -150.0));
}
@@ -2201,17 +2226,17 @@ void tst_QGeoRectangle::unite_data()
}
-void tst_QGeoRectangle::extendShape()
+void tst_QGeoRectangle::extendRectangle()
{
QFETCH(QGeoRectangle, box);
QFETCH(QGeoCoordinate, coord);
QFETCH(QGeoRectangle, out);
- box.extendShape(coord);
+ box.extendRectangle(coord);
QCOMPARE(box, out);
}
-void tst_QGeoRectangle::extendShape_data()
+void tst_QGeoRectangle::extendRectangle_data()
{
QTest::addColumn<QGeoRectangle>("box");
QTest::addColumn<QGeoCoordinate>("coord");
diff --git a/tests/auto/qgeoroutereply/tst_qgeoroutereply.cpp b/tests/auto/qgeoroutereply/tst_qgeoroutereply.cpp
index 447181f2..de406b40 100644
--- a/tests/auto/qgeoroutereply/tst_qgeoroutereply.cpp
+++ b/tests/auto/qgeoroutereply/tst_qgeoroutereply.cpp
@@ -197,7 +197,7 @@ void tst_QGeoRouteReply::abort()
reply->abort();
QCOMPARE(signalerror->count(), 0);
- QCOMPARE(signalfinished->count(), 1);
+ QCOMPARE(signalfinished->count(), 0);
}
void tst_QGeoRouteReply::error()
diff --git a/tests/auto/qgeoserviceprovider/tst_qgeoserviceprovider.cpp b/tests/auto/qgeoserviceprovider/tst_qgeoserviceprovider.cpp
index 121253fa..6a9457fe 100644
--- a/tests/auto/qgeoserviceprovider/tst_qgeoserviceprovider.cpp
+++ b/tests/auto/qgeoserviceprovider/tst_qgeoserviceprovider.cpp
@@ -67,7 +67,7 @@ void tst_QGeoServiceProvider::tst_availableServiceProvider()
// Currently provided plugins
if (provider.count() != 8)
qWarning() << provider;
- QCOMPARE(provider.count(), 8);
+ QVERIFY(provider.count() >= 8);
// these providers are deployed
QVERIFY(provider.contains(QStringLiteral("mapbox")));
QVERIFY(provider.contains(QStringLiteral("here")));
diff --git a/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp b/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp
index cc2672b2..22fb6589 100644
--- a/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp
+++ b/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp
@@ -37,6 +37,7 @@
#include <QtCore/QString>
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
+#include <QtPositioning/private/qwebmercator_p.h>
#include <QtLocation/QGeoServiceProvider>
#include <QtLocation/private/qgeotiledmap_p.h>
#include <QtLocation/private/qgeomappingmanager_p.h>
@@ -100,7 +101,7 @@ void tst_QGeoTiledMap::initTestCase()
QStringLiteral("/../../../plugins"));
#endif
QVariantMap parameters;
- parameters["tileSize"] = 16;
+ parameters["tileSize"] = 256;
parameters["maxZoomLevel"] = 8;
parameters["finishRequestImmediately"] = true;
QGeoServiceProvider *provider = new QGeoServiceProvider("qmlgeo.test.plugin",parameters);
@@ -109,7 +110,7 @@ void tst_QGeoTiledMap::initTestCase()
QVERIFY2(provider->error() == QGeoServiceProvider::NoError, "Could not load plugin: " + provider->errorString().toLatin1());
m_map.reset(static_cast<QGeoTiledMapTest*>(mappingManager->createMap(this)));
QVERIFY(m_map);
- m_map->setViewportSize(QSize(16, 16));
+ m_map->setViewportSize(QSize(256, 256));
m_fetcher = static_cast<QGeoTileFetcherTest*>(m_map->m_engine->tileFetcher());
m_tilesCounter.reset(new FetchTileCounter());
connect(m_fetcher, SIGNAL(tileFetched(const QGeoTileSpec&)), m_tilesCounter.data(), SLOT(tileFetched(const QGeoTileSpec&)));
@@ -126,7 +127,7 @@ void tst_QGeoTiledMap::fetchTiles()
m_map->setPrefetchStyle(style);
QGeoCameraData camera;
- camera.setCenter(QGeoProjection::mercatorToCoord(QDoubleVector2D( 0.5 , 0.5 )));
+ camera.setCenter(QWebMercator::mercatorToCoord(QDoubleVector2D( 0.5 , 0.5 )));
//prev_visible
camera.setZoomLevel(zoomLevel-1);
diff --git a/tests/auto/qgeotiledmapscene/qgeotiledmapscene.pro b/tests/auto/qgeotiledmapscene/qgeotiledmapscene.pro
index c3ec6e91..0db4b544 100644
--- a/tests/auto/qgeotiledmapscene/qgeotiledmapscene.pro
+++ b/tests/auto/qgeotiledmapscene/qgeotiledmapscene.pro
@@ -5,4 +5,4 @@ INCLUDEPATH += ../../../src/location/maps
SOURCES += tst_qgeotiledmapscene.cpp
-QT += location positioning-private testlib
+QT += location-private positioning-private testlib
diff --git a/tests/auto/qgeotiledmapscene/tst_qgeotiledmapscene.cpp b/tests/auto/qgeotiledmapscene/tst_qgeotiledmapscene.cpp
index 3d43ebd8..6b3dc1f6 100644
--- a/tests/auto/qgeotiledmapscene/tst_qgeotiledmapscene.cpp
+++ b/tests/auto/qgeotiledmapscene/tst_qgeotiledmapscene.cpp
@@ -33,8 +33,8 @@
#include "qgeocameratiles_p.h"
#include "qgeocameradata_p.h"
#include "qabstractgeotilecache_p.h"
-
-#include <QtPositioning/private/qgeoprojection_p.h>
+#include <QtLocation/private/qgeoprojection_p.h>
+#include <QtPositioning/private/qwebmercator_p.h>
#include <QtPositioning/private/qdoublevector2d_p.h>
#include <qtest.h>
@@ -52,7 +52,7 @@ class tst_QGeoTiledMapScene : public QObject
Q_OBJECT
private:
- void row(QString name, double screenX, double screenY, double cameraCenterX, double cameraCenterY,
+ void row(QString name, double screenX, double screenX2, double screenY, double cameraCenterX, double cameraCenterY,
double zoom, int tileSize, int screenWidth, int screenHeight, double mercatorX, double mercatorY){
// expected behaviour of wrapping
@@ -62,7 +62,7 @@ class tst_QGeoTiledMapScene : public QObject
mercatorX -= 1.0;
QTest::newRow(qPrintable(name))
- << screenX << screenY
+ << screenX << screenX2 << screenY
<< cameraCenterX << cameraCenterY
<< zoom << tileSize
<< screenWidth << screenHeight
@@ -74,6 +74,7 @@ class tst_QGeoTiledMapScene : public QObject
int tileSize, int screenWidth, int screenHeight)
{
double screenX;
+ double screenX2;
double screenY;
double mercatorX;
double mercatorY;
@@ -84,76 +85,92 @@ class tst_QGeoTiledMapScene : public QObject
double scaledHalfLengthX = halfLength * scaleX;
double scaledHalfLengthY = halfLength * scaleY;
- // top left
- screenX = 0.0;
+ bool matchingMapEnds = false;
+ if (screenWidth == std::pow(2.0, zoom) * tileSize)
+ matchingMapEnds = true;
+
+ // bottom left
+ screenX = screenX2 = 0.0;
+ if (matchingMapEnds)
+ screenX2 = qAbs(screenX - 1.0) * screenWidth;
screenY = 1.0 * screenHeight;
mercatorX = cameraCenterX - scaledHalfLengthX;
mercatorY = cameraCenterY + scaledHalfLengthY;
- row (name + QString("_topLeftScreen"), screenX, screenY, cameraCenterX, cameraCenterY,
+ row (name + QString("_bottomLeftScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY);
- // top
- screenX = 0.5 * screenWidth;
+ // bottom
+ screenX = screenX2 = 0.5 * screenWidth;
screenY = 1.0 * screenHeight;
mercatorX = cameraCenterX;
mercatorY = cameraCenterY + scaledHalfLengthY;
- row (name + QString("_topScreen"), screenX, screenY, cameraCenterX, cameraCenterY,
+ row (name + QString("_bottomScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY);
- // top right
- screenX = 1.0 * screenWidth;
+ // bottom right
+ screenX = screenX2 = 1.0 * screenWidth;
+ if (matchingMapEnds)
+ screenX2 = qAbs(screenX - 1.0) * screenWidth;
screenY = 1.0 * screenHeight;
mercatorX = cameraCenterX + scaledHalfLengthX;
mercatorY = cameraCenterY + scaledHalfLengthY;
- row (name + QString("_topRightScreen"), screenX, screenY, cameraCenterX, cameraCenterY,
+ row (name + QString("_bottomRightScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY);
// left
- screenX = 0.0 * screenWidth;
+ screenX = screenX2 = 0.0 * screenWidth;
+ if (matchingMapEnds)
+ screenX2 = qAbs(screenX - 1.0) * screenWidth;
screenY = 0.5 * screenHeight;
mercatorX = cameraCenterX - scaledHalfLengthX;
mercatorY = cameraCenterY;
- row (name + QString("_leftScreen"), screenX, screenY, cameraCenterX, cameraCenterY,
+ row (name + QString("_leftScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY);
// center
- screenX = 0.5 * screenWidth;
+ screenX = screenX2 = 0.5 * screenWidth;
screenY = 0.5 * screenHeight;
mercatorX = cameraCenterX;
mercatorY = cameraCenterY;
- row (name + QString("_centerScreen"), screenX, screenY, cameraCenterX, cameraCenterY,
+ row (name + QString("_centerScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY);
// right
- screenX = 1.0 * screenWidth;
+ screenX = screenX2 = 1.0 * screenWidth;
+ if (matchingMapEnds)
+ screenX2 = qAbs(screenX - 1.0) * screenWidth;
screenY = 0.5 * screenHeight;
mercatorX = cameraCenterX + scaledHalfLengthX;
mercatorY = cameraCenterY;
- row (name + QString("_rightScreen"), screenX, screenY, cameraCenterX, cameraCenterY,
+ row (name + QString("_rightScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY);
- // bottom left
- screenX = 0.0;
+ // top left
+ screenX = screenX2 = 0.0;
+ if (matchingMapEnds)
+ screenX2 = qAbs(screenX - 1.0) * screenWidth;
screenY = 0.0;
mercatorX = cameraCenterX - scaledHalfLengthX;
mercatorY = cameraCenterY - scaledHalfLengthY;
- row (name + QString("_bottomLeftrScreen"), screenX, screenY, cameraCenterX, cameraCenterY,
+ row (name + QString("_topLeftScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY);
- // bottom
- screenX = 0.5 * screenWidth;
+ // top
+ screenX = screenX2 = 0.5 * screenWidth;
screenY = 0.0;
mercatorX = cameraCenterX;
mercatorY = cameraCenterY - scaledHalfLengthY;
- row (name + QString("_bottomScreen"), screenX, screenY, cameraCenterX, cameraCenterY,
+ row (name + QString("_topScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY);
- // bottom right
- screenX = 1.0 * screenWidth;
+ // top right
+ screenX = screenX2 = 1.0 * screenWidth;
+ if (matchingMapEnds)
+ screenX2 = qAbs(screenX - 1.0) * screenWidth;
screenY = 0.0;
mercatorX = cameraCenterX + scaledHalfLengthX;
mercatorY = cameraCenterY - scaledHalfLengthY;
- row (name + QString("_bottomRightScreen"), screenX, screenY, cameraCenterX, cameraCenterY,
+ row (name + QString("_topRightScreen"), screenX, screenX2, screenY, cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight, mercatorX, mercatorY);
}
@@ -164,21 +181,21 @@ class tst_QGeoTiledMapScene : public QObject
double cameraCenterX;
double cameraCenterY;
- // top left
+ // bottom left
cameraCenterX = 0;
cameraCenterY = 1.0;
- screenPositions(name + QString("_topLeftCamera"), cameraCenterX, cameraCenterY,
+ screenPositions(name + QString("_bottomLeftCamera"), cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight);
- // top
+ // bottom
cameraCenterX = 0.5;
cameraCenterY = 1.0;
- screenPositions(name + QString("_topCamera"), cameraCenterX, cameraCenterY,
+ screenPositions(name + QString("_bottomCamera"), cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight);
- // top right
+ // bottom right
cameraCenterX = 1.0;
cameraCenterY = 1.0;
- screenPositions(name + QString("_topRightCamera"), cameraCenterX, cameraCenterY,
+ screenPositions(name + QString("_bottomRightCamera"), cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight);
// left
cameraCenterX = 0.0;
@@ -195,25 +212,26 @@ class tst_QGeoTiledMapScene : public QObject
cameraCenterY = 0.5;
screenPositions(name + QString("_rightCamera"), cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight);
- // bottom left
+ // top left
cameraCenterX = 0.0;
cameraCenterY = 0.0;
- screenPositions(name + QString("_bottomLeftCamera"), cameraCenterX, cameraCenterY,
+ screenPositions(name + QString("_topLeftCamera"), cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight);
- // bottom
+ // top
cameraCenterX = 0.5;
cameraCenterY = 0.0;
- screenPositions(name + QString("_bottomCamera"), cameraCenterX, cameraCenterY,
+ screenPositions(name + QString("_topCamera"), cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight);
- // bottom right
+ // top right
cameraCenterX = 1.0;
cameraCenterY = 0.0;
- screenPositions(name + QString("_bottomRightCamera"), cameraCenterX, cameraCenterY,
+ screenPositions(name + QString("_topRightCamera"), cameraCenterX, cameraCenterY,
zoom, tileSize, screenWidth, screenHeight);
}
void populateScreenMercatorData(){
QTest::addColumn<double>("screenX");
+ QTest::addColumn<double>("screenX2");
QTest::addColumn<double>("screenY");
QTest::addColumn<double>("cameraCenterX");
QTest::addColumn<double>("cameraCenterY");
@@ -229,8 +247,8 @@ class tst_QGeoTiledMapScene : public QObject
int screenWidth;
int screenHeight;
QString name;
- tileSize = 16;
- zoom = 4.0;
+ tileSize = 256;
+ zoom = 1.0; // 4 tiles in the map. map size = 2*tileSize x 2*tileSize
/*
ScreenWidth = t
@@ -259,6 +277,7 @@ class tst_QGeoTiledMapScene : public QObject
name = QString("_(2t x t)");
screenCameraPositions(name, zoom, tileSize, screenWidth, screenHeight);
+
/*
Screen Width = t * 2
Screen Height = t * 2
@@ -269,38 +288,13 @@ class tst_QGeoTiledMapScene : public QObject
screenCameraPositions(name, zoom, tileSize, screenWidth, screenHeight);
}
- private slots:
-
- void useVerticalLock(){
- QGeoCameraData camera;
- camera.setZoomLevel(4.0);
- camera.setCenter(QGeoProjection::mercatorToCoord(QDoubleVector2D(0.0, 0.0)));
-
- QGeoCameraTiles ct;
- ct.setTileSize(16);
- ct.setCameraData(camera);
- ct.setScreenSize(QSize(16,16));
-
- QGeoTiledMapScene mapScene;
- mapScene.setTileSize(16);
- mapScene.setScreenSize(QSize(16,16*32));
- mapScene.setCameraData(camera);
- QVERIFY(!mapScene.verticalLock());
- mapScene.setUseVerticalLock(true);
- mapScene.setVisibleTiles(ct.createTiles());
- QVERIFY(mapScene.verticalLock());
-
- // Test the case when setting vertical lock has no effect
- QGeoTiledMapScene mapScene2;
- mapScene2.setTileSize(16);
- mapScene2.setScreenSize(QSize(16,16));
- mapScene2.setCameraData(camera);
- QVERIFY(!mapScene2.verticalLock());
- mapScene2.setUseVerticalLock(true);
- mapScene2.setVisibleTiles(ct.createTiles());
- QVERIFY(!mapScene2.verticalLock());
- }
+ // Calculates the distance in mercator space of 2 x coordinates, assuming that 1 == 0
+ double wrappedMercatorDistance(double x1, double x2)
+ {
+ return qMin(qMin(qAbs(x1 - 1.0 - x2), qAbs(x1 - x2)), qAbs(x1 + 1.0 - x2));
+ }
+ private slots:
void screenToMercatorPositions(){
QFETCH(double, screenX);
QFETCH(double, screenY);
@@ -315,7 +309,8 @@ class tst_QGeoTiledMapScene : public QObject
QGeoCameraData camera;
camera.setZoomLevel(zoom);
- camera.setCenter(QGeoProjection::mercatorToCoord(QDoubleVector2D(cameraCenterX, cameraCenterY)));
+ QGeoCoordinate centerCoordinate = QWebMercator::mercatorToCoord(QDoubleVector2D(cameraCenterX, cameraCenterY));
+ camera.setCenter(centerCoordinate);
QGeoCameraTiles ct;
ct.setTileSize(tileSize);
@@ -328,11 +323,22 @@ class tst_QGeoTiledMapScene : public QObject
mapGeometry.setCameraData(camera);
mapGeometry.setVisibleTiles(ct.createTiles());
- QDoubleVector2D point(screenX,screenY);
- QDoubleVector2D mecartorPos = mapGeometry.itemPositionToMercator(point);
+ QGeoProjectionWebMercator projection;
+ projection.setViewportSize(QSize(screenWidth,screenHeight));
+ projection.setCameraData(camera);
- QCOMPARE(mecartorPos.x(),mercatorX);
- QCOMPARE(mecartorPos.y(),mercatorY);
+ QDoubleVector2D point(screenX,screenY);
+ QDoubleVector2D mercartorPos = projection.unwrapMapProjection(projection.itemPositionToWrappedMapProjection(point));
+
+ const double tolerance = 0.00000000001; // FuzzyCompare is too strict here
+ QVERIFY2(wrappedMercatorDistance(mercartorPos.x(), mercatorX) < tolerance,
+ qPrintable(QString("Accepted: %1 , Actual: %2")
+ .arg(QString::number(mercatorX))
+ .arg(QString::number(mercartorPos.x()))));
+ QVERIFY2(qAbs(mercartorPos.y() - mercatorY) < tolerance,
+ qPrintable(QString("Accepted: %1 , Actual: %2")
+ .arg(QString::number(mercatorY))
+ .arg(QString::number(mercartorPos.y()))));
}
void screenToMercatorPositions_data()
@@ -342,6 +348,7 @@ class tst_QGeoTiledMapScene : public QObject
void mercatorToScreenPositions(){
QFETCH(double, screenX);
+ QFETCH(double, screenX2);
QFETCH(double, screenY);
QFETCH(double, cameraCenterX);
QFETCH(double, cameraCenterY);
@@ -354,7 +361,8 @@ class tst_QGeoTiledMapScene : public QObject
QGeoCameraData camera;
camera.setZoomLevel(zoom);
- camera.setCenter(QGeoProjection::mercatorToCoord(QDoubleVector2D(cameraCenterX, cameraCenterY)));
+ QGeoCoordinate coord = QWebMercator::mercatorToCoord(QDoubleVector2D(cameraCenterX, cameraCenterY));
+ camera.setCenter(coord);
QGeoCameraTiles ct;
ct.setTileSize(tileSize);
@@ -367,10 +375,18 @@ class tst_QGeoTiledMapScene : public QObject
mapGeometry.setCameraData(camera);
mapGeometry.setVisibleTiles(ct.createTiles());
+ QGeoProjectionWebMercator projection;
+ projection.setViewportSize(QSize(screenWidth,screenHeight));
+ projection.setCameraData(camera);
+
QDoubleVector2D mercatorPos(mercatorX, mercatorY);
- QPointF point = mapGeometry.mercatorToItemPosition(mercatorPos).toPointF();
+ QPointF point = projection.wrappedMapProjectionToItemPosition(projection.wrapMapProjection(mercatorPos)).toPointF();
- QCOMPARE(point.x(), screenX);
+ QVERIFY2((point.x() == screenX) || (point.x() == screenX2),
+ qPrintable(QString("Accepted: { %1 , %2 } Actual: %3")
+ .arg(QString::number(screenX))
+ .arg(QString::number(screenX2))
+ .arg(QString::number(point.x()))));
QCOMPARE(point.y(), screenY);
}