You should not use MKDirections since it is not made for following a precalculated path but to give you the fastest route to the destination! Therefore I will use MKMapOverlayRenderer instead!
There are several things you can to achieve this. I want to talk about easy algorithm for removing the unnecessary waypoints:
NSArray* path = YOURPATH
NSMutableArray* waypoints = [path mutableCopy];
CGFloat smoothness = 0.01;
for(NSInteger scale=1;scale<log2(waypoints.count);scale++)
{
for(NSInteger index = 0; index<waypoints.count-2;index++)
{
CLLocation *start = [waypoints objectAtIndex:index];
CLLocation *middle = [waypoints objectAtIndex:index+1];
CLLocation *end = [waypoints objectAtIndex:index+2];
CGFloat dist_start_end = [end distanceFromLocation:start];
CGFloat dist_start_middle_end = [middle distanceFromLocation:start]+[end distanceFromLocation:middle];
CGFloat diff = dist_start_end-dist_start_middle_end;
CGFloat ratio = diff/(dist_start_end);
if (ratio<1+smoothness) {
[waypoints removeObjectAtIndex:index+1];
index-=1;
}
}
}
This should remove the unwanted points. You should playaround with the 'smoothness' variable. The bigger the value, the more details will be removed! (therefore better compression)
Now with this array, you can construct your bezier path!
I will not go into the details on how to actually put the bezier path onto the map, there are so many other questions about this on Stackoverflow and also tutorials on the internet. But I will shortly touch on how you should create/use the two control points of the bezier path:
Given the waypoints array we created above, you will probably add some additional control points, in order to avoid driving directions taking a shortcut through a building. Therefore you should calculate the control points between two actual points on the path like this:
CGFloat cornerRadius = 5;
NSMutableArray* pathPoints = [NSMutableArray new];
if (waypoints.count>1) {
[pathPoints addObject:[waypoints objectAtIndex:0]];
[pathPoints addObject:[waypoints objectAtIndex:0]];
[pathPoints addObject:[waypoints objectAtIndex:1]];
[pathPoints addObject:[waypoints objectAtIndex:1]];
}
for (NSInteger index = 1;index<waypoints.count-1;index++) {
CLLocation* lastLocation = [waypoints objectAtIndex:index-1];
CLLocation* currentLocation = [waypoints objectAtIndex:index];
CLLocation* nextLocation = [waypoints objectAtIndex:index+1];
[pathPoints addObject:currentLocation];
CGFloat latDiff = currentLocation.coordinate.latitude - lastLocation.coordinate.latitude;
CGFloat longDiff = currentLocation.coordinate.longitude - lastLocation.coordinate.longitude;
CGFloat dist = [currentLocation distanceFromLocation:lastLocation];
CGFloat controlPointALat = cornerRadius*latDiff/dist;
CGFloat controlPointALong = cornerRadius*longDiff/dist;
CLLocation* controlPointA =
[[CLLocation alloc] initWithLatitude:controlPointALat longitude:controlPointALong];
[pathPoints addObject:controlPointA];
if (index<waypoints.count-2) {
CLLocation* nextNextLocation = [waypoints objectAtIndex:index+2];
latDiff = nextNextLocation.coordinate.latitude - nextLocation.coordinate.latitude;
longDiff = nextNextLocation.coordinate.longitude - nextLocation.coordinate.longitude;
dist = [nextNextLocation distanceFromLocation:nextLocation];
CGFloat controlPointBLat = cornerRadius*latDiff/dist;
CGFloat controlPointBLong = cornerRadius*longDiff/dist;
CLLocation* controlPointB =
[[CLLocation alloc] initWithLatitude:controlPointBLat longitude:controlPointBLong];
[pathPoints addObject:controlPointB];
}else{
[pathPoints addObject:controlPointA];
}
[pathPoints addObject:nextLocation];
}
Now you can use this pathArray to build your bezierPaths with a simple for loop:
for(NSInteger index=0;index<pathPoints.count-3;index+=4)
{
CLLocation *start = [pathPoints objectAtIndex:index];
CLLocation *controlPointA = [pathPoints objectAtIndex:index+1];
CLLocation *controlPointB = [pathPoints objectAtIndex:index+2];
CLLocation *end = [pathPoints objectAtIndex:index+3];
//BEZIER CURVE HERE
}
You can either use a UIBezierPath and use the CGPath property to create your MKMapOverlayRenderer, or you can directly use a CGPath. Later adding the path to your map is described here:
MKMapOverlayRenderer
Createing a UIBezierPath is described here:
UIBezierPath