Statens Vegvesen REST API - Routing Service

This document describes the REST API published by Statens Vegvesen for accessing the public Routing Service using data from the National Road Database (NVDB)

Introduction

The REST API exposes routing functionality for calculating routes on the NVDB-database. The API exposes both an OpenLS inherited XML-format and a JSON format

XSD-definition of the xml returned can be found here:
RouteplanningMessages-1.xsd
OpenLS.xsd (Extended)

Contents

Audience

This document is intended for website and mobile developers who want to use compute direction data. It provides an introduction to using the API and reference material on the available parameters.

Usage Limits

Use of the API is subject to a query limit of 2,500 directions requests per day. Individual directions requests may contain up to 8 intermediate waypoints in the request.

Authentication

All requests to the API (including fetching the REST documentation) must be accompanied by the appropriate HTTP basic auth headers (retreive your username and password by contacting ruteplan (at) vegvesen.no ).

New and more web-friendly authentication will (hopefully) be availabe soon, Good and our IT department willing.

CoordinateSystem

Input and output coordinates are expressed in the ETRS89 / UTM zone 33N coordinate system (EPSG:25833).

This is very similar to WGS84 / UTM zone 33N (EPSG:32633). For many practical applications – including this service – the difference is so small you can ignore it, typically less than half a meter. For route finding applications you can happily use both EPSG:32633 and EPSG:25833 as if they were the same.

Directions Requests

The service is documented as a WADL definition that can be retreived here

A Directions API request is an HTTP URL of the following form:

https://www.vegvesen.no/ws/no/vegvesen/ruteplan/routingservice_v2_0/routingservice/?parameters

Request Parameters

Certain parameters are required while others are optional. As is standard in URLs, all parameters are separated using the ampersand (&) character. The list of parameters and their possible values are enumerated below.
The Rourint API defines a routing request using the following URL parameters:

Example of a typical request with all parameters set:

    https://www.vegvesen.no/ws/no/vegvesen/ruteplan/routingservice_v2_0/routingservice/?stops=277648.71063131,6760327.2812364;292465.40693137,6695768.8187861&returnDirections=true&returnGeometry=true&lang=en-US&format=xml&streetname_hints=Vibes%20gate;Bygate;Kongens%20gate

Alternative routes

When using the route_type alternative three different route-suggestions are returned as alternatives for the given start and stop point. For an alternative to be considered valid there are some rules specifying how much longer travel time a route can have against the fastest route and how much different it must be compared to the others.

Route statistics

The result contains statistics about the given route in the RouteSummary-element. Statistics is TotalDistance, TotalTime, Envelope of the route and Accumulated properties.
Accumulated properties
The results contain these Accumulated properties for the route

  • TotalTollLarge - Total toll fee (accounting for discount rules) travelling the route without stops with a large vehicle (truck or bus)
  • TotalTollSmall - Total toll fee (accounting for discount rules) travelling the route without stops with a small vehicle (car)
  • TotalTollLargeWithoutDiscount - Sum of toll fees (not accounting for discount rules) travelling the route with a large vehicle (truck or bus)
  • TotalTollSmallWithoutDiscount - Sum toll fees (not accounting for discount rules) travelling the route with a small vehicle (car)
  • Compressed geometry

    Compressed geometries (on RouteInstruction/CompressedGeometry and RouteGeometry/CompressedGeometry) are generated according to ESRI:s open specification of Compressed Geometries.


    C# code for decompressing compressed geometry

    public class XY
    {
        public double x;
        public double y;
    }
    public class XYZ : XY
    {
        public double z;
    }
    
    private char[] m_abc = {'0','1','2','3','4','5','6','7','8','9',
                'a','b','c','d','e','f','g','h','i','j',
                'k','l','m','n','o','p','q','r','s','t','u','v'};
    
    public XY[] ExtractPointsFromCompressedGeometry(System.String compresedGeometry)
    {
        // initialize result storage
        System.Collections.Generic.List points = new System.Collections.Generic.List();
        int flags = 0;
    
        int nIndex_XY = 0;
        int nIndex_Z = 0;
        double dMultBy_XY = 0;
        double dMultBy_Z = 0;
    
        // Versions before 9.3 doesn't have support for z. 
        // If first element is 0 we can harvest z from the compressed geometry
        int firstElement = ExtractInt(compresedGeometry, ref nIndex_XY);
        if (firstElement == 0) //post 9.3 format
        {
            int version = ExtractInt(compresedGeometry, ref nIndex_XY);
            flags = ExtractInt(compresedGeometry, ref nIndex_XY);
            dMultBy_XY = (double)ExtractInt(compresedGeometry, ref nIndex_XY);
        }
        else
            dMultBy_XY = (double)firstElement;
    
        int nLength;
        if (flags == 0)
            nLength = compresedGeometry.Length; // reduce call stack
        else
        {
            nLength = compresedGeometry.IndexOf('|');
            if ((flags & 1) == 1) //has Zs
            {
                nIndex_Z = nLength + 1;
                dMultBy_Z = (double)ExtractInt(compresedGeometry, ref nIndex_Z);
            }
        }
        int nLastDiffX = 0;
        int nLastDiffY = 0;
        int nLastDiffZ = 0;
        while (nIndex_XY != nLength)
        {
            //X
            int nDiffX = ExtractInt(compresedGeometry, ref nIndex_XY);
            int nX = nDiffX + nLastDiffX; // decompress
            nLastDiffX = nX;
            double dX = (double)nX / dMultBy_XY;
            //Y
            int nDiffY = ExtractInt(compresedGeometry, ref nIndex_XY);
            int nY = nDiffY + nLastDiffY; // decompress
            nLastDiffY = nY;
            double dY = (double)nY / dMultBy_XY;
    
            if ((flags & 1) == 1) //has Zs
            {  //Z
                int nDiffZ = ExtractInt(compresedGeometry, ref nIndex_Z);
                int nZ = nDiffZ + nLastDiffZ; // decompress
                nLastDiffZ = nZ;
                double dZ = (double)nZ / dMultBy_Z;
    
                XYZ point = new XYZ() { x = dX, y = dY, z = dZ };
                        
                // add result item
                points.Add(point);
            }
            else {
                XY point = new XY() { x = dX, y = dY };
                        
                // add result item
                points.Add(point);
            }
        }
    
        return points.ToArray();
    }
    
    // Read one integer from compressed geometry string by using passed position
    // Returns extracted integer, and re-writes nStartPos for the next integer
    private int ExtractInt(string src, ref int nStartPos)
    {
        bool bStop = false;
        System.Text.StringBuilder result = new System.Text.StringBuilder();
        int nCurrentPos = nStartPos;
        while (!bStop)
        {
            char cCurrent = src[nCurrentPos];
            if (cCurrent == '+' || cCurrent == '-' || cCurrent == '|')
            {
                if (nCurrentPos != nStartPos)
                {
                    bStop = true;
                    continue;
                }
            }
            result.Append(cCurrent);
            nCurrentPos++;
            if (nCurrentPos == src.Length) // check overflow
                bStop = true;
        }
        int nResult = int.MinValue;
        if (result.Length != 0)
        {
            nResult = FromStringRadix32(result.ToString());
            nStartPos = nCurrentPos;
        }
        return nResult;
    }
    
    // Sample input and output: +1lmo -> 55000
    private int FromStringRadix32(string s) // exception
    {
        int result = 0;
        for (int i = 1; i < s.Length; i++)
        {
            char cur = s[i];
            System.Diagnostics.Debug.Assert((cur >= '0' && cur <= '9') || (cur >= 'a' && cur <= 'v'));
            if (cur >= '0' && cur <= '9')
                result = (result << 5) + System.Convert.ToInt32(cur) - System.Convert.ToInt32('0');
            else if (cur >= 'a' && cur <= 'v')
                result = (result << 5) + System.Convert.ToInt32(cur) - System.Convert.ToInt32('a') + 10;
            else throw new System.ArgumentOutOfRangeException(); // exception
        }
        if (s[0] == '-')
            result = -result;
        else if (s[0] != '+')
            throw new System.ArgumentOutOfRangeException(); // exception
        return result;
    }
    

    Routing Responses

    XML output

    A sample HTTP request is shown below, calculating the route from FLESAKERVEGEN, HAMAR to SMESTADGUTUA, EIDSVOLL

    https://www.vegvesen.no/ws/no/vegvesen/ruteplan/routingservice_v2_0/routingservice/?stops=277648.71063131,6760327.2812364;292465.40693137,6695768.8187861&returnDirections=true&returnGeometry=true&format=xml

    The XML returned by this request is shown below.

    
    <?xml version="1.0"?>
    <RouteResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:no:vegvesen:geodata:routeplanning:messages:RoutePlanningMessages-1">
          <RouteSummary xmlns="http://www.opengis.net/xls">
                <TotalDistance value="79028.2664547377" />
                <TotalTime value="77.5722737024577" />
                <RouteEnvelope minx="277604.30000279" miny="6695575.00012278" maxx="298017.59009041" maxy="6760785.91012249" />
                <AccumulatedProperties>
                    <AccumulatedProperty PropertyName="TotalTollLarge" Value="0"/>
                    <AccumulatedProperty PropertyName="TotalTollSmall" Value="0"/>
                    <AccumulatedProperty PropertyName="TotalTollLargeWithoutDiscount" Value="0"/>
                    <AccumulatedProperty PropertyName="TotalTollSmallWithoutDiscount" Value="0"/>
                </AccumulatedProperties>
          </RouteSummary>
          <RouteGeometry xmlns="http://www.opengis.net/xls">
                <LineString srsName="urn:ogc:def:crs:EPSG:6.6:32633" id="p1">
                      <pos dimension="2">277685.5 6760533</pos>
                      <pos dimension="2">277606.3 6760610.6</pos>
                      <pos dimension="2">277604.3 6760633.1</pos>
                      ...
                      <pos dimension="2">292476.9 6695711</pos>
                      <pos dimension="2">292502.7 6695752.2</pos>
                      <pos dimension="2">292504.1 6695764.6</pos>
                </LineString>
          </RouteGeometry>
          <RouteInstructionsList lang="en-US" xmlns="http://www.opengis.net/xls">
                <RouteInstruction duration="-P0Y0M0DT0H0M0S">
                      <Instruction>Start at Location 1</Instruction>
                      <CompressedGeometry>+1+8f5m+6ea2l+0+0</CompressedGeometry>
    		  <ManeuverType>Depart</ManeuverType>
                      <distance value="0" />
                </RouteInstruction>
                <RouteInstruction duration="P0Y0M0DT0H0M47.0838799S">
                      <Instruction>Go north on skogsbilsveg toward privat veg</Instruction>
                      <CompressedGeometry>+1+8f5m+6ea2l-2g+2e-2+m+k+1s</CompressedGeometry>
                      <ManeuverType>Straight</ManeuverType>
                      <distance value="0.19618283318196" />
                </RouteInstruction>
                ...
                <RouteInstruction duration="P0Y0M0DT0H2M54.4035258S">
                      <Instruction>Continue on E6</Instruction>
                      <CompressedGeometry>+1+8tfo+6cgge-12-j-10+6-b+6-a-7-16-f-9m-8a-5h-5l-25-2h-2u-3s-45-6e-2p-5a-1m-3r-1i-42-15-3i-ap-14e-8-7-1h-46-l-12-1i-1f</CompressedGeometry>
                      <ManeuverType>Straight</ManeuverType>
                      <distance value="3.37011644170256" />
                      <Attributes>
                            <Attribute id="vegloggen:38241">
                                  <AttributeType>vegloggen:Midlertidig stengt</AttributeType>
                                  <Values>
                                        <Value key="ingress" value="Stengt på grunn av vegarbeid. Omkjøring er skiltet. Gjelder fra 31.03.2011 klokken 21:00 til 14.04.2011 klokken 05:30." />
                                        <Value key="heading" value="Minnesund - Hamar (Ny Minnesund bru)" />
                                        <Value key="urgency" value="X" />
                                        <Value key="roadType" value="Ev" />
                                        <Value key="roadNumber" value="6" />
                                  </Values>
                                  <Locations>
                                        <Location northing="6701250.0754337274" easting="291798.22438834608" SRS="EPSG:32633" />
                                        <Location northing="6701250.0754337274" easting="291798.22438834608" SRS="EPSG:32633" />
                                  </Locations>
                            </Attribute>
                      </Attributes>
                </RouteInstruction>
                ...
                <RouteInstruction duration="-P0Y0M0DT0H3M34.7483648S">
                      <Instruction>Continue on Rv19</Instruction>
                      <CompressedGeometry>+1+7njp+699bl-3-14-dr-jt-gt-m0-13h-nn-1ku-hn-11v+i-1ae+1s-35b+17d</CompressedGeometry>
                      <distance value="10.7789670770843" />
                      <ManeuverType>Stop</ManeuverType>
                      <Attributes>
                            <Attribute>
                                  <AttributeType>nvdb:Vegtype</AttributeType>
                                  <Values>
                                        <Value key="type" value="FERGE" />
                                  </Values>
                            </Attribute>
                            <Attribute>
                                  <AttributeType>nvdb:Ferge</AttributeType>
                                  <Values>
                                        <Value key="Navn" value="07-230" />
                                        <Value key="URL" value="http://ferje.websrv02.reiseinfo.no/ruter/t/07-230.htm" />
                                  </Values>
                            </Attribute>
                      </Attributes>
                </RouteInstruction>
                ...
                <RouteInstruction duration="-P0Y0M0DT0H0M0S">
                      <Instruction>Finish at Location 2, on the left</Instruction>
                      <CompressedGeometry>+1+8tko+6caql+0+0</CompressedGeometry>
                      <ManeuverType>Straight</ManeuverType>
                      <distance value="0" />
                </RouteInstruction>
          </RouteInstructionsList>
    </RouteResponse>
    
    

    JSON output

    A sample HTTP request is shown below, calculating the route from Moss to Horten, OK:

    https://www.vegvesen.no/ws/no/vegvesen/ruteplan/routingservice_v2_0/routingservice/?stops=255705,6596507;241697,6596651&returnDirections=true&returnGeometry=true&format=json

    The JSON result is shown below. Because directions results can be quite verbose, repeated elements within the response have been omitted for clarity.

    
    {
       "directions":[
          {
             "features":[
                {
                   "attributes":{
                      "ETA":-2209161600000,
                      "length":0,
                      "maneuverType":"esriDMTDepart",
                      "roadFeatures":[
    
                      ],
                      "text":"Start at Location 1",
                      "time":0
                   },
                   "compressedGeometry":"+1+7cuc+699f7+0+0"
                },
                {
                   "attributes":{
                      "ETA":-2209161600000,
                      "length":10.7789670770843,
                      "maneuverType":"esriDMTBearLeft",
                      "roadFeatures":[
                         {
                            "attributeType":"nvdb:Vegtype",
                            "values":[
                               {
                                  "key":"type",
                                  "value":"FERGE"
                               }
                            ]
                         },
                         {
                            "attributeType":"nvdb:Ferge",
                            "values":[
                               {
                                  "key":"Navn",
                                  "value":"07-230"
                               },
                               {
                                  "key":"URL",
                                  "value":"http:\/\/ferje.websrv02.reiseinfo.no\/ruter\/t\/07-230.htm"
                               }
                            ]
                         }
                      ],
                      "text":"Bear left on Rv19",
                      "time":49.5832485545877
                   },
                   "compressedGeometry":"+1+7ean+69811+35b-17d+1ae-1s+11v-i+1ku+hn+13h+nn+gt+m0+dr+jt+3+14"
                },
                {
                   "attributes":{
                      "ETA":-2209161600000,
                      "length":0,
                      "maneuverType":"esriDMTStop",
                      "roadFeatures":[
    
                      ],
                      "text":"Finish at Location 2, on the left",
                      "time":0
                   },
                   "compressedGeometry":"+1+7mm8+699pb+0+0"
                }
             ],
             "routeId":1,
             "routeName":"Location 1 - Location 2",
             "summary":{
                "envelope":{
                   "xmax":253604.000003007,
                   "xmin":242628.400003141,
                   "ymax":6596425.10012316,
                   "ymin":6593253.60012317
                },
                "totalDriveTime":55.7109598962278,
                "totalLength":15.4397134926439,
                "totalTime":55.7
             }
          }
       ],
       "routes":{
          "features":[
             {
                "attributes":{
                   "Name":"Location 1 - Location 2",
                   "ObjectID":1,
                   "Shape_Length":15439.4895014742,
                   "Total_DriveTime tourist":0,
                   "Total_Meters":15439.7134926438,
                   "Total_Minutes":55.7109598962278,
                   "Total_Toll large":0,
                   "Total_Toll small":0,
                   "Total_Toll_Without_Discount large":0,
                   "Total_Toll_Without_Discount small":0
                },
                "geometry":{
                   "paths":[
                      [
                         [
                            253021.1,
                            6596406.9001
                         ],
                         [
                            252971.5,
                            6596405.6001
                         ]
                      ]
                   ]
                }
             }
          ]
       }
    }
    
    

    Matrix Requests (One to Many)

    The Matrix API answers requests on a HTTP URL of the following form:

    https://www.vegvesen.no/ws/no/vegvesen/ruteplan/routingservice_v2_0/routingservice/?parameters

    Matrix Request Parameters

    Certain parameters are required while others are optional. As is standard in URLs, all parameters are separated using the ampersand (&) character. The list of parameters and their possible values are enumerated below.
    The Matrix API defines a routing request using the following URL parameters:

    Example of a typical request with all parameters set:

            https://www.vegvesen.no/ws/no/vegvesen/ruteplan/routingservice_v2_0/routingservice/?from=260835,6650766&stops=229155,6630427;232248,6623853;267803,6626733;281425,6675976;260284,6714506&format=json&route_type=best
        

    JSON output

    The resposne to the above request looks like

        
            {
                "results": [
                    {
                        "distanceMeters": 48851,
                        "durationSeconds": 2974,
                        "toStopIndex": 0,
                        "toStopLocation": {
                            "X": 229155,
                            "Y": 6630427
                        }
                    },
                    {
                        "distanceMeters": 48917,
                        "durationSeconds": 2504,
                        "toStopIndex": 1,
                        "toStopLocation": {
                            "X": 232248,
                            "Y": 6623853
                        }
                    },
                    {
                        "distanceMeters": 31956,
                        "durationSeconds": 2056,
                        "toStopIndex": 2,
                        "toStopLocation": {
                            "X": 267803,
                            "Y": 6626733
                        }
                    },
                    {
                        "distanceMeters": 45657,
                        "durationSeconds": 2883,
                        "toStopIndex": 3,
                        "toStopLocation": {
                            "X": 281425,
                            "Y": 6675976
                        }
                    },
                    {
                        "distanceMeters": 85783,
                        "durationSeconds": 5025,
                        "toStopIndex": 4,
                        "toStopLocation": {
                            "X": 260284,
                            "Y": 6714506
                        }
                    }
                ]
            }
        
    

    XML output

    The resposne to the above request looks like

        
            <MatrixResult xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
                <Results>
                    <MatrixResultRow>
                        <ToStopIndex>0</ToStopIndex>
                        <DurationSeconds>2974</DurationSeconds>
                        <DistanceMeters>48851</DistanceMeters>
                        <ToStopLocation>
                            <X>229155</X>
                            <Y>6630427</Y>
                        </ToStopLocation>
                    </MatrixResultRow>
                    <MatrixResultRow>
                        <ToStopIndex>1</ToStopIndex>
                        <DurationSeconds>2504</DurationSeconds>
                        <DistanceMeters>48917</DistanceMeters>
                        <ToStopLocation>
                            <X>232248</X>
                            <Y>6623853</Y>
                        </ToStopLocation>
                    </MatrixResultRow>
                    <MatrixResultRow>
                        <ToStopIndex>2</ToStopIndex>
                        <DurationSeconds>2056</DurationSeconds>
                        <DistanceMeters>31956</DistanceMeters>
                        <ToStopLocation>
                            <X>267803</X>
                            <Y>6626733</Y>
                        </ToStopLocation>
                    </MatrixResultRow>
                    <MatrixResultRow>
                        <ToStopIndex>3</ToStopIndex>
                        <DurationSeconds>2883</DurationSeconds>
                        <DistanceMeters>45657</DistanceMeters>
                        <ToStopLocation>
                            <X>281425</X>
                            <Y>6675976</Y>
                        </ToStopLocation>
                    </MatrixResultRow>
                    <MatrixResultRow>
                        <ToStopIndex>4</ToStopIndex>
                        <DurationSeconds>5025</DurationSeconds>
                        <DistanceMeters>85783</DistanceMeters>
                        <ToStopLocation>
                            <X>260284</X>
                            <Y>6714506</Y>
                        </ToStopLocation>
                    </MatrixResultRow>
                </Results>
            </MatrixResult>
        
    

    Features in respons data

    Attribute types and its values are listed in the table below:

    AttributeType Value1 Value2 Value3 Value4 Value5 Value6 Value7 Value8
    vegloggen:Trafikkmelding key:DESCRIPTION, Description of the event key:LOCATION_DESCRIPTION, Description of the affected road key:RECORD_SECONDARY_TYPE, Message Type according to DatexII standard key:COUNTY_NUMBER, County-number for the actal message key:ROAD_NUMBER, Roadnumber key:SITUATION_ID, Identifier for the message, same as in DatexII key:OVERALL_START_TIME, From when the message is valid key:OVERALL_END_TIME, To when the message is valid
    vegloggen:Trafikkmelding is a general attribute type for all traffic messages. Sometimes a more detailed classification is given. That can be any of [vegloggen:Midlertidig stengt, vegloggen:Nattestengt, vegloggen:Vinterstengt, vegloggen:Kolonnekjøring, vegloggen:Åpen for trafikk, vegloggen:Redusert framkommelighet, vegloggen:Trafikkflyt, vegloggen:Vær- og føreforhold]
    reisetid key:forsinkelse, Current estimated TravelTime delay
    nvdb:Vegtype key:type, Values can be (FERGE, TURISTVEG, ATK-STREKNING)
    nvdb:Bomstasjon key:Navn, Name of the toll station key:TakstLitenBil, Toll for a small vehicle key:TakstStorBil, Toll for a large vehicle key:Autopass, Whether or not it is possible to pass the toll station with an autopass
    nvdb:Ferge key:Navn, Name of the route key:Url, Url to the timetable
    nvdb:Rasteplass key:Navn, Name of the rest stop
    nvdb:ATK-Punkt Traffic camera
    nvdb:Turistveg key:Navn, Name of the road key:Url, Url where more information can be found about the road

    Example:

    
      <Attribute>
        <AttributeType>vegloggen:Trafikkmelding</AttributeType>
        <Values>
          <Value key="RECORD_ID" value=""/>
          <Value key="SITUATION_ID" value=""/>
          <Value key="COUNTY_NUMBER" value=""/>
          <Value key="ROAD_NUMBER" value=""/>
          <Value key="OVERALL_START_TIME" value=""/>
          <Value key="OVERALL_END_TIME" value=""/>
          <Value key="DESCRIPTION" value=""/>
          <Value key="LOCATION_DESCRIPTION" value=""/>
          <Value key="RECORD_SECONDARY_TYPE" value=""/>
        </Values>
      </Attribute>
      
      <Attribute>
        <AttributeType>nvdb:Bomstasjon</AttributeType>
        <Values>
          <Value key="Navn" value=""/>
          <Value key="TakstLitenBil" value=""/>
          <Value key="TakstStorBil" value=""/>
          <Value key="Autopass" value=""/>
        </Values>
      </Attribute>
      
      <Attribute>
        <AttributeType>nvdb:Vegtype</AttributeType>
        <Values>
          <Value key="type" value="FERGE" />
          <Value key="type" value="TURISTVEG" />
        </Values>
      </Attribute>