Search code examples
swifthere-apiheremapsheremaps-ios-sdkheremap-navigation

HERE API:Swift. Wierd behaviour : Loops in a route - Creating a route based on GPS trace creates loops. / passthrough waypoints


im trying to create a route that follows a gps trace i provide. The gps trace is cleaned up and it has no loops in it and is in correct order. I checked it with other services. It has 1920 points. You can find the trace here GPX Files Sadly if i create a route based on provided sdk example (github) i get loops in my path.

I was hoping you could help me to solve following problems:

  1. how do i avoid loops while creating route by using HERE ios Swift SDK

  2. how do i set route options is such way to follow provided point array and not create a fastest or balanced route.

Since i could not find those functions in Ios sdk i used additional REST API to filter the route a bit to remove all points that were not matched correctly according to here maps... before drawing the route.. ie everything with low probability, warnings, big distance to the road... yet the result is still not good. Here is a cleaned up file.. the file is being created after the original was maped / run once through HERE Maps. In this file all points that have low confidence or produce warnings or have big distance to original points .. are removed. This is the one i use to create a route and it still have the same issues like loops and weird turns.

Thank you very much in advance! BR.

So far i have this code:

private lazy var router = NMACoreRouter()



 @objc func do_routing_stuff( gps_trace :[NMAWaypoint]) {
    var stops = [Any]()
    stops = gps_trace
    

    let routingMode = NMARoutingMode(routingType: .fastest,
                                     transportMode: .car,
                                     routingOptions: .avoidHighway)
    
    // Trigger the route calculation
           router.calculateRoute(withStops: stops ,
                                      routingMode: routingMode)
           { [weak self] routeResult, error in
               guard error == .none else {
                   self?.showMessage("Error:route calculation returned error code \(error.rawValue)")
                   return
               }

               guard let result = routeResult, let routes = result.routes, routes.count > 0 else {
                   self?.showMessage("Error:route result returned is not valid")
                   return
               }

               // Let's add the 1st result onto the map
               self?.route = routes[0]
               self?.updateMapRoute(with: self?.route)

              // self?.startNavigation()
           }
    
}

private func updateMapRoute(with route: NMARoute?) {
    // remove previously created map route from map
    if let previousMapRoute = mapRoute {
        mapView.remove(mapObject:previousMapRoute)
    }
    
    guard let unwrappedRoute = route else {
        return
    }
    
    mapRoute = NMAMapRoute(unwrappedRoute)
    mapRoute?.traveledColor = .clear
    _ = mapRoute.map{ mapView?.add(mapObject: $0) }
    
    // In order to see the entire route, we orientate the
    // map view accordingly
    if let boundingBox = unwrappedRoute.boundingBox {
        geoBoundingBox = boundingBox
        mapView.set(boundingBox: boundingBox, animation: .linear)
    }
}

enter image description here enter image description here

in comparison same route presented with leaflet maps.

pic4

enter image description here


Solution

  • I believe the problem you have is that you are feeding the Routing API a large number of waypoints, all of which are in close proximity to each other.

    You have almost 2000 waypoints in your GPX file (and ~1300 in your cleaned one). Each of these waypoints is less than 10 meters distance from their closest neighbors. This is not the type of data that the Routing API is really designed to work with.

    I've experimented with your GPX Trace and I have come up with the following solution: simply skip a bunch of coordinates in your trace.

    First, clean up your trace using the Route Matching API (which I believe you have been doing).

    Second, pick the first trkpt in the GPX file as your first waypoint for the Routing call. Then skip the next 20 points. Pick the following trkpoint as the second waypoint. Repeat this until you are at the end of the file. Then add the last trkpt in the trace as the final waypoint.

    Then call the Routing API and you should get a good match between your trace and your route, without any loops or other weird routing artefacts.

    Some notes:

    I have picked 20 as the number of traces to skip, because this would put about 200m in between each waypoint. That should be close enough to ensure that the Routing API does not deviate too much from the traced route. For larger traces you may wish to increase that number. For traces in urban environments with lots alternate routes, you may want to use a smaller number.

    It's important to clean the data with the Route Matching API first, to avoid picking outliers as waypoints.

    Also, you may not wish to use the "avoidHighways" option. Given your use case, there doesn't seem to be a benefit and I could see it causing additional problems.