-
Notifications
You must be signed in to change notification settings - Fork 1
OSRM normalized file format
This page documents the normalized format of the binary files map.osrm,map.osrm.restrictions and map.osrm.names, which are generated by ./osrm-extract and used as input by ./osrm-prepare. This information can be used to use OSRM with geographical data that has not the Openstreetmap (OSM) format.
Attention: all the numeric values (int and short) are little endian. Note that some bytes arose from data structure alignment.
This file contains all the street names appearing in the dataset. There is no specific order required and it is fine when a name appears only once for multiple ways with the same name.
The file starts with:
- (unsigned int (4 bytes)): number of names
Next for each name:
- (unsigned int (4 bytes)): bytelength of the name (can be zero in case of empty name)
- (bytestring): the street name
The first part of this file contains all usable nodes: any OSM node that appears in a routable way is a usable node. Nodes can be tagged as 'bollard'. This means that 2 ways end in this kind of node and that you cannot pass this node. The second part lists all routable edges. Any routable OSM way part becomes an edge. This means that an OSM way of n nodes generates n-1 routable edges. (In other data formats it is common that the routing network is modeled as graph, in which the edges have a linestring attribute. In this case, any linestring of size n generates n-1 routable edges.) A flag indicates whether the edge can be navigated in one (= the forward) direction or in both directions.
The file starts with:
- (unsigned int (4 bytes)): number of usable nodes
Next for each usable node ORDERED BY ID:
- (signed int (4 bytes)): round( latitude in dig.dec.degree * 100000)
- (signed int (4 bytes)): round(longitude in dig.dec.degree * 100000)
- (unsigned int (4 bytes)): id of the node
- (4 bytes: Default): 00 00 00 00 -- 01 xx xx xx in case of bollard and xx 01 xx xx in case of traffic light
The next part starts with:
- (unsigned int (4 bytes)): number of edges
Next for each edge ORDERED BY TARGET ID:
- (unsigned int (4 bytes)): ref of the start-node
- (unsigned int (4 bytes)): ref of the target-node.
- (signed int (4 bytes): edge distance (unit): m); MUST be > 0
- (short (2 bytes)): 00 00 in case of bidirectional; 01 00 in case of single direction
- (signed int (4 bytes): edge weight (unit): 1/10s); MUST be > 0
- (short (2 bytes): edge type): i.e. the rank number in the applied speed profile (first profile has position 0) Currently, it is only used in the instruction filtering mechanism: roughly speaking, an instruction is generated only when the rank numbers differ.
- (unsigned int (4 bytes)): streetname position in map.osrm.names (first street name has position 0)
- (bool (1 byte)): 01 in case of roundabout; 00 otherwise
- (bool (1 byte)): 01 in case of ignoreInGrid; 00 otherwise (This field can be used in order to ignore the edge during data preparation; probably it is driven by the excludeFromGrid-entry in the speed profile (typically used for ferry-type and internal for pier-type); probably the effect is that a route can never start or stop in the middle of a set of excludeFromGrid-segment)
- (bool (1 byte)): 01 in case of accessRestricted; 00 otherwise
This file contains all turn restrictions appearing in the dataset.
The file starts with:
- (unsigned int (4 bytes)): number of usable restrictions
Next for each restriction ORDERED BY THE TO-WAY(!) REF):
- (unsigned int (4 bytes)): ref of the via-node
- (unsigned int (4 bytes)): ref of the from-node. The authors defined the from-node as the node within the from-way which is the closest to the via-node. This node does not need to connect to another way.
- (unsigned int (4 bytes)): ref of the to-node. The authors defined the to-node as the node within the to-way which is the closest to the via-node. This node does not need to connect to another way.
- ((8 bits)): currently, only the first bit is used, resulting in HEX 00 or HEX 01. 00 indicates it is a forbidden turn. 01 indicated it is the only allowed turn (so the others are forbidden).
- ((3 bytes)): Hex-code 7F 00 00
RouteYou.com has been experimenting with importing (proprietary) non-OSM data directly to the .osrm format. Below, you can find an experimental osrm-binary interface in PHP (! :S). There is a code example in the end.
<?php
class OSRMWriter
{
public static $INT_BITS = 32;
public static $SHORT_BITS = 16;
public static $SIGNED_INT_FORMAT = 'l'; //l signed long (always 32 bit, machine byte order)
public static $UNSIGNED_INT_FORMAT = 'L'; //L unsigned long (always 32 bit, machine byte order)
public static $SIGNED_SHORT_FORMAT = 's'; //s signed short (always 16 bit, machine byte order)
public static $UNSIGNED_SHORT_FORMAT = 'S'; //S unsigned short (always 16 bit, machine byte order)
private $_mainFileName;
private $_osrmStream;
private $_nameStream;
private $_restrictionStream;
private $_namePosition = 0;
public function __construct($mainFileName) { // $mainFileName example "data.osrm"
$this->_mainFileName = $mainFileName;
$this->_osrmStream = fopen($mainFileName,'w+b');
$this->_nameStream = fopen($mainFileName . '.names','w+b');
$this->_restrictionStream = fopen($mainFileName . '.restrictions','w+b');
}
public static function writeUnsignedInt($fileStream, $uInt)
{
if ((gettype($uInt) == "integer") && ($uInt >= 0) && ($uInt < pow(2,self::$INT_BITS))) {
fwrite($fileStream, pack(self::$UNSIGNED_INT_FORMAT, $uInt));
} else throw new Exception('Unsigned integer ' . $uInt . ": wrong type or invalid range.");
}
public static function writeSignedInt($fileStream, $sInt)
{
if ((gettype($sInt) == "integer") && ($sInt >= -pow(2,(self::$INT_BITS-1))) && ($sInt < pow(2,(self::$INT_BITS-1)))) {
fwrite($fileStream, pack(self::$SIGNED_INT_FORMAT, $sInt));
} else throw new Exception('Signed integer ' . $sInt . ": wrong type or invalid range.");
}
public static function writeUnsignedShort($fileStream, $uInt)
{
if ((gettype($uInt) == "integer") && ($uInt >= 0) && ($uInt < pow(2,self::$SHORT_BITS))) {
fwrite($fileStream, pack(self::$UNSIGNED_SHORT_FORMAT, $uInt));
} else throw new Exception('Unsigned short ' . $uInt . ": wrong type or invalid range.");
}
public static function writeSignedShort($fileStream, $sInt)
{
if ((gettype($sInt) == "integer") && ($sInt >= -pow(2,(self::$SHORT_BITS-1))) && ($sInt < pow(2,(self::$SHORT_BITS-1)))) {
fwrite($fileStream, pack(self::$SIGNED_SHORT_FORMAT, $sInt));
} else throw new Exception('Signed short ' . $sInt . ": wrong type or invalid range.");
}
public static function writeHexCode($fileStream, $hex) // $hex example 0x1A
{
if ((gettype($hex) == "integer") && ($hex >= 0) && ($hex < 256)) {
fwrite($fileStream, chr($hex));
} else throw new Exception('Hexadecimal ' . $hex . ": wrong type or invalid range.");
}
public static function writeString($fileStream, $str)
{
if ((gettype($str) == "string")) {
fwrite($fileStream, $str);
} else throw new Exception('String ' . $str . ": wrong type.");
}
// RESTRICTIONS step 1
public function writeNumberOfRestrictions($number)
{
self::writeUnsignedInt($this->_restrictionStream, $number);
}
// RESTRICTIONS step 2: write restrictions in to-way(!) order
public function writeRestriction($viaNode, $fromNode, $toNode, $isForbidden)
{
self::writeUnsignedInt($this->_restrictionStream, $viaNode);
self::writeUnsignedInt($this->_restrictionStream, $fromNode);
self::writeUnsignedInt($this->_restrictionStream, $toNode);
self::writeHexCode($this->_restrictionStream, ($isForbidden? 0x00: 0x01));
self::writeHexCode($this->_restrictionStream, 0x7F);
self::writeHexCode($this->_restrictionStream, 0x00);
self::writeHexCode($this->_restrictionStream, 0x00);
}
// NAMES step 1
public function writeNumberOfNames($number)
{
self::writeUnsignedInt($this->_nameStream, $number);
}
// NAMES step 2: write names. This function returns the name position.
public function writeName($name)
{
self::writeUnsignedInt($this->_nameStream, strlen($name));
self::writeString($this->_nameStream, $name);
$this->_namePosition++;
return ($this->_namePosition - 1);
}
// DATA step 1
public function writeNumberOfNodes($number)
{
self::writeUnsignedInt($this->_osrmStream, $number);
}
// DATA step 2: write nodes in node id order
public function writeNode($lat, $lon, $id, $bollard, $trafficLight)
{
self::writeSignedInt($this->_osrmStream, (int)(round($lat*100000)));
self::writeSignedInt($this->_osrmStream, (int)(round($lon*100000)));
self::writeUnsignedInt($this->_osrmStream, $id);
self::writeHexCode($this->_osrmStream, ($bollard? 0x01: 0x00));
self::writeHexCode($this->_osrmStream, ($trafficLight? 0x01: 0x00));
self::writeHexCode($this->_osrmStream, 0x00);
self::writeHexCode($this->_osrmStream, 0x00);
}
// DATA step 3
public function writeNumberOfEdges($number)
{
self::writeUnsignedInt($this->_osrmStream, $number);
}
// DATA step 4: write edges in target node id order
public function writeEdge($startNode, $targetNode, $meters, $biDirectional, $seconds, $speedProfilePosition, $namePosition, $roundAbout, $ignoreInGrid, $accessRestricted)
{
self::writeUnsignedInt($this->_osrmStream, $startNode);
self::writeUnsignedInt($this->_osrmStream, $targetNode);
$intMeters = (int)(round($meters));
self::writeSignedInt($this->_osrmStream, ($intMeters == 0? 1 : $intMeters));
self::writeHexCode($this->_osrmStream, ($biDirectional? 0x00: 0x01));
self::writeHexCode($this->_osrmStream, 0x00);
$intSeconds = (int)(round($seconds*10));
self::writeSignedInt($this->_osrmStream, ($intSeconds == 0? 1 : $intSeconds));
self::writeUnsignedShort($this->_osrmStream, $speedProfilePosition);
self::writeUnsignedInt($this->_osrmStream, $namePosition);
self::writeHexCode($this->_osrmStream, ($roundAbout? 0x01: 0x00));
self::writeHexCode($this->_osrmStream, ($ignoreInGrid? 0x01: 0x00));
self::writeHexCode($this->_osrmStream, ($accessRestricted? 0x01: 0x00));
}
public function closeStreams()
{
fclose($this->_osrmStream);
fclose($this->_nameStream);
fclose($this->_restrictionStream);
}
/* OSRM output example
$osrm = new OSRMWriter("test.osrm");
$osrm->writeNumberOfRestrictions(1); // Ordered by to way id !!!
$osrm->writeRestriction(12303, 9100, 999, true);
$osrm->writeNumberOfNames(4);
$osrm->writeName("E17");
$osrm->writeName("E40");
$osrm->writeName("E19");
$osrm->writeName("Sluipweg");
$osrm->writeNumberOfNodes(6); // Ordered by node id !!! !!! !!!
$osrm->writeNode(49.5675, 5.532, 666, false, false); // virton
$osrm->writeNode(51.016001, 5.300446, 999, false, false); // zolder
$osrm->writeNode(51.164, 4.141, 9100, false, false); // sint-niklaas
$osrm->writeNode(50.777, 3.5242, 9600, false, false); // kwaremont
$osrm->writeNode(51.205679, 4.421539, 12303, false, false); // antwerpen
$osrm->writeNode(51.054, 3.705, 12309, false, false); // gent
$osrm->writeNumberOfEdges(7); // ordered by target node id !!!
$osrm->writeEdge(666, 999, 10000, true, 900, 0, 2, false, false, false);
$osrm->writeEdge(12303, 999, 10000, true, 900, 0, 2, false, false, false);
$osrm->writeEdge(12309, 9100, 10000, true, 900, 0, 0, false, false, false);
$osrm->writeEdge(12303, 9100, 10000, true, 900, 0, 0, false, false, false);
$osrm->writeEdge(12309, 9600, 10000, true, 900, 0, 1, false, false, false);
$osrm->writeEdge(9100, 9600, 10000, false, 900, 0, 3, false, false, false);
$osrm->writeEdge(666, 9600, 10000, true, 900, 0, 1, false, false, false);
$osrm->closeStreams();
*/
}
?>