【问题标题】:How to setRegion with google maps sdk for iOS?如何使用适用于 iOS 的 google maps sdk 设置区域?
【发布时间】:2013-02-23 12:12:35
【问题描述】:

如何使用 google maps sdk for iOS 设置区域? 我想为标记的位置和半径设置缩放。

【问题讨论】:

    标签: ios google-maps-sdk-ios


    【解决方案1】:

    更新:

    以下原始答案在 SDK 1.2 版中已过时 - 您现在可以使用 GMSCameraUpdate 类的 fitBounds: 方法:

    https://developers.google.com/maps/documentation/ios/reference/interface_g_m_s_camera_update


    原答案:

    MapKit 中的MKMapPoint 类型定义了地图的二维投影。尽管投影的实际值是不透明的,但它们最终等同于缩放级别 20 的像素。这可用于将纬度/经度值转换为像素,从而转换为比例,从而转换为缩放级别。

    首先定义两个位置,指定您要显示的区域的边界。这些可能是边界框的对角,也可能只是两个位置,例如:

    CLLocationCoordinate2D location1 = 
        CLLocationCoordinate2DMake(-33.8683, 151.2086); // Sydney
    CLLocationCoordinate2D location2 = 
        CLLocationCoordinate2DMake(-31.9554, 115.8585); // Perth
    

    如果您要包含两个以上的点,您可以自己计算它们的边界。这也可以使用GMSCoordinateBounds 来完成,例如:

    GMSCoordinateBounds* bounds =
        [[GMSCoordinateBounds alloc]
        initWithCoordinate: CLLocationCoordinate2DMake(-33.8683, 151.2086) // Sydney
        andCoordinate: CLLocationCoordinate2DMake(-31.9554, 115.8585)]; // Perth
    bounds = [bounds including: 
        CLLocationCoordinate2DMake(-12.4667, 130.8333)]; // Darwin
    CLLocationCoordinate2D location1 = bounds.southWest;
    CLLocationCoordinate2D location2 = bounds.northEast;
    

    接下来,您需要获取地图视图的大小(以磅为单位)。你可以使用这个:

    float mapViewWidth = _mapView.frame.size.width;
    float mapViewHeight = _mapView.frame.size.height;
    

    但这只有在您已经创建了地图视图时才有效。另外,如果您使用getting started guide 中的示例代码,则将框架设置为CGRectZero,因为稍后将设置实际大小以填充屏幕。在这些情况下,如果您正在创建全屏地图,那么您可能需要这样的东西:

    float mapViewWidth = [UIScreen mainScreen].applicationFrame.size.width;
    float mapViewHeight = [UIScreen mainScreen].applicationFrame.size.height;
    

    否则,请使用您在创建地图视图时使用的大小。

    现在您有了计算相机位置所需的信息:

    MKMapPoint point1 = MKMapPointForCoordinate(location1);
    MKMapPoint point2 = MKMapPointForCoordinate(location2);
    
    MKMapPoint centrePoint = MKMapPointMake(
        (point1.x + point2.x) / 2,
        (point1.y + point2.y) / 2);
    CLLocationCoordinate2D centreLocation = MKCoordinateForMapPoint(centrePoint);
    
    double mapScaleWidth = mapViewWidth / fabs(point2.x - point1.x);
    double mapScaleHeight = mapViewHeight / fabs(point2.y - point1.y);
    double mapScale = MIN(mapScaleWidth, mapScaleHeight);
    
    double zoomLevel = 20 + log2(mapScale);
    
    GMSCameraPosition *camera = [GMSCameraPosition
        cameraWithLatitude: centreLocation.latitude
        longitude: centreLocation.longitude
        zoom: zoomLevel];
    

    然后您可以使用此相机初始化地图视图,或将地图视图设置为此相机。

    要编译此代码,您需要将 MapKit 框架添加到您的项目中,然后将其导入:

    #import <MapKit/MapKit.h>
    

    请注意,如果您的坐标跨越日期线,则此代码不会处理环绕。例如,如果您尝试将此代码用于东京和夏威夷,而不是显示太平洋地区,它将尝试显示几乎整个世界。在纵向模式下,无法缩小到足以看到左侧的夏威夷和右侧的东京,因此地图最终以非洲为中心,两个位置都不可见。如果你愿意,你可以修改上面的代码来处理日期行的环绕。

    【讨论】:

    • 嗨撒克逊人。只需阅读此答案。难道正确的zoomLevel是“double zoomLevel = 21.0f + log2(mapScale);”。我刚刚检查了 GoogleMaps SDK 中可能的最大缩放级别,它似乎是 21.0f;顺便说一下,最小缩放级别是 2.0f;
    • 嗨@xen100,20 在那里,因为MKMapPoint 相当于缩放级别20 的像素。如果您的边界非常小,那么mapScale 最终会大于1.0,所以zoomLevel 最终会大于 20。如果缩放级别大于 SDK 的限制,那么它会将缩放级别限制在它可以支持的范围内。
    • 谢谢。这对我帮助很大。如果您使用标记以位置坐标为边界,我建议您稍微减小视图的宽度和高度,这样标记最终不会正好位于视图的边缘。
    • @ChristopherShortt:好主意!
    【解决方案2】:

    更新

    所有问题都已在最新版本的 Google 地图 (1.5) 中得到修复。现在可以使用标准方法[mapView_ animateWithCameraUpdate:[GMSCameraUpdate fitBounds:bounds]]; 代替下面的代码


    原始答案

    [GMSCameraUpdate fitBounds] 在我的 SDK (1.2.0) 版本中没有给出准确的结果。我正在使用下面的代码而不是它。公式取自Mercator Projection。根据Google Documentation,世界在纬度上以 85 度为界。

    #import <stdlib.h>
    
    -(void) animateBoundsNorth:(CGFloat)north West:(CGFloat)west South:(CGFloat)south East:(CGFloat)east Padding:(int)padding {
    
        CGFloat northRad = north * M_PI / 180.0;
        CGFloat northProj = logf(tanf(M_PI_4 + northRad/2.0));
        CGFloat southRad = south * M_PI / 180.0;
        CGFloat southProj = logf(tanf(M_PI_4 + southRad/2.0));
        CGFloat topRad = 85.0 * M_PI / 180.0;
        CGFloat topProj = logf(tanf(M_PI_4 + topRad/2.0));
        CGFloat zoomLat = log2f((mapView_.bounds.size.height - padding * 2) * 2 * topProj /(northProj - southProj)) - 8;
        CGFloat zoomLon = log2f((mapView_.bounds.size.width - padding * 2) * 360/(east - west)) - 8;
    
        GMSCameraUpdate *update = [GMSCameraUpdate setTarget:CLLocationCoordinate2DMake((north+south)/2.0, (west+east)/2.0) zoom:MIN(zoomLat, zoomLon)];
    
    
        [mapView_ animateWithCameraUpdate:update];
    
    
    }
    

    【讨论】:

    • 我有一个问题。我怎样才能得到 "north" 、 "west" 、 "south" 、 "east" 和 "padding" ?
    • 其实没有,问题还没有解决。我正在使用 Google Maps v1.7.2,当我尝试使用 GMSCameraUpdate fitBounds 方法时它不起作用。我最终看到地图一直放大到可以看到整个北美。我可以让它正常工作的唯一方法是使用上面的 animateWithBoundsNorth: 方法。
    【解决方案3】:

    Saxun Druce 的回答非常好。但此外,如果您想从任何位置计算半径,您可以使用以下代码:

        CLLocationCoordinate2D center = CLLocationCoordinate2DMake([currentLocationLat doubleValue],[currentLocationLong doubleValue]);
    float radius = 25*1000; //radius in meters (25km)
    
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(center, radius*2, radius*2);
    
    CLLocationCoordinate2D  northEast = CLLocationCoordinate2DMake(region.center.latitude - region.span.latitudeDelta/2, region.center.longitude - region.span.longitudeDelta/2);
    CLLocationCoordinate2D  southWest = CLLocationCoordinate2DMake(region.center.latitude + region.span.latitudeDelta/2, region.center.longitude + region.span.longitudeDelta/2);
    
    GMSCoordinateBounds* bounds = [[GMSCoordinateBounds alloc]
                                   initWithCoordinate: northEast
                                   andCoordinate: southWest];
    

    【讨论】:

    • 您的答案符合我的要求,但您能否为您的答案添加更多解释?
    【解决方案4】:

    如果你有谷歌地图的'far-left'和'near-right'角的纬度和经度,你可以使用下面的代码快速显示数据

         var region:GMSVisibleRegion = GMSVisibleRegion()
         region.nearLeft = CLLocationCoordinate2DMake(nearleflat, nearleftlong)
         region.farRight = CLLocationCoordinate2DMake(fareastlat,fareastlong)
         let bounds = GMSCoordinateBounds(coordinate: region.nearLeft,coordinate: region.farRight)
         let camera = googleMapView.cameraForBounds(bounds, insets:UIEdgeInsetsZero)
         googleMapView.camera = camera;
    

    This 链接也可能对相关的事情有所帮助。

    【讨论】:

    • 这对我有帮助。但是我得到的两点几乎超出了屏幕,我怎样才能得到更多的中心两点:nearLeft 和 farRight?感谢您的帮助!
    【解决方案5】:

    我目前正在使用这种方法。

    self.markers 是一个字典,其标记由位置 ID 存储,self.currentLocation 是一个 CLLocation2D,self.mapView 是一个 GMSMapView。

    这里的数学是检查是否匹配宽度或高度上的大小,然后根据 x1 / pow(2, zoom1) = x2 / pow(2, zoom2 )",导致 zoom2 = log2(x2 * pow(2, self.mapView.camera.zoom) / x1)。

    - (void)fitMarkers
    {
        if (2 > self.markers.count)
        {
            [self.mapView animateToCameraPosition:[GMSCameraPosition cameraWithTarget:self.currentLocation.coordinate zoom:kZoom]];
    
            return;
        }
    
        NSArray* markers = self.markers.allValues;
    
        GMSCoordinateBounds* markerBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:((id<GMSMarker>)markers[0]).position andCoordinate:((id<GMSMarker>)markers[1]).position];
    
        for (id<GMSMarker> marker in markers)
        {
            markerBounds = [markerBounds including:marker.position];
        }
    
        // get marker bounds in points
        CGPoint markerBoundsTopLeft = [self.mapView.projection pointForCoordinate:CLLocationCoordinate2DMake(markerBounds.northEast.latitude, markerBounds.southWest.longitude)];
        CGPoint markerBoundsBottomRight = [self.mapView.projection pointForCoordinate:CLLocationCoordinate2DMake(markerBounds.southWest.latitude, markerBounds.northEast.longitude)];
    
        // get user location in points
        CGPoint currentLocation = [self.mapView.projection pointForCoordinate:self.currentLocation.coordinate];
    
        CGPoint markerBoundsCurrentLocationMaxDelta = CGPointMake(MAX(fabs(currentLocation.x - markerBoundsTopLeft.x), fabs(currentLocation.x - markerBoundsBottomRight.x)), MAX(fabs(currentLocation.y - markerBoundsTopLeft.y), fabs(currentLocation.y - markerBoundsBottomRight.y)));
    
        // the marker bounds centered on self.currentLocation
        CGSize centeredMarkerBoundsSize = CGSizeMake(2.0 * markerBoundsCurrentLocationMaxDelta.x, 2.0 * markerBoundsCurrentLocationMaxDelta.y);
    
        // inset the view bounds to fit markers
        CGSize insetViewBoundsSize = CGSizeMake(self.mapView.bounds.size.width - kMarkerSize / 2.0 - kMarkerMargin, self.mapView.bounds.size.height - kMarkerSize / 2.0 - kMarkerSize);
    
        CGFloat x1;
        CGFloat x2;
    
        // decide which axis to calculate the zoom level with by comparing the width/height ratios
        if (centeredMarkerBoundsSize.width / centeredMarkerBoundsSize.height > insetViewBoundsSize.width / insetViewBoundsSize.height)
        {
            x1 = centeredMarkerBoundsSize.width;
            x2 = insetViewBoundsSize.width;
        }
        else
        {
            x1 = centeredMarkerBoundsSize.height;
            x2 = insetViewBoundsSize.height;
        }
    
        CGFloat zoom = log2(x2 * pow(2, self.mapView.camera.zoom) / x1);
    
        GMSCameraPosition* camera = [GMSCameraPosition cameraWithTarget:self.currentLocation.coordinate zoom:zoom];
    
        [self.mapView animateToCameraPosition:camera];
    }
    

    【讨论】:

    • 这或多或少也是我想出的解决方案。
    【解决方案6】:

    根据 GoogleMaps iOS sdk 1.9.2 的新版本, 我们可以使用相机的位置、缩放级别、查看角度进行设置。

    GMSCameraPosition* camera = [GMSCameraPosition cameraWithLatitude:28.6100
                                                                longitude:77.2300
                                                                     zoom:14.0
                                                                  bearing:0
                                                             viewingAngle:0.00];
        self.mapView = [GMSMapView mapWithFrame:CGRectMake(0, 45, self.view.frame.size.width, self.view.frame.size.height - 45) camera:camera];
        mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    
        mapView.delegate = self;
        mapView.myLocationEnabled = YES;
        mapView.mapType = kGMSTypeTerrain;
        mapView.settings.compassButton = YES;
        mapView.settings.myLocationButton = YES;
        [self.mapView setMinZoom:10 maxZoom:18];
    
        GMSMarker* marker = [[GMSMarker alloc] init];
        marker.position = CLLocationCoordinate2DMake(28.6100, 77.2300);
        marker.title = @"New Delhi";
        marker.snippet = @"Capital Of India";
    
        marker.map = self.mapView;
        marker.appearAnimation = kGMSMarkerAnimationPop;
        marker.icon = [GMSMarker markerImageWithColor:[UIColor grayColor]];
        [self.view addSubview:self.mapView];
    

    供进一步参考see this PDF document

    您还可以根据需要设置最小和最大缩放级别:

    [self.mapView setMinZoom:10 maxZoom:30];
    

    希望这能解决问题。

    【讨论】:

      【解决方案7】:

      我翻遍了框架的头文件,只找到了可以用于下面代码的接口,可以作为一个开始。这里的问题是我在其他标题之一中找不到任何 GMSCoordinateBounds 的导入,所以我找不到在 GMSMapView 中显示该区域的方法。

      GMSVisibleRegion region;
      region.farLeft = CLLocationCoordinate2DMake(farLeftLatitude, farLeftlongitude);
      region.farRight = CLLocationCoordinate2DMake(farRightlatitude, farRightlongitude); 
      
      GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithRegion:region];
      

      【讨论】:

      • 但是如何设置这个区域呢?
      【解决方案8】:

      截至 2014 年 6 月,this answer 是迭代给定标记数组并相应设置边界的最简单方法。

      【讨论】:

        【解决方案9】:

        //我发现这个方法对我有用

        func setMapZoomToRadius(lat:Double, lng:Double, var mile:Double)
            {
        
                let center = CLLocationCoordinate2DMake(lat, lng)           
                let radius: Double = (mile ) * 621.371 
        
                let region = MKCoordinateRegionMakeWithDistance(center, radius * 2.0, radius * 2.0)
        
        
                let northEast = CLLocationCoordinate2DMake(region.center.latitude - region.span.latitudeDelta, region.center.longitude - region.span.longitudeDelta)
                let  southWest = CLLocationCoordinate2DMake(region.center.latitude + region.span.latitudeDelta, region.center.longitude + region.span.longitudeDelta)
        
        
                print("\(region.center.longitude)  \(region.span.longitudeDelta)")
                let bounds = GMSCoordinateBounds(coordinate: southWest, coordinate: northEast)
        
                let camera = googleMapView.cameraForBounds(bounds, insets:UIEdgeInsetsZero)
                 googleMapView.camera = camera;
        
              }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多