Tuesday, 8 March 2016

How to Geocode and Reverse Geocode using bing maps API? Part 1

Geocoding is the process of converting an address into geographical coordinates(longitutde, latitude) and reverse geocoding is, well reverse of it. It converts geographical coordinates to an address.

In this tutorial we'll learn how to convert any location/address entered by user to geographical coordinates and display a pushpin at that specified location.

To add map to your app, read my previous post.

We'll modify the UI a bit, we'll add a textbox and a button. The following code can be used to achieve this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<StackPanel Orientation="Vertical">
  <StackPanel Orientation="Horizontal">
     <TextBox Name="enterValue" PlaceholderText="Enter address/coordinates"
                FontSize="24" Margin="8" Width="300" Height="44" />
       <Button Content="Go" Click="Button_Click"></Button>
    </StackPanel>
    <Maps:MapControl
            x:Name="MapControl1"
            MapServiceToken="Token Value"
            ZoomLevel="3"
            Height="550"
            />
 </StackPanel>

In the click event of button, read the value entered by user and then pass it on to another function called Geocode which contains the actual logic of geo-coding. The code for the click event of button is given below.

1
2
3
4
5
6
7
8
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            string valueEntered = enterValue.Text;
            if (valueEntered != null || valueEntered != "")
            {
                Geocode(valueEntered);
            }
        }

The above code simply assigns the value of the textbox to a string and before passing it as an argument to the Geocode function, makes sure that it's not empty.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
private async void Geocode(string valueEntered)
{

   BasicGeoposition location = new BasicGeoposition();
   location.Latitude = 33.6667;
   location.Longitude = 73.1667;
   Geopoint hintPoint = new Geopoint(location);
   MapLocationFinderResult result =
      await MapLocationFinder.FindLocationsAsync(valueEntered, hintPoint);

   if (result.Status == MapLocationFinderStatus.Success)
   {
       BasicGeoposition newLocation = new BasicGeoposition();
       newLocation.Latitude = result.Locations[0].Point.Position.Latitude;
       newLocation.Longitude = result.Locations[0].Point.Position.Longitude;
       Geopoint geoPoint = new Geopoint(newLocation);
       MapAddress mapAddress = result.Locations[0].Address;
       string address = mapAddress.FormattedAddress;
       AddMapIcon(geoPoint, address);
    }
}

In the above code we have created a variable "location" of type BasicGeopostion and set it's longitude and latitude to the coordinates of Pakistan.

The reason behind setting it's coordinates to Pakistan is that this variable will be used as a hint point while geo-coding. Given my geographical location I am assuming that most of my users will be from Pakistan and that is why I have used that as a hint point. You can modify the hint point based on the geographical source of your queries.

Now let's dissect line 8-9.

MapLocationFinderResult returns the result of MapLocationFinderQuery.

MapLocationFinder is a static class that has three functions,

1) FindLocationsAsync(string address, Geopoint referencePoint) , this function will return just one result.
2) FindLocationsAsync(string address, Geopoint referencePoint), int maxCount), this function returns the number of maxCount result.
3) FindLocationsAtAsync(Geopoint queryPoint), this is called reverse geo-coding.

You must have noticed the use of async and await keywords. The reason behind it is that the return type of all three functions of MapLocationFinder class is IAsyncOperation<TResult>.

The marked async method uses the await keyword, which tells the compiler that it can't move past that point until the awaited asynchronous process is complete.

Finally the value returned by FindLocationsAsync(), which is a read-only collection of elements that can be accessed by index, is stored in the variable result of type MapLocationFinderResult.

The if statement compares the status of the result query to the enum MapLocationFinderStatus and if it is successful we proceed ahead.

Finally we create a new variable called "newLocation" of type BasicGeoposition and assign it's latitude and longitude to the coordinates of Location at index 0 of list Locations. Then we assign the address of this location to another variable mapAddress of type MapAddress which can hold an address of a geographical location. To store the address in a string type variable we will simply call the read-only property FormattedAddress of MapAddress which returns the complete result in a string format.

We also created a new Geopoint variable from the newLocation variable of type BasicGeoposition using the parameterized constructor.

Now we pass geoPoint and address to another function called AddMapIcon().


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
        private async void AddMapIcon(Geopoint geoPoint, String address)
        {
            if (mapIcon != null)
            {
                MapControl1.MapElements.Remove(mapIcon);
            }
            mapIcon.Location = geoPoint;
            mapIcon.Title = address;

            MapControl1.MapElements.Add(mapIcon);
            await MapControl1.TrySetViewAsync(geoPoint);
        }

We declared mapIcon as a class field just to make sure that there is only a single pushpin at any given time.

The above code simply removes mapIcon from the MapControl1 if it's not null. Otherwise sets it's Location and Title eto the passed parameters.

Line 10 adds the mapIcon to MapControl1 and Line 11 animates camera movement as map shifts it's center from one location to another.

In the next post we will learn how to reverse geo-code.

Monday, 7 March 2016

How to add Map to your UWP app?

To add maps to your UWP app, you need MapControl and following three namespaces

Windows.UI.Xaml.Controls.Maps: This namespace contains MapControl itself.
Windows.Devices.Geolocation: This namespace allows you to get user location and contains Geofencing API as well.
Windows.Services.Maps: This one supports several utility classes which allows to find location by address (Geocoding) and reverse Geocoding (find address by location) etc.

Also MapControl is not in default XAML namespaces, so we need to add a new namespace to XAML file, as shown below.

xmlns:Maps="using:Windows.UI.Xaml.Controls.Maps"

To use map services in Windows 10 application, you need to acquire a token from the Map Dev Center

Sign in, Advance to My Account -> My Keys and click on create a new key. Select Universal Windows App as Application type from the drop down list.
































Without the map service token, your app works fine but you will see a warning message that MapServiceToken is not specified and without the MapServiceToken you cannot publish your app.

Once you have added the maps namespace in your XAML file, add MapControl using the following code.

<Maps:MapControl
            x:Name="MapControl1"
            MapServiceToken="Token Value"
            ZoomLevel="8"
            />

Finally run your app. A map like the following will be displayed, you can drag or move it around, zoom in or zoom out.


This is just the first step towards building cool map apps. The next most basic feature of any map is the ability to display info about points of interest by adding images, shapes, pushpins and etc.

Let's see how we can add a pushpin to our map.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
        private void AddMapIcon()
        {
            BasicGeoposition location = new BasicGeoposition();
            location.Latitude = 33.6667;
            location.Longitude = 73.1667;
            MapIcon mapIcon;
            mapIcon = new MapIcon();
            if (mapIcon != null)
            {

                MapControl1.MapElements.Remove(mapIcon);
            }
            
            mapIcon.Location = new Geopoint(location);
            mapIcon.Title = "Pakistan";
            MapControl1.MapElements.Add(mapIcon);
            MapControl1.Center = new Geopoint(location);

        }

At first we declared a variable of type BasicGeoposition structure. It provides the basic information to describe a geographic position. It has three fields latitude, longitude and altitude. The altitude field is used only if we are displaying a 3D map.

We'll use MapIcon with default image(you can also customize image by using Image property), to display a pushpin at our desired geographical point. Line 13 creates a geographic point object for the given position and assigns it to Location property of mapIcon. 

Line 15 adds the mapIcon to MapControl1 and line 16 centers our map to the specified location.

Run the app.


 In the next tutorial we'll learn how to geo-code and reverse geo-code.