4

GoogleMaps SDKを使用していますが、現在GMSVisibleRegionをCLRegionに変換しようとしています。

GMSVisibleRegionは次のように定義されます。

typedef struct {
  CLLocationCoordinate2D nearLeft;
  CLLocationCoordinate2D nearRight;
  CLLocationCoordinate2D farLeft;
  CLLocationCoordinate2D farRight;
} GMSVisibleRegion;

そうするための最速の方法は何ですか?

残念ながら、開発者が「近い」と「遠い」という名前で何を意味するのかを理解するのは困難です。このコメントも役立つと思います。

/**
 * Returns the region (four location coordinates) that is visible according to
 * the projection.
 *
 * The visible region can be non-rectangular. The result is undefined if the
 * projection includes points that do not map to anywhere on the map (e.g.,
 * camera sees outer space).
 */
 - (GMSVisibleRegion)visibleRegion;

どうもありがとう!

編集:わかりました。私の最初のステップは、GMSVisibleRegionのMKCoordinateRegionを作成することでした。

GMSVisibleRegionをMKCoordinateRegionに変換するために、次のコードを提案します。異議がある場合。


+ (MKCoordinateRegion)regionForCenter:(CLLocationCoordinate2D)center andGMSVisibleRegion:(GMSVisibleRegion)visibleRegion
{
    CLLocationDegrees latitudeDelta = visibleRegion.farLeft.latitude - visibleRegion.nearLeft.latitude;
    CLLocationDegrees longitudeDelta = visibleRegion.farRight.longitude - visibleRegion.farLeft.longitude;
    MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);

    return MKCoordinateRegionMake(center, span);
}
4

4 に答える 4

11

私の推測では、「近い」は画面の下部にあるビューの隅であり、「遠い」は画面の上部にある隅です。これは、ビューを傾けた場合、下隅がカメラに最も近く、上隅がカメラから最も遠いためです。

これを に変換する 1 つの方法CLRegionは、カメラのターゲットを中心として使用し、最大距離から 4 つのコーナーまでの半径を計算することです。これは、領域上で最もぴったりと合う円ではないかもしれませんが、いずれにしても円はビューの四角形に収まらないため、十分に近い可能性があります。

CLLocationCoordinate2 つの値の間のメートル単位の距離を計算するヘルパー関数を次に示します。

double getDistanceMetresBetweenLocationCoordinates(
    CLLocationCoordinate2D coord1, 
    CLLocationCoordinate2D coord2)
{
    CLLocation* location1 = 
        [[CLLocation alloc] 
            initWithLatitude: coord1.latitude 
            longitude: coord1.longitude];
    CLLocation* location2 = 
        [[CLLocation alloc] 
            initWithLatitude: coord2.latitude 
            longitude: coord2.longitude];

    return [location1 distanceFromLocation: location2];
}

次に、は次のCLRegionように計算できます。

GMSMapView* mapView = ...;
...
CLLocationCoordinate2D centre = mapView.camera.target;
GMSVisibleRegion* visibleRegion = mapView.projection.visibleRegion;

double nearLeftDistanceMetres = 
    getDistanceMetresBetweenLocationCoordinates(centre, visibleRegion.nearLeft);
double nearRightDistanceMetres = 
    getDistanceMetresBetweenLocationCoordinates(centre, visibleRegion.nearRight);
double farLeftDistanceMetres = 
    getDistanceMetresBetweenLocationCoordinates(centre, visibleRegion.farLeft);
double farRightDistanceMetres = 
    getDistanceMetresBetweenLocationCoordinates(centre, visibleRegion.farRight);
double radiusMetres = 
    MAX(nearLeftDistanceMetres, 
    MAX(nearRightDistanceMetres, 
    MAX(farLeftDistanceMetres, farRightDistanceMetres)));

CLRegion region = [[CLRegion alloc] 
    initCircularRegionWithCenter: centre radius: radius identifier: @"id"];

アップデート:

の更新に関してMKCoordinateRegion、サンプル コードが機能しない可能性があります。マップが 90 度回転している場合、farLeftnearLeftは同じ緯度になりfarRightfarLeftと は同じ経度になるため、緯度と経度のデルタはゼロになります。

farLeftfarRight、の 4 つすべてをループし、それぞれの緯度と経度の最小値と最大値を計算し、そこからデルタを計算する必要があります。nearLeftnearRight

Google Maps SDK for iOS にはヘルパー クラスが含まれており、このクラスの一部が既に実行されています - GMSCoordinateBounds. で初期化できますGMSVisibleRegion

GMSMapView* mapView = ...;
....
GMSVisibleRegion visibleRegion = mapView.projection.visibleRegion;
GMSCoordinateBounds bounds = 
    [[GMSCoordinateBounds alloc] initWithRegion: visibleRegion];

GMSCoordinateBoundsthen には、境界を定義する プロパティnorthEastとプロパティがあります。southWestしたがって、次のようにデルタを計算できます。

CLLocationDegrees latitudeDelta = 
    bounds.northEast.latitude - bounds.southWest.latitude;
CLLocationDegrees longitudeDelta = 
    bounds.northEast.longitude - bounds.southWest.longitude;

境界から中心を計算することもできるため、MKCoordinateRegion次のようになります。

CLLocationCoordinate2D centre = CLLocationCoordinate2DMake(
    (bounds.southWest.latitude + bounds.northEast.latitude) / 2,
    (bounds.southWest.longitude + bounds.northEast.longitude) / 2);
MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
return MKCoordinateRegionMake(centre, span);
于 2013-03-05T00:25:09.347 に答える
4

これまでに提供されたすべての回答と修正に基づいてボイラープレート コードを探している人のために、ここregionに GMSMapView のカテゴリとして実装されています。

//
//  GMSMapViewExtensions.h
//

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

@interface GMSMapView (GMSMapViewExtensions)

@end

//
//  GMSMapViewExtensions.m
//

#import "GMSMapViewExtensions.h"

@implementation GMSMapView (GMSMapViewExtensions)

- (MKCoordinateRegion) region {
    GMSVisibleRegion visibleRegion = self.projection.visibleRegion;
    GMSCoordinateBounds * bounds = [[GMSCoordinateBounds alloc] initWithRegion: visibleRegion];

    CLLocationDegrees latitudeDelta = bounds.northEast.latitude - bounds.southWest.latitude;

    CLLocationCoordinate2D centre;
    CLLocationDegrees longitudeDelta;

    if (bounds.northEast.longitude >= bounds.southWest.longitude) {
        // Standard case
        centre = CLLocationCoordinate2DMake(
            (bounds.southWest.latitude + bounds.northEast.latitude) / 2,
            (bounds.southWest.longitude + bounds.northEast.longitude) / 2);
        longitudeDelta = bounds.northEast.longitude - bounds.southWest.longitude;
    } else {
        // Region spans the international dateline
        centre = CLLocationCoordinate2DMake(
            (bounds.southWest.latitude + bounds.northEast.latitude) / 2,
            (bounds.southWest.longitude + bounds.northEast.longitude + 360) / 2);
        longitudeDelta = bounds.northEast.longitude + 360 - bounds.southWest.longitude;
    }

    MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
    return MKCoordinateRegionMake(centre, span);
}


- (MKMapRect)visibleMapRect {
    MKCoordinateRegion region = [self region];
    MKMapPoint a = MKMapPointForCoordinate(CLLocationCoordinate2DMake(
        region.center.latitude + region.span.latitudeDelta / 2,
        region.center.longitude - region.span.longitudeDelta / 2));
     MKMapPoint b = MKMapPointForCoordinate(CLLocationCoordinate2DMake(
        region.center.latitude - region.span.latitudeDelta / 2,
        region.center.longitude + region.span.longitudeDelta / 2));
     return MKMapRectMake(MIN(a.x, b.x), MIN(a.y, b.y), ABS(a.x - b.x), ABS(a.y - b.y));
}

@end

使用例:

GMSMapView * mapView = .... // init code
MKCoordinateRegion mapRegion = mapView.region;
于 2014-05-22T13:31:07.930 に答える
4

@Saxon Druce の回答に基づいて、これは MKCoordinateRegion を設定およびregion使用するための簡単な拡張機能です。GMSMapView

extension GMSMapView {
    var region : MKCoordinateRegion {
        get {
            let position = self.camera
            let visibleRegion = self.projection.visibleRegion()
            let bounds = GMSCoordinateBounds(region: visibleRegion)
            let latitudeDelta = bounds.northEast.latitude - bounds.southWest.latitude
            let longitudeDelta = bounds.northEast.longitude - bounds.southWest.longitude
            let center = CLLocationCoordinate2DMake(
                (bounds.southWest.latitude + bounds.northEast.latitude) / 2,
                (bounds.southWest.longitude + bounds.northEast.longitude) / 2)
            let span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta)
            return MKCoordinateRegionMake(center, span)
        }
        set {
            let northEast = CLLocationCoordinate2DMake(newValue.center.latitude - newValue.span.latitudeDelta/2, newValue.center.longitude - newValue.span.longitudeDelta/2)
            let southWest = CLLocationCoordinate2DMake(newValue.center.latitude + newValue.span.latitudeDelta/2, newValue.center.longitude + newValue.span.longitudeDelta/2)
            let bounds = GMSCoordinateBounds(coordinate: northEast, coordinate: southWest)
            let update = GMSCameraUpdate.fitBounds(bounds, withPadding: 0)
            self.moveCamera(update)
        }
    }
}
于 2015-06-19T12:32:11.277 に答える