Annotation Along Route in Mapkit

Annotation along route in MapKit

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];

}

How to add annotations at a certain distance along a MKPolyline route using iOS MapKit in Swift?

Treat your poly line points as a sequence of line segments. Start out with the target distance, 13 miles. Iterate over the points as line segments - .windows(ofCount: 2), compute the length of that line segment, if remaining distance is < line segment length, then your target point is the point that is 'remaining distance' from start of line segment in the direction of end of line segment. Otherwise, subtracting the line segment's length from remaining distance, until either you find your target or fall off the end of the poly line. The question of whether each line segment on poly line represents straight line (along map projection) or great circles (on surface of earth) is unimportant unless the distance between points is large.

MapKit: Route not being displayed between two annotations

You've almost got it.

The one issue that you need to resolve is the use of the MKMapView delegate functions.

The easiest way to do that is to subclass MKMapView and make your own map view that has conforms to MKMapViewDelegate.

Firstly, create your own map view, subclassing MKMapView and conforming to MKMapViewDelegate. At the moment you're only really using the rendererFor overlay delegate method so I'll just implement that, but you can add other methods if you require them.

class WrappableMapView: MKMapView, MKMapViewDelegate {

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = .red
renderer.lineWidth = 4.0
return renderer
}
}

Then you need to update your UIViewRepresentable to use the new WrappableMapView that you just created. I have gone for making a functional example, so here I am passing in the request and destination locations. You can handle this how you want but at least this will give you something that works.

struct MyMapView: UIViewRepresentable {

@Binding var requestLocation: CLLocationCoordinate2D
@Binding var destinationLocation: CLLocationCoordinate2D

private let mapView = WrappableMapView()

func makeUIView(context: UIViewRepresentableContext<MyMapView>) -> WrappableMapView {
mapView.delegate = mapView // make sure we set our delegate to be the mapView we just created
return mapView
}

func updateUIView(_ uiView: WrappableMapView, context: UIViewRepresentableContext<MyMapView>) {

let requestAnnotation = MKPointAnnotation()
requestAnnotation.coordinate = requestLocation
requestAnnotation.title = "Package Title"
uiView.addAnnotation(requestAnnotation)

let destinationAnnotation = MKPointAnnotation()
destinationAnnotation.coordinate = destinationLocation
destinationAnnotation.title = "Destination"
uiView.addAnnotation(destinationAnnotation)

let requestPlacemark = MKPlacemark(coordinate: requestLocation)
let destinationPlacemark = MKPlacemark(coordinate: destinationLocation)

let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: requestPlacemark)
directionRequest.destination = MKMapItem(placemark: destinationPlacemark)
directionRequest.transportType = .automobile

let directions = MKDirections(request: directionRequest)
directions.calculate { response, error in
guard let response = response else { return }

let route = response.routes[0]
uiView.addOverlay(route.polyline, level: .aboveRoads)

let rect = route.polyline.boundingMapRect
uiView.setRegion(MKCoordinateRegion(rect), animated: true)

// if you want insets use this instead of setRegion
// uiView.setVisibleMapRect(rect, edgePadding: .init(top: 50.0, left: 50.0, bottom: 50.0, right: 50.0), animated: true)
}

}
}

Finally we can put it all together with a ContentView that shows it works:

struct ContentView: View {

@State var requestLocation = CLLocationCoordinate2D(latitude: 51.509865, longitude: -0.118092)
@State var destinationLocation = CLLocationCoordinate2D(latitude: 51.501266, longitude: -0.093210)

var body: some View {
MyMapView(requestLocation: $requestLocation, destinationLocation: $destinationLocation)
}
}

This is what it should look like:

Map View with route


One thing to note, using the rendererFor overlay delegate function in the simulator causes an error. This only happens in the simulator and not on device, so don't be surprised if you see an error message like this in the console.

2019-11-08 18:50:30.034066+0000 StackOverflow[80354:9526181] Compiler error: Invalid library file


Related Topics



Leave a reply



Submit