I'm creating a Map app in iPhone using MKMapView.
I did successfully find my current location and zoom on that point like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mapView.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.mapView setShowsUserLocation:YES];
}
-(void) mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
MKAnnotationView *annotationView = [views objectAtIndex:0];
id<MKAnnotation> mp = [annotationView annotation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate], 1550, 1550);
[self.mapView setRegion:region animated:YES];
}
The problem that I want to solve is:
I have a location on the map (this code in viewDidLoad):
CLLocationCoordinate2D location = [self getLocationFromAddressString:#"San Francisco, CA, United States"];
// location.latitude = 37.78608;
// location.longitude = -122.407398;
MapViewAnnotation *mapAnnotation = [[MapViewAnnotation alloc] initWithTitle:#"Store location" coordinate:location];
[self.mapView addAnnotation:mapAnnotation];
and this is the mapViewAnnotation:
#implementation MapViewAnnotation
#synthesize title = _title;
#synthesize coordinate = _coordinate;
- (id) initWithTitle:(NSString *) t coordinate:(CLLocationCoordinate2D) c {
self = [super init];
if(self) {
_title = t;
_coordinate = c;
}
return self;
}
#end
I want to have a proper zoomLevel and mapCenter for this location and my current location.
I could do that successfully in Android using MapController.zoomToSpan(). How can I fix it in iPhone Map?
create array of location and after that center mapview with all AnnotationPins
-(void) RoutscenterMap
{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90;
CLLocationDegrees maxLon = -180;
CLLocationDegrees minLat = 90;
CLLocationDegrees minLon = 180;
for(int idx = 0; idx < arrLocation.count; idx++)// here use your array or points
{
CLLocation* currentLocation = [arrLocation objectAtIndex:idx];
if(currentLocation.coordinate.latitude > maxLat)
maxLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.latitude < minLat)
minLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.longitude > maxLon)
maxLon = currentLocation.coordinate.longitude;
if(currentLocation.coordinate.longitude < minLon)
minLon = currentLocation.coordinate.longitude;
}
region.center.latitude = (maxLat + minLat) / 2;
region.center.longitude = (maxLon + minLon) / 2;
region.span.latitudeDelta = (maxLat - minLat) * 2;
region.span.longitudeDelta = (maxLon - minLon) * 2;
[mapView setRegion:region animated:YES];
}
also you can add location in array like bellow...
CLLocation *temploc=[[CLLocation alloc]initWithLatitude:latitude longitude:longtitude];
[arrLocation addObject:temploc];
after that use this array to center the map
i hope this help you...
:)
This is the way that I could implement it:
CLLocationCoordinate2D topLeftCoord;
topLeftCoord.latitude = -90;
topLeftCoord.longitude = 180;
CLLocationCoordinate2D bottomRightCoord;
bottomRightCoord.latitude = 90;
bottomRightCoord.longitude = -180;
for(id<MKAnnotation> annotation in mapView.annotations) {
topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);
bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
}
MKCoordinateRegion region;
region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1;
// Add a little extra space on the sides
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1;
region = [mapView regionThatFits:region];
[mapView setRegion:region animated:YES];
Related
The following is the code I have used to load mapview.
- (void)getLatLongCoordinates:(NSString*) addressStr firstNameTitle:(NSString*) firstNamesTitle lastNameTitle:(NSString*) lastNamesTitle {
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
[geocoder geocodeAddressString:addressStr completionHandler:^(NSArray *placemarks, NSError *error) {
self.placemarksArray = placemarks;
CLPlacemark *placeInfo = [placemarks objectAtIndex:0];
mapCenter.latitude = placeInfo.location.coordinate.latitude;
mapCenter.longitude = placeInfo.location.coordinate.latitude;
[annotationPoint setCoordinate:mapCenter];
[annotationPointsArray addObject:annotationPoint];
addAnnotation = [[[MyAddressAnnotation alloc] initWithCoordinate:mapCenter title:firstNamesTitle SubTitle:lastNamesTitle ]autorelease];
addAnnotation.firstNameTitle = firstNamesTitle;
addAnnotation.lastNameTitle = lastNamesTitle;
[mapView addAnnotation:addAnnotation];
}];
}
I need to call the the method [self zoomToFitMapAnnotations:mapView withArray:annotationPointsArray];
to fit all the contacts in the mapview at the maximum zoom level. Till the previous implementations I have been successfully using the following code. But since I am using blocks now, I am a bit confused about when to call this method. I need to obtain all the location coordinates before I call this method and pass the array to it.
-(void)zoomToFitMapAnnotations:(MKMapView*)mapViews withArray:(NSArray*)anAnnotationArray
{
if([mapViews.annotations count] == 0) return;
CLLocationCoordinate2D topLeftCoord;
topLeftCoord.latitude = -90;
topLeftCoord.longitude = 180;
CLLocationCoordinate2D bottomRightCoord;
bottomRightCoord.latitude = 90;
bottomRightCoord.longitude = -180;
for(MKPointAnnotation* annotation in anAnnotationArray)
{
topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);
bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
}
MKCoordinateRegion region;
region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1;
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1;
region = [mapViews regionThatFits:region];
[mapView setRegion:region animated:NO];
}
Where is the right place in the above piece of code to call the above method or do I need to find some other way to do this.
Edit: I avoided using the mapCenter and accessed the co-ordinates directly from placeInfo in the getLatLongCoordinates method and I am getting it right and the issue is solved. But I am still bemused, why the first way didn't work.
I use this method in my of my case
generally i call this method after i add annotation in my mapview..so it best way is to call this method after add annotationView to mapVIEW.
use this code zoomToFitMapAnnotations
-(void)zoomToFitMapAnnotations:(MKMapView*)mapView_
{
if([mapView_.annotations count] == 0)
return;
CLLocationCoordinate2D topLeftCoord;
topLeftCoord.latitude = -90;
topLeftCoord.longitude = 180;
CLLocationCoordinate2D bottomRightCoord;
bottomRightCoord.latitude = 90;
bottomRightCoord.longitude = -180;
for(CKMapAnnotationView* annotation in mapView_.annotations)
{
topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);
bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
}
MKCoordinateRegion region;
region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1;
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1;
region = [mapView_ regionThatFits:region];
[mapView_ setRegion:[self validRegion:region] animated:YES];
}
EDIT: to call this function after load annotations
[self zoomToFitMapAnnotations:mapView];
i have an application in which i am dropping multiple annotations on the map. But now i want to span my map when these annotations are dropped.This is my code for adding annotation on map.
- (void)viewDidLoad {
[super viewDidLoad];
mapView.mapType = MKMapTypeStandard;
mapView.showsUserLocation = YES;
NSMutableArray *annotations = [[NSMutableArray alloc]init];
[annotations addObjectsFromArray:appDelegate.maparray];
NSLog(#"%#",annotations);
if ([annotations count])
{
for (int i =0; i < [annotations count]; i++)
{
dict = [annotations objectAtIndex:i];
MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = [[dict objectForKey:#"Latitude"] floatValue];
region.center.longitude = [[dict objectForKey:#"Longitude"] floatValue];
region.span.longitudeDelta = 0.6f;
region.span.latitudeDelta = 0.6f;
Title = [dict objectForKey:#"Title"];
description = [dict objectForKey:#"DescriptionMobile"];
NSLog(#"%#",description);
NSURL *url = [NSURL URLWithString:[dict objectForKey:#"Image"]];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
image = [[UIImage alloc] initWithData:data];
MyAnnotation *ann = [[MyAnnotation alloc] init];
ann.title = Title;
ann.subtitle = description;
[mapView addAnnotation:ann];
}
}
}
How to span my map to my annotation point so that all my annoations are visible and my map also zooms.Thanks
Try this code ,it worked for me
- (void)zoomToFitMapAnnotations:(MKMapView *)mapView {
if ([mapView.annotations count] == 0) return;
CLLocationCoordinate2D topLeftCoord;
topLeftCoord.latitude = -90;
topLeftCoord.longitude = 180;
CLLocationCoordinate2D bottomRightCoord;
bottomRightCoord.latitude = 90;
bottomRightCoord.longitude = -180;
for(Annotation *annotation in mapView.annotations) {
topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);
bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
}
MKCoordinateRegion region;
region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1;
// Add a little extra space on the sides
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1;
// Add a little extra space on the sides
region = [mapView regionThatFits:region];
[mapView setRegion:region animated:YES];
}
I think you miss this line:
ann.coordinate = region.center;
I am making an augmented reality project and want to create a zoom effect in an image: I want that image to scale up when the distance is reduced.
I have distance already.
I have the image.
I have the maximum distance under which the zoom kicks in.
Following code is use for the zooming par as the distance of the pin.
-(void) centerMap
{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90;
CLLocationDegrees maxLon = -180;
CLLocationDegrees minLat = 120;
CLLocationDegrees minLon = 150;
NSArray *temp=self.AS;
// NSArray *temp=[NSArray arrayWithArray:[NSArray arrayWithArray:[reports objectAtIndex:0]]];
for (int i=0; i<[temp count];i++) {
Place* home = [[[Place alloc] init] autorelease];
home.latitude = [[[temp objectAtIndex:i] valueForKey:#"latitude"]floatValue];
home.longitude =[[[temp objectAtIndex:i] valueForKey:#"longitude"]floatValue];
PlaceMark* from = [[[PlaceMark alloc] initWithPlace:home] autorelease];
CLLocation* currentLocation = (CLLocation*)from ;
if(currentLocation.coordinate.latitude > maxLat)
maxLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.latitude < minLat)
minLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.longitude > maxLon)
maxLon = currentLocation.coordinate.longitude;
if(currentLocation.coordinate.longitude < minLon)
minLon = currentLocation.coordinate.longitude;
region.center.latitude = (maxLat + minLat) / 2;
region.center.longitude = (maxLon + minLon) / 2;
region.span.latitudeDelta = maxLat - minLat;
region.span.longitudeDelta = maxLon - minLon;
}
[mapView setRegion:region animated:YES];
}
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
if (annotation == mapView.userLocation)
return nil;
MKPinAnnotationView *pin = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier: #"asdf"];
if (pin == nil)
pin = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier: #"asdf"] autorelease];
else
pin.annotation = annotation;
pin.userInteractionEnabled = YES;
UIButton *disclosureButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[disclosureButton setFrame:CGRectMake(0, 0, 30, 30)];
pin.rightCalloutAccessoryView = disclosureButton;
pin.pinColor = MKPinAnnotationColorRed;
//pin.animatesDrop = YES;
[pin setEnabled:YES];
[pin setCanShowCallout:YES];
return pin;
}
This code may help to create new application,
I have code that takes a title and an address of a location,then get coordinates from google maps csv, then add annotation. It works, but when I want to add 50 or more annotation at once it freezes for about 30-40 seconds and then displays annotations, so what I want to know is did I screw up memory management and that's why it's so slow, or something else? Can I speed it up?
Here is the code:
- (void) addAnnotation: (NSString*) annoTitle: (NSString*) annoAddress
{
NSString *address = annoAddress;
NSString *urlString = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString]];
NSArray *listItems = [locationString componentsSeparatedByString:#","];
float langcoord = [[listItems objectAtIndex:2] floatValue];
float longcoord = [[listItems objectAtIndex:3] floatValue];
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(langcoord, longcoord);
// Create an instance of MapPoint with the current data
Annotation *annotation = [[Annotation alloc] initWithCoordinate:coord title:annoTitle];
// Add it to the map view
[mapView addAnnotation:annotation];
// MKMapView retains its annotations, so we can release it
[annotation release];
}
Following methods are use for the multiple pin on MapKit.
-(void)viewWillAppear:(BOOL)animated {
NSArray *AS=[NSArray arrayWithArray:[reports objectAtIndex:0]];
for (int i=0; i<[AS count]; i++) {
Place* home = [[[Place alloc] init] autorelease];
home.name = [[AS objectAtIndex:i] valueForKey:#"comments"];
home.latitude = [[[AS objectAtIndex:i] valueForKey:#"latitude"]floatValue];
home.longitude = [[[AS objectAtIndex:i] valueForKey:#"longitude"]floatValue];
valueForKey:#"latitude"]floatValue],[[[AS objectAtIndex:i] valueForKey:#"longitude"]floatValue]];
PlaceMark* from = [[[PlaceMark alloc] initWithPlace:home] autorelease];
[mapView addAnnotation:from];
}
[self centerMap];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
Centralized Map between two pins
-(void) centerMap
{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90;
CLLocationDegrees maxLon = -180;
CLLocationDegrees minLat = 120;
CLLocationDegrees minLon = 150;
NSArray *temp=[NSArray arrayWithArray:[NSArray arrayWithArray:[reports objectAtIndex:0]]];
for (int i=0; i<[temp count];i++) {
Place* home = [[[Place alloc] init] autorelease];
home.latitude = [[[temp objectAtIndex:i] valueForKey:#"latitude"]floatValue];
home.longitude =[[[temp objectAtIndex:i] valueForKey:#"longitude"]floatValue];
PlaceMark* from = [[[PlaceMark alloc] initWithPlace:home] autorelease];
CLLocation* currentLocation = (CLLocation*)from ;
if(currentLocation.coordinate.latitude > maxLat)
maxLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.latitude < minLat)
minLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.longitude > maxLon)
maxLon = currentLocation.coordinate.longitude;
if(currentLocation.coordinate.longitude < minLon)
minLon = currentLocation.coordinate.longitude;
region.center.latitude = (maxLat + minLat) / 2;
region.center.longitude = (maxLon + minLon) / 2;
region.span.latitudeDelta = maxLat - minLat;
region.span.longitudeDelta = maxLon - minLon;
}
[mapView setRegion:region animated:YES];
}
Define the multiple annotation here.
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
if (annotation == mapView.userLocation)
return nil;
MKPinAnnotationView *pin = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier: #"asdf"];
if (pin == nil)
pin = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier: #"asdf"] autorelease];
else
pin.annotation = annotation;
pin.userInteractionEnabled = YES;
UIButton *disclosureButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[disclosureButton setFrame:CGRectMake(0, 0, 30, 30)];
pin.rightCalloutAccessoryView = disclosureButton;
pin.pinColor = MKPinAnnotationColorRed;
pin.animatesDrop = YES;
[pin setEnabled:YES];
[pin setCanShowCallout:YES];
return pin;
}
More details and download the sample code here.
I am currently working on google maps.Using the GPS, I obtain the user's lat long information and hit a web service to obtain the nearest 5 stores available. I am able to plot the pins for it but the problem is how to fit the 5 pins to a maximum zoom scale ? I mean how does one obtain the latitude and longitude delta of the span in order to zoom as well as fit all the pins at the same time?
Try the following...
-(void)zoomToFitMapAnnotations:(MKMapView*)mapView
{
if([mapView.annotations count] == 0)
return;
CLLocationCoordinate2D topLeftCoord;
topLeftCoord.latitude = -90;
topLeftCoord.longitude = 180;
CLLocationCoordinate2D bottomRightCoord;
bottomRightCoord.latitude = 90;
bottomRightCoord.longitude = -180;
for(DisplayMap* annotation in mapView.annotations)
{
topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);
bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
}
MKCoordinateRegion region;
region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1;
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1;
region = [mapView regionThatFits:region];
[mapView setRegion:region animated:YES];
}
There is a good post on how to do this here
The finished code I used to achieve this is here...
-(void)zoomToFitMapAnnotations:(MKMapView*)mv
{
if([mv.annotations count] == 0)
return;
CLLocationCoordinate2D topLeftCoord;
topLeftCoord.latitude = -90;
topLeftCoord.longitude = 180;
CLLocationCoordinate2D bottomRightCoord;
bottomRightCoord.latitude = 90;
bottomRightCoord.longitude = -180;
for(MapViewAnnotate* annotation in mv.annotations)
{
topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);
bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
}
MKCoordinateRegion region;
region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides
region = [mv regionThatFits:region];
[mv setRegion:region animated:YES];
}
This assumes you're using annotation objects in from an annotation class similar to this (stored in an array)....
MapViewAnnotate.h
#interface MapViewAnnotate : NSObject <MKAnnotation>
{
NSString *title;
NSString *subtitle;
CLLocationCoordinate2D coordinate;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t subtitle:(NSString *)s;
#end
MapViewAnnotate.m
#import "PropertyMapViewAnnotate.h"
#implementation MapViewAnnotate
#synthesize coordinate, title, subtitle;
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t subtitle:(NSString *)s
{
[super init];
coordinate = c;
[self setTitle:t];
[self setSubtitle:s];
return self;
}
- (void)dealloc
{
[title release];
[subtitle release];
[super dealloc];
}
#end