TPEG and Google Maps

February 08, 2009

Introduction

If, like me, you have a bizarre fascination with maps you can't have failed to notice that Google Maps are appearing on an ever-increasing number of websites, some for valid and useful reasons, some not so much. Now, if you head over to https://maps.google.com/ and zoom in on a major US city you might notice that there is a Traffic button at the top right of the map. Click this and you'll get traffic data overlaid on the map, looking a bit like Figure 1 below.

Figure 1: New York Traffic

Now if you zoom in somewhere in the UK you will get this traffic info, unless you're here in Scotland, but the overlays seem a bit off to me and I've yet to see any icons that will display message windows with more information. I've no doubt that Google will address these issues in due course, but in the meantime there is a way of getting detailed traffic info (albeit without the nice coloured overlays) onto a Google Map, namely TPEG.

What's TPEG?

TPEG stands for Transport Protocol Experts Group and they have agreed standards for Binary and XML transmission of Traffic and Travel Information (TTI). For more information have a look at the TPEG links in the References section at the end of this post. In the UK, Auntie Beeb is helpfully publishing TPEG data in both Binary and XML formats (and you thought they were all about scamming phone voters). The XML document for road traffic information lives at http://www.bbc.co.uk/travelnews/tpeg/en/local/rtm/rtm_tpeg.xml and there's a corresponding public transport document at http://www.bbc.co.uk/travelnews/tpeg/en/pti/pti_tpeg.xml. In the next few steps I'll demonstrate how to display a subset of this data on a very simple ASP.NET website using Google Maps.

Creating the Website

I'm going to be using Visual Studio 2008 for this but 2005 will do just the same. Open up Visual Studio and create a new Web Site project. In addition to the App_Data folder that's created for you, add an App_Code and a Bin folder to the project. Firstly, download the zip file from Subgurim.NET which wraps the functionality of a Google Map into an ASP.NET web control and extract the GMaps.dll into the Websites Bin folder.

Next, get yourself a copy of the road traffic information XML file (just download it from the link above) and copy it into the App_Data folder.

Now, to make working with the data a little bit easier, we'll create a schema definition for the XML (we can't download one because it's based on a DTD currently) and then use xsd.exe to get ourselves a class file. Open up the rtm_tpeg file in Visual Studio, go to the XML menu and select Create Schema. When you get the resulting rtm_tpeg.xsd file on the screen save that into the App_Data folder too.

Open the Visual Studio Command Prompt, navigate to your App_Data folder, and execute the following command to create a C# class in your App_Code folder: xsd.exe rtm_tpeg.xsd /c /language:cs /o:../App_Code. If you're working in VB.NET simply change the language switch to /language:vb. The structure of your Website should new resemble Figure 2.

Figure 2: Website Structure

Now, we can add the map control to our web page and start adding information windows to it. Open up your default.aspx page and edit it so that it resembles the following: –

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="default.aspx.cs" Inherits="_default" %>
<%@ Register Assembly="GMaps" Namespace="Subgurim.Controles" TagPrefix="gmap" %> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
    <head runat="server">
        <title>TPEG and Google Maps</title>
        <style type="text/css">
        html, body
        {
            margin: 0px 0px 0px 0px;
            padding: 0px 0px 0px 0px;
            height: 100%;
        }
        v:*
        {
            behavior: url(#default#VML);
        }
        </style>
    </head>
    <body>
        <form id="mapForm" runat="server">
            <gmap:GMap ID="map" runat="server" Width="100%" Height="100%" />
        </form>
    </body>
</html>

Open the default.aspx.cs and modify it to look like: –

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using Subgurim.Controles;
 
public partial class _default : System.Web.UI.Page
{
 
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            map.setCenter(new GLatLng(55.864536, -4.263103));
            map.GZoom = 12;
            map.addControl(new GControl(GControl.preBuilt.SmallMapControl));
            string uri = "http://www.bbc.co.uk/travelnews/tpeg/en/local/rtm/rtm_tpeg.xml";
            BindData(uri);
        }
    }
 
    private void BindData(string uri)
    {
        XmlDocument xml = new XmlDocument();
        xml.Load(uri);
        XmlNodeReader nr = new XmlNodeReader(xml.DocumentElement);
        XmlSerializer xs = new XmlSerializer(typeof(tpeg_document));
        tpeg_document tpeg = (tpeg_document)xs.Deserialize(nr);
        for (int i = 0; i < tpeg.Items.Length; i++)
        {
            if (tpeg.Items[i] is tpeg_message)
            {
                tpeg_message message = tpeg.Items[i] as tpeg_message;
                if (message.Item is road_traffic_message)
                {
                    road_traffic_message rtmessage = message.Item as road_traffic_message;
                    for (int j = 0; j < rtmessage.Items.Length; j++)
                    {
                        if (rtmessage.Items[j] is location_container)
                        {
                            location_container loc = rtmessage.Items[j] as location_container;
                            for (int k = 0; k < loc.Items.Length; k++)
                            {
                                if (loc.Items[k] is location_coordinates)
                                {
                                    location_coordinates coords = loc.Items[k] as location_coordinates;
                                    for (int l = 0; l < coords.Items.Length; l++)
                                    {
                                        if (coords.Items[l] is WGS84)
                                        {
                                            WGS84 latLong = coords.Items[l] as WGS84;
                                            double latitude = double.Parse(latLong.latitude);
                                            double longitude = double.Parse(latLong.longitude);
                                            StringBuilder sb = new StringBuilder();
                                            sb.Append("<p>");
                                            sb.Append(message.summary[0].Value);
                                            sb.Append("</p>");
                                            GMarker marker = new GMarker(new GLatLng(latitude, longitude));
                                            map.addInfoWindow(new GInfoWindow(marker, sb.ToString(), false));
                                            map.addGMarker(marker);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Briefly, we set centre the map on Glasgow, set the zoom level and add the small map control. Set the uri parameter to the XML TPEG feed (if you find that this takes a while to download you can always use the saved version in your App_Data folder). The BindData() method de-serialises the XML into our tpeg_document class and then starts to loop through the road traffic messages in the document. Without going into the gory details of the TPEG schema, the message contains a summary, which we write to the infoWindow, and location co-ordinates which allow us to add the marker icon in the right place.

Hit the F5 key to run the application, allowing Visual Studio to modify your web.config file if you like, and marvel (if you're easily impressed) at live traffic information on a Google Map.

Figure 3: Glasgow Traffic

What Next

You'll notice on the figure above that you often get two markers closely spaced on the same stretch of road. These tend to be the start and end points of heavy congestion and Google would display these as coloured overlays on the map. We can render a polyline on top of the map given a start and end point but the problem with that is it will be a straight line and won't follow the road (probably). If you can find out how to overlay a line following the road then you'd be getting pretty close to what Google can do.

References

Maps

TPEG


Profile picture

Written by Stuart Whiteford
A software developer with over 20 years' experience developing business applications primarily using Microsoft technologies including ASP.NET (Web Forms, MVC and Core), SQL Server and Azure.