Annotation along route in MapKit
Solution 1
Questioner's edit:
Finally made it work with the help of this answer. I added this to the code below, where it says Here do the magic:
MKMapPoint middlePoint = route.polyline.points[route.polyline.pointCount/2];
[self createAndAddAnnotationForCoordinate:MKCoordinateForMapPoint(middlePoint)];
Original answer:
I don't know whether this will work or not. Just my idea on your question.
I guess you would have created the routes as following (Check my inline comments)
MKDirectionsRequest *request =
[[MKDirectionsRequest alloc] init];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = _destination;
request.requestsAlternateRoutes = NO;
MKDirections *directions =
[[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle error
} else {
for (MKRoute *route in response.routes)
{
[_routeMap addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
//Here do the magic
//MKPolyline confronts to MKOverlay so you can get the coordinate like
//route.polyline.coordinate once you get the coordinate then you can build
//a annotation. A annotation is nothing but a coordinate with some title.
//According to MKOverlay coordinate property it justs gives you the
//center point of the overlay area
[self createAndAddAnnotationForCoordinate:route.polyline.coordinate]
}
}
}];
Adding Annotation
-(void) createAndAddAnnotationForCoordinate : (CLLocationCoordinate2D) coordinate{
MyAnnotation* annotation= [[MyAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = @"Any Title";
annotation.subtitle = @"Any Subtitle";
[yourMap addAnnotation: annotation];
}
Solution 2
If you want to know the middle for swift you can use the following code :
MKCoordinateForMapPoint(route.polyline.points()[route.polyline.pointCount/2])
Exemple of use :
directions.calculateDirectionsWithCompletionHandler ({
(response: MKDirectionsResponse?, error: NSError?) in
if error == nil {
self.showRoute(response!)
}
else{
print("some error")
}
})
func showRoute(response:MKDirectionsResponse){
for route in response.routes {
self.map.addOverlay(route.polyline, level: MKOverlayLevel.AboveRoads)
self.map.setCenterCoordinate(route.polyline.coordinate, animated: true)
self.map.setRegion(MKCoordinateRegionMakeWithDistance(route.polyline.coordinate, route.distance*0.75, route.distance*0.75), animated: true)
let routeAnnotation = MKPointAnnotation()
routeAnnotation.coordinate = MKCoordinateForMapPoint(route.polyline.points()[route.polyline.pointCount/2])
map.addAnnotation(routeAnnotation)
}
}
Daniel Larsson
Updated on June 04, 2022Comments
-
Daniel Larsson almost 2 years
I'm using MapKit to display directions between locations, and I'm looking for a way to add an annotation that works similarly to the route annotation in the Apple Maps app, where annotations are showing each route's travel time (as shown in the image below). I am already drawing the directions correctly, the problem at hand is how to calculate a pair of coordinates along the route. That is, where to drop the annotation.
I thought about somehow using the
MKDirection
(which contains complete directions, step by step) but I am not sure how I would generate a pair of coordinates that are somewhere in the middle of the route.I have not been able to find any kind of support for this in the MapKit documentation. Any ideas?
This is how I generate the route and display it.
- (void)generateRoute { MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init]; request.source = [MKMapItem mapItemForCurrentLocation]; request.destination = self.destinationMapItem; MKDirections *directions = [[MKDirections alloc] initWithRequest:request]; [directions calculateDirectionsWithCompletionHandler: ^(MKDirectionsResponse *response, NSError *error) { if (error) { // Handle Error } else { [self showRoute:response]; } }]; } - (void)showRoute:(MKDirectionsResponse *)response { [self.mapView removeOverlays:self.mapView.overlays]; for (MKRoute *route in response.routes) { [self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads]; } [self fitRegionToRoute]; } - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay { MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay]; renderer.strokeColor = [UIColor blueColor]; renderer.alpha = 0.7; renderer.lineWidth = 4.0; return renderer; }
-
Daniel Larsson over 10 yearsI like your idea, but this would only look good when the route is a straight line. Consider a route that goes in a circle, wouldn't the annotation end up in the middle of the circle instead of on the route?
-
ipraba over 10 yearsIf we are considering a MKCircle your question would be correct but as we are considering a MKPolyine i guess coordinate of MKPolyline should be on the line i guess. My suggestion is worth a try. I m not sure of the output.
-
Daniel Larsson over 10 yearsI will try it out and get back to you when I know!
-
ipraba over 10 yearsAwesome. Waiting for the result
-
Daniel Larsson over 10 yearsTried it out, the annotation ends up in between the two locations. Therefore, If the route has the form of an L, the annotation will be placed right between the start and finish, a long way from the actual route. Great suggestion though.
-
ipraba over 10 yearsOk. Now try another MKOverlay property boundingMapRect. This will give you MapRect. MapRect contains MKMapPoints and MKMapPoint can be converted into coordinates using MKCoordinateForMapPoint. So if you are able to retrieve any starting point of a overlay that can be your annotation. Check for all possiblities of getting a coordinate from route.polyline
-
Daniel Larsson over 10 yearsYeah that is what I am trying out right now. Also trying to use the points that are in polyline.points. Will let you know when I have tried it!
-
Daniel Larsson over 10 yearsIt's working! What I did was to get the middle point through MKMapPoint middlePoint = route.polyline.points[route.polyline.pointCount/2]; and then [self createAndAddAnnotationForCoordinate:MKCoordinateForMapPoint(middlePoint)];. Put that in your answer and I will accept it!
-
Daniel Larsson over 10 yearsThank you, looks like a great framework. A bit too much for this task though, I have already implemented many of those features myself.
-
Admin over 10 yearsAs @daniellarsson already noted, the
coordinate
property of an overlay does not give a point on the line (it's just the geometric center of the rectangle that bounds the overlay) so unless the overlay is a single straight line, it's not the "middle of the line". -
Admin over 10 yearsAdditionally, the solution of using the coordinate from the midpoint of the array of points in the polyline is reasonable only when the line segments in the polyline are about equal in length. Eg. If you have a polyline with 3 points (2 line segments) and the first line segment is much shorter than the second line segment, using the coordinate at the midpoint of the array will not put an annotation "midway along the polyline".
-
Craig over 10 yearsAn example of Anna's point could be that it takes 10 turns to get to the motorway from your house but on one to get off the motorway to the store, the midpoint of the direction array is much closer to the start than the end. To counteract that you could find the center point of the bounding rect as you originally did, and then cycle through the end points and center points of the individual directions to find the closest one to the center. It'll be near to the geographical center of the route and on the line. It'll be tripped up by horseshoe shaped routes, but who does that anyway?
-
Siten over 10 yearsBut What is the _destination?