Bing Maps and the Open Map Community Connections

Recap – Automatic Road Detection

Before looking at the new front door application, a bit of history might be helpful about the recent direction that Microsoft’s mapping utilities have been taken. You may be aware that, a few months ago, Microsoft released an application that could be used to automatically detect roads from an aerial imagery photograph. The images below show an example output from the service when processing an imagery tile of part of the city of Norwich:



 


 
One interesting aspect of the service (remember this service is created and hosted by Microsoft, on their azure platform) is that the resulting points were provided in osmchangeformat – and could be used directly to import road data into Open Street Map. This would potentially allow OSM to create and mass import vector road data in previously unmapped areas automatically and easily, without the manual process of a user tracing the road path by hand.

The Front Door Application

The new front door application, which you can access at http://frontdoor.cloudapp.net/follows a similar model of utilising Bing Maps aerial imagery to potentially benefit the open map community…. how?

Anybody who accesses the site is presented with a random aerial image of a location, and is invited to drag a single pushpin onto the front-door of the nearest house. Here’s the image I was presented with when I went to the site just now:

For this one, I’m going to say that the front door of the house is most likely to be just to the left of the driveway, so I dragged the pushpin to about here:

The new location is submitted, and you get shown a new image. What’s the point? Well, if enough people separately agree on the same location for the front door of this house, the new location is used to update local search results in Bing Maps as well as contributing address data to Open Street Maps – crowd-sourced, frontdoor geocoding of properties…

It’s great to see Microsoft continuing to make use of the Open Database Licence and contributing their imagery for use for the benefit of Open Street Maps again (Bing Maps aerial imagery is also available within the PotLatch OSM editor to enable people to trace the location of features and the outlines of building etc.), as well as thinking up innovative uses of the aerial imagery they have available… I wonder what app they might come up with next?

Open Street Map Road Types For Display and Routefinding

We displayed a set of ways imported from Open Street Map in SQL Server Management Studio. It looked like this:

image_thumb1

Now, as I stated previously, OSM ways don’t equate to roads. Ways can be any arbitrary series of nodes, so although at first glance it may appear to be so, the map above does not represent a roadmap. A single way may represent several roads, or only a single segment of one road. Many ways are nothing to do with roads at all – they may be rivers, or railway lines. Ways may also denote the boundaries of an area, such as a county, a park, or a building.

To create a dataset of OSM roads (or footpaths, tracks etc.) suitable for routefinding or display in a road map, it is necessary to retrieve only those ways that contain a tag element with a k attribute of “highway”. The corresponding v attribute describes the type of highway. Examples of possible values include:

  • cycleway
  • footway
  • motorway
  • path
  • pedestrian
  • primary
  • residential
  • road
  • secondary
  • service
  • steps
  • tertiary
  • track
  • unclassified

Note that this list isn’t exhaustive – the design of the OSM schema means that editors can tag ways or nodes with any values, but this is a list of some of the commonly-used tags.

There are many reasons why you might want to categorise each of these highway types separately.

  • Consider access for different modes of transport, for example; clearly, a car can’t go down a cycleway. Nor can a tractor go on a motorway, or a cycle go down steps (unless you’re planning some sort of stunt bike ride).
  • If you’re designing a route-finding application, you might want to consider and compare the relative costs of travelling down different routes. Motorway segments generally have a higher speed limit than primary roads, which in turn have higher average speed than secondary roads, etc. Therefore, a route that maximises the percentage travelled on higher-status roads may well be shorter in time, even if it covers a longer distance.
  • When drawing features onto a map, it’s usual to display different categories of highways with different styles (e.g. motorways coloured blue, primary roads thicker than secondary, tracks as dotted/dashed lines).

As a simple example, to style the Spatial Results tab view of my OSM map to show different categories of roads with different thicknesses I created a table to attach a weight to each highway type, as follows:
 


 
CREATE TABLE RoadWeights (
highwaytype varchar(32),
roadweight int
);
INSERT INTO RoadWeights VALUES
(‘motorway’, 15),
(‘motorway_Link’, 15),
(‘trunk’, 10),
(‘trunk_Link’, 10),
(‘primary’, 8),
(‘primary_Link’, 8),
(‘secondary’, 5),
(‘tertiary’, 3),
(‘residential’, 1),
(‘unclassified’, 0);

Then, I edited my SELECT query to only display rows from my Ways table that were tagged with one of my chosen highway types, and buffered the geography LineString representing each road by the corresponding weight from the RoadWeights table:

SELECT
w.wayid,
wt.TagValue AS highwaytype,
w.geog4326.STBuffer(ISNULL(roadweight,0))
FROM
ways w
INNER JOIN waytags wt ON w.wayid = wt.wayid AND wt.TagName = ‘Highway’
LEFT JOIN RoadWeights rw ON wt.TagValue = rw.highwaytype
WHERE
wt.TagValue IN (‘motorway’, ‘motorway_Link’, ‘trunk’, ‘trunk_Link’, ‘primary’, ‘primary_Link’, ‘secondary’, ‘tertiary’, ‘residential’, ‘unclassified’)

Even when viewed in the SSMS Spatial Results tab, the map already becomes much cleaner than the result shown at the top of this post – with the Norwich inner ring road and its primary arterial roads now clearly visible (and also, the train tracks coming into the railway station on the south east of the city are no longer shown)

Clearly you wouldn’t normally optimise your dataset just for the purposes of display in the SSMS spatial results tab, but you can apply this same technique to attach any other properties that correspond to the type of road – the average road speed limit, accessibility, or styling options that should be passed to a front-end display, for example.

Open Street Map and ESRI tiles on Bing Maps

In a previous post, I explained how to replace the base tile layer in the Bing Maps Silverlight control with an ESRI tile layer. In this post, I’ll show how to do the same but using the Bing Maps AJAX v7 control. You can use this technique to use the Bing Maps AJAX control, but replace the Bing imagery with OSM tiles or the ESRI tile layers used in the previous Silverlight post, as well as many other tile sources.

The first step is to specify not to load the default Bing Maps tile layer. Do this by specifying the mercator MapTypeId in the options passed to the constructor when you first initialise the map:

[php]mapTypeId: Microsoft.Maps.MapTypeId.mercator[/php]

The next step is to create a new TileSource. The uriConstructor of the TileSource must return the correct URI for a requested tile. If your tile provider names its tiles according to the default Bing Maps quadkey numbering system, then the uriConstructor can be a simple string using the {quadkey} placeholder. This will be replaced with the appropriate quadkey when the tile is requested:

[php]var tileSource = new Microsoft.Maps.TileSource(
{  uriConstructor: ‘http://www.microsoft.com/maps/isdk/ajax/layers/lidar/{quadkey}.png’ }
);[/php]

However, for OSM tiles, or any other tile providers that not follow the basic quadkey numbering system, we instead need a function to construct the appropriate URI for each tile. I’ll do this in a function called getTilePath, and I’ll specify this in the TileSource uriConstructor as follows:

[php]var tileSource = new Microsoft.Maps.TileSource({ uriConstructor: getTilePath });[/php]

The getTilePath function will return a string with the appropriate URI for the requested tile. For OSM tiles, a typical tile looks like http://tile.openstreetmap.org/zoom/x/y.png. The function to create this tile is therefore:

[php]function getTilePath(tile) {
return "http://tile.openstreetmap.org/" + tile.levelOfDetail + "/" + tile.x + "/" + tile.y + ".png";
}[/php]

Put this all together and your code should look like this:

[php]<!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">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
function GetMap() {
// Create a basic map
var map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),
{ credentials: "YOURBINGMAPSKEYHERE",
center: new Microsoft.Maps.Location(56, 2),
zoom: 5,
// Don’t load the Bing base map tiles
mapTypeId: Microsoft.Maps.MapTypeId.mercator
});

// Create the tile source
var tileSource = new Microsoft.Maps.TileSource({ uriConstructor: getTilePath });

// Construct the layer using the tile source
var tilelayer = new Microsoft.Maps.TileLayer({ mercator: tileSource, opacity: 1 });

// Push the tile layer to the map
map.entities.push(tilelayer);
}

function getTilePath(tile) {
// Construct the URI path for an OSM tile based on tile zoom/x/y
return "http://tile.openstreetmap.org/" + tile.levelOfDetail + "/" + tile.x + "/" + tile.y + ".png";
}
</script>
</head>
<body onload="GetMap();">
<div id=’mapDiv’ style="position:relative; width:640px; height:480px;"></div>
</body>
</html>[/php]


And here’s what it looks like:

image

If you want to try some other tile providers, replace the URI constructed by the getTilePath() function with some of the following:

DeLorme World Basemap

[php]function getTilePath(tile) {
return "http://server.arcgisonline.com/ArcGIS/rest/services/Specialty/DeLorme_World_Base_Map/MapServer/tile/"
+ tile.levelOfDetail + "/" + tile.y + "/" + tile.x;
}[/php]

image

ESRI World Imagery

[php]function getTilePath(tile) {
return "http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/"
+ tile.levelOfDetail + "/" + tile.y + "/" + tile.x;
}[/php]

image