Bing Maps v.7 control on an Address Rather than a known Latitude/Longitude

This was a question that came up at the cloudhack event last weekend – when you create a new instance of the Bing Maps AJAX control, you specify the centrepoint of the map in latitude and longitude coordinates, using the center property in the viewOptions passed to the constructor. For example:

[php]
var map = new Microsoft.Maps.Map( document.getElementById("mapDiv"),
{ credentials: ENTERYOURBINGMAPSKEY,
center: new Microsoft.Maps.Location(54, -4),
mapTypeId: Microsoft.Maps.MapTypeId.aerial,
zoom: 12
});

[/php]

(You can view more information on the viewOptions parameters here: http://msdn.microsoft.com/en-us/library/gg427628.aspx )
 


 
However, what if you want to create a map centred on an address instead of a latitude/longitude coordinate? This seems like a fairly simple, common request, so I was a bit surprised to find that none of the Microsoft method reference guides nor any of the “interactive SDK” sites provide an example showing how to do this.

Fortunately, it’s not too tricky to do so, for the benefit of everyone other than those teams at the cloudhack event who asked me, I thought I’d write it up here ;)

First, you need to geocode the address into latitude and longitude coordinates (using theREST Locations API is the easiest way to do so direct from javascript). Then, in the jsonp callback function that is executed after the geocode service returns its results, create and centre the map on the returned coordinates. Here’s an example (note that you will need to replace ENTERYOURBINGMAPSKEY here with some valid credentials, or else the call to the REST service will fail and the map will not be created):

[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">
var map = null;
var credentials = "ENTERYOURBINGMAPSKEY";

function GetMap() {

// Define the address on which to centre the map
var addressLine = "54 Chiswell Street"; // Street Address
var locality = "London"; // City or town name
var adminDistrict = ""; // County
var country = "UK"; // Country, obviously
var postalCode = "" //Postcode

// Construct a request to the REST geocode service
var geocodeRequest = "http://dev.virtualearth.net/REST/v1/Locations"
+ "?countryRegion=" + country
+ "&addressLine=" + addressLine
+ "&locality=" + locality
+ "&adminDistrict=" + adminDistrict
+ "&postalCode=" + postalCode
+ "&key=" + credentials
+ "&jsonp=GeocodeCallback"; // This function will be called after the geocode service returns its results

// Call the service
CallRestService(geocodeRequest);
}

function GeocodeCallback(result) {
// Check that we have a valid response
if (result && result.resourceSets && result.resourceSets.length > 0 && result.resourceSets[0].resources && result.resourceSets[0].resources.length > 0) {

// Create a Location based on the geocoded coordinates
var coords = result.resourceSets[0].resources[0].point.coordinates;
centerPoint = new Microsoft.Maps.Location(coords[0], coords[1]);

// Create a map centred on the location
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),
{ credentials: credentials,
center: centerPoint,
mapTypeId: Microsoft.Maps.MapTypeId.aerial,
zoom: 18
});

// Add a pushpin as well
var pushpin = new Microsoft.Maps.Pushpin(map.getCenter());
map.entities.push(pushpin);
}
}

// This is a generic function to call a REST service and insert the JSON
// results into the head of the document
function CallRestService(request) {
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", request);
var dochead = document.getElementsByTagName("head").item(0);
dochead.appendChild(script);
}
</script>
</head>
<body onload="GetMap();">
<div id=’mapDiv’ style="position: relative; width: 400px; height: 600px;">
</div>
</body>
</html>

[/php]

Here’s the resulting map:

Parsing Free-Text Addresses and a UK Postcode Regular Expression Pattern

We’ll be attempting to replicate the functionality of Google Maps using nothing but freely-available tools and data – SQL Server Express, OS Open Data, and a dash of Silverlight.

One of the features I’ll be demonstrating is a basic geocoding function – i.e. given an address, placename, or landmark, how do you look up and return the coordinates representing the location so that the map can centre on that place? This is not really a spatial question at all – it’s a question of parsing a free-text user input and using that as the basis of a text search of the database.

The simplest way of doing this is to force your users to enter Street Number, Street Name, Town, and Postcode in separate input elements (and these match the fields in your database). In this case, your query becomes straightforward:

SELECT X, Y FROM AddressDatabase WHERE StreetNumber = ‘10’ AND StreetName = ‘Downing Street’ AND Town=’London’

Most databases don’t contain the location of every individual address. If there is no exact matching StreetNumber record, then you typically find the closest matching properties on the same road and interpolate between them (it seems reasonable to assume that Number 10 Downing Street will be somewhere between Number 9 and Number 11).

Forcing users to enter each element of the address separately doesn’t necessarily create the most attractive UI, however. What’s more common is to use a single free-text search box into which users can type whatever they’re searching for – a placename, address, landmark, postcode etc. Nice UI, but horrible to make sense of the input. In these cases, the user might supply:

“10 Downing Street, London”

“Downing Street, St James’, LONDON”

“10, Downing St. SW1A 2AA”

…not to mention “10 Downig Street. London”, and any other many of misspellings or alternative formats.

One approach you might want to take in these cases is to use a RegEx pattern matcher to determine if any part of the string supplied is a postcode. The UK postcode format is defined by British Standard BS7666, and can be described using the following regular expression pattern:

(GIR 0AA|[A-PR-UWYZ]([0-9][0-9A-HJKPS-UW]?|[A-HK-Y][0-9][0-9ABEHMNPRV-Y]?) [0-9][ABD-HJLNP-UW-Z]{2})

Matching the supplied address string against this RegEx doesn’t prove that a valid postcode was supplied, but just that some part of the user input matched the format for a postcode. The matching substring can then be looked up (say, against the CodePoint Open dataset) to confirm that it is real.

Once you’ve identified the postcode, you can then run a query to retrieve a list of roadnames that lie in that postcode, from something like the OSLocator dataset, and scan the remainder of the input to see if it contains any of those names. You can also scan for any numeric characters in the first part of the text input, which might represent a house number. If you find a matching property, with the same road name and valid postcode, you can be pretty sure you’ve found a match.

If you find more than valid match, or possibly several partial matches only, then you can of course present a disambiguation dialogue box – “Is this the 10 Downing Street you meant?”. For example, there are many “10 Downing Street”s in the UK – from Liverpool to Llanelli and Farnham to Fishwick…. without knowing either the town or the postcode, it could have referred to any of the following:

image

Illusory Laptop Repair – A Most Elegant Google Places Hack

This story of intrigue comes to you via a discovery of Eric Petreska, the quite brilliant head of of Maximum Results Marketing, a local search marketing firm in Spring Hill Fl.


When you search for virus removal Olean NY you see an interesting result.

Not our listing for a service my brother provides…. no, the other one…for Illusory Laptop Repair. A quick drive by or Streetview look-see would soon convince you that 154 Main St, Bradford, is anything but a vibrant downtown location. It is however, smack dab at the centroid of the Bradford.

What is this? MapSpam creeping into the hinterlands? Not to worry, I am on it…

Well rather I am it. OK I admit it, I created it. I couldn’t resist. You know scientific protocol testing, that sort of thing… all for the good of humanity. I couldn’t very well report on it, if I hadn’t tested it.

The truth? It is such an elegant hack, so simple yet so powerful, I really wanted to prove to myself that this one was in fact real.  The local area code phone # rings into my office via Google voice, the record was secured via a PO Box that I have access to in Bradford PA. Sometimes the most powerful hacks are really not hacks at all, just a simple creative use of an existing feature .

Here is Eric’s description of how it works in his own words (bold mine):

The problem is the differences between how the Post Office interprets addresses and how Google places interprets addresses.

If I create a new listing in google places and I give it this information

Name: Maximum Enterprises
Street Address (1st line) : 100 W. 1st Street
Street Address (2nd line): 225 E. 9th St. Suite 101, #9876 (my note: this could be any deliverable address PO Box, UPS Box or Street Address)
City: Los Angeles
State: California
Zip Code: 90112

Then I select “Verify by mail.”

Google sends the PIN number with this address:

Maximum Enterprises
100 W. 1st Street
225 E. 9th St. Suite 101, #9876
Los Angeles, CA 90112

Here’s what happens. The Post Office eventually delivers that PIN# to the UPS store at 225 E. 9th St. Suite 101 (it will take a bit of extra time for handling, the ZIP code is actually wrong for the UPS store, so it will kick around the Post Offices a bit before it eventually gets delivered). The guy at the UPS store puts in in box 9876 (fictitious box #, he’ll probably trash it or return it, but if I had an actual box there, and used that number for my address on Google, it would go in my box).

I get the PIN and verify it, and Google places my location marker at 100 W. 1st Street (49 feet from the point that Google uses for “Los Angeles, CA”).

The post office delivers to the last address line, the line on the envelope closest to the ZIP code. Google places the marker at the first address line. This difference in handling allows anyone to “verify by mail” for any address they want to use that is in the same city as their actual mailing address (or a UPS store/Virtual office location in that city).

The technique would work with almost any second line address that is viable… a real street address, UPS stop, a PO Box. It could be used to achieve multiple listings in a city by using your real address in the line two, a listing in addition to your main location in the burbs or with a PO Box, like in my case, to get presence in a different city for a very low cost. I removed the PO Box from the second line of my listing after getting verified without any need for reverification so as not to have a PO Box visible on the Places page.

I do not know if this technique is still viable. It was reported to Google approximately two months ago. They have not informed me whether it was patched and I have not tested whether it still works. If you try it for yourself (in the name of science and discovery only!), let me know.