2

地球の特定の地域を常に画面に表示しようとしています。私は周りを見回して、ちょっとうまくいくコードを見つけましたが、実際にはうまくいくコードはありませんでした.

このメソッドを MKMapViewController にドロップすると、ディスプレイ上の領域が特定のズーム範囲内に維持されます。領域とズームの組み合わせがディスプレイよりも小さい場合、つまり画面に完全に表示されている場合、これは期待どおりに機能します。

領域とズームの組み合わせが画面よりも大きい場合は、うまく機能します。アウト オブ バウンドを検出してマップを移動しましたが、オフセットが反転しているように見えますか? マップが前後または上下に「跳ねる」状況に陥ります。

バウンスの原因や停止方法がわかりません。

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    // Keep map in the zoom range we want
    int zoom = self.map.zoomLevel;
    if (self.map.zoomLevelFine > (float)self.maxZoom && self.maxZoom > 0)
    {
        zoom = self.maxZoom;
        [self.map setCenterCoordinate:self.map.centerCoordinate zoomLevel:self.maxZoom animated:YES];
    }
    else if (self.map.zoomLevelFine < (float)self.minZoom && self.maxZoom > 0)
    {
        zoom = self.minZoom;
        [self.map setCenterCoordinate:self.map.centerCoordinate zoomLevel:self.minZoom animated:YES];
    }

    // Figure out the current on screen boundry
    MKCoordinateSpan span = self.map.region.span;
    double north = self.map.centerCoordinate.latitude + (span.latitudeDelta / 2);
    double south = self.map.centerCoordinate.latitude - (span.latitudeDelta / 2);
    double east = self.map.centerCoordinate.longitude + (span.longitudeDelta / 2);
    double west = self.map.centerCoordinate.longitude - (span.longitudeDelta / 2);

    // get the offsets
    float offsetLong = 0.0;
    float offsetLat = 0.0;
    if (self.topLeftLong < west && self.btmRightLong < east)
    {
        offsetLong = west - self.topLeftLong;
    }
    else if (self.topLeftLong > west && self.btmRightLong > east)
    {
        offsetLong = east - self.btmRightLong;
    }

    if (self.topLeftLat > north && self.btmRightLat > south)
    {
        offsetLat = north - self.topLeftLat;
    }
    else if (self.topLeftLat < north && self.btmRightLat < south)
    {
        offsetLat = south - self.btmRightLat;
    }

    // Keep the map on screen
    if (offsetLat != 0.0 || offsetLong != 0.0)
    {
        [self.map setCenterCoordinate:CLLocationCoordinate2DMake(self.map.centerCoordinate.latitude - offsetLat,
                                                                 self.map.centerCoordinate.longitude - offsetLong)
                            zoomLevel:zoom animated:YES];
    }

    // Debug
    NSLog(@"Center: %f, %f, Zoom: %f", self.map.centerCoordinate.latitude, self.map.centerCoordinate.longitude, self.map.zoomLevelFine);
    NSLog(@"A north: %f west: %f south: %f east: %f", north, west, south, east);
    NSLog(@"B north: %f west: %f south: %f east: %f", self.topLeftLat, self.topLeftLong, self.btmRightLat, self.btmRightLong);
    NSLog(@"offset %f, %f", offsetLong, offsetLat);
}

このスニペットを init メソッドに追加すると、画面にオアフ島が表示されるようにマップがセットアップされます。

// Get some basic setings
self.topLeftLat = 21.714852;
self.topLeftLong = -158.286896;
self.btmRightLat = 21.245862;
self.btmRightLong = -157.646942;
self.minZoom = 9.0;
self.maxZoom = 13.0;

上記の方法では、マップの操作に役立つカテゴリも使用しています。

MKMapView+Extra.h

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface MKMapView (Extra)


#pragma mark -
#pragma mark Zoom methods
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
                  zoomLevel:(NSUInteger)zoomLevel
                   animated:(BOOL)animated;
- (int) zoomLevel;
- (float) zoomLevelFine;

#pragma mark -
#pragma mark Region methods
- (void)setRegionTopLeft:(CLLocationCoordinate2D)topLeft
             bottomRight:(CLLocationCoordinate2D)bottomRight
                animated:(BOOL)animated;
- (CLLocationCoordinate2D)centerPointFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
                                           bottomRight:(CLLocationCoordinate2D)bottomRight;
- (MKCoordinateSpan)spanFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
                              bottomRight:(CLLocationCoordinate2D)bottomRight;
@end

MKMapView+Extra.m

#import "MKMapView+Extra.h"

#define MERCATOR_OFFSET 268435456
#define MERCATOR_RADIUS 85445659.44705395

@implementation MKMapView (ZoomLevel)

#pragma mark -
#pragma mark Map conversion methods

- (double)longitudeToPixelSpaceX:(double)longitude
{
    return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * M_PI / 180.0);
}

- (double)latitudeToPixelSpaceY:(double)latitude
{
    return round(MERCATOR_OFFSET - MERCATOR_RADIUS * logf((1 + sinf(latitude * M_PI / 180.0)) / (1 - sinf(latitude * M_PI / 180.0))) / 2.0);
}

- (double)pixelSpaceXToLongitude:(double)pixelX
{
    return ((round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / M_PI;
}

- (double)pixelSpaceYToLatitude:(double)pixelY
{
    return (M_PI / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / M_PI;
}

#pragma mark -
#pragma mark Helper methods

- (MKCoordinateSpan)coordinateSpanWithMapView:(MKMapView *)mapView
                             centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
                                 andZoomLevel:(NSUInteger)zoomLevel
{
    // convert center coordiate to pixel space
    double centerPixelX = [self longitudeToPixelSpaceX:centerCoordinate.longitude];
    double centerPixelY = [self latitudeToPixelSpaceY:centerCoordinate.latitude];

    // determine the scale value from the zoom level
    NSInteger zoomExponent = 20 - zoomLevel;
    double zoomScale = pow(2, zoomExponent);

    // scale the map’s size in pixel space
    CGSize mapSizeInPixels = mapView.bounds.size;
    double scaledMapWidth = mapSizeInPixels.width * zoomScale;
    double scaledMapHeight = mapSizeInPixels.height * zoomScale;

    // figure out the position of the top-left pixel
    double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
    double topLeftPixelY = centerPixelY - (scaledMapHeight / 2);

    // find delta between left and right longitudes
    CLLocationDegrees minLng = [self pixelSpaceXToLongitude:topLeftPixelX];
    CLLocationDegrees maxLng = [self pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
    CLLocationDegrees longitudeDelta = maxLng - minLng;

    // find delta between top and bottom latitudes
    CLLocationDegrees minLat = [self pixelSpaceYToLatitude:topLeftPixelY];
    CLLocationDegrees maxLat = [self pixelSpaceYToLatitude:topLeftPixelY + scaledMapHeight];
    CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);

    // create and return the lat/lng span
    MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
    return span;
}

#pragma mark -
#pragma mark Public zoom methods

- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
                  zoomLevel:(NSUInteger)zoomLevel
                   animated:(BOOL)animated
{
    NSLog(@"setCenterCoordinate: zoomLevel:%d animated:", zoomLevel);
    // clamp large numbers to 28
    zoomLevel = MIN(zoomLevel-1, 28);

    // use the zoom level to compute the region
    MKCoordinateSpan span = [self coordinateSpanWithMapView:self centerCoordinate:centerCoordinate andZoomLevel:zoomLevel];
    MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);

    // set the region like normal
    [self setRegion:region animated:animated];
}

- (int) zoomLevel
{
    return 21 - round(log2(self.region.span.longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * self.bounds.size.width)));
}

- (float) zoomLevelFine
{
    return 21.0 - log2(self.region.span.longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * self.bounds.size.width));
}

#pragma mark -
#pragma mark Public region methods
- (void)setRegionTopLeft:(CLLocationCoordinate2D)topLeft
             bottomRight:(CLLocationCoordinate2D)bottomRight
                animated:(BOOL)animated
{
    CLLocationCoordinate2D center = [self centerPointFromRegionTopLeft:topLeft bottomRight:bottomRight];
    MKCoordinateSpan span = [self spanFromRegionTopLeft:topLeft bottomRight:bottomRight];
    MKCoordinateRegion region = MKCoordinateRegionMake(center, span);

    // set the region like normal
    [self setRegion:region animated:animated];
}

- (CLLocationCoordinate2D)centerPointFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
                                           bottomRight:(CLLocationCoordinate2D)bottomRight
{
    CLLocationCoordinate2D centerPoint;

    centerPoint.latitude = ((topLeft.latitude + bottomRight.latitude) / 2);
    centerPoint.longitude = ((topLeft.longitude + bottomRight.longitude) / 2);

    return centerPoint;
}

- (MKCoordinateSpan)spanFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
                              bottomRight:(CLLocationCoordinate2D)bottomRight
{
    MKCoordinateSpan span;

    span.latitudeDelta = fabs(bottomRight.latitude - topLeft.latitude);
    span.longitudeDelta = fabs(bottomRight.longitude - topLeft.longitude);

    return span;
}

@end
4

0 に答える 0