(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Windows 8.1: Location-aware apps - Part #1: What's new in geolocation

(5 votes)
Andrea Boschin
>
Andrea Boschin
Joined Nov 17, 2009
Articles:   91
Comments:   9
More Articles
0 comments   /   posted on Oct 21, 2013
Categories:   Windows 8

Tweet

Mobile devices have grown a lot in the last years and a lot of practical applications are developing a huge market around them. One of the most important points that made the success of mobile devices is the availability of sensor that uses the Global Positioning System (GPS) to detect the geographic location of the devices. GPS Sensor is supported in Windows Store apps since the very first release but it has got a number of new and important features that maximizes the capabilities of your device giving new horizons to your ideas.

At the basic.

People that build a GPS application in Windows 8 knows that the only class used by the location system is the Geocoordinate. This type contains a number of properties related to the location: Latitude, Longitude and Altitude describes the tridimensional position detected by the sensor, heading (direction) and speed add some more useful information that are calculated on the basis of multiple sampling. In Windows 8.1, all these properties still exist but they have been deprecated. If you try to use them you get a warning with this text: "Altitude may be altered or unavailable after Windows 8.1. Instead, use Geocoordinate.Point".

The following diagram shows the types involved in this changes: The new "Point" property in the Geocoordinate class opens to a new interesting perpective, just because it opens to new future extensions. At the basic of this property there is the IGeoShape interface that, as the name suggests, may describe complex shapes and not only points.

image

As you can see, there is almost another classe implementing IGeoShape. It is the Geocircle. This class is used to describe a circular area, made of a center and a radius around it. The use of this class is related to the Geofencing, that is the interception of events related to a geographic area. (I'll cover this argument later).

Together with the Point property, the Geocoordinate class got another two properties. The SatelliteData is the central point when you need to determine the accuracy of the satellite information. It's properties are able to describe the precision on the basis of the position of satellites in the sky. The argument is pretty complex but, to oversimplify, this parameter can figure if you are getting information from satellites that cover only a little part of the sky (less precise) or well distributed and effective. Finally the PositionSource property lets you know how the position has been detected. In Windows 8 the position can be calculated with many sources, Cellular cells, Satellites, Wi-fi and IP address. All these have different precision and it is important to know what is the source of your measurement.

Getting the position

The way you get a position in Windows 8.1 has not changed, but I'll include an example for the sake of completeness. The main handle for the reading of the location is in the Geolocator class.

   1: private async void Button_Click(object sender, RoutedEventArgs e)
   2: {
   3:     Geolocator locator = new Geolocator();
   4:     locator.DesiredAccuracy = PositionAccuracy.High;
   5:  
   6:     var location = await locator.GetGeopositionAsync().AsTask();
   7:  
   8:     this.DisplayInfo(location);
   9: }

Once you create an instance of the type, you can first of all determine the accuracy you want, setting the DesiredAccuracy property to Default or High. As a practical result, when you set the value to High the device will try to use always the most reliable source available, that is Satellite. It this is not available because the device does not have a GPS sensor the positioning is calculated to the next accurate source and then so on. On my desktop PC, that does not have a GPS sensor, nor a cellular or wi-fi connection, the value always returns IPAddress that is the less precise source available. Definitely you have never to strictly rely on positioning precision, since it always try to return a value but this may be very inaccurate. Here is the result of the snippet on my tablet.

Screenshot (1)

As you can see the PositionSource is Wi-Fi. This is because I'm in a closed room and the GPS probably is not able to receive accurate information.

The number "4326" in the SpatialReferenceId refers to the WGS84 projection system that is the most common spatial reference, used by Bing and Google as an example. This means you can directly use the Latitude and Longitude on a Bing Map without the need of any conversion.

The Geolocator allows you to get the position, as a sequence of events, on the basis of a threshold distance between samples. To setup this you can hook up the PositionChanged event and setup the MovementThreshold property to the required amount of meters. Additionally you can also set the ReportInterval property to indicate the minimum time between different samples, so you can slow down the flow of information and preserve battery from being drained.

Slice the world

Getting a position from your device is for sure a great thing if you need to mark static positions on the earth surface, but listen to me who I've worked on geospatial solutions, it is nothing. When you have a device able to track a geographical position and you want to develop a system on top of it, you immediately meet the need to handle the dynamic aspect of geo location and not only the collection of positions. And in a device like this, it may become an hard task to monitor changes of position, while on the go, and check if they match with given point to track some high level object like a vehicle trip or a goods move.

Windows 8.1 makes a great step forward in this direction letting you define a so-called "geo-fence", that is a geographical area that is monitored by the device automatically. A Geofence in WinRT is defined as an element that have an "ID", useful to handle multiple locations, and a shape that is an instance of IGeoShape.

Given what we previously said, at the moment WinRT only supports circular shapes. a Geopoint is an IGeoShape but it is too small to be handled by a positioning system. It is almost impossible to detect a Geofence as a point source. So the only shape we can reasonably use is the Geocircle. In my experience, the tracking of circular position does not always suffice, expecially if you have to handle close positions. But for many applications circular areas are good.

The main point to handle Geofences is the GeofenceMonitor. It is a singleton object, returned by the Current property and is represents the system-wide instance of the monitor. So be careful. This object esposes a Geofences collection that shows only geofences added by the current application/user. You can user this property to append new geofences, but you always have to handle this collection like a persistent item. Infact if you add an element and then you close the app, when you enter agin the element is still there. So, the better is to handle your collection being always care of the IDs you entered and at least clear them when you enter the application or double check before adding that the element does not exists.

Let me propose a simple example. In this example I'll use the previous code to detect the current position and add a geofence around it.

   1: private async void Button_Click(object sender, RoutedEventArgs e)
   2: {
   3:     Geolocator locator = new Geolocator();
   4:  
   5:     var location = await locator.GetGeopositionAsync().AsTask();
   6:  
   7:     this.DisplayInfo(location);
   8:  
   9:     Geofence fence = GeofenceMonitor.Current.Geofences.FirstOrDefault(o => o.Id == "here");
  10:     
  11:     if (fence == null)
  12:     {
  13:         GeofenceMonitor.Current.Geofences.Add(
  14:             new Geofence(
  15:                 "here",
  16:                 new Geocircle(location.Coordinate.Point.Position, 50.0),
  17:                 MonitoredGeofenceStates.Entered,
  18:                 false,
  19:                 TimeSpan.FromSeconds(10)));
  20:     }
  21: }

So, after the position has been detected, the first operation is to check is a Geofence with id equals to "here" already exist. Only if the instance does not exists a new Geofence is created and added to the collection. The new geofence has a number of properties. Other to the ID and shape

So, after the position has been detected, the first operation is to check is a Geofence with id equals to "here" already exist. Only if the instance does not exists a new Geofence is created and added to the collection. The new geofence has a number of properties. Besides to the ID and shape that are intuitive, the other properties are the following:

  • monitoredStatus is a flag property that indicate events we need to be nodified. We can use a boolean OR to specify multiple values like Entered | Exited
  • singleUse let say if the geofence is persistent. Is single use is true, the Geofence is automatically removed after it has been hit by an event.
  • dwellTime is the threshold value the device should remain into the geofence before an event is raised. In this case 10 seconds.

In the example, when you hit the button, the position is detected and added as a Geofences. After 10 seconds the GeofenceStateChanged event should be raised (stated that we are still in it). And we handle is as follow:

   1: private void MainPage_Loaded(object sender, RoutedEventArgs e)
   2: {
   3:    GeofenceMonitor.Current.GeofenceStateChanged += Current_GeofenceStateChanged;
   4: }
   5:  
   6: private async void Current_GeofenceStateChanged(GeofenceMonitor sender, object args)
   7: {
   8:    await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
   9:        () =>
  10:        {
  11:            Geofence changed = (from gf in sender.Geofences
  12:                                where gf.MonitoredStates != MonitoredGeofenceStates.None
  13:                                select gf).FirstOrDefault();
  14:  
  15:            if (changed != null)
  16:            {
  17:                txtMessage.Text = string.Format("The geofence with id '{0}' changed to '{1}'", changed.Id, changed.MonitoredStates);
  18:            }
  19:        });
  20: }

In this code I search for Geofences that are in a status different from "None" and I display a message in a textbox. With more that a single Geofence the code should be much more complex to handle multiple changes. Be sure you can handle more that a single Geofence signaled ad a time, because nothing prevents you to add items that cover the same position.

Workin' on the go...

The Geofences system is really interesting and straightforward to be used. Unfortunately the code I've shown only works while the application is running. And we for sure know that this is not always true in a WinRT system. It is the reason why the geofencing also supports background tasks, ad this will be the argument from the next article in the series.


Subscribe

Comments

No comments

Add Comment

Login to comment:
  *      *       

From this series