I am new in iphone development, i want to draw path between 5 location how i can draw path in google map.
I want path from location1 to location2 , location2 to location3, location3 to location4 and location4 to location5.
here is my code
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *d1,*d2,*d3,*d4,*d5;
d1=[NSDictionary dictionaryWithObjectsAndKeys:#"location1",#"comments",#"1",#"id",#"23.02941395",#"latitude",#"72.54620655",#"longitude",nil];
d2=[NSDictionary dictionaryWithObjectsAndKeys:#"location2",#"comments",#"2",#"id",#"23.028359049999995",#"latitude",#"72.54537318333334",#"longitude",nil];
d3=[NSDictionary dictionaryWithObjectsAndKeys:#"location3",#"comments",#"3",#"id",#"23.029545",#"latitude",#"72.546036",#"longitude",nil];
d4=[NSDictionary dictionaryWithObjectsAndKeys:#"location4",#"comments",#"4",#"id",#"23.030050",#"latitude",#"72.546226",#"longitude",nil];
d5=[NSDictionary dictionaryWithObjectsAndKeys:#"location5",#"comments",#"5",#"id",#"23.030050",#"latitude",#"72.546022",#"longitude",nil];
self.reports=[NSArray arrayWithObjects:d1,d2,d3,d4,d5,nil];
for (NSDictionary *d in self.reports) {
float latitude=[[d valueForKey:#"latitude"] floatValue];
float longitude=[[d valueForKey:#"longitude"] floatValue];
Place* home = [[[Place alloc] init] autorelease];
home.name = [d valueForKey:#"comments"];
home.latitude = latitude;
home.longitude = longitude;
PlaceMark *from = [[[PlaceMark alloc] initWithPlace:home] autorelease];
[mapView addAnnotation:from];
}
[self centerMap];
}
-(void) centerMap
{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90;
CLLocationDegrees maxLon = -180;
CLLocationDegrees minLat = 120;
CLLocationDegrees minLon = 150;
NSMutableArray *temp=[NSArray arrayWithArray:self.reports];
NSLog(#"%#",temp);
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;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSString *strTitle = [NSString stringWithFormat:#"%#",[view.annotation title]];
NSMutableDictionary *d;
NSMutableArray *temp=[NSArray arrayWithArray:self.reports];
for (int i = 0; i<[temp count]; i++)
{
d = (NSMutableDictionary*)[temp objectAtIndex:i];
NSString *strAddress = [NSString stringWithFormat:#"%#",[d valueForKey:#"comments"]];
if([strAddress isEqualToString:strTitle]) {
[self presentModalViewController:self.nxtDetailsVCtr animated:YES];
[self.nxtDetailsVCtr.lblDetail setText:strAddress];
break;
}
}
}
You can use NVPlolineAnnotation to draw line inside the map. Here is the Source Code.
Frameworks needed
QuartzCore.framework
CoreLocation.framework
MapKit.framework
Files Needed
JSONKit.h
JSONKit.m
Set -fno-objc-arc in compile source for JSON in case of ARC.
In header File
__block IBOutlet MKMapView *__mapView;
NSArray* routes;
MKPointAnnotation *startLocation;
MKPointAnnotation *endLocation;
MKPolyline *polyLine;
Implementation piece of code...
- (void)viewDidLoad
{
// [__mapView setShowsUserLocation:YES];
[__mapView setZoomEnabled:YES];
[__mapView setScrollEnabled:YES];
[__mapView setMapType:MKMapTypeStandard];
[__mapView setDelegate:self];
routes=[[NSArray alloc] init];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)drawPath:(id)sender {
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
[self showRouteFrom:startLocation to:endLocation];
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
if (polyLine) {
[__mapView setVisibleMapRect:[polyLine boundingMapRect]];
[__mapView addOverlay:polyLine];
[self centerMap];
}
NSLog(#"drawing path completed");
});
});
}
-(void) showRouteFrom: (id<MKAnnotation>)source to:(id<MKAnnotation>)destination;
{
if(routes)
{
[__mapView removeAnnotations:[__mapView annotations]];
}
[__mapView addAnnotation:source];
[__mapView addAnnotation:destination];
NSLog(#"source title is %#",source.title);
NSLog(#"destination title is %#",destination.title);
routes = [self calculateRoutesFrom:source.coordinate to:destination.coordinate];
NSLog(#"routes are %#",routes);
NSInteger numberOfSteps = routes.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++)
{
CLLocation *location = [routes objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
NSLog(#"poly line to be added as ovelay is %#",polyLine);
}
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t
{
NSString* saddr = [NSString stringWithFormat:#"%f,%f", f.latitude, f.longitude];
NSString* daddr = [NSString stringWithFormat:#"%f,%f", t.latitude, t.longitude];
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&sensor=false&avoid=highways&mode=",saddr,daddr];
NSLog(#"Fired API %#",apiUrlStr);
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
NSError* error = nil;
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSASCIIStringEncoding error:&error];
NSDictionary *dic=[apiResponse objectFromJSONString];
if (dic!=nil) {
NSArray *routPoints=[[NSArray alloc] initWithArray:[dic valueForKey:#"routes"]];
NSDictionary *polylineOverview=[[routPoints objectAtIndex:0] valueForKey:#"overview_polyline"];
NSString *polylinePoints = [polylineOverview objectForKey:#"points"];
return [self decodePolyLine:[polylinePoints mutableCopy]];
}
return nil;
}
- (NSMutableArray *)decodePolyLine: (NSMutableString *)encoded
{
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\" options:NSLiteralSearch range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len)
{
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
//printf("[%f,", [latitude doubleValue]);
//printf("%f]", [longitude doubleValue]);
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:loc];
}
return array;
}
#pragma mark- MKMapView delegate method
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor purpleColor];
polylineView.lineWidth = 5.0;
NSLog(#"polyline in viewFor overlay: %#",polylineView);
return polylineView;
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(#"did update user location called ");
MKCoordinateRegion region;
region.span.latitudeDelta = .005;
region.span.longitudeDelta = .005;
region.center = userLocation.coordinate;
[mapView setRegion:region animated:YES];
}
-(void) centerMap
{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90.0;
CLLocationDegrees maxLon = -180.0;
CLLocationDegrees minLat = 90.0;
CLLocationDegrees minLon = 180.0;
for(int idx = 0; idx < routes.count; idx++)
{
CLLocation* currentLocation = [routes 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.0;
region.center.longitude = (maxLon + minLon) / 2.0;
region.span.latitudeDelta = 0.01;
region.span.longitudeDelta = 0.01;
region.span.latitudeDelta = ((maxLat - minLat)<0.0)?100.0:(maxLat - minLat);
region.span.longitudeDelta = ((maxLon - minLon)<0.0)?100.0:(maxLon - minLon);
[__mapView setRegion:region animated:YES];
}
#pragma mark- UITextField delegate method
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
[self.view bringSubviewToFront:textField];
CGRect rect=textField.frame;
[[NSUserDefaults standardUserDefaults] setValue:NSStringFromCGRect(rect) forKey:#"textFieldRect"];
rect.origin.y=self.view.frame.size.height-260;
[UIView animateWithDuration:0.3 animations:^{
[textField setFrame:rect];
}];
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
NSString *rectStr=[[NSUserDefaults standardUserDefaults] valueForKey:#"textFieldRect"];
NSArray *rectArray=[rectStr componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"{,} "]];
CGRect rect;
rect.origin.x=[[rectArray objectAtIndex:2] floatValue];
rect.origin.y=[[rectArray objectAtIndex:4] floatValue];
rect.size.width=[[rectArray objectAtIndex:8] floatValue];
rect.size.height=[[rectArray objectAtIndex:10] floatValue];
[UIView animateWithDuration:0.3 animations:^{
[textField setFrame:rect];
}];
[textField resignFirstResponder];
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
NSDictionary *locationDic=[self getLatLongOfPlace:[textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
NSDictionary *latLongDic=[[[[[locationDic valueForKey:#"results"] objectAtIndex:0] valueForKey:#"geometry"]valueForKey:#"viewport"] valueForKey:#"northeast"];
if (textField.tag==0) {
startLocation=[[MKPointAnnotation alloc] init];
[startLocation setCoordinate:CLLocationCoordinate2DMake([[latLongDic valueForKey:#"lat"] floatValue], [[latLongDic valueForKey:#"lng"] floatValue])];
startLocation.title=[textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}else{
endLocation=[[MKPointAnnotation alloc] init];
[endLocation setCoordinate:CLLocationCoordinate2DMake([[latLongDic valueForKey:#"lat"] floatValue], [[latLongDic valueForKey:#"lng"] floatValue])];
endLocation.title=[textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
NSLog(#"object at index is viewport %#",[[[[[locationDic valueForKey:#"results"] objectAtIndex:0] valueForKey:#"geometry"]valueForKey:#"viewport"] valueForKey:#"northeast"]);
}
#pragma mark Getting lat long from place name.
-(NSDictionary*)getLatLongOfPlace:(NSString*)place
{
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#&sensor=true",place];
NSLog(#"Fired URL:- %#",apiUrlStr);
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
NSError* error = nil;
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSASCIIStringEncoding error:&error];
NSDictionary *dic=[apiResponse objectFromJSONString];
return dic;
}
Here is SampleCode I made
NOTE:--- In case if sample doesn't work for u jsut this line in viewDidLoad Method
// [__mapView setShowsUserLocation:YES];
Screenshot
#import "ViewController.h"
#import "JSONKit.h"
#interface ViewController ()
#end
#implementation ViewController
NSMutableArray *locationarry ;
NSMutableDictionary * citywiselatlong ;
- (void)viewDidLoad
{
locationarry = [[NSMutableArray alloc]initWithObjects:#"Ahmedabad",#"Rajkot",#"Baroda",#"Surat", nil];
citywiselatlong = [[NSMutableDictionary alloc]init];
[self locationfind];
NSMutableString* TotalXMLString = [[NSMutableString alloc]init];
[TotalXMLString appendFormat:#"http://maps.googleapis.com/maps/api/distancematrix/json?origins="];
[TotalXMLString appendFormat:#"%#,%#&destinations=",[[citywiselatlong valueForKey:[locationarry objectAtIndex:0]] valueForKey:#"lat"] ,[[citywiselatlong valueForKey:[locationarry objectAtIndex:0]] valueForKey:#"lng"]];
for (int i = 1; i < [locationarry count]; i++) {
[TotalXMLString appendFormat:#"%#,%#",[[citywiselatlong valueForKey:[locationarry objectAtIndex:i]] valueForKey:#"lat"] ,[[citywiselatlong valueForKey:[locationarry objectAtIndex:i]] valueForKey:#"lng"]];
if (i != [locationarry count] -1 ) {
[TotalXMLString appendFormat:#"|"];
}
else
{
[TotalXMLString appendFormat:#"&mode=driving&sensor=false"];
}
}
NSURL* apiUrl = [NSURL URLWithString:[TotalXMLString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
NSError* error = nil;
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSASCIIStringEncoding error:&error];
NSDictionary *dic=[apiResponse objectFromJSONString];
NSLog(#"%#",dic);
NSMutableArray * distance = [[NSMutableArray alloc]initWithArray:[[[[dic valueForKey:#"rows"] objectAtIndex:0] valueForKey:#"elements"]valueForKey:#"distance"]];
for (int j= 0 ; j < [distance count]; j++) {
NSMutableDictionary *data = [[NSMutableDictionary alloc]initWithDictionary:[distance objectAtIndex:j]];
}
NSLog(#"%#",distance);
[__mapView setShowsUserLocation:YES];
[__mapView setZoomEnabled:YES];
[__mapView setScrollEnabled:YES];
[__mapView setMapType:MKMapTypeHybrid];
[__mapView setDelegate:self];
routes=[[NSArray alloc] init];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark- MKMapView delegate method
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor purpleColor];
polylineView.lineWidth = 5.0;
NSLog(#"polyline in viewFor overlay: %#",polylineView);
return polylineView;
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(#"did update user location called ");
MKCoordinateRegion region;
region.span.latitudeDelta = .005;
region.span.longitudeDelta = .005;
region.center = userLocation.coordinate;
[mapView setRegion:region animated:YES];
}
- (NSMutableArray *)decodePolyLine: (NSMutableString *)encoded
{
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\" options:NSLiteralSearch range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len)
{
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
//printf("[%f,", [latitude doubleValue]);
//printf("%f]", [longitude doubleValue]);
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:loc];
}
return array;
}
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t
{
NSString* saddr = [NSString stringWithFormat:#"%f,%f", f.latitude, f.longitude];
NSString* daddr = [NSString stringWithFormat:#"%f,%f", t.latitude, t.longitude];
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&sensor=false&avoid=highways&mode=",saddr,daddr];
NSLog(#"Fired API %#",apiUrlStr);
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
NSError* error = nil;
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSASCIIStringEncoding error:&error];
NSDictionary *dic=[apiResponse objectFromJSONString];
if (dic!=nil) {
NSArray *routPoints=[[NSArray alloc] initWithArray:[dic valueForKey:#"routes"]];
NSDictionary *polylineOverview=[[routPoints objectAtIndex:0] valueForKey:#"overview_polyline"];
NSString *polylinePoints = [polylineOverview objectForKey:#"points"];
return [self decodePolyLine:[polylinePoints mutableCopy]];
}
return nil;
}
- (IBAction)drawPath:(id)sender {
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
[self showRouteFrom:startLocation to:endLocation];
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
if (polyLine) {
[__mapView setVisibleMapRect:[polyLine boundingMapRect]];
[__mapView addOverlay:polyLine];
}
NSLog(#"drawing path completed");
});
});
}
-(void) showRouteFrom: (id<MKAnnotation>)source to:(id<MKAnnotation>)destination;
{
routes = [self calculateRoutesFrom:source.coordinate to:destination.coordinate];
NSLog(#"routes are %#",routes);
NSInteger numberOfSteps = routes.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++)
{
CLLocation *location = [routes objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[polyLineArray addObject:polyLine];
}
- (IBAction)drawMultiple:(id)sender
{
polyLineArray=[[NSMutableArray alloc] init];
MKPointAnnotation *start=[[MKPointAnnotation alloc] init];
MKPointAnnotation *end=[[MKPointAnnotation alloc] init];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
for (int i=0;i<locationarry.count-1;i++)
{
NSArray *part = [[NSArray alloc]initWithArray:[[locationarry objectAtIndex:i] componentsSeparatedByString:#","]];
NSDictionary *dic=[citywiselatlong objectForKey:[part objectAtIndex:0]];
[start setCoordinate:CLLocationCoordinate2DMake([[dic valueForKey:#"lat"] floatValue], [[dic valueForKey:#"lng"] floatValue])];
part = [[NSArray alloc]initWithArray:[[locationarry objectAtIndex:i +1 ] componentsSeparatedByString:#","]];
dic=[citywiselatlong objectForKey:[part objectAtIndex:0]];
[end setCoordinate:CLLocationCoordinate2DMake([[dic valueForKey:#"lat"] floatValue], [[dic valueForKey:#"lng"] floatValue])];
[self showRouteFrom:start to:end];
}
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
NSArray *part = [[NSArray alloc]initWithArray:[[locationarry objectAtIndex:0] componentsSeparatedByString:#","]];
NSDictionary *tempDic=[[NSDictionary alloc] initWithDictionary:[citywiselatlong objectForKey:[part objectAtIndex:0]]];
[start setCoordinate:CLLocationCoordinate2DMake([[tempDic valueForKey:#"lat"] floatValue], [[tempDic valueForKey:#"lng"] floatValue])];
if (polyLine) {
[__mapView setVisibleMapRect:[polyLine boundingMapRect]];
for (MKPolyline *pLine in polyLineArray) {
[__mapView addOverlay:pLine];
}
}
for (int i =0 ; i< [locationarry count]; i ++)
{
NSArray *part = [[NSArray alloc]initWithArray:[[locationarry objectAtIndex:i] componentsSeparatedByString:#","]];
NSDictionary *dic=[citywiselatlong objectForKey:[part objectAtIndex:0]];
MKPointAnnotation *first=[[MKPointAnnotation alloc] init];
MKPointAnnotation *second=[[MKPointAnnotation alloc] init];
[first setCoordinate:CLLocationCoordinate2DMake([[dic valueForKey:#"lat"] floatValue], [[dic valueForKey:#"lng"] floatValue])];
if(i+1<[locationarry count])
{
NSArray *part = [[NSArray alloc]initWithArray:[[locationarry objectAtIndex:i + 1] componentsSeparatedByString:#","]];
dic=[citywiselatlong objectForKey:[part objectAtIndex:0]];
[second setCoordinate:CLLocationCoordinate2DMake([[dic valueForKey:#"lat"] floatValue], [[dic valueForKey:#"lng"] floatValue])];
}
else
{
NSArray *part = [[NSArray alloc]initWithArray:[[locationarry objectAtIndex:i] componentsSeparatedByString:#","]];
dic=[citywiselatlong objectForKey:[part objectAtIndex:0]];;
[second setCoordinate:CLLocationCoordinate2DMake([[dic valueForKey:#"lat"] floatValue], [[dic valueForKey:#"lng"] floatValue])];
}
if (i==0)
{
[__mapView addAnnotation:first];
[__mapView addAnnotation:second];
}
else
{
[__mapView addAnnotation:second];
}
}
NSLog(#"drawing path completed");
});
});
}
-(void) centerMap
{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90.0;
CLLocationDegrees maxLon = -180.0;
CLLocationDegrees minLat = 90.0;
CLLocationDegrees minLon = 180.0;
for(int idx = 0; idx < routes.count; idx++)
{
CLLocation* currentLocation = [routes 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.0;
region.center.longitude = (maxLon + minLon) / 2.0;
region.span.latitudeDelta = 0.01;
region.span.longitudeDelta = 0.01;
region.span.latitudeDelta = ((maxLat - minLat)<0.0)?100.0:(maxLat - minLat);
region.span.longitudeDelta = ((maxLon - minLon)<0.0)?100.0:(maxLon - minLon);
[__mapView setRegion:region animated:YES];
}
#pragma mark- UITextField delegate method
-(void)locationfind
{
for (int i = 0; i < [locationarry count]; i++) {
NSDictionary *locationDic=[self getLatLongOfPlace:[[locationarry objectAtIndex:i] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
NSDictionary *latLongDic=[[[[locationDic valueForKey:#"results"] objectAtIndex:0] valueForKey:#"geometry"]valueForKey:#"location"];
NSArray *part = [[NSArray alloc]initWithArray:[[locationarry objectAtIndex:i] componentsSeparatedByString:#","]];
[citywiselatlong setObject:latLongDic forKey:[part objectAtIndex:0]];
NSLog(#"%#",citywiselatlong);
}
}
#pragma mark Getting lat long from place name.
-(NSDictionary*)getLatLongOfPlace:(NSString*)place
{
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#&sensor=true",place];
NSLog(#"Fired URL:- %#",apiUrlStr);
NSURL* apiUrl = [NSURL URLWithString:[apiUrlStr stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
NSError* error = nil;
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSASCIIStringEncoding error:&error];
NSDictionary *dic=[apiResponse objectFromJSONString];
return dic;
}
#end
For drawing multiple points you can use it as
need to declare mutable array in header file
NSMutableArray *polyLineArray;
Implementation file need minor changes as ===
-(void) showRouteFrom: (id<MKAnnotation>)source to:(id<MKAnnotation>)destination;
{
NSLog(#"source title is %#",source.title);
NSLog(#"destination title is %#",destination.title);
routes = [self calculateRoutesFrom:source.coordinate to:destination.coordinate];
NSLog(#"routes are %#",routes);
NSInteger numberOfSteps = routes.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++)
{
CLLocation *location = [routes objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[polyLineArray addObject:polyLine];
// NSLog(#"poly line to be added as ovelay is %#",polyLine);
}
- (IBAction)drawMultiple:(id)sender
{
polyLineArray=[[NSMutableArray alloc] init];
NSDictionary *kolkata,*delhi,*chennai,*mumbai,*pune;
kolkata=[NSDictionary dictionaryWithObjectsAndKeys:#"location1",#"comments",#"1",#"id",#"23.0083321",#"latitude",#"88.54276659999",#"longitude",nil];
delhi=[NSDictionary dictionaryWithObjectsAndKeys:#"location2",#"comments",#"2",#"id",#"28.889816",#"latitude",#"77.3418147",#"longitude",nil];
chennai=[NSDictionary dictionaryWithObjectsAndKeys:#"location3",#"comments",#"3",#"id",#"13.23339843",#"latitude",#"80.3322912",#"longitude",nil];
mumbai=[NSDictionary dictionaryWithObjectsAndKeys:#"location4",#"comments",#"4",#"id",#"19.2716339",#"latitude",#"72.9864994",#"longitude",nil];
pune=[NSDictionary dictionaryWithObjectsAndKeys:#"location5",#"comments",#"5",#"id",#"18.6346965",#"latitude",#"73.9894867",#"longitude",nil];
NSArray *arrayOfLocations=[[NSArray alloc] initWithObjects:kolkata,delhi,chennai,mumbai,pune,nil];
MKPointAnnotation *start=[[MKPointAnnotation alloc] init];
MKPointAnnotation *end=[[MKPointAnnotation alloc] init];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
for (int i=0;i<arrayOfLocations.count-1;i++)
{
NSDictionary *dic=[arrayOfLocations objectAtIndex:i];
[start setCoordinate:CLLocationCoordinate2DMake([[dic valueForKey:#"latitude"] floatValue], [[dic valueForKey:#"longitude"] floatValue])];
dic=[arrayOfLocations objectAtIndex:i+1];
[end setCoordinate:CLLocationCoordinate2DMake([[dic valueForKey:#"latitude"] floatValue], [[dic valueForKey:#"longitude"] floatValue])];
[self showRouteFrom:start to:end];
}
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
NSDictionary *tempDic=[[NSDictionary alloc] initWithDictionary:[arrayOfLocations objectAtIndex:0]];
[start setCoordinate:CLLocationCoordinate2DMake([[tempDic valueForKey:#"latitude"] floatValue], [[tempDic valueForKey:#"longitude"] floatValue])];
[__mapView addAnnotation:start];
[__mapView addAnnotation:end];
if (polyLine) {
[__mapView setVisibleMapRect:[polyLine boundingMapRect]];
for (MKPolyline *pLine in polyLineArray) {
[__mapView addOverlay:pLine];
}
}
NSLog(#"drawing path completed");
});
});
}
If u need sample code here it is
Output is --------
Use BreadCrumbs here is the sample code ..it is very useful ...u can customize the code according to ur requirement
https://developer.apple.com/library/ios/samplecode/Breadcrumb/Introduction/Intro.html
App crashes with error:
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x21481c10> was mutated while being enumerated.'
This happen only if I move over mapview when my annotations is loading. If I doesn't touch map, no error occurred.
- (void) startloading
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
[self loadPList];
});
}
my code is:
- (void) loadPList
{
#autoreleasepool {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:#"test.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSMutableArray *annotations = [[NSMutableArray alloc]init];
NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ;
[ annotationsToRemove removeObject:mapView.userLocation ] ;
[ mapView removeAnnotations:annotationsToRemove ] ;
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"blackKey"])
{
NSArray *ann = [dict objectForKey:#"Black"];
for(int i = 0; i < [ann count]; i++) {
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:#"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:#"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:#"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:#"Icon"];
[mapView addAnnotation:myAnnotation]; // SIGNAL SIGABRT
[annotations addObject:myAnnotation];
}
}
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"blueyellowKey"])
{
NSArray *ann = [dict objectForKey:#"BlueYellow"];
for(int i = 0; i < [ann count]; i++) {
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:#"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:#"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:#"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:#"Icon"];
[mapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
}
}
}
}
I think you should change your loadPlist method to this, and then just call [self loadPlist] to invoke it:
- (void) loadPList
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:#"test.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
//ALL THIS CODE FROM HERE ON OUT IS NOT THREAD SAFE! YOU ARE ACCESSING THE UI AND MUST PERFORM IT ON THE MAIN THREAD!
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableArray *annotations = [[NSMutableArray alloc]init];
NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ;
[ annotationsToRemove removeObject:mapView.userLocation ] ;
[ mapView removeAnnotations:annotationsToRemove ] ;
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"blackKey"])
{
NSArray *ann = [dict objectForKey:#"Black"];
for(int i = 0; i < [ann count]; i++) {
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:#"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:#"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:#"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:#"Icon"];
[mapView addAnnotation:myAnnotation]; // SIGNAL SIGABRT
[annotations addObject:myAnnotation];
}
}
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"blueyellowKey"])
{
NSArray *ann = [dict objectForKey:#"BlueYellow"];
for(int i = 0; i < [ann count]; i++)
{
NSString *coordinates = [[ann objectAtIndex:i] objectForKey:#"Coordinates"];
double realLatitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:1] doubleValue];
double realLongitude = [[[coordinates componentsSeparatedByString:#","] objectAtIndex:0] doubleValue];
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude;
theCoordinate.longitude = realLongitude;
myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
myAnnotation.title = [[ann objectAtIndex:i] objectForKey:#"Name"];
myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:#"Address"];
myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:#"Icon"];
[mapView addAnnotation:myAnnotation];
[annotations addObject:myAnnotation];
}
}
}
});
}
This performs the IO work of reading in the annotations in the background, and then passes off the UI work back to the main thread. Hope this helps!
I am trying to find the path between two locations on Mapkit. All I have is two locations. Now I have to find the exact path between these points and draw a line between these points using MapKit. I have gone through several examples in which they are using .csv files. In that .csv file they have stored the latitude and longitude values of the full path and drawing line based on those values.
But here I am trying to draw a line without knowing the path. So is there any way to find the path dynamically and draw a line?
Below is the code to finds path & draws line between two locations.
To implement below class:
_mapRecord = [[PSMapDirection alloc] initWithFrame:CGRectMake(0.0, 49.0, 320.0, 411.0)];
[self.view addSubview:_mapRecord];
MapDirection.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "RegexKitLite.h"
#interface MapDirection : UIView<MKMapViewDelegate>
{
MKMapView* mapView;
NSArray* routes;
BOOL isUpdatingRoutes;
}
-(void) showRouteFrom: (MKAnnotation*) f to:(MKAnnotation*) t;
#end
MapDirection.m
#import "MapDirection.h"
#interface MapDirection()
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) from to: (CLLocationCoordinate2D) to;
-(void) centerMap;
#end
- (id) initWithFrame:(CGRect) frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
mapView.showsUserLocation = NO;
[mapView setDelegate:self];
[self addSubview:mapView];
}
return self;
}
- (NSMutableArray *)decodePolyLine: (NSMutableString *)encoded
{
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\" options:NSLiteralSearch range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len)
{
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
//printf("[%f,", [latitude doubleValue]);
//printf("%f]", [longitude doubleValue]);
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:loc];
}
return array;
}
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t
{
NSString* saddr = [NSString stringWithFormat:#"%f,%f", f.latitude, f.longitude];
NSString* daddr = [NSString stringWithFormat:#"%f,%f", t.latitude, t.longitude];
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.google.com/maps?output=dragdir&saddr=%#&daddr=%#", saddr, daddr];
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
//NSLog(#"api url: %#", apiUrl);
NSError* error = nil;
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSASCIIStringEncoding error:&error];
NSString *encodedPoints = [apiResponse stringByMatching:#"points:\\\"([^\\\"]*)\\\"" capture:1L];
return [self decodePolyLine:[encodedPoints mutableCopy]];
}
-(void) centerMap
{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90.0;
CLLocationDegrees maxLon = -180.0;
CLLocationDegrees minLat = 90.0;
CLLocationDegrees minLon = 180.0;
for(int idx = 0; idx < routes.count; idx++)
{
CLLocation* currentLocation = [routes 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.0;
region.center.longitude = (maxLon + minLon) / 2.0;
region.span.latitudeDelta = 0.01;
region.span.longitudeDelta = 0.01;
region.span.latitudeDelta = ((maxLat - minLat)<0.0)?100.0:(maxLat - minLat);
region.span.longitudeDelta = ((maxLon - minLon)<0.0)?100.0:(maxLon - minLon);
[mapView setRegion:region animated:YES];
}
-(void) showRouteFrom: (MKAnnotation*) f to:(MKAnnotation*) t
{
if(routes)
{
[mapView removeAnnotations:[mapView annotations]];
}
[mapView addAnnotation:f];
[mapView addAnnotation:t];
routes = [self calculateRoutesFrom:f.coordinate to:t.coordinate];
NSInteger numberOfSteps = routes.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++)
{
CLLocation *location = [routes objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[mapView addOverlay:polyLine];
[self centerMap];
}
#pragma mark MKPolyline delegate functions
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor purpleColor];
polylineView.lineWidth = 5.0;
return polylineView;
}
#end
Sample Map Route for starting points - "41.967659,-87.627869" and destination points - "41.574361,-91.083069"
Here The way in which I am able to draw direction between two points(Location).
First of all download GoogleMap sdk from this link and integrate into your application.
Now API key required and you can create as par given guidelines on this link.
Below are Code that draw direction on google map between two location.
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t {
NSString* saddr = [NSString stringWithFormat:#"%f,%f", f.latitude, f.longitude];
NSString* daddr = [NSString stringWithFormat:#"%f,%f", t.latitude, t.longitude];
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&sensor=false&avoid=highways&mode=driving",saddr,daddr]];
NSError *error=nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init] ;
[request setURL:url];
[request setHTTPMethod:#"POST"];
NSURLResponse *response = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error: &error];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONWritingPrettyPrinted error:nil];
return [self decodePolyLine:[self parseResponse:dic]];
}
- (NSString *)parseResponse:(NSDictionary *)response {
NSArray *routes = [response objectForKey:#"routes"];
NSDictionary *route = [routes lastObject];
if (route) {
NSString *overviewPolyline = [[route objectForKey:
#"overview_polyline"] objectForKey:#"points"];
return overviewPolyline;
}
return #"";
}
-(NSMutableArray *)decodePolyLine:(NSString *)encodedStr {
NSMutableString *encoded = [[NSMutableString alloc]
initWithCapacity:[encodedStr length]];
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0,
[encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1)
: (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1)
: (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *location = [[CLLocation alloc] initWithLatitude:
[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:location];
}
return array;
}
- (void)loadMapViewWithDirection {
float lat = 23.050671;
float lng = 72.541351;
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:lat
longitude:lng
zoom:10];
GMSMapView * mapView = [GMSMapView mapWithFrame:CGRectMake(0, 75, 320, self.view.frame.size.height-kHeaderRect.size.height) camera:camera];
self.mapView.myLocationEnabled = YES;
float sourceLatitude = 23.050671;
float sourceLongitude = 72.541351;
float destLatitude = 23.036138;
float destLongitude = 72.603836;
GMSMarker *sourceMarker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(sourceLatitude, sourceLongitude);
marker.map = self.mapView;
GMSMarker *destMarker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(destLatitude, destLongitude);
marker.map = self.mapView;
self.mapView.delegate = self;
[self drawDirection:CLLocationCoordinate2DMake(sourceLatitude, sourceLongitude) and:CLLocationCoordinate2DMake(destLatitude, destLongitude)];
[self.view addSubview:self.mapView];
}
- (void) drawDirection:(CLLocationCoordinate2D)source and:(CLLocationCoordinate2D) dest {
GMSPolyline *polyline = [[GMSPolyline alloc] init];
GMSMutablePath *path = [GMSMutablePath path];
NSArray * points = [self calculateRoutesFrom:source to:dest];
NSInteger numberOfSteps = points.count;
for (NSInteger index = 0; index < numberOfSteps; index++)
{
CLLocation *location = [points objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
[path addCoordinate:coordinate];
}
polyline.path = path;
polyline.strokeColor = [UIColor redColor];
polyline.strokeWidth = 2.f;
polyline.map = self.mapView;
// Copy the previous polyline, change its color, and mark it as geodesic.
polyline = [polyline copy];
polyline.strokeColor = [UIColor greenColor];
polyline.geodesic = YES;
polyline.map = self.mapView;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self loadMapViewWithDirection];
}
You can refer this code, it does exactly what you want.EDIT: and this also
I don't think you can do this locally. Implementing an algoritm for finding a path between two gps points requires a lot of input data (data from the maps) and you don't have this. Only a map provider can afford to implement such algoritm and expose an API for using it. I think Google have routing API, but I haven't played around with it...
https://developers.google.com/maps/documentation/directions/
Note that the TOS say that you have to display the results on a Google map, so you'll have to disable the functionality on the next iOS release
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.
Thanks for the help in advance... this one has been killing me for the past couple of hours.
I am currently pulling in a JSON feed and storing it in a NSDictionary & NSArray. I'm trying to add an annotation for each item being pulled in (time, type, latitude, and longitude). So far, I can extract each value from the Array and have them all repeat with a "for" in the console (see code below).
How to I store these values as an annotation? Any help would be great.
Below is my failed attempt...
- (void)viewDidLoad {
[super viewDidLoad];
// Download JSON Feed
NSDictionary *feed = [self downloadFeed];
NSArray *streams = (NSArray *)[feed valueForKey:#"stream"];
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = 29.719023;
region.center.longitude = -114.157110;
region.span.longitudeDelta = 0.01f;
region.span.latitudeDelta = 0.01f;
[mapView setRegion:region animated:YES];
[mapView setDelegate:self];
int Info;
for (Info = 0; Info < streams.count; Info++) {
NSDictionary *stream = (NSDictionary *)[streams objectAtIndex:Info];
NSLog(#"Time: %#", [stream valueForKey:#"TheTime"]);
NSLog(#"Type: %#", [stream valueForKey:#"Type"]);
NSLog(#"Longitude: %#", [stream valueForKey:#"Longitude"]);
NSLog(#"Latitude: %#", [stream valueForKey:#"Latitude"]);
NSString *getLat = [[NSString alloc] initWithFormat: #"%#", [stream valueForKey:#"Latitude"]];
NSString *getLong = [[NSString alloc] initWithFormat: #"%#", [stream valueForKey:#"Longitude"]];
NSString *getCoord = [[NSString alloc] initWithFormat: #"{%#,%#}", getLat, getLong];
getCoordinates = getCoord;
DisplayMap *ann = [[DisplayMap alloc] init];
ann.title = #"%#", [stream valueForKey:#"TheTime"];
ann.subtitle = #"%#", [stream valueForKey:#"Type"];
ann.coordinate = getCoordinates;
[mapView addAnnotation:ann];
}
}
Here is the code for DisplayMap
DisplayMap.h
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#interface DisplayMap : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#end
And now DisplayMap.m
#import "DisplayMap.h"
#implementation DisplayMap
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
-(void)dealloc{
[title release];
[super dealloc];
}
#end
What type is getCoordinates? Whatever the case, its definitely not being initialized right.
Assuming that your storing Latitude and Longitude as strings in your dictionary, this should do the trick.
double lat = [[stream valueForKey:#"Latitude"] doubleValue];
double lon = [[stream valueForKey:#"Longitude"] doubleValue];
CLLocationCoordinate2D coord = { lat, lon };
DisplayMap *ann = [[DisplayMap alloc] init];
ann.title = [stream valueForKey:#"TheTime"];
ann.subtitle = [stream valueForKey:#"Type"];
ann.coordinate = coord;
[mapView addAnnotation:ann];
At first glance :
ann.title = #"%#", [stream valueForKey:#"TheTime"];
should be
ann.title = [NSString stringWithFormat: #"%#", [stream valueForKey:#"TheTime"]];
I guess