mapwidget.qml: more improvements for the dynamic zoom-in/out

The QML Map has a couple of methods - toCoordinate(someQPointF) and
fromCoordinate(someQGeoCoordinate). Ideally, if one passes a point to
toCoordinate() and then attempts to convert the resulted coordinates
back to the point, the same point in the Map view port with minimal error
should be retrieved. That's not always the case - e.g. near
47.400200 -123.142066, which means that the methods are not exactly
*reliable* and there might be Map class bugs at hand.

The new zoom-in and zoom-out improvements try to work around the above:
- for both centerOnRectangle() and centerOnCoordinate(), if no good
zoom-out level is found (newZoomOut), the zoom-out is set to the default
value of defaultZoomOut. In practice, this prevents the case where the map
does not zoom-out at all when going from one place to another
- centerOnRectangle() now uses rectangle diagonals to estimate a fit,
instead of checking if 2 points (top-left and bottom-right) are visible
in the viewport. The usage of fromCoordinate() was giving bad results
in this case and comparing distances (diagonals) is more reliable
but more expensive on the CPU.

Due to the inconsistencies of toCoordinate() and fromCoordinate()
the dynamic zoom-in and zoom-out are still not ideal, but the current
implementation is somewhat usable with decent accuracy.

Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
This commit is contained in:
Lubomir I. Ivanov 2017-08-08 02:10:23 +03:00 committed by Dirk Hohndel
parent 514c298600
commit f21ae69f7b

View file

@ -164,16 +164,20 @@ Item {
newZoom = 2.6 newZoom = 2.6
newZoomOut = newZoom newZoomOut = newZoom
} else { } else {
var newZoomOutFound = false
var zoomStored = zoomLevel var zoomStored = zoomLevel
newZoomOut = zoomLevel newZoomOut = zoomLevel
while (zoomLevel > minimumZoomLevel) { while (zoomLevel > minimumZoomLevel) {
var pt = fromCoordinate(coord) var pt = fromCoordinate(coord)
if (pointIsVisible(pt)) { if (pointIsVisible(pt)) {
newZoomOut = zoomLevel newZoomOut = zoomLevel
newZoomOutFound = true
break break
} }
zoomLevel-- zoomLevel--
} }
if (!newZoomOutFound)
newZoomOut = defaultZoomOut
zoomLevel = zoomStored zoomLevel = zoomStored
newZoom = defaultZoomIn newZoom = defaultZoomIn
} }
@ -190,29 +194,30 @@ Item {
} else { } else {
var centerStored = QtPositioning.coordinate(center.latitude, center.longitude) var centerStored = QtPositioning.coordinate(center.latitude, center.longitude)
var zoomStored = zoomLevel var zoomStored = zoomLevel
var ptCenter var newZoomOutFound = false
var ptTopLeft
var ptBottomRight
// calculate zoom out // calculate zoom out
newZoomOut = zoomLevel newZoomOut = zoomLevel
while (zoomLevel > minimumZoomLevel) { while (zoomLevel > minimumZoomLevel) {
ptCenter = fromCoordinate(centerStored) var ptCenter = fromCoordinate(centerStored)
ptTopLeft = fromCoordinate(topLeft) var ptCenterRect = fromCoordinate(centerRect)
ptBottomRight = fromCoordinate(bottomRight) if (pointIsVisible(ptCenter) && pointIsVisible(ptCenterRect)) {
if (pointIsVisible(ptCenter) && pointIsVisible(ptTopLeft) && pointIsVisible(ptBottomRight)) {
newZoomOut = zoomLevel newZoomOut = zoomLevel
newZoomOutFound = true
break break
} }
zoomLevel-- zoomLevel--
} }
if (!newZoomOutFound)
newZoomOut = defaultZoomOut
// calculate zoom in // calculate zoom in
center = newCenter center = newCenter
zoomLevel = maximumZoomLevel zoomLevel = maximumZoomLevel
var diagonalRect = topLeft.distanceTo(bottomRight)
while (zoomLevel > minimumZoomLevel) { while (zoomLevel > minimumZoomLevel) {
ptTopLeft = fromCoordinate(topLeft) var c0 = toCoordinate(Qt.point(0.0, 0.0))
ptBottomRight = fromCoordinate(bottomRight) var c1 = toCoordinate(Qt.point(width, height))
if (pointIsVisible(ptTopLeft) && pointIsVisible(ptBottomRight)) { if (c0.distanceTo(c1) > diagonalRect) {
newZoom = zoomLevel newZoom = zoomLevel - 2.0
break break
} }
zoomLevel-- zoomLevel--