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.
This commit is contained in:
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
return MGLCoordinateBoundsMake(MGLLocationCoordinate2DFromLatLng(latLngBounds.sw),
|
||||
MGLLocationCoordinate2DFromLatLng(latLngBounds.ne));
|
||||
}
|
||||
|
||||
mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBounds coordinateBounds)
|
||||
{
|
||||
return mbgl::LatLngBounds(MGLLatLngFromLocationCoordinate2D(coordinateBounds.sw), MGLLatLngFromLocationCoordinate2D(coordinateBounds.ne));
|
||||
}
|
||||
|
||||
- (MGLCoordinateBounds)visibleCoordinateBounds
|
||||
{
|
||||
return MGLCoordinateBoundsFromLatLngBounds(self.viewportBounds);
|
||||
}
|
||||
|
||||
- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds animated:(BOOL)animated
|
||||
{
|
||||
// NOTE: does not disrupt tracking mode
|
||||
|
||||
CLLocationCoordinate2D center = CLLocationCoordinate2DMake((northEastCoordinate.latitude + southWestCoordinate.latitude) / 2, (northEastCoordinate.longitude + southWestCoordinate.longitude) / 2);
|
||||
|
||||
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);
|
||||
|
||||
[self setCenterCoordinate:center zoomLevel:zoomLevel animated:animated];
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user