Show / Hide Table of Contents

Shapefiles

By default Itinero works with OSM data but it's perfectly capable of handling other data. Think closed alternatives like TomTom MultiNet or HERE but there are also several open datasets out there most of them managed by local governments. Most of these datasets are available as shapefile and can be loaded using Itinero.IO.Shape.

RouterDb from Shapefile

This is an example of loading data from a shapefile into a router db. We are using an open dataset from the Dutch government called 'NWB', the 'national road registry'. We can't include samples for MultiNet or HERE because we're not sure we are allowed to do this.

You can check a full working sample here.

Vehicle definition

First of all make sure to convert your shapefile to use WGS84. The shapefile you're using has to contain two columns per geometry identifying endpoints or junctions for Itinero to be able to link them together in a network.

After that, the most important part is creating a vehicle definition that describes the attributes in the shapefile in such a way that Itinero knows how to handle the data. A profile basically translates the information in the columns of the shapefile into speed, distance and access information. An example vehicle profile:

-- car globals
name = "nwb.car"

-- global profile parameters.
-- defines columns in the shapefile.
parameters = {
  source_vertex = "JTE_ID_BEG",
  target_vertex = "JTE_ID_END"
}

-- whitelists for profile and meta
profile_whitelist = {
  "BST_CODE", 
  "BAANSUBSRT", 
  "RIJRICHTNG", 
  "WEGBEHSRT", 
  "HECTO_LTTR"
}
meta_whitelist = {
  "STT_NAAM"
}

-- default speed profiles
speed_profiles = {
  ["BVD"] = { speed = 50, oneway = nil },
  ["AF"] = { speed = 70, oneway = nil },
  ["OP"] = { speed = 70, oneway = nil },
  ["HR"] = { speed = 120, oneway = nil },
  ["MRB"] = { speed = 30, oneway = true},
  ["NRB"] = { speed = 30, oneway = true}
}


-- profile definitions linking a function to a profile
profiles = {
  {
    name = "",
    function_name = "factor_and_speed",
    metric = "time"
  },
  { 
    name = "shortest",
    function_name = "factor_and_speed",
    metric = "distance",
  }
}

-- the main function turning attributes into a factor_and_speed and a tag whitelist
function factor_and_speed (attributes, result)

  result.speed = 0
  result.direction = 0
  result.canstop = true
  result.attributes_to_keep = {}

  -- get default speed profiles
  local BST_CODE = attributes.BST_CODE -- code of road type.
  local speed_profile = speed_profiles[BST_CODE]
  local speed = 70
  local direction = 0 -- bidirectional default
  result.attributes_to_keep.BST_CODE = true -- keep this code.
  if speed_profile then
    speed = speed_profile.speed
    if speed_profile.oneway then
      direction = 1 -- this type of edge is oneway forward by default
    end
  end

  local RIJRICHTNG = attributes.RIJRICHTNG -- oneway code.
  if RIJRICHTNG then
    result.attributes_to_keep.RIJRICHTNG = true -- keep the oneway stuff
    if RIJRICHTNG == "H" then
      direction = 1
    elseif RIJRICHTNG == "T" then
      direction = 2
    end
  end

  result.speed = speed -- speed in km/h
  result.direction = direction
  result.canstop = true
end

-- instruction generators
instruction_generators = {
  {
    applies_to = "", -- applies to all profiles when empty
    generators = {
    {
      name = "start",
      function_name = "get_start"
    },
    { 
      name = "stop",
      function_name = "get_stop"
    },
    {
      name = "roundabout",
      function_name = "get_roundabout"
    },
    {
      name = "turn",
      function_name = "get_turn"
    }
    }
  }
}

-- gets the first instruction
function get_start (route_position, language_reference, instruction)
  if route_position.is_first() then
    local direction = route_position.direction()
    instruction.text = itinero.format(language_reference.get("Start {0}."), language_reference.get(direction));
    instruction.shape = route_position.shape
    return 1
  end
  return 0
end

-- gets the last instruction
function get_stop (route_position, language_reference, instruction) 
  if route_position.is_last() then
    instruction.text = language_reference.get("Arrived at destination.");
    instruction.shape = route_position.shape
    return 1
  end
  return 0
end

function contains (attributes, key, value)
  if attributes then
    return localvalue == attributes[key];
  end   
end

-- gets a roundabout instruction
function get_roundabout (route_position, language_reference, instruction) 
  if (route_position.attributes.BST_CODE == "NRB" or 
    route_position.attributes.BST_CODE == "MRB") and
      (not route_position.is_last()) then
    local attributes = route_position.next().attributes
    if attributes.junction then
    else
      local exit = 1
      local count = 1
      local previous = route_position.previous()
      while previous and (previous.attributes.BST_CODE == "NRB" or 
        previous.attributes.BST_CODE == "MRB") do
        local branches = previous.branches
        if branches then
          branches = branches.get_traversable()
          if branches.count > 0 then
            exit = exit + 1
          end
        end
        count = count + 1
        previous = previous.previous()
      end

            instruction.text = itinero.format(language_reference.get("Take the {0}th exit at the next roundabout."), "" .. exit)
            if exit == 1 then
                instruction.text = itinero.format(language_reference.get("Take the first exit at the next roundabout."))
            elseif exit == 2 then
                instruction.text = itinero.format(language_reference.get("Take the second exit at the next roundabout."))
            elseif exit == 3 then
                instruction.text = itinero.format(language_reference.get("Take the third exit at the next roundabout."))
            end
            instruction.type = "roundabout"
            instruction.shape = route_position.shape
            return count
        end
    end
    return 0
end

-- gets a turn
function get_turn (route_position, language_reference, instruction) 
    local relative_direction = route_position.relative_direction().direction

    local turn_relevant = false
    local branches = route_position.branches
    if branches then
        branches = branches.get_traversable()
        if relative_direction == "straighton" and
            branches.count >= 2 then
            turn_relevant = true -- straight on at cross road
        end
        if  relative_direction != "straighton" and 
            branches.count > 0 then
            turn_relevant = true -- an actual normal turn
        end
    end

    if turn_relevant then
        local next = route_position.next()
        local name = nil
        if next then
            name = next.attributes.STT_NAAM
        end
        if name then
            instruction.text = itinero.format(language_reference.get("Go {0} on {1}."), 
                language_reference.get(relative_direction), name)
            instruction.shape = route_position.shape
        else
            instruction.text = itinero.format(language_reference.get("Go {0}."), 
                language_reference.get(relative_direction))
            instruction.shape = route_position.shape
        end

        return 1
    end
    return 0
end

You will need to create the same kind of profile for your own dataset, telling Itinero what to do and how to load the data.

Loading the data

Once this is done you can use the profile to create routerdb as follows:

// create a new router db and load the shapefile.
var vehicle = new Car(); // load data for the car profile.
var routerDb = new RouterDb(EdgeDataSerializer.MAX_DISTANCE);
routerDb.LoadFromShape("/path/to/shape/", "wegvakken.shp", vehicle);

// write the router db to disk for later use.
routerDb.Serialize("nwb.routerdb");

RouterDb to Shapefile

If for whatever reason you want to go in the opposite direction there is also an extension method in Itinero.IO.Shape to write a routerdb as a shapefile. To write a shapefile with support for car, bicycle and pedestrian just do:

var profiles = new Profile[] {
  routerDb.GetSupportedProfile("car"),
  routerDb.GetSupportedProfile("bicycle"),
  routerDb.GetSupportedProfile("pedestrian")
};
routerDb.WriteToShape("shapefile", profiles);
Back to top Built by Itinero, MIT licensed.