In the previous traffic-based tutorial Integrating Historical Traffic Data we demonstrated how to add and use HERE historical traffic data in a simple routing application.

This tutorial will present a simple map control and a checkbox to toggle HERE's real-time traffic on and off. When the checkbox in this tutorial is checked, the application will download the latest real-time traffic data ( http://traffic.geobase.info/NAVTEQLAXRealTimeTraffic.xml.gz.), decompress the file, and then render the updated traffic data on to the map. For a comprehensive description of GeoBase traffic features please refer to the GeoBase API documentation. This documentation is included with your GeoBase installation and is also available online: http://docs.geobase.info/.

Prerequisites

This tutorial assumes familiarity with Microsoft Visual Studio. You will need a copy of Visual Studio 2005 or later and a moderately specified desktop computer. You will need a licensed copy of the GeoBase SDK. A 30-day free-of-charge trial may be downloaded from the GeoBase developer portal: http://geozone.geobase.info/. Two versions of the trial SDK are available, one loaded with US (West Coast) map data, the other version loaded with map data for UK and Ireland.

In this tutorial we will use the ICSharpCode.SharpZipLib assembly to decompress traffic source files downloaded from the internet. If you want to use this assembly you can download the library from the ICSharpCode website: http://www.icsharpcode.net/OpenSource/SharpZipLib/Default.aspx.

Introduction

Combining GeoBase with NAVTEQ's real-time traffic data, a traffic layer can be displayed on a map (see image below) with colored links indicating the average traffic speed (red = slowest, green = fastest).

The average traffic speed along any link, is among other factors, dependent on the day of the week, and the time of the day. The speed of a link is expressed by coloring the link according to the average speed of vehicles, at a specific time, at a fraction of the link's speed limit. The relationships are:

  • Red <31% of speed limit
  • Orange <62% of speed limit
  • Yellow <92% of speed limit
  • Green >=92% of speed limit

GeoBase supports NAVTEQ's incident, predictive, and real-time traffic data. The traffic data files (or 'sources'), may be already stored on a local machine, or downloaded when required from the internet. Either way, GeoBase provides a number of classes to assist with both loading these files and rendering the traffic data onto a map control. These classes include:

  • Traffic - a collection of traffic sources
  • TrafficFetcher - used to retrieve up-to-date Traffic objects
  • TrafficRenderer - used to render a Traffic object on to a map control

Traffic Class

A Traffic object is a collection of one or more traffic sources (where each source implements the ITrafficSource interface), which may be queried to determine the speed of traffic along a given link using the GetSpeed() method. The speed value returned using the GetSpeed() method will be the lowest value found for the given link ID and time.

If more than one traffic source is specified, the traffic sources will be searched in order of priority, which is simply the order in which the traffic sources are listed when implementing the ITrafficSource collection.

ITrafficSource Interface

The ITrafficSource interface is implemented to resolve a given TMC (Traffic Message Channel) code and DateTime to a TrafficInfo. GeoBase provides classes with implementations of this interface in support of the following traffic data:

  • Incident - NavteqIncidentTrafficSource
  • Predictive - NavteqPredictiveRealTimeTrafficSource
  • Real-time - NavteqRealTimeTrafficSource

Additional traffic data sources can be added to your application with the ITrafficSource interface. The interface exposes the GetTrafficInfo() method, and the CreatedTime property. To implement this interface, code must be provided for both GetTrafficInfo() and CreatedTime.

  • GetTrafficInfo() - return the TrafficInfo for the given TMC code at the specified DateTime. The speed can be found from the traffic source data by searching for the given TMC code with the given time, and then extracting the speed from the found TMC code.
  • CreatedTime - get the DateTime for when the traffic data was created. 

TrafficFetcher Class

The TrafficFetcher class is used to retrieve an up-to-date Traffic object based on traffic information from the Traffic's sources. The class exposes the AddSource() and GetLatestTraffic() methods. Use the AddSource() method to populate the TrafficFetcher’s list with the traffic’s sources, and GetLatestTraffic() to obtain the latest data.

It should be noted though, that the TrafficFetcher does not automate the process of obtaining an updated Traffic, but instead, provides the GetLatestTraffic() method, which can be called synchronously, or asynchronously. These methods are described in more detail, below:

To add a traffic source to a trafficFetcher's list, use the AddSource() method. Repeat this method call for the number of sources you wish to add. AddSource() is an overloaded method – for this tutorial, we’ll use the following signature:

public void AddSource (string url, Type type, TimeSpan timeRange, HandleDataDelegate zipFunction)

The parameters are as follows:

  • url - the URL from which to obtain the data
  • type - the type of the traffic source (for example: NavteqRealTimeTrafficSource, or NavteqIncidentTrafficSource )
  • timeRange - the amount of time that the traffic data from the traffic source is valid for, before an update is required
  • zipFunction - the function to call when the compressed data is received

To retrieve the latest Traffic, use the GetLatestTraffic() method. This is an overloaded method – for this tutorial, we’ll use the following signature:

public Traffic GetLatestTraffic (DateTime RoutingTime, bool blocking, TimeSpan timeout)

The parameters are as follows:

  • RoutingTime - the date/time to retrieve the traffic data for
  • blocking – true (synchronous) / false (asynchronous mode)
  • timeout - the maximum time to wait (block) for the traffic sources to be updated. Set to -1 to wait indefinetely - not required if blocking is set to false.

For synchronous mode, set blocking to true. In this mode the Traffic object will not be returned until all the ITrafficSources have been updated, or the timeout time has elapsed. For asynchronous mode set blocking to false and wait until the TrafficUpdated event is called, signaling that the ITrafficSource data has been updated.

TrafficRenderer Class

The TrafficRenderer is used to render a traffic object on to a map control. The TrafficRenderer is created with the most recent Traffic object, and then simply added to the map’s RendererList, which will take care of rendering the traffic data onto the map.

Putting it all together

As mentioned in the introduction, this tutorial application will:

  1. download the latest real-time traffic data
  2. decompress the file
  3. render the updated traffic data on to the map. To achieve this we’ll need to create a Traffic object, a TrafficFetcher object and a RendererList object.  We'll then need to add the Traffic’s sources to the TrafficFetcher’s list (just one source in this case), using the TrafficFetcher’s AddSource() method. Then we can download the latest traffic data using the TrafficFetcher’s GetLatestTraffic() method and decompress the data.
  4. With the newly created Traffic, we’ll create a new TrafficRenderer and add it to the RendererList which will take care of rendering the traffic onto the map.

Creating the project

  1. Open a new instance of Visual Studio, create a C# Windows Forms Application and add geobase.net.dll as a reference.
  2. Add geobase.dll to the project, and set the "Copy to output" property to "copy if newer".
  3. If you are using the ICSharpCode.SharpZipLib assembly to decompress the received files, add the ICSharpCode.SharpZipLib.dll as a reference .

Design the form

In the Visual Studio design view add a map control and a check box to the form, similar to the image below. Set the properties of the map control, and check box as per the list below. The CenterLat, and CenterLon properties position the map over the Los Angeles area.

Set the following properties:

Form1

  • Text = "Real-Time Traffic Data"

MapCtrl

  • Name = mapCtrl
  • CenterLat = 34
  • CenterLon = -118
  • Zoom = 100

CheckBox

  • Name = trafficEnabled
  • Checked = false
  • Text = "Real-time Traffic Data"

Add the code

Open the code view, and add the following 'using' statements:

using System.IO;
using Telogis.GeoBase;
using Telogis.GeoBase.Traffic;

We will be using the following GeoBase classes: Traffic, TrafficFetcher, and RendererList. Remember that the TrafficFetcher exposes two methods: AddSource(), and GetLatestTraffic(). We will use the AddSource() method to add the Traffic’s source to the TrafficFetcher’s list, and the GetLatestTraffic() method to provide the latest traffic data update from the list of ITrafficSources. When we get updated traffic data, we will add it to the RendererList. Add the following declarations:

TrafficFetcher trafficFetcher; 
Traffic traffic; 
RendererList trafficRendererList;

Create new instances of the TrafficFetcher and the RendererList, and add the event handler for the TrafficUpdated event. We’ll also add the traffic source at this point using the AddSource() method. In the form's constructor, add:

trafficFetcher = new TrafficFetcher(); 
trafficFetcher.AddSource(
    "http://traffic.geobase.info/NAVTEQLAXRealTimeTraffic.xml.gz",//source 
    typeof(NavteqRealTimeTrafficSource), //type of source
    TimeSpan.FromMinutes(15), //valid time before update permitted 
    new HandleDataDelegate(Unzip) //function to call when data arrives 
); 

trafficRendererList = new RendererList(); 
trafficFetcher.TrafficUpdated += new EventHandler(trafficFetcher_TrafficUpdated);

Add the event handler code for the TrafficUpdated event. This will call the map control's 'Invalidate()' method which will force the map to be redrawn whenever we receive updated traffic data.

void trafficFetcher_TrafficUpdated(object sender, EventArgs e){ 
    //Redraw map when update is received mapCtrl.
    Invoke(new MethodInvoker(mapCtrl.Invalidate));
}

If the checkbox is checked then we need to set the 'trafficRendererList' as the IMapRenderer for the map control, and call the getTraffic() method to download the latest traffic data. Add the checkbox's 'checkChanged' event handler:

private void trafficEnabled_CheckedChanged(object sender, EventArgs e){ 
    if (trafficEnabled.Checked == true) { 
        //Set the mapCtrl to use the trafficRendererlist;
        mapCtrl.Renderer = trafficRendererList; 
        //Add the traffic layer to the map 
        getTraffic(); 
    } else{ 
        //Clear out the trafficRendererlist
        trafficRendererList.Clear(); 
        //Redraw the map without the traffic layer
        mapCtrl.Invalidate(); 
    } 
}

The getTraffic() method is responsible for:

  • getting the latest traffic data from the list of sources
  • adding the TrafficRenderer to the trafficRendererList

Add the getTraffic() method: 

private void getTraffic(){ 
    //Get the latest traffic data update from the list of ITrafficSources, 
    //based on the given date/time. 
    traffic = trafficFetcher.GetLatestTraffic( DateTime.Now, true, TimeSpan.FromSeconds(5)); 
    //Add to the rendererlist 
    trafficRendererList.Add(new TrafficRenderer(traffic, DateTime.Now)); 
}

Finally we'll add the Unzip() method to deal with decompressing the latest traffic data - remember that Unzip was the last parameter in the AddSource() method. Add the following code for Unzip():

static Stream Unzip(Stream input){ 
    //Unzip the file 
    MemoryStream memStream = new MemoryStream(); 
    ICSharpCode.SharpZipLib.GZip.GZipInputStream gzipStream = new ICSharpCode.SharpZipLib.GZip.GZipInputStream(input); 

    byte[] data = new byte[2048]; 

    while (true){ 
        int size = gzipStream.Read(data, 0, data.Length); 
        if (size > 0) memStream.Write(data, 0, size); 
        else break; 
    } 

    memStream.Seek(0, SeekOrigin.Begin); 
    return memStream; 
}

Testing

Build and run your application. In the first instance you'll be presented with a map centered on Los Angeles. Check the checkbox to add the real-time traffic layer.

 

Published, Jul 7th 2016, 22:30

Tagged under: dotnet traffic geobase routing maps