iOS Multiple Polyline Overlay causes memory issue - ios

I’m using mkmapview in my application it contains multiple polyline overlay and multiple custom annotations, while running the application receiving memory warning oftenly, I struggled a lot
Thanks in advance.
for (int i = 0; i<[latArray count]-1; i++)
{
NSString *lat1 = [latArray objectAtIndex:i];
NSString *longi1 = [longArray objectAtIndex:i];
firstPlace = CLLocationCoordinate2DMake([lat1 doubleValue], [longi1 doubleValue]);
NSString *lat2 = [latArray objectAtIndex:i+1];
NSString *longi2 = [longArray objectAtIndex:i+1];
secPlace = CLLocationCoordinate2DMake([lat2 doubleValue], [longi2 doubleValue]);
[self directionRequest:firstPlace :secPlace index:i];
}
-(void)directionRequest:(CLLocationCoordinate2D )firstCord :(CLLocationCoordinate2D )secCord index:(int)index
{
#try
{
MKPlacemark *source=[[MKPlacemark alloc]initWithCoordinate:firstCord addressDictionary:[NSDictionary dictionaryWithObjectsAndKeys:#"",#"", nil]];
MKMapItem *sourceMapItem=[[MKMapItem alloc]initWithPlacemark:source];
[sourceMapItem setName:#""];
MKPlacemark *destination=[[MKPlacemark alloc]initWithCoordinate:secCord addressDictionary:[NSDictionary dictionaryWithObjectsAndKeys:#"",#"", nil]];
MKMapItem *destinationMapitem=[[MKMapItem alloc]initWithPlacemark:destination];
[destinationMapitem setName:#""];
MKDirectionsRequest *dirRequest=[[MKDirectionsRequest alloc]init];
[dirRequest setSource:sourceMapItem];
[dirRequest setDestination:destinationMapitem];
// dirRequest.requestsAlternateRoutes = YES;
[dirRequest setTransportType:MKDirectionsTransportTypeAutomobile];
MKDirections *direction=[[MKDirections alloc]initWithRequest:dirRequest];
[direction calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error)
{
// NSLog(#"response = %#",response);
NSArray *arrRoutes = [response routes];
[arrRoutes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
MKRoute *rout = obj;
MKPolyline *line = [rout polyline];
[iMapView addOverlay:line];
}];
}];
}
#catch (NSException *exception)
{
}
}

Related

How to get directions between two addresses in iOS

I'm using this code to try get directions between two locations. But it outputs co-ordinates using latitude and longitude. But what I want is to get directions for searching based on 2 addresses. How can I get this code to work with addresses?
MKPlacemark *source = [[MKPlacemark alloc]initWithCoordinate:CLLocationCoordinate2DMake(37.776142, -122.424774) addressDictionary:[NSDictionary dictionaryWithObjectsAndKeys:#"",#"", nil] ];
MKMapItem *srcMapItem = [[MKMapItem alloc]initWithPlacemark:source];
[srcMapItem setName:#""];
MKPlacemark *destination = [[MKPlacemark alloc]initWithCoordinate:CLLocationCoordinate2DMake(37.73787, -122.373962) addressDictionary:[NSDictionary dictionaryWithObjectsAndKeys:#"",#"", nil] ];
MKMapItem *distMapItem = [[MKMapItem alloc]initWithPlacemark:destination];
[distMapItem setName:#""];
MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
[request setSource:srcMapItem];
[request setDestination:distMapItem];
[request setTransportType:MKDirectionsTransportTypeAny];
MKDirections *direction = [[MKDirections alloc]initWithRequest:request];
[direction calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
NSLog(#"response = %#",response);
NSArray *arrRoutes = [response routes];
[arrRoutes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
MKRoute *rout = obj;
MKPolyline *line = [rout polyline];
[mapview addOverlay:line];
NSLog(#"Rout Name : %#",rout.name);
NSLog(#"Total Distance (in Meters) :%f",rout.distance);
NSArray *steps = [rout steps];
NSLog(#"Total Steps : %lu",(unsigned long)[steps count]);
NSMutableArray *stepsArray=[[NSMutableArray alloc] init];
[steps enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"Rout Instruction : %#",[obj instructions]);
NSLog(#"Rout Distance : %f",[obj distance]);
[stepsArray addObject:[obj instructions]];
}];
[self myShowDirections:response];
self.steps.text=[NSString stringWithFormat:#"%#",stepsArray];
First you need to check ios8 in your view didload
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
// self.map.showsUserLocation=YES;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager setDistanceFilter:kCLDistanceFilterNone];
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0){
NSUInteger code = [CLLocationManager authorizationStatus];
if (code == kCLAuthorizationStatusNotDetermined && ([locationManager respondsToSelector:#selector(requestAlwaysAuthorization)] || [locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])) {
// choose one request according to your business.
if([[NSBundle mainBundle] objectForInfoDictionaryKey:#"NSLocationAlwaysUsageDescription"]){
[locationManager requestAlwaysAuthorization];
} else if([[NSBundle mainBundle] objectForInfoDictionaryKey:#"NSLocationWhenInUseUsageDescription"]) {
[locationManager requestWhenInUseAuthorization];
} else {
NSLog(#"Info.plist does not contain NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription");
}
}
-(void) centerMapForCoordinateArray:(CLLocationCoordinate2D *)routes andCount:(int)count{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90;
CLLocationDegrees maxLon = -180;
CLLocationDegrees minLat = 90;
CLLocationDegrees minLon = 180;
for(int idx = 0; idx <count; idx++)
{
CLLocationCoordinate2D currentLocations = routes[idx];
if(currentLocations.latitude > maxLat)
maxLat = currentLocations.latitude;
if(currentLocations.latitude < minLat)
minLat = currentLocations.latitude;
if(currentLocations.longitude > maxLon)
maxLon = currentLocations.longitude;
if(currentLocations.longitude < minLon)
minLon = currentLocations.longitude;
}
region.center.latitude = (maxLat + minLat) / 2;
region.center.longitude = (maxLon + minLon) / 2;
region.span.latitudeDelta = maxLat - minLat;
region.span.longitudeDelta = maxLon - minLon;
[self.map setRegion:region animated:YES];
}
- (MKPolyline *)polylineWithEncodedString:(NSString *)encodedString {
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
free(coords);
return polyline;
}
- (void)getDirections {
CLLocation *newLocation = [[CLLocation alloc] initWithLatitude:currentLocation.coordinate.latitude longitude:currentLocation.coordinate.longitude];
MKPointAnnotation *provider = [[MKPointAnnotation alloc] init];
provider.coordinate = CLLocationCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude);
provider.title = [self getAddress];
[self.map addAnnotation:provider];
// 13.069166 80.191388
CLLocationCoordinate2D location;
// location.latitude =12.982672000000000000; // change to your coordinate latitude
// location.longitude =80.263380999999980000;
location.latitude =[self.Latitude doubleValue]; // change to your coordinate latitude
location.longitude =[self.Longtitude doubleValue];
CLLocation *keyPlace = [[CLLocation alloc] initWithLatitude:location.latitude longitude:location.longitude];
MKPointAnnotation *user = [[MKPointAnnotation alloc] init];
user.coordinate = CLLocationCoordinate2DMake(keyPlace.coordinate.latitude, keyPlace.coordinate.longitude);
NSString *add=[NSString stringWithFormat:#"%f %f",location.latitude,location.longitude];
NSString *tit=[self getAddressFromLatLong:add];
user.title=tit;
[self.map addAnnotation:user];
CLLocationCoordinate2D endCoordinate;
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=false&mode=driving", newLocation.coordinate.latitude, newLocation.coordinate.longitude, keyPlace.coordinate.latitude, keyPlace.coordinate.longitude]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!error) {
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&error];
if ([[responseDict valueForKey:#"status"] isEqualToString:#"ZERO_RESULTS"]) {
[[[UIAlertView alloc] initWithTitle:#"Error"
message:#"Could not route path from your current location"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil, nil] show];
return;
}
int points_count = 0;
if ([[responseDict objectForKey:#"routes"] count])
points_count = (int)[[[[[[responseDict objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] count];
if (!points_count) {
[[[UIAlertView alloc] initWithTitle:#"Error"
message:#"Could not route path from your current location"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil, nil] show];
return;
}
CLLocationCoordinate2D points[points_count];
NSLog(#"routes %#", [[[[responseDict objectForKey:#"routes"] objectAtIndex:0]objectForKey:#"overview_polyline"] objectForKey:#"points"]
);
MKPolyline *polyline = [self polylineWithEncodedString:[[[[responseDict objectForKey:#"routes"] objectAtIndex:0]objectForKey:#"overview_polyline"] objectForKey:#"points"]];
[self.map addOverlay:polyline];
int j = 0;
NSArray *steps = nil;
if (points_count && [[[[responseDict objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] count])
steps = [[[[[responseDict objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
for (int i = 0; i < points_count; i++) {
double st_lat = [[[[steps objectAtIndex:i] objectForKey:#"start_location"] valueForKey:#"lat"] doubleValue];
double st_lon = [[[[steps objectAtIndex:i] objectForKey:#"start_location"] valueForKey:#"lng"] doubleValue];
//NSLog(#"lat lon: %f %f", st_lat, st_lon);
if (st_lat > 0.0f && st_lon > 0.0f) {
points[j] = CLLocationCoordinate2DMake(st_lat, st_lon);
j++;
}
double end_lat = [[[[steps objectAtIndex:i] objectForKey:#"end_location"] valueForKey:#"lat"] doubleValue];
double end_lon = [[[[steps objectAtIndex:i] objectForKey:#"end_location"] valueForKey:#"lng"] doubleValue];
//NSLog(#"lat %f lng %f",end_lat,end_lon);
//if (end_lat > 0.0f && end_lon > 0.0f) {
points[j] = CLLocationCoordinate2DMake(end_lat, end_lon);
endCoordinate = CLLocationCoordinate2DMake(end_lat, end_lon);
j++;
//}
}
NSLog(#"points Count %d",points_count);
// MKPolyline *polyline = [MKPolyline polylineWithCoordinates:points count:points_count];
// [self.mapView addOverlay:polyline];
[self centerMapForCoordinateArray:points andCount:points_count];
}
}
- (MKPolylineRenderer *)mapView:(MKMapView *)mapView
viewForOverlay:(id<MKOverlay>)overlay {
MKPolylineRenderer *polylineView = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
polylineView.lineWidth = 3;
polylineView.strokeColor = [[UIColor alloc] initWithRed:5.0/255 green:102.0/255 blue:48.0/255 alpha:1];
return polylineView;
}
EDIT:
-(void)showRoute:(MKDirectionsResponse *)response
{
for (MKRoute *route in response.routes){
[mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
}
}
-(void)getPathDirections:(CLLocationCoordinate2D)source withDestination:(CLLocationCoordinate2D)destination{
MKPlacemark *placemarkSrc = [[MKPlacemark alloc] initWithCoordinate:source addressDictionary:nil];
MKMapItem *mapItemSrc = [[MKMapItem alloc] initWithPlacemark:placemarkSrc];
MKPlacemark *placemarkDest = [[MKPlacemark alloc] initWithCoordinate:destination addressDictionary:nil];
MKMapItem *mapItemDest = [[MKMapItem alloc] initWithPlacemark:placemarkDest];
[mapItemSrc setName:#"name1"];
[mapItemDest setName:#"name2"];
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
[request setSource:mapItemSrc];
[request setDestination:mapItemDest];
[request setTransportType:MKDirectionsTransportTypeAutomobile];
request.requestsAlternateRoutes = NO;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle Error
// UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"ShareMyTable" message:#"Root Map not available to your location." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
// [alert show];
} else {
[mapView removeOverlays:mapView.overlays];
[self showRoute:response];
}
}];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
// 41,142,175
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolyline *route = (MKPolyline *)overlay;
MKPolylineRenderer *routeRenderer = [[MKPolylineRenderer alloc] initWithPolyline:route];
routeRenderer.strokeColor = [UIColor colorWithRed:(41/255.0) green:(142/255.0) blue:(175/255.0) alpha:0.6f];
routeRenderer.lineWidth = 2.5;
return routeRenderer;
}
else return nil;
}
you can read about supported country list
link
When you find any rout between two places,than always use different source and destination place.
In your code you use same latitude and longitude so MKDirections have no Rout to make direction.
So in Your code use different Lat. and Long.
Like...
KPlacemark *source = [[MKPlacemark alloc]initWithCoordinate:CLLocationCoordinate2DMake(37.776142, -122.424774) addressDictionary:[NSDictionary dictionaryWithObjectsAndKeys:#"",#"", nil] ];
MKMapItem *srcMapItem = [[MKMapItem alloc]initWithPlacemark:source];
[srcMapItem setName:#""];
MKPlacemark *destination=[[MKPlacemarkalloc]initWithCoordinate:CLLocationCoordinate2DMake(40.73787, -142.373962) addressDictionary:[NSDictionary dictionaryWithObjectsAndKeys:#"",#"", nil] ];
After use this Latitude and Longitude you can draw your rout any two places.
I hope my answer is helpful for you.

Do not add annotations repeated

I am inserting some annotations that are coming from a json server, but I wanted to check if the annotation is already on the map, if so, does not add it again. For they are being added on each other , have someone help me solve this problem?
my code:
// adiciona produtos ao mapa
- (void)adicionaAnnotationsNoMapa:(id)objetos{
NSMutableArray *annotationsPins = [[NSMutableArray alloc] init];
for (NSDictionary *annotationDeProdutos in objetos) {
CLLocationCoordinate2D location;
AnnotationMap *myAnn;
myAnn = [[AnnotationMap alloc] init];
location.latitude = [[annotationDeProdutos objectForKey:#"latitude"] floatValue];
location.longitude = [[annotationDeProdutos objectForKey:#"longitude"] floatValue];
myAnn.coordinate = location;
myAnn.title = [annotationDeProdutos objectForKey:#"name"];
myAnn.subtitle = [NSString stringWithFormat:#"R$ %#",[annotationDeProdutos objectForKey:#"price"]];
myAnn.categoria = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id_categoria"]];
myAnn.idProduto = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id"]];
[annotationsPins addObject:myAnn];
}
[self.mapView addAnnotations:annotationsPins];
}
You can iterate through annotations already on MkMapView and see if they are already there:
NSArray * annotations = [self.mapView.annotations copy];
for (NSDictionary *annotationDeProdutos in objetos)
{
// Check if annotation in annotations are duplicate of annotationDeProdutos.
// You can match using name.
}
Or the other way if you only want to show annotations from single server call:
[self.mapView removeAnnotations: self.mapView.annotations];
// Now add from JSON response.
You can do this for each of your annotations:
if(![self.mapView.annotations containsObject: myAnn]) {
[self.mapView addAnnotations: myAnn];
}
I solved the problem with this code :
// adiciona produtos ao mapa
- (void)adicionaAnnotationsNoMapa:(id)objetos{
NSMutableArray *annotationsPins = [[NSMutableArray alloc] init];
for (NSDictionary *annotationDeProdutos in objetos) {
CLLocationCoordinate2D location;
AnnotationMap *myAnn;
myAnn = [[AnnotationMap alloc] init];
location.latitude = [[annotationDeProdutos objectForKey:#"latitude"] floatValue];
location.longitude = [[annotationDeProdutos objectForKey:#"longitude"] floatValue];
myAnn.coordinate = location;
myAnn.title = [annotationDeProdutos objectForKey:#"name"];
myAnn.subtitle = [NSString stringWithFormat:#"R$ %#",[annotationDeProdutos objectForKey:#"price"]];
myAnn.categoria = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id_categoria"]];
myAnn.idProduto = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id"]];
if (self.mapView.annotations.count <1) {
[annotationsPins addObject:myAnn];
} else {
__block NSInteger foundIndex = NSNotFound;
[annotationsPins enumerateObjectsUsingBlock:^(AnnotationMap *annotation, NSUInteger idx, BOOL *stop) {
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:location.latitude longitude:location.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
if ([loc1 distanceFromLocation:loc2] <= 1.0f) {
foundIndex = idx;
*stop = YES;
}
}];
if (foundIndex != NSNotFound) {
[annotationsPins addObject:myAnn];
}
}
}
[self.mapView addAnnotations:annotationsPins];
}

how to draw line between x number of moving annotations?

Hai am new to xcode am developing an iOS app for vehicle tracking using mkmap I need to draw lines between the annotations for every 5 seconds based on the vehicle moving, My prob is it draw the line for the first time only and from the second refresh interval it it won't works my code is below,
- (void)viewDidLoad
{
[super viewDidLoad];
aTimer = [NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:#selector(timerFired:)
userInfo:nil
repeats:YES];
}
-(void)timerFired:(NSTimer *) theTimer
{
NSArray *existingpoints = MapViewC.annotations;
if ([existingpoints count])
[MapViewC removeAnnotations:existingpoints];
NSString *urlMapString=[NSString stringWithFormat:#"http://www.logix.com/logix_webservice/map.php?format=json&truckno=%#",nam2];
NSURL *urlMap=[NSURL URLWithString:urlMapString];
NSData *dataMap=[NSData dataWithContentsOfURL:urlMap];
NSError *errorMap;
NSDictionary *jsonMap = [NSJSONSerialization JSONObjectWithData:dataMap options:kNilOptions error:&errorMap]; NSArray *resultsMap = [jsonMap valueForKey:#"posts"];
NSArray *resMap = [resultsMap valueForKey:#"post"];
NSArray *latitudeString=[resMap valueForKey:#"latitude"];
NSString *latOrgstring = [latitudeString objectAtIndex:0];
latitude=[latOrgstring doubleValue];
NSArray *longitudeString=[resMap valueForKey:#"longitude"];
NSString *longOrgstring = [longitudeString objectAtIndex:0];
longitude=[longOrgstring doubleValue];
NSString *ignation=[[resMap valueForKey:#"ignition"]objectAtIndex:0];
//MAP VIEW Point
MKCoordinateRegion myRegion;
//Center
CLLocationCoordinate2D center;
center.latitude=latitude;
center.longitude=longitude;
//Span
MKCoordinateSpan span;
span.latitudeDelta=0.01f;
span.longitudeDelta=0.01f;
myRegion.center=center;
myRegion.span=span;
//Set our mapView
[MapViewC setRegion:myRegion animated:YES];
//Annotation
//1.create coordinate for use with the annotation
//CLLocationCoordinate2D wimbLocation;
wimbLocation1.latitude=latitude;
wimbLocation1.longitude=longitude;
Annotation * myAnnotation= [Annotation alloc];
CLLocation *someLocation=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:someLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSDictionary *dictionary = [[placemarks objectAtIndex:0] addressDictionary];
addressOutlet=[dictionary valueForKey:#"Street"];
City=[dictionary valueForKey:#"City"];
State=[dictionary valueForKey:#"State"];
myAnnotation.coordinate=wimbLocation1;
if (addressOutlet!=NULL&&City!=NULL)
{
myAnnotation.title=addressOutlet;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#,%#", City, State];
}
[self.MapViewC addAnnotation:myAnnotation];
[self line];
}];
}
-(void)line
{
CLLocationCoordinate2D coordinateArray[2];
coordinateArray[0] = CLLocationCoordinate2DMake(latitude, longitude);
coordinateArray[1] = CLLocationCoordinate2DMake(latitude, longitude);
self.routeLine = [MKPolyline polylineWithCoordinates:coordinateArray count:2];
[self.MapViewC addOverlay:self.routeLine];
}
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
if(overlay == self.routeLine)
{
if(nil == self.routeLineView)
{
self.routeLineView = [[MKPolylineView alloc] initWithPolyline:self.routeLine];
self.routeLineView.fillColor = [UIColor redColor];
self.routeLineView.strokeColor = [UIColor redColor];
self.routeLineView.lineWidth = 5;
}
return self.routeLineView;
}
return nil;
}
Kindly advice me to correct my errors. Thanks in advance...
Try this.... this will help you...
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
{
self.routeLineView = [[MKPolylineView alloc] initWithPolyline:self.routeLine];
self.routeLineView.strokeColor = [UIColor redColor];
self.routeLineView.lineWidth = 5;
}
return self.routeLineView;
}

iOS Parse GeoPoints & MapBox Shapes

So i am wondering how to go about retrieving Parse coordinates and drawing a shape using MapBox.
I can retrieve the coordinates and plot them individually (using PARSE) on a map fine:
PFQuery *locationQuery = [PFQuery queryWithClassName:#"Location"];
[locationQuery whereKeyExists:#"location"];
locationQuery.cachePolicy = kPFCachePolicyNetworkElseCache;
[locationQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %lu scores.", (unsigned long)objects.count);
NSLog(#"Object is %# and %#", [objects objectAtIndex:0],[objects objectAtIndex:1]);
for (PFObject *gp in objects) {
//How to get PFGeoPoint and then a location out of an object
PFGeoPoint *location = [gp objectForKey:#"location"];
NSLog(#"Hi there my name is: %f", location.latitude);
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(location.latitude, location.longitude);
//This is how to populate the data with a title
NSString *title = [NSString stringWithFormat:#"%#", gp.createdAt];
RMPointAnnotation *annotation3 = [[RMPointAnnotation alloc] initWithMapView:mapView coordinate:coordinate andTitle:title];
[mapView addAnnotation:annotation3];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
Adding a shape to a map (using MapBox) is doable as well:
//Line for streets location arrays, etc MapBox
NSArray *locations = [NSArray arrayWithObjects:[[CLLocation alloc] initWithLatitude:-33.980852 longitude:151.072498],
[[CLLocation alloc] initWithLatitude:-33.981769 longitude:151.072300],
[[CLLocation alloc] initWithLatitude:-33.982018 longitude:151.072257],
[[CLLocation alloc] initWithLatitude:-33.982187 longitude:151.072225], nil, nil];
RMAnnotation *annoation43 = [[RMAnnotation alloc] initWithMapView:mapView coordinate:((CLLocation *)[locations
objectAtIndex:0]).coordinate andTitle:#"Hola biatches!"];
annoation43.userInfo = locations;
[annoation43 setBoundingBoxFromLocations:locations];
[mapView addAnnotation:annoation43];
NSLog(#"It is working Dora!");
-(RMMapLayer *)mapView:(RMMapView *)mapViewer layerForAnnotation:(RMAnnotation *)annotation {
if (annotation.isUserLocationAnnotation)
return nil;
RMShape *shape = [[RMShape alloc] initWithView:mapView];
//Line dashes and colours and widths, etc
shape.lineColor = [UIColor orangeColor];
shape.lineWidth = 4.0;
shape.scaleLineWidth = YES;
shape.scaleLineDash = YES;
shape.lineDashLengths = [NSArray arrayWithObjects:[NSNumber numberWithInt:4], [NSNumber numberWithInt:6], nil];
shape.lineDashPhase = 3.0f;
for (CLLocation *location in (NSArray *)annotation.userInfo)
[shape addLineToCoordinate:location.coordinate];
return shape;
}
I am wondering how i would get MapBox to draw a shape from these coordinates? I have had a few attempts and am getting nowhere so someone with a better mind than i would be greatly appreciated. If you need any more information let me know.
I figured it out - my solution i was attempting was fine - i was initialising the array WITHIN the loop and so it was recreating the array each time and so was overwriting each new coordinate and trying to draw a shape using only one coordinate.
PFQuery *locationQuery2 = [PFQuery queryWithClassName:#"Location"];
[locationQuery2 whereKeyExists:#"location"];
locationQuery2.limit = 4;
locationQuery2.cachePolicy = kPFCachePolicyNetworkElseCache;
[locationQuery2 findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %lu scores.", (unsigned long)objects.count);
NSLog(#"Object is %# and %#", [objects objectAtIndex:0],[objects objectAtIndex:1]);
NSMutableArray *locations = [[[NSMutableArray alloc] init] mutableCopy];
for (PFObject *gp in objects) {
//How to get PFGeoPoint and then a location out of an object
PFGeoPoint *location = [gp objectForKey:#"location"];
NSLog(#"Hi there my name is not: %f", location.latitude);
CLLocation *coordinate = [[CLLocation alloc] initWithLatitude:location.latitude longitude:location.longitude];
//Line for streets location arrays, etc MapBox
[locations addObject:coordinate];
RMAnnotation *annoation43 = [[RMAnnotation alloc] initWithMapView:mapView coordinate:((CLLocation *)[locations objectAtIndex:0]).coordinate andTitle:#"Hola biatches!"];
annoation43.userInfo = locations;
[annoation43 setBoundingBoxFromLocations:locations];
[mapView addAnnotation:annoation43];
NSLog(#"It is working Dora!");
NSLog(#"Yeah its is: %#", locations);
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];

Route drawing on Google Maps for iOS not following the street lines

I'm developing an iOS app which is using Google Directions API to draw routes on maps which are provided by Google Maps SDK. It works well on small distance although when I zoom the map camera very close I see that the route polylines are often getting out of the streets. When the distance is longer it's a real disaster and it's not following the streets curves if I zoom in. I'm getting the points from the overview-polyline which I receive from the Directions API but it seems like the polyline is not that poly as I want. On Android it works perfectly. Could it be that Google sends different directions to iOS than Android? Has some of you had the same problem as me?
EDIT:
-(int) requestDirecionsAndshowOnMap:(GMSMapView *)aMapView{
NSArray* mode=[[NSArray alloc]initWithObjects:#"transit",#"bicycling",#"walking",#"driving", nil];
NSString *depart=[[NSString alloc] initWithFormat:#""];
NSString *origin=[[NSString alloc] initWithFormat:#""];
NSString *destination=[[NSString alloc] initWithFormat:#""];
if (self.setLanguage)
self.setLanguage=[NSString stringWithFormat:#"language=%#",self.setLanguage];
else self.setLanguage=#"language=en";
if (searchModeOption==0) {
if (self.departDate==nil) {
self.departDate=[NSDate date];
}
depart=[NSString stringWithFormat:#"&departure_time=%i",(int)[self.departDate timeIntervalSince1970]];
}
if (self.origin) {
origin=[NSString stringWithFormat:#"origin=%#",self.origin];
}else if (self.originCoordinate.latitude && self.originCoordinate.longitude){
origin=[NSString stringWithFormat:#"origin=%f,%f",self.originCoordinate.latitude,self.originCoordinate.longitude];
}else{
NSLog(#"No origin setted");
return -1;
}
if (self.destination) {
destination=[NSString stringWithFormat:#"destination=%#",self.destination];
}else if (self.destinationCoordinate.latitude && self.destinationCoordinate.longitude){
destination=[NSString stringWithFormat:#"destination=%f,%f",self.destinationCoordinate.latitude,self.destinationCoordinate.longitude];
}else{
NSLog(#"No destination setted");
return -1;
}
NSString* URLforRequest=[[NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?%#&%#&sensor=false&%#&alternative=false&mode=%#%#",origin,destination,self.setLanguage,[mode objectAtIndex:searchModeOption],depart] stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];
// NSLog(#"%#",URLforRequest);
NSURLRequest *requests = [NSURLRequest requestWithURL:[NSURL URLWithString:URLforRequest]];
[NSURLConnection sendAsynchronousRequest:requests queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if (error==nil && data) {
// NSLog(#"%#",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
directions = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
if (error) {
NSLog(#"%#",error);
}
NSString* status=[directions objectForKey:#"status"];
NSLog(#"Status: %#", status);
if ([status isEqualToString:#"OK"]) {
[self decodeResult];
if (aMapView)
[self showOnMap:aMapView];
}
}else NSLog(#"%#",error);
[[NSNotificationCenter defaultCenter] postNotificationName:#"Request Done" object:nil];
}];
return 0;
}
-(void) decodeResult{
self.destination=[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"end_address"];
self.distance=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"distance"] objectForKey:#"text"] doubleValue];
self.duration=[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"duration"] objectForKey:#"text"];
//Get Array of Instructions
self.instrunctions=[[NSMutableArray alloc] init];
for (int n=0; n<[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"]count]; n++) {
[self.instrunctions addObject:[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] objectAtIndex:n] objectForKey:#"html_instructions"]];
}
//Get Overview Polyline
NSString *polystring=[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"overview_polyline"] objectForKey:#"points"];
NSMutableArray* decodedpolystring=[self decodePolyLine:polystring];
int numberOfCC=[decodedpolystring count];
GMSMutablePath *path = [GMSMutablePath path];
for (int index = 0; index < numberOfCC; index++) {
CLLocation *location = [decodedpolystring objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
[path addLatitude:coordinate.latitude longitude:coordinate.longitude];
}
self.overviewPolilyne= [GMSPolyline polylineWithPath:path];
//Get Coordinates of origin and destination to be displayed on a map
float lat=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"end_location"] objectForKey:#"lat"] floatValue];
float lng=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"end_location"] objectForKey:#"lng"] floatValue];
CLLocationCoordinate2D tmp;
tmp.latitude=lat;
tmp.longitude=lng;
self.destinationCoordinate=tmp;
lat=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"start_location"] objectForKey:#"lat"] floatValue];
lng=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"start_location"] objectForKey:#"lng"] floatValue];
tmp.latitude=lat;
tmp.longitude=lng;
self.originCoordinate=tmp;
}
-(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)showOnMap:(GMSMapView *)aMapView{
GMSPolyline *polyline =self.overviewPolilyne;
polyline.strokeColor = [UIColor blueColor];
polyline.strokeWidth = 2.f;
//polyline.geodesic = YES;
polyline.map = aMapView; }
UPDATE:
I had to process every step's polyline, not just the overview-polyline. Now it works perfectly.
Here's the code I'm using now:
// Get polyline
GMSMutablePath *path = [GMSMutablePath path];
NSMutableArray *polyLinesArray = [[NSMutableArray alloc] init];
int zero=0;
NSArray *steps = [[[[[directions objectForKey:#"routes"] objectAtIndex:zero] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
for (int i=0; i<[[[[[[directions objectForKey:#"routes"] objectAtIndex:zero] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"]count]; i++) {
NSString* encodedPoints =[[[steps objectAtIndex:i]objectForKey:#"polyline"]valueForKey:#"points"];
polyLinesArray = [self decodePolyLine:encodedPoints];
NSUInteger numberOfCC=[polyLinesArray count];
for (NSUInteger index = 0; index < numberOfCC; index++) {
CLLocation *location = [polyLinesArray objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
[path addLatitude:coordinate.latitude longitude:coordinate.longitude];
if (index==0) {
[self.coordinates addObject:location];
}
}
}
self.overviewPolilyne = [GMSPolyline polylineWithPath:path];
What I basically did before was that I was getting and working only with the information I'm receiving in the routes while if you check the JSON file you're receiving from Google Directions API, you'll see that you receive much more information in the <legs> and the <steps>. This is the information we need to produce the proper results and the right polyline.
Good luck! :)

Resources