I am using the GoogleMaps SDK and currently I am trying to convert a GMSVisibleRegion to a CLRegion.
GMSVisibleRegion is defined as:
typedef struct {
CLLocationCoordinate2D nearLeft;
CLLocationCoordinate2D nearRight;
CLLocationCoordinate2D farLeft;
CLLocationCoordinate2D farRight;
} GMSVisibleRegion;
What is the fastest way to do so?
Unfortunately it is difficult to understand what the developer meant with the naming "near" and "far". I think this comment can also be useful:
/**
* 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;
Thanks a lot!
EDIT: Ok my first step was to create a MKCoordinateRegion of a GMSVisibleRegion.
I propose the following code to transform a a GMSVisibleRegion to a MKCoordinateRegion. Any objections.
+ (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);
}
My guess is that 'near' is for the corners of the view at the bottom of the screen, and 'far' is for the corners at the top of the screen. This is because if you've tilted the view, then the bottom corners are nearest to the camera, and the top corners are furthest from the camera.
One way to turn this into a CLRegion
might be to use the camera's target as the centre, and then calculate the radius from the maximum distance to the four corners. This might not be the tightest fitting circle over the region, but since a circle can't fit the quadrilateral of the view anyway, it may be close enough.
Here's a helper function to calculate the distance in metres between two CLLocationCoordinate
values:
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];
}
Then the CLRegion
can be calculated like this:
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:
Regarding your update for MKCoordinateRegion
, your example code may not work. If the map has been rotated 90 degrees, then farLeft
and nearLeft
will have the same latitude, and farRight
and farLeft
will have the same longitude, and so your latitude and longitude deltas would be zero.
You would need to loop over all four of the farLeft
, farRight
, nearLeft
, nearRight
, calculate the min and max of the latitude and longitude of each, and then calculate the delta from that.
The Google Maps SDK for iOS includes a helper class which already does some of this for you - GMSCoordinateBounds
. It can be initialized with a GMSVisibleRegion
:
GMSMapView* mapView = ...;
....
GMSVisibleRegion visibleRegion = mapView.projection.visibleRegion;
GMSCoordinateBounds bounds =
[[GMSCoordinateBounds alloc] initWithRegion: visibleRegion];
The GMSCoordinateBounds
then has northEast
and southWest
properties which define the bounds. So you could calculate the deltas as follows:
CLLocationDegrees latitudeDelta =
bounds.northEast.latitude - bounds.southWest.latitude;
CLLocationDegrees longitudeDelta =
bounds.northEast.longitude - bounds.southWest.longitude;
You could also calculate the centre from the bounds, and therefore the 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);