Skip to main content

Routing

Massif Maps embeds Valhalla: turn-by-turn routing for car, bicycle, pedestrian and more, run either against an HTTP endpoint or entirely offline from tiles on the device. The same service also does map matching — snapping a recorded GPS trace back onto the road network. Indoor routing uses a separate engine, SGRE, over a graph you supply.

Routing is a service you create, a request you create, and a call. Nothing about it touches the map, so a route can be computed with no map view at all.

No hosted service

The CARTO routing endpoints are gone with the rest of the CARTO services. Point customServiceURL at a Valhalla server you run or a public one, or ship offline tiles.

Online​

MassifObject router = Massif.object("routing", "router", Spec.of("valhalla-online"));
router.set("customServiceURL", "https://valhalla1.openstreetmap.de/{service}");
router.set("profile", "bicycle");

MassifObject request = Massif.object("routing", "query", Spec.of("request")
.set("projection", "EPSG:4326")
.set("points", new double[][] {{5.7249, 45.1877}, {5.7148, 45.1916}}));

// Free-form Valhalla options are JSON, so they are a call rather than a property.
request.call("setCustomParameter", "language", "fr-FR");

router.callAsync("calculateRoute", route -> {
double metres = route.getDouble("totalDistance", 0);
long steps = route.getLong("instructionCount", 0);
for (int i = 0; i < steps; i++) {
MassifObject step = route.call("getInstruction", i);
Log.i(TAG, step.getString("streetName", "") + ": " + step.getString("instruction", ""));
}
}, request);

Points are [longitude, latitude] in the projection the request names. {service} in the URL is substituted per Valhalla endpoint (route, trace_route, …).

Measured against the public OSM endpoint on a phone: a 1 km walking route came back in 681 ms, 72 positions and 21 instructions.

Offline​

Ship a Valhalla tile package (a SQLite file, .vtiles) with the app or download it, then point the service at it. No network, no key, and the same request and result shape:

MassifObject router = Massif.object("routing", "router", Spec.of("valhalla-offline")
.set("path", "/sdcard/routing/france.vtiles"));
router.set("profile", "auto");

multi-valhalla-offline takes several packages and picks the one that covers the request, which is what a per-country download UI wants:

MassifObject router = Massif.object("routing", "router", Spec.of("multi-valhalla-offline"));
router.call("add", "/sdcard/routing/france.vtiles");
router.call("add", "/sdcard/routing/switzerland.vtiles");

Building the tiles is Valhalla's own job — valhalla_build_tiles over an OSM extract. The SDK does not read that directory or tar, though: it reads one SQLite file in the MBTiles layout (a tiles table plus metadata), so the built tiles have to be packed into one.

Offline routing runs on the device's CPU, so a very long route over a large package takes seconds rather than the hundreds of milliseconds a server takes. Keep the packages regional.

Reading the result​

totalDistance / totalTimemetres and seconds
pointCount / instructionCountcounts, as properties
getInstruction(i)one maneuver: action, pointIndex, distance, streetName, instruction
instructionsJSONevery maneuver as one JSON array, in one call instead of one per field
getPoints()the whole path as a flat x0,y0,x1,y1,… buffer

Read the path with getPoints() rather than the points property: a 9 km cycling route is 562 positions, which as JSON is a 15 KB string to build, cross and parse. The flat buffer is one crossing and no copy — and it applies no projection, so read projection.name to know what the numbers are.

To draw the route, feed those positions to a line element, or — for many routes at once — through the GeoJSON tiling pyramid. Turn arrows are a feature of their own: maneuver arrows.

Map matching​

Same service, a different request. match-request adds the accuracy of the measured points, in metres:

MassifObject request = Massif.object("routing", "trace", Spec.of("match-request")
.set("projection", "EPSG:4326")
.set("accuracy", 10)
.set("points", recordedTrace));

router.callAsync("matchRoute", result -> …, request);

Indoor routing​

SGREOfflineRoutingService (experimental) routes over a graph the app provides as GeoJSON — corridors, stairs, lifts, with your own edge costs. It is a separate engine from Valhalla and is not tied to OSM data at all. See the SGRE sources and all/modules/routing/SGREOfflineRoutingService.i for the constructor.

Routing without the map​

The repository also ships routing-lib: Valhalla and its bindings, with no renderer and no map view. If your app only needs routes, that is a much smaller dependency — see the installation guide.

Full spec keys, properties and methods: routing reference.