diff options
author | Minh Nguyễn <mxn@1ec5.org> | 2015-06-23 15:20:50 -0700 |
---|---|---|
committer | Minh Nguyễn <mxn@1ec5.org> | 2015-06-25 21:54:53 -0700 |
commit | c57799f26cf06995629cfdee55bdd4a94452b320 (patch) | |
tree | 97ace2a4b513fbf92092343f3f747698c6c8c675 | |
parent | f5c1e2630e553a727a91f0de623bf3ec1bdcc559 (diff) | |
download | qtlocation-mapboxgl-c57799f26cf06995629cfdee55bdd4a94452b320.tar.gz |
Reimplemented fit to bounds
The new implementation is now public and takes advantage of MGLCoordinateBounds. It is re-ported from `Camera.prototype.fitBounds()` in mapbox/mapbox-gl-js to ensure correct behavior. A new function, MGLCoordinateBoundsMake(), makes it easier to create an MGLCoordinateBounds for use with this method.
-rw-r--r-- | include/mbgl/ios/MGLMapView.h | 8 | ||||
-rw-r--r-- | include/mbgl/ios/MGLTypes.h | 7 | ||||
-rw-r--r-- | include/mbgl/map/map.hpp | 1 | ||||
-rw-r--r-- | platform/ios/MGLMapView.mm | 34 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 21 |
5 files changed, 60 insertions, 11 deletions
diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index bf258ee82e..001e7aa678 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -118,6 +118,14 @@ IB_DESIGNABLE * @param animated Specify `YES` if you want the map view to animate scrolling and zooming to the new location or `NO` if you want the map to display the new location immediately. */ - (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel animated:(BOOL)animated; +/** Returns the coordinate bounds visible in the receiver’s viewport. */ +- (MGLCoordinateBounds)visibleCoordinateBounds; + +/** Changes the receiver’s viewport to fit the given coordinate bounds, optionally animating the change. +* @param bounds The bounds that the viewport will show in its entirety. +* @param animated Specify `YES` to animate the change by smoothly scrolling and zooming or `NO` to immediately display the given bounds. */ +- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds animated:(BOOL)animated; + /** The heading of the map (measured in degrees) relative to true north. * * The value `0` means that the top edge of the map view corresponds to true north. The value `90` means the top of the map is pointing due east. The value `180` means the top of the map points due south, and so on. */ diff --git a/include/mbgl/ios/MGLTypes.h b/include/mbgl/ios/MGLTypes.h index 65d5e7846d..9213dafb37 100644 --- a/include/mbgl/ios/MGLTypes.h +++ b/include/mbgl/ios/MGLTypes.h @@ -28,6 +28,13 @@ typedef struct { CLLocationCoordinate2D ne; } MGLCoordinateBounds; +NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsMake(CLLocationCoordinate2D sw, CLLocationCoordinate2D ne) { + MGLCoordinateBounds bounds; + bounds.sw = sw; + bounds.ne = ne; + return bounds; +} + NS_ASSUME_NONNULL_END #pragma clang diagnostic push diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index e7474005e4..42ae72bb70 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -95,6 +95,7 @@ public: void setZoom(double zoom, Duration = Duration::zero()); double getZoom() const; void setLatLngZoom(LatLng latLng, double zoom, Duration = Duration::zero()); + void fitBounds(LatLngBounds bounds, Duration = Duration::zero()); void resetZoom(); double getMinZoom() const; double getMaxZoom() const; diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 4c014d12cf..b8fea9d8e8 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -1445,20 +1445,32 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) [self setZoomLevel:zoomLevel animated:NO]; } -- (void)zoomToSouthWestCoordinate:(CLLocationCoordinate2D)southWestCoordinate northEastCoordinate:(CLLocationCoordinate2D)northEastCoordinate animated:(BOOL)animated +MGLCoordinateBounds MGLCoordinateBoundsFromLatLngBounds(mbgl::LatLngBounds latLngBounds) { - // NOTE: does not disrupt tracking mode + return MGLCoordinateBoundsMake(MGLLocationCoordinate2DFromLatLng(latLngBounds.sw), + MGLLocationCoordinate2DFromLatLng(latLngBounds.ne)); +} - CLLocationCoordinate2D center = CLLocationCoordinate2DMake((northEastCoordinate.latitude + southWestCoordinate.latitude) / 2, (northEastCoordinate.longitude + southWestCoordinate.longitude) / 2); +mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBounds coordinateBounds) +{ + return mbgl::LatLngBounds(MGLLatLngFromLocationCoordinate2D(coordinateBounds.sw), MGLLatLngFromLocationCoordinate2D(coordinateBounds.ne)); +} - CGFloat scale = _mbglMap->getScale(); - CGFloat scaleX = _mbglMap->getWidth() / (northEastCoordinate.longitude - southWestCoordinate.longitude); - CGFloat scaleY = _mbglMap->getHeight() / (northEastCoordinate.latitude - southWestCoordinate.latitude); - CGFloat minZoom = _mbglMap->getMinZoom(); - CGFloat maxZoom = _mbglMap->getMaxZoom(); - CGFloat zoomLevel = MAX(MIN(log(scale * MIN(scaleX, scaleY)) / log(2), maxZoom), minZoom); +- (MGLCoordinateBounds)visibleCoordinateBounds +{ + return MGLCoordinateBoundsFromLatLngBounds(self.viewportBounds); +} - [self setCenterCoordinate:center zoomLevel:zoomLevel animated:animated]; +- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds animated:(BOOL)animated +{ + // NOTE: does not disrupt tracking mode + CGFloat duration = animated ? MGLAnimationDuration : 0; + + _mbglMap->fitBounds(MGLLatLngBoundsFromCoordinateBounds(bounds), secondsAsDuration(duration)); + + [self unrotateIfNeededAnimated:animated]; + + [self notifyMapChange:@(animated ? mbgl::MapChangeRegionDidChangeAnimated : mbgl::MapChangeRegionDidChange)]; } - (CLLocationDirection)direction @@ -2212,7 +2224,7 @@ CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng) desiredSouthWest.longitude != actualSouthWest.longitude) { // assumes we won't disrupt tracking mode - [self zoomToSouthWestCoordinate:desiredSouthWest northEastCoordinate:desiredNorthEast animated:YES]; + [self setVisibleCoordinateBounds:MGLCoordinateBoundsMake(desiredSouthWest, desiredNorthEast) animated:YES]; } } } diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index c25d307c6e..fd0701591b 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -146,6 +146,27 @@ void Map::setLatLngZoom(LatLng latLng, double zoom, Duration duration) { update(Update::Zoom); } +void Map::fitBounds(LatLngBounds bounds, Duration duration) { + // Zoom level calculation below assumes no rotation. + setBearing(0); + + // Calculate the center point, respecting the projection. + vec2<double> nePixel = pixelForLatLng(bounds.ne); + vec2<double> swPixel = pixelForLatLng(bounds.sw); + vec2<double> centerPixel = (nePixel + swPixel) * 0.5; + LatLng centerLatLng = latLngForPixel(centerPixel); + + // Calculate the zoom level. + double scaleX = getWidth() / (nePixel.x - swPixel.x); + double scaleY = getHeight() / (nePixel.y - swPixel.y); + double minZoom = getMinZoom(); + double maxZoom = getMaxZoom(); + double zoom = std::log2(getScale() * std::fmin(scaleX, scaleY)); + zoom = std::fmax(std::fmin(zoom, maxZoom), minZoom); + + setLatLngZoom(centerLatLng, zoom, duration); +} + void Map::resetZoom() { setZoom(0); } |