我正在使用GoogleMaps SDK,目前我正在尝试将GMSVisibleRegion转换为CLRegion。
gmsvisiblereregion定义为:
typedef struct {
CLLocationCoordinate2D nearLeft;
CLLocationCoordinate2D nearRight;
CLLocationCoordinate2D farLeft;
CLLocationCoordinate2D farRight;
} GMSVisibleRegion;
最快的方法是什么?
不幸的是,很难理解开发人员用"近"one_answers"远"命名的意思。我认为这条评论也很有用:
/**
* 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;
非常感谢!
编辑:好的,我的第一步是创建一个gmsvisiblereregion的mkcoordinaterereregion。
我建议使用以下代码将gmsvisiblereregion转换为mkcoordinaterereregion。任何反对意见。
+ (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);
}
我猜'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"];
更新:
关于MKCoordinateRegion
的更新,您的示例代码可能无法工作。如果地图已经旋转了90度,那么farLeft
和nearLeft
将具有相同的纬度,farRight
和farLeft
将具有相同的经度,因此您的纬度和经度增量将为零。
你需要循环所有四个farLeft
, farRight
, nearLeft
, nearRight
,计算纬度和经度的最小值和最大值,然后计算从中得到的增量。
Google Maps SDK for iOS包含了一个助手类,它已经为你做了一些这样的事情- GMSCoordinateBounds
。它可以用GMSVisibleRegion
:
GMSMapView* mapView = ...;
....
GMSVisibleRegion visibleRegion = mapView.projection.visibleRegion;
GMSCoordinateBounds bounds =
[[GMSCoordinateBounds alloc] initWithRegion: visibleRegion];
GMSCoordinateBounds
则具有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);
纯粹主义者附录
如果你想绝对严格,你需要在国际日期变更线附近进行修正。在大多数应用程序中,这将是浪费精力,但这个问题最近一直给我带来很大的痛苦,所以我想把它扔到社区
基于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,就得到了地球另一边的一个点。
东北的特殊情况。经度小于西南角。经度需要处理
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);
基于@Saxon Druce的回答,这是在GMSMapView
上使用mkcoordinatereregion设置和获得region
的快速扩展
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)
}
}
}
对于那些正在寻找基于到目前为止提供的所有答案和更正的样板代码的人来说,这里是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;