2013-03-04 67 views
3

我正在使用GoogleMaps SDK,目前我正嘗試將GMSVisibleRegion轉換爲CLRegion。將GMSVisibleRegion轉換爲CLRegion或MKCoordinateRegion

GMSVisibleRegion被定義爲:

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

什麼是這樣做的最快方法是什麼?

不幸的是,很難理解開發人員對「near」和「far」命名的含義。我覺得這個評論也可以用:

/** 
* 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); 
} 

回答

9

我的猜測是'near'是在屏幕底部的視角,'far'是在屏幕頂部的角落。這是因爲如果您已經傾斜視圖,那麼底部角落距離相機最近,而頂部角落距離相機最遠。

將此變爲CLRegion的一種方法可能是將相機的目標作爲中心,然後計算從最大距離到四角的半徑。這可能不是該地區最緊密的擬合圓,但是由於圓不能適合視圖的四邊形,所以它可能足夠接近。

這裏是一個輔助函數來計算兩個CLLocationCoordinate值之間米的距離:

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:

關於MKCoordinateRegion的更新,您的示例代碼可能不會RK。如果地圖旋轉90度,則farLeftnearLeft將具有相同的緯度,並且farRightfarLeft將具有相同的經度,因此您的緯度和經度增量將爲零。

你會需要循環的farLeftfarRightnearLeftnearRight所有四個,計算出每個緯度和經度的最小值和最大值,然後從計算的增量。

適用於iOS的Google Maps SDK包含一個輔助類,它已經爲您執行了一些操作 - GMSCoordinateBounds。它可以與GMSVisibleRegion進行初始化:

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

GMSCoordinateBounds於是具有northEastsouthWest屬性限定了邊界。所以,你可以計算出增量如下:

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快速擴展是啊,這是有道理的!我在我面前有一個示例代碼來評估你的答案。並會盡快向您報告。希望將來會有更好的文檔。 – 2013-03-05 08:35:38

+0

Hi @ xen100,我爲你的問題的後半部分添加了一個關於'MKCoordinateRegion'的更新。 – 2013-03-05 12:59:39

+0

非常感謝!你救了我的一天! :) – 2013-03-05 14:03:27

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度)。加起來併除以2表示在地球的錯誤一側。

特殊情況下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 

用例:

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

基於@Saxon德魯斯的答案,這是關於設置和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) 
     } 
    } 
}