Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to setRegion with google maps sdk for iOS?

How to setRegion with google maps sdk for iOS? I want set zoom for location and radius of markers.

like image 832
Mecid Avatar asked Nov 27 '22 07:11

Mecid


2 Answers

UPDATE:

The original answer below is obsolete as of version 1.2 of the SDK - you can now use the fitBounds: method of the GMSCameraUpdate class:

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


Original answer:

The MKMapPoint type in MapKit defines a 2D projection of a map. Although the actual values of the projection are meant to be opaque, they turn out to be equivalent to pixels at zoom level 20. This can be used to convert lat/lon values to pixels, and therefore a scale, and therefore a zoom level.

Start by defining two locations which specify the bounds of the region you want to display. These could be opposite corners of the bounding box, or just two locations, for example:

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

If you have more than two points that you want to include, you could calculate the bounds of them yourself. This can also be done using GMSCoordinateBounds, for example:

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;

Next, you need to get the size of the map view in points. You could use this:

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

But that will only work if you've already created the map view. Also, if you're using the sample code in the getting started guide, the frame is set to CGRectZero, as the actual size will be set later to fill the screen. In these cases if you're creating a full-screen map then you might want something like this:

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

Otherwise, use the size which you're creating your map view with.

Now you have the info necessary to calculate the camera position:

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];

You can then initialize the map view with this camera, or set the map view to this camera.

For this code to compile, you will need to add the MapKit framework to your project, and then also import it:

#import <MapKit/MapKit.h>

Note that this code doesn't handle wrap-around if your coordinates span across the date line. For example if you tried using this code with Tokyo and Hawaii, instead of displaying an area of the Pacific, it will try to display almost the entire world. In portrait mode it's not possible to zoom out far enough to see Hawaii on the left and Tokyo on the right, and so the map ends up centred on Africa with neither location visible. You could modify the above code to handle the wrap-around at the date line if you wanted to.

like image 163
Saxon Druce Avatar answered Dec 09 '22 17:12

Saxon Druce


UPDATE

All issues were fixed in the latest version of Google maps (1.5). Standard method [mapView_ animateWithCameraUpdate:[GMSCameraUpdate fitBounds:bounds]]; can noow be used instead of the code below


ORIGINAL ANSWER

[GMSCameraUpdate fitBounds] does not give accurate results in my version of the SDK (1.2.0). I am using the code below instead of it. The formulae are taken from the Mercator Projection. The world is latitudonally bounded at 85 degrees as per Google Documentation.

#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];


}
like image 34
Evgeny Tanhilevich Avatar answered Dec 09 '22 16:12

Evgeny Tanhilevich