We’re building support for external raster data sources in OSRM. This will unlock countless possibilities in OSRM — most immediately for us it means the ability to run elevation-aware routing profiles, letting us better optimize for the way humans really bike or walk.

The OSRM raster source feature is data-agnostic, meaning it’s BYOData — it can consume just about any geo-referenced raster dataset. The elevation case is obvious, where queried values are numeric, but you could also write a routing profile to optimize for any kind of data you have — air quality, crime rates, you name it. Since it’s written natively in C++, it doesn’t introduce the magnitude of slowdown inherent to database queries.

Using an external data source in a routing profile is easy — just as OSRM Lua profiles require a node_function and a way_function, they’ll optionally call a source_function to load a source into memory and a segment_function to query that source per graph segment. So your profile would now have two additional functions that look like this:

--------------------------------------------------
-- Called once to load raster sources into memory.
--------------------------------------------------

function source_function ()
    -- Define lat/lon min/max and data dimensions from environment variable reads
    raster_source = load_raster_data(
        "./srtm_bayarea.asc",
        LON_MIN,
        LON_MAX,
        LAT_MIN,
        LAT_MAX,
        NROWS,
        NCOLS)
end

--------------------------------------------------
-- Called per segment to update edge weights.
--------------------------------------------------
function segment_function (source, target, distance, weight)
    local sourceData = get_raster_interpolate(raster_source, source.lon, source.lat)
    local targetData = get_raster_interpolate(raster_source, target.lon, target.lat)
    local elev_delta = targetData.datum - sourceData.datum

    local penalize = 0

    slope = math.abs(elev_delta / distance)
    if elev_delta < 0 then
        slope = slope / 3
    end

    if slope < 0.01 then
        penalize = 0
    elseif slope < 0.05 then
        penalize = 0.25
    elseif slope < 0.1 then
        penalize = 0.65
    else
        penalize = 0.9
    end

    weight.speed = weight.speed * (1 - penalize)
end

That means later this summer, the bicycle profile on the Mapbox Directions API, which has thus far been insensitive to any kind of hill or mountain, will return something much more sensible for the average urban bicyclist. We’re fine-tuning the parameters on a sample we’ve got running with a Bay Area extract, and we’re pretty excited about the results. Below, the red and pink lines represent new routes, dashed gray is the default bicycle route, and the graph represents elevation:

Keep an eye out for the raster source feature to be merged into mainline OSRM in the near future and the elevation-aware bicycle routing profile in the Mapbox Directions API. Hit me up on Twitter if you want to talk routing at @lbudorick.