2013-03-04 6 views
3

GoogleMaps SDK를 사용하고 있으며 현재 GMSVisibleRegion을 CLRegion으로 변환하려고합니다.GMSVisibleRegion을 CLRegion 또는 MKCoordinateRegion으로 변환하십시오.

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

그렇게 할 수있는 가장 빠른 방법은 무엇입니까 :로

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; 

감사합니다.

EDIT : 제 첫 걸음은 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); 
} 

답변

9

내 생각 엔 '근처'는 화면 상단의 모서리입니다 '까지'화면 하단의보기의 모서리를 위해, 그리고 있다는 점이다. 왜냐하면보기를 기울이면 가장 아래쪽 모서리가 카메라에 가장 가깝고 위쪽 모서리가 카메라에서 가장 멀리 떨어져 있기 때문입니다.

CLRegion으로 바꾸는 한 가지 방법은 카메라의 타겟을 가운데로 사용한 다음 최대 거리에서 네 모서리까지 반경을 계산하는 것입니다. 이 지역에 가장 적합한 피팅 서클이 아닐 수도 있지만 어쨌든 원이보기의 사변형에 맞지 않을 수 있으므로 충분히 가까울 수 있습니다.

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"]; 

UPDATE :

여기

CLLocationCoordinate 값 사이에서 m의 거리를 계산하는 도우미 함수의 MKCoordinateRegion에 대한 업데이트와 관련하여 예제 코드가 작동하지 않을 수 있습니다. rk. 지도가 90도 회전 된 경우 farLeftnearLeft은 동일한 위도를 가지며 farRightfarLeft은 동일한 경도를 갖기 때문에 위도와 경도의 델타는 0이됩니다.

당신은 farLeft, farRight, nearLeft, nearRight의 네 돌이 필요 각각의 위도와 경도의 최소 및 최대를 계산 한 다음 그에서 델타를 계산합니다.

iOS 용 Google지도 SDK에는 도우미 클래스가 포함되어 있는데이 도우미 클래스 중 일부는 이미 GMSCoordinateBounds입니다. GMSVisibleRegion로 초기화 할 수 있습니다 다음 GMSCoordinateBounds 다음 경계를 정의 northEastsouthWest 특성을 가지고

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

.당신은 델타를 계산할 수 있도록 다음과 같이

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); 
+0

에 MKCoordinateRegion를 사용하여 region을 얻기에 빠른 확장이 그래이 의미가 있습니다! 귀하의 답변을 평가하기 위해 샘플 코드가 제게 있습니다. 그리고 곧 당신을보고 할 것입니다. 앞으로 더 나은 문서가되기를 바랍니다. –

+0

안녕하세요 @ xen100, 나는'MKCoordinateRegion'에 대한 질문의 후반부에 대한 업데이트를 추가했습니다. –

+0

고마워요! 너는 나의 하루를 구했다! :) –

7

부록 절대적으로 엄격한 것은 국제 데이터 라인을 중심으로 수정해야 할 사항입니다. 대부분의 애플 리케이션에서 노력의 낭비가 될 수 있지만이 문제는 나중에 큰 슬픔을 불러 일으켜서 커뮤니티 모자에 던져 넣을 생각이었습니다.

Druce의 업데이트에 대한 빌드 (두렵다는 의견이 없습니다). ..

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

위도 그것을하고 아무것도 필요하지 않습니다

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

거래는 실행이 남서부 일본의 코너 (140 경도)와이있을 수 있습니다 국제 날짜 변경선에 걸쳐있는 지역 알래스카의 북동쪽 코너 (경도 -150). 두 개를 더하고 나누면 지구 반대편에 포인트가 생깁니다.

northEast.longitude이 southWest.longitude보다 여기에 지금까지 제공하는 모든 답변 및 수정에 따라 상용구 코드를 찾고있는 사람들을위한

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); 
3

을 처리 할 필요가 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 
,

사용 예 : @Saxon Druce의 답변에 따라

GMSMapView * mapView = .... // init code 
MKCoordinateRegion mapRegion = mapView.region; 
2

,이 설정하고 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) 
     } 
    } 
}