首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将GMSVisibleRegion转换为CLRegion或MKCoordinateRegion

将GMSVisibleRegion转换为CLRegion或MKCoordinateRegion
EN

Stack Overflow用户
提问于 2013-03-05 02:13:42
回答 4查看 6.8K关注 0票数 4

我正在使用GoogleMaps软件开发工具包,目前我正在尝试将GMSVisibleRegion转换为CLRegion。

GMSVisibleRegion定义为:

代码语言:javascript
复制
typedef struct {
  CLLocationCoordinate2D nearLeft;
  CLLocationCoordinate2D nearRight;
  CLLocationCoordinate2D farLeft;
  CLLocationCoordinate2D farRight;
} GMSVisibleRegion;

执行此操作的最快方法是什么?

不幸的是,很难理解开发人员命名“近”和“远”是什么意思。我认为这条评论也很有用:

代码语言:javascript
复制
/**
 * 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。任何反对意见。

代码语言:javascript
复制
+ (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);
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-03-05 08:25:09

我猜“near”是指屏幕底部的视图角落,而“far”是指屏幕顶部的角落。这是因为如果您倾斜了视图,则底部角距离摄影机最近,而顶部角距离摄影机最远。

将其转换为CLRegion的一种方法可能是使用相机的目标作为中心,然后计算从最大距离到四个角的半径。这可能不是该区域上最紧密的拟合圆,但由于圆无论如何都不能拟合视图的四边形,所以它可能足够接近。

下面是一个辅助函数,用于计算两个CLLocationCoordinate值之间以米为单位的距离:

代码语言:javascript
复制
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

代码语言:javascript
复制
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将具有相同的经度,因此您的纬度和经度差值将为零。

您需要遍历farLeftfarRightnearLeftnearRight中的所有四个,计算每一个的纬度和经度的最小和最大值,然后从中计算增量。

Google Maps SDK for iOS包含一个helper类,它已经为您完成了其中的一些工作-- GMSCoordinateBounds。它可以使用GMSVisibleRegion进行初始化

代码语言:javascript
复制
GMSMapView* mapView = ...;
....
GMSVisibleRegion visibleRegion = mapView.projection.visibleRegion;
GMSCoordinateBounds bounds = 
    [[GMSCoordinateBounds alloc] initWithRegion: visibleRegion];

然后,GMSCoordinateBounds具有定义边界的northEastsouthWest属性。因此,您可以按如下方式计算增量:

代码语言:javascript
复制
CLLocationDegrees latitudeDelta = 
    bounds.northEast.latitude - bounds.southWest.latitude;
CLLocationDegrees longitudeDelta = 
    bounds.northEast.longitude - bounds.southWest.longitude;

您还可以从边界计算中心,从而计算MKCoordinateRegion

代码语言:javascript
复制
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);
票数 11
EN

Stack Overflow用户

发布于 2013-05-16 20:40:59

纯粹主义者附录

如果你想要绝对严谨,你需要在国际日期变更线周围做一个修正。这在大多数应用程序中都是浪费精力的,但这个问题最近一直给我带来很大的痛苦,所以我想把它扔到社区帽子里去

基于Druce的更新(恐怕我不能发表评论)。

代码语言:javascript
复制
GMSMapView* mapView = ...;
....
GMSVisibleRegion visibleRegion = mapView.projection.visibleRegion;
GMSCoordinateBounds bounds = 
    [[GMSCoordinateBounds alloc] initWithRegion: visibleRegion];

Latitude不需要对它做任何操作

代码语言:javascript
复制
CLLocationDegrees latitudeDelta = 
bounds.northEast.latitude - bounds.southWest.latitude;

根据协议,一个跨越国际日期变更线的地区可能在日本有southWest角(+140经度),在阿拉斯加有northEast角(-150经度)。加起来再除以2得出的是地球另一边的一个点。

northEast.longitude小于southWest.longitude的特殊情况需要处理

代码语言:javascript
复制
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);
票数 9
EN

Stack Overflow用户

发布于 2014-05-22 21:31:08

对于任何基于目前提供的所有答案和更正来寻找样板代码的人,这里是作为GMSMapView上的一个类别实现的region

代码语言:javascript
复制
//
//  GMSMapViewExtensions.h
//

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

@interface GMSMapView (GMSMapViewExtensions)

@end

代码语言:javascript
复制
//
//  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

使用示例:

代码语言:javascript
复制
GMSMapView * mapView = .... // init code
MKCoordinateRegion mapRegion = mapView.region;
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15208181

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档