Closed jumbopilot closed 4 years ago
If you want the navigation SDK to follow a predefined route without any consideration for the road network, you can create a Route whose shape is a great circle between the destinations. In navigation SDK v0.38, you’d pass a JSON-formatted dictionary into Route(json:waypoints:options:)
to create this route. Once #2275 lands, you’ll decode the route from JSON data instead:
// https://docs.mapbox.com/api/navigation/#route-object
let routeJSON: [String: Any?] = [
"duration": 3 * 3600,
"distance": 3_000_000,
"geometry": greatCircle,
"legs": [
// https://docs.mapbox.com/api/navigation/#route-leg-object
[
"duration": 3 * 3600,
"distance": 3_000_000,
"steps": [
[
"driving_side": "right",
"geometry": greatCircle,
"mode": "driving",
"maneuver": [
"bearing_before": 0,
"bearing_after": 0,
"location": [
greatCircle.coordinates[0].longitude,
greatCircle.coordinates[0].latitude,
],
"type": "depart",
"instruction": "Take off",
],
"weight": 1,
"duration": 3 * 3600,
"distance": 3_000_000,
"name": "",
"mode": "driving",
"bannerInstructions": [
[
"distanceAlongGeometry": 3_000_000,
"primary": [
"text": "Land",
"components": [
[
"text": "Land",
"type": "text",
],
],
"type": "arrive",
],
"secondary": nil,
],
],
],
[
"driving_side": "right",
"geometry": [
[greatCircle.coordinates[0].longitude, greatCircle.coordinates[0].latitude],
[greatCircle.coordinates[0].longitude, greatCircle.coordinates[0].latitude],
],
"mode": "driving",
"maneuver": [
"bearing_before": 0,
"bearing_after": 0,
"location": [
greatCircle.coordinates[1].longitude,
greatCircle.coordinates[1].latitude,
],
"type": "arrive",
"instruction": "Land",
],
"weight": 1,
"duration": 3 * 3600,
"distance": 3_000_000,
"name": "",
"mode": "driving",
"bannerInstructions": [],
],
],
"summary": "",
],
],
]
let routeData = try! JSONSerialization.data(withJSONObject: routeJSON, options: [])
let options = NavigationRouteOptions(waypoints: [origin, destination], profileIdentifier: DirectionsProfileIdentifier(rawValue: "jumbopilot/flying"))
options.shapeFormat = .geoJSON
let decoder = JSONDecoder()
decoder.userInfo[.options] = options
let route = try decoder.decode(Route.self, from: routeData)
Neither this SDK nor Turf provides a function for generating a great circle: mapbox/turf-swift#12. But you could port the Turf.js implementation, or if you’re OK with the inaccuracy of a straight-line animation in Spherical Mercator projection, you could use a straight linestring.
The other consideration is that the SDK’s default zoom level is at ground level. You’d want the zoom level to vary parabolically. That would require changes to this method:
If your goal is to simply imitate a flying motion, then the map SDK’s MGLMapView.fly(to:duration:peakAltitude:completionHandler:)
method would be much more straightforward than repurposing turn-by-turn navigation for flight.
Hi Minh,
I'm glad this topic gets more attention.
My requirements/intention are:
The last one is a long term milestone. Others are short term milestones.
Related to 1.: I understand Navigation SDK will soon be extended to consider JSON route like described above, which is a feasible way to me. Why wouldn't I be able to use the core navigation waypoint route guidance as is? Because standard route guidance is connected to the road network only? Wouldn't it make sense to allow such a functional switch to disregard the road network nd have this .flight route option?
Will point 2. and 3. be supported by Navigation SDK?
To be honest, flying (or swimming or sailing) use cases are nowhere near the top of our priority list. We have our hands full with only four routing profiles as it is, but we also prize customizability to handle unexpected use cases. Consider the huge code block above nothing more than a workaround. 🙂
A basic assumption of the turn-by-turn navigation functionality in the navigation SDK is that it compares your actual location to a predefined geometry. (Substitute your actual location for a fake one when route simulation is enabled.) But it’s a fair request to have more granular control over camera motion, which a flight simulator–like application might use to provide a much simpler geometry than the Directions API would – and no turn maneuvers.
Another issue you’ll run into is that the map SDK doesn’t currently support tilting (increasing the pitch) beyond 60 degrees or so: mapbox/mapbox-gl-native#6908. At that pitch, the camera still looks slightly downward instead of straight ahead as you’d expect of a conventional aircraft. There is a workaround for this limitation – lowering the horizon – but it causes severe performance degradation: mapbox/mapbox-gl-native#15163.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Stale.
This is about providing a route based on 3D waypoints used as single destination point/coordinate by informing about the direction (just like a compass needle), linear travel distance and ETA mechanisms, but using the CLLocation data type instead of the OSM route (road bound) algorithm.
Something like simply overriding the NavigationRouteOptions
// Specify that the route is intended for automobiles avoiding traffic let options = NavigationRouteOptions(waypoints: [origin, destination], profileIdentifier: .automobileAvoidingTraffic)
or overriding the calculate method:
// Generate the route object and draw it on the map _ = Directions.shared.calculate(options) { [unowned self] (waypoints, routes, error) in self.directionsRoute = routes?.first }
Basically, I just have an origin (3D user location) and a destination (3D coordinate) and calculate the above mentioned metrics and provide them to the Directions object. Is this feasible?
I'd be happy Mapbox is evaluating this option in order to re-use the lower route guidance views including Distance, Direction, ETA from Mapbox.
An alternative could be to allow creating/reusing the lower navigation pane apart the remaining navigation kit.