XML Web Services, GIS, and Location Technologies - Part 2

December 16, 2002
Share

Sharing is Caring

Editor's Note: If you missed part 1 of this series, find it HERE.

In part one, we talked about XML Web services, and the value they bring to the GIS and business geographics world.Hopefully this left you wanting to learn more, and to see how XML Web services can be used practically in applications that need to provide mapping and other related location based functionality.Here in part two, we will examine a real application built with the Microsoft MapPoint .NET XML Web service to get a first hand look and an appreciation of the simplicity this new generation of location technologies brings to your applications.The application is built with Visual Basic and runs on your desktop like any other Windows application. It makes calls to the MapPoint .NET service to do street address geocoding, place finding, map rendering, and multi-point driving directions calculations. Since we are of course building it with XML Web services, it will be lightweight; will not require any data installation on your machine, and all of the mapping specific code will fit on a napkin.

Although we will be looking at code in a moment, even if you are not a programmer, there is much here of interest for you.We will get started by installing and running the compiled application. No programming skills needed.We will walk through the application and examine its functionality piece by piece, feature by feature.

We will be using the MapPoint .NET Web service to provide the mapping functionality needed by the application. MapPoint .NET is a hosted Web service, exposing it's functionality via a simple SOAP API.This single, easy to learn API is used by developers to build location intelligence into their applications.The same API used by a developer in Italy is used by a developer in the United States.Driving directions, map rendering, Geocoding, reverse Geocoding, proximity search, and all of MapPoint's functionality is available via this same API.Web developers, desktop developers, mobile developers, you guessed it, the same API.

Running the application
There are two things you need to do in order to run the application.First, you will need to have the .NET framework runtime installed.If you don't already have it, you can get it here:

Next, you will download the compiled, ready-to-run application here:
Save the zip file anywhere on your system and extract the DirectionsmagTutorial.exe file.Double-click on the .EXE to run it.

The application lets you add a number of stops to a route, one at a time.When all of the stops have been added, you can hit the 'Get Route' button to generate driving directions.Here is a screen shot of the running application: Start by adding your first stop.Choose your country from the dropdown list, and then enter a place or street address. If entering a street address, make sure you include a city or zip code. The following are examples of valid input:

  • Madison st & 4th ave, seattle
  • 90 Birch Drive, Pleasantville, NY
  • Fresno
  • Shea Stadium
  • SFO
  • ·90210
After hitting the 'Add Stop' button, the map will re-center and an icon will mark the location of the stop. Once you have added at least 2 stops to your itinerary, you can hit the 'Get Route' button to retrieve point-to-point driving directions and an interactive route map.You can click on the map to re-center it, and the scroll bar to the right of the map will control your zoom level.Selecting a route instruction from the list of turns will center the map on that turn.Think about what you just did: Street Geocoding, map rendering, and driving directions calculations.All you installed was a 65,000 byte application to do it, you didn't have to worry about data incompatibilities or any of the other standard GIS issues we covered in part one.With very little additional development effort, things like integration with corporate data, point of interest data from the MapPoint service, demographic data and more can be performed.

Building the application
For the application programmers reading this tutorial, we will now look at the Visual Basic source code that drives the application.

Requirements to follow the tutorial:

  • Visual Studio .NET - This is the Integrated development environment we will use for building the application
  • A MapPoint .NET developer account.If you don't have your own, you can use the shared account that was created for this tutorial:
    • UserID - 2330
    • Password - YUzRJ9Be (CaSe MaTteRs!)
    • Expires - 31-Jan-2003
  • The source code and related files for the Visual Studio .NET project
    • Download the source code here
If you are reading this article after the shared account has expired, you can sign up for your own private credentials on the Web.There is no charge to do so, and it takes just a few moments to fill in the form:
http://www.microsoft.com/mappoint/net/evaluation
Download and unzip the project anywhere on your system.Start Visual studio .NET and open the .SLN (solution) file. You're now ready to follow along as we look at the major areas of the application.

The User Interface
Once the project has loaded, your desktop should look much like the screenshot below.The UI is completely standard and like every other Visual Basic application you've ever looked at.After all, that's one of the major benefits of XML Web services - you use them right where you need them, in all of the programming environments that you're already used to, utilizing any of the programming languages you are familiar with.No surprises."OK People, there's nothing to see here.Move along." The Web Service Reference
To make our development tool aware of our Web service, we add a Web reference to the project.In the solution explorer (CTRL-ALT-L to display it), you will see a folder called Web References. Here you will find an entry for each referenced XML Web service in your application.In this case, we have just one - The MapPoint .NET service. It has been renamed MPNet to keep our code easier to read.Click on the MPNet service to view its properties.The 'Web Reference URL' property is the WSDL file that we talked about in part one.It is an explicit URL that points to the definition of all of this Web services functionality.

To add another Web service to the project, you would use the 'Project -> Add Web Reference...' menu choice. This brings up the 'Add Web reference' dialog where you can specify and valid WSDL file to be added to your project.

Once the WSDL file is specified, you can immediately take advantage of any of its functionality.The only missing link is security.How is access to the Web service controlled? How are authentic requests distinguished from unauthorized access attempts? The MapPoint .NET service uses Digest Authentication to validate each request made to the service.This is the reason you need to sign up for credentials before you are able to use the service.Remember, for the purpose of this tutorial, temporary credentials have been supplied to you.If we look at the Form1's Load() event, you will find the code that takes your MapPoint .NET UserID and password and instantiates NetworkCredential objects for each of the services we will be using:

myFindService.Credentials = New NetworkCredential("2330", "YUzRJ9Be")
myRenderService.Credentials = New NetworkCredential("2330", "YUzRJ9Be")
myRouteService.Credentials = New NetworkCredential("2330", "YUzRJ9Be")


It's that simple.Once your legitimate credentials are set, each call your application makes to the service will be validated.

The Geocode
When the 'Add Stop' button is pressed, we need to geocode whatever was entered in the search field.It could be a full street address, or perhaps just a place descriptor such as a landmark, city, post code, etc...The MapPoint .NET Web service provides a method for performing a street geocode and another method to geocode place descriptors. Our strategy here will be to try the input as a street, and if no good results are found, make a subsequent call to try a place search.As an added bonus, the FindAddress() method can be passed an unparsed address string, which will be parsed and geocoded in one step.Here is the code to perform the Street Geocode:

'Initialize the centerpoint to null.If we find a good match, set it
CenterPoint = Nothing

'Based on the selected Country, select a MapPoint Datasource to search
If cmbCountry.Text = "Canada" Or cmbCountry.Text = "United States" Then
myDataSourceName = "MapPoint.NA"
Else
myDataSourceName = "MapPoint.EU"
End If

Try
'Start by trying the input as a Street Address.If we don't make a
'hit, we will then try the input as a place.

'Populate a FindAddressSpecification with the search options
Dim findAddressSpec As New FindAddressSpecification()
findAddressSpec.InputAddress = New Address()
findAddressSpec.InputAddress.FormattedAddress = txtStreet.Text
findAddressSpec.InputAddress.CountryRegion = cmbCountry.Text
findAddressSpec.DataSourceName = myDataSourceName

'Try to find the address
Try
foundAddressResults = myFindService.FindAddress(findAddressSpec)
Catch ex As System.Web.Services.Protocols.SoapException
'An error occured during the search.
foundAddressResults = Nothing
End Try

We simply populate an Address object and pass it to the FindAddress() method.Note that if you have discrete address component fields for street, city, state, and postcode, you can pass these in the Address object as well.

Next we need to check to see if any valid matches were found.If we have a single good match, we will set the CenterPoint variable with the coordinate.If more than one good match was found, we will display a dialog to the user allowing them to select one of the candidates.

'Did we get any results?
If (Not foundAddressResults Is Nothing) Then
'If we have exactly one hit, use it as the centerpoint for this stop
If foundAddressResults.NumberFound = 1 Then
Dim fr As FindResult = foundAddressResults.Results(0)
CenterPoint = New LatLong()
CenterPoint = fr.FoundLocation.LatLong
myViews(0) = fr.FoundLocation.BestMapView.ByHeightWidth
End If

'If more than one candidate, show a dialog that allows the user to choose one
If foundAddressResults.NumberFound > 1 Then
Dim frm As New CandidatePicker()
frm.ShowDialog(Me)
End If
End If

Finally, it's possible that no matches or candidates at all were found.If this is the case, chances are good that the user didn't enter a complete address, but instead, just a place description such as '90210', 'Dallas', 'Space Needle', or 'SFO' for example. In this case, we make a call to MapPoint .NET's Find() method to geocode the place.
'If searching as a street address didn't yield a hit, lets try a place find
If CenterPoint Is Nothing Then
Dim findSpec As New MPNet.FindSpecification()
findSpec.InputPlace = txtStreet.Text
findSpec.DataSourceName = myDataSourceName

Dim foundResults As MPNet.FindResults
foundResults = myFindService.Find(findSpec)

'If a place was found, we will use the first candidate as our stop.
If Not foundResults Is Nothing And foundResults.NumberFound > 0 Then
Dim fr As FindResult = foundResults.Results(0)
CenterPoint = New LatLong()
CenterPoint = fr.FoundLocation.LatLong
myViews(0) = fr.FoundLocation.BestMapView.ByHeightWidth
End If
End If

Note that in each case that a location was found, we took the location's BestMapView and saved it in an array of MapViews.We will use this as the initial view for our map in the next section on MapRendering.The advantage of hanging onto this view versus creating a view at the found coordinate is that the MapPoint .NET service will have set for us the optimal zoom and scale for the map based on what was found.The best view of a street address is different than a city which is different than a landmark.By using the provided View, we know we will get an appropriate initial Map.

The Map Render
MapPoint .NET's GetMap() method provides a host of options for returning aesthetically pleasing maps to your application.You can request a map with a variety of options including routes, styles, and custom icons, and choose to have the map returned as a gif image directly to your application or as a fully qualified URL path to be embedded in a web application.You can perform advanced drawing and annotation on your maps as well (see the territory demo at http://demo.mappoint.net for a good example of this).The GetMap() method takes a MapSpecification object as a parameter.Here is where you specify the size and format of your map, along with all of the other parameters just mentioned.

In our application we will request a map of the current location and specify that we want the binary of the rendered map returned directly to our application.We will then display it in a picture box on our form.After all of the parameters are set, GetMap() is called and the returned MapImage object is displayed on our form with just one more line of code.

Dim mapSpec As New MPNet.MapSpecification()
mapSpec.DataSourceName = myDataSourceName
'Request the map sized to fit in our picturebox
PixelWidth = pbMap.Width
PixelHeight = pbMap.Height
mapSpec.Options = New MPNet.MapOptions()
mapSpec.Options.Format = New MPNet.ImageFormat()
mapSpec.Options.Format.Height = PixelHeight
mapSpec.Options.Format.Width = PixelWidth
'MapPoint .NET supports many MapStyles.We will go with 'Road', but
'have fun and experiment with some of the others, such as terrain
mapSpec.Options.Style = MPNet.MapStyle.Road
mapSpec.Options.FontSize = MapFontSize.Smaller
mapSpec.Pushpins = StopPins
mapSpec.Views = myViews
mapSpec.Route = myRoute
'Make the call to the MapPoint .NET service and display the
'resulting map in the picturebox
Dim mapImages() As MPNet.MapImage
mapImages = myRenderService.GetMap(mapSpec)
pbMap.Image = _
New Bitmap(New System.IO.MemoryStream(mapImages(0).MimeData.Bits))


To make the map interactive (allow pan and zoom), we will hang onto the MapView that was used in the getMap() request.We can use this later in the MouseDown() event for the picture box to re-center the map.Given the Mouse click location in Pixels, we can ask the RenderService to convert the coordinate to a LatLong object. Then of course a new map can be requested at this newly derived coordinate, like this:

Dim pc As New MPNet.PixelCoord()
pc.X = e.X
pc.Y = e.Y
Dim points(0) As MPNet.PixelCoord
points(0) = pc
'Convert from pixels to LatLong
myViews(0).CenterPoint = myRenderService.ConvertToLatLong( _
points, myViews(0), PixelWidth, PixelHeight)(0)


Driving Directions
Once the user has created at least two stops for the route, they can hit the 'Get Route' button to request driving directions and a map highlighting the route.We start by creating an array of SegmentSpecification objects, one for each stop.A SegmentSpecification holds the coordinate of the Stop, and its name.Here is the code to request the route from the MapPoint .NET service:

'Add each stop to a RouteSegmentSpec object
Dim ThisStop As Integer
Dim routeSegmentsSpec(NumberOfStops - 1) As SegmentSpecification
For ThisStop = 0 To NumberOfStops - 1
routeSegmentsSpec(ThisStop) = New SegmentSpecification()
routeSegmentsSpec(ThisStop).Waypoint = New Waypoint()
routeSegmentsSpec(ThisStop).Waypoint.Name = "Stop " & ThisStop
routeSegmentsSpec(ThisStop).Waypoint.Location = New Location()
routeSegmentsSpec(ThisStop).Waypoint.Location.LatLong = _
StopPins(ThisStop).LatLong
Next
Dim routeSpec As New RouteSpecification()
routeSpec.DataSourceName = myDataSourceName
routeSpec.Segments = routeSegmentsSpec
'Request the route and directions from the MapPoint .NET service
myRoute = myRouteService.CalculateRoute(routeSpec)


As you can see, the CalculateRoute() method takes a RouteSpecification object as it's sole parameter.The RouteSpecification contains everything, including the set of stops, that MapPoint will need to generate directions.You have the ability to specify a number of additional options on the RouteSpecification that are not shown here such as driver profile information and shortest route/fastest route preference.

Once the route is calculated, it is easy to iterate through the individual turn instructions and display them in a list box, text box or whatever your User Interface calls for.

'Loop through each segment, and each segment's directions
'Put the text of each turn in a list box
lstDirections.Items.Clear()

Dim myDirection As Direction
Dim thisSegment As Segment
Dim segmentNumber As Integer = -1
Dim locs(myRoute.Itinerary.Segments.Length - 1) As Location

For Each thisSegment In myRoute.Itinerary.Segments
segmentNumber = segmentNumber + 1
locs(segmentNumber) = New MPNet.Location()
locs(segmentNumber).LatLong = thisSegment.Waypoint.Location.LatLong

For Each myDirection In thisSegment.Directions
lstDirections.Items.Add(myDirection.Instruction.ToString())
Next
Next

In this case, we add an element to a list box for each instruction.The user can then select any instruction in the list to quickly center the map there.

Summary
Hopefully this two-part article has provided a good feel for what is possible today with XML Web services and mapping applications.If you would like to learn more and start building applications on your own, I would suggest downloading the MapPoint .NET SDK.In addition to providing a detailed reference to the entire API, it contains an exhaustive set of code samples in C# and Visual Basic for every property and method in the API.You will also find tables detailing the Cartographic and Point of Interest data in the service.You can find the SDK at MSDN here:

http://msdn.microsoft.com/library/en-us/dnmapnet30/html/map_sdk3ntro.asp

Also, for developers using the Java language, you can find a good sample application here:

http://demo.mappoint.net/#NonDotNet


Share

Sharing is Caring


Geospatial Newsletters

Keep up to date with the latest geospatial trends!

Sign up

Search DM

Get Directions Magazine delivered to you
Please enter a valid email address
Please let us know that you're not a robot by using reCAPTCHA.
Sorry, there was a problem submitting your sign up request. Please try again or email editors@directionsmag.com

Thank You! We'll email you to verify your address.

In order to complete the subscription process, simply check your inbox and click on the link in the email we have just sent you. If it is not there, please check your junk mail folder.

Thank you!

It looks like you're already subscribed.

If you still experience difficulties subscribing to our newsletters, please contact us at editors@directionsmag.com