Introduction
This tutorial will demonstrate how to add and use historical traffic data in a simple routing application. The user will be able to create a route, and then compare how the route can differ due to traffic variations over different days, and times of day.
Traffic Data
Combining GeoBase with traffic data, a traffic layer can be displayed on a map (see figure below) with colored links indicating the average traffic speed (red = slowest, green = fastest). GeoBase supports a number of traffic data sources, including Inrix (incident, predictive, and real-time), and NAVTEQ (incident, predictive, and real-time).
.png)
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 table below shows the relationship:
| Color | Fraction of speed limit |
| Red | <31% |
| Orange | <62% |
| Yellow | <92% |
| Green | >=92% |
In this tutorial, we will use GeoBase's Traffic, and TrafficFetcher classes. A Traffic object is a collection of traffic data sources, implemented with the ITrafficSource interface, which can be used to create optimum routes with respect to traffic conditions for a specific date and time of day. The TrafficFetcher is used to retrieve up-to-date Traffic objects, based on information from the Traffic's sources.
Prerequisites
This tutorial relies on historical traffic data files; sample data can be found here, on the Sample Data page: select the Traffic product "USA Pac West Traffic - 2009 Q1 - GBv3.0".
Setting Up
Download an example historical data file (see Prerequisites above).
Open a new instance of Visual Studio, and add geobase.net.dll as a reference.
Add geobase.dll, and set to "copy if newer".
Design the form
Create the form to look similar to that of the figure below. Notice the blank label in the bottom-left-hand corner. This will be used to display the time and distance - set the AutoSize property to True.

Name and set the controls as per the table below:
| Control |
Name | Properties |
| MapCtrl | mapCtrl | |
| TextBox | textBoxFilename | ReadOnly = true |
| CheckBox | trafficEnabled | Text = "Use Traffic Data:", Checked = false, Enabled = false |
| Button | buttonBrowse | Text = "Browse..." |
| DateTimePicker | dateCtrl | Format = Short |
| DateTimePicker | timeCtrl | Format = Time, ShowUpDown = true |
| Label | labelTimeAndDistance | (no text), AutoSize = True |
| Label | filenameLabel | Text = "Historical Data:" |
Add a right-click context menu and give it the name 'ContextMenuStrip'.The context menu will provide the following three options:
- Add Stop – add route stops at the position of the mouse pointer
- Clear Route – remove all stops, and the displayed route from the map
- Get Directions – display the route on the map, and calculate time and distance

Rename the menu items:
- Add Stop – 'addStopToolStripMenuItem'
- Clear Route – 'clearRouteToolStripMenuItem'
- Get Directions – 'getDirectionsToolStripMenuItem'
Open the code view, and add the following 'using' statements:
using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Windows.Forms; using Telogis.GeoBase; using Telogis.GeoBase.Routing; using Telogis.GeoBase.Traffic;
Along with the routes, the traffic data is added to the map control as a layer. Add the following declarations:
//Renderers private Route route; private RendererList directionsRendererList; private RendererList trafficRendererList; private DateTime routingTime;
And in the form's constructor, add:
// Set up route route = new Route(); routingTime = DateTime.Now; // Set up renderers directionsRendererList = new RendererList(); trafficRendererList = new RendererList(); RendererList rendererList = new RendererList(); rendererList.Add(route); rendererList.Add(directionsRendererList); rendererList.Add(trafficRendererList); mapCtrl.Renderer = rendererList;
Whenever the 'Browse...' button is pressed, an OpenFileDialog will open, and the user can select a historical traffic data file (*.gbhb). We will then create a TrafficFetcher object, and assign the 'gbhb' file as the TrafficFetcher’s source. Once the file has been selected, we'll check the 'trafficEnabled' check box as well so that the application will incorporate the traffic data into the route calculation.
Add the following declarations:
private TrafficFetcher trafficFetcher; private Traffic traffic; private LatLon clickLocation;
Create a buttonBrowse_Click event handler:
void buttonBrowse_Click(object sender, EventArgs e) {
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Historical Traffic Files (*.gbhb)|*.gbhb|All files (*.*)|*.*";
ofd.Title = "Select Historical Traffic File";
if (ofd.ShowDialog() == DialogResult.OK) {
try {
// Create a new fetcher & add the specified traffic source
trafficFetcher = new TrafficFetcher();
trafficFetcher.AddSource(new HistoricalTrafficSource(ofd.FileName));
trafficEnabled.Checked = trafficEnabled.Enabled = true;
textBoxFilename.Text = ofd.FileName;
} catch (Exception ex) {
// Something went wrong, the file is probably not a valid gbhb file
trafficFetcher = null;
textBoxFilename.Text = "";
trafficEnabled.Checked = trafficEnabled.Enabled = false;
MessageBox.Show(ex.Message);
}
}
trafficChanged();
}
Notice that the buttonBrowse_Click handler calls the trafficChanged() method – this is called from other methods too, and is used to clear and refresh the traffic renderer list. Add the following code:
void trafficChanged() {
traffic = null;
trafficRendererList.Clear();
if (trafficFetcher != null && trafficEnabled.Checked) {
// Grab traffic data for the specified time & render it on the map
traffic = trafficFetcher.GetLatestTraffic(routingTime);
trafficRendererList.Add(new TrafficRenderer(traffic, routingTime));
}
mapCtrl.Invalidate();
}
Whenever a right-click event occurs, we need to show the context menu. Add the following MouseUp event handler to the MapCtrl:
void mapCtrl_MouseUp(object sender, MouseEventArgs e) {
// Show the context menu on right-click
if (mapCtrl.ActiveMouseHandler == null && e.Button == MouseButtons.Right) {
clickLocation = mapCtrl.XYtoLatLon(e.X, e.Y);
contextMenuStrip.Show(mapCtrl, e.Location);
}
}
Add three more event handlers for the three context menu items:
- addStopToolStripMenuItem_Click
- clearRouteToolStripMenuItem_Click
- getDirectionsToolStripMenuItem_Click
In the 'addStopToolStripMenuItem_Click()' handler, add a stop to the route using the AddStop() method. The stop will be placed at the position of the mouse.
void addStopToolStripMenuItem_Click(object sender, EventArgs e) {
route.AddStop(new RouteStop(clickLocation));
mapCtrl.Invalidate();
}
In the 'clearRouteToolStripMenuItem_Click()' handler, clear the route from the map control, and reset the time and distance label.
void clearRouteToolStripMenuItem_Click(object sender, EventArgs e) {
route.Clear();
labelTimeAndDistance.Text = "";
directionsRendererList.Clear();
mapCtrl.Invalidate();
}
In the 'getDirectionsToolStripMenuItem_Click()' handler, if traffic data is being used then a new TrafficRouting object is created, which is used to configure the routing strategy. Also, because the route does not know about the changes to its routing strategy, the event needs to force the route to be recalculated. When the directions have been calculated, the time and distance are displayed using the labelTimeAndDistance label.
void getDirectionsToolStripMenuItem_Click(object sender, EventArgs e) {
// Reset the current strategy and add traffic routing if we have some
route.Strategy = new RoutingStrategyFastest();
if (traffic != null) {
new TrafficRouting(traffic).setUpRouteStrategy(route.Strategy);
}
route.CurrentTime = routingTime;
try {
// Route does not know about changes to its Strategy so we need to force recalculation.
route.ForceRecalculate();
directionsRendererList.Clear();
Directions directions = route.GetDirections();
directionsRendererList.Add(directions);
labelTimeAndDistance.Text = String.Format("{0:0.00} miles, {1:0.00} minutes", directions.GetTotalDistance(DistanceUnit.MILES), directions.GetTotalTime().TotalMinutes);
mapCtrl.Invalidate();
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
If the trafficEnabled check box changes, call the trafficChanged method:
void trafficEnabled_CheckedChanged(object sender, EventArgs e) {
trafficChanged();
}
Because the traffic layer is based on a particular date and time, whenever the date / time pickers change, we need to update the traffic object's routing time.
void dateCtrl_ValueChanged(object sender, EventArgs e) {
routingTime = dateCtrl.Value.Date + timeCtrl.Value.TimeOfDay;
trafficChanged();
}
Testing
This simple application was tested by placing a route that traveled north through Los Angeles, at two different times of the day.
The first was set up for 4am, where the traffic was very light. The route is displayed in the figure below, with time and distance displayed as: 6.65 miles, 12.20 minutes, respectively.

Next, the time was changed from 4am, to 7am. The figure below shows how both the general traffic speed, and the calculated route has changed. The calculated distance and time has also changed to: 8.19 miles, and 13.78 minutes, respectively.
.png)
The final figure shows the same information as the figure above, but with the traffic layer removed, so that the new route can be seen more easily.

Published, Jun 20th 2010, 20:10
Tagged under: dotnet traffic geobase routing map data navigation route optimization maps
