Adding GPS location to the Map

Windows Phone has a built-in API for retrieving the current location of the phone, and we can use this to place a marker on the phone.  The GeoCoordinateWatcher in the System.Device.dll is class to use for this. Basically you new up a new class, and use the PositionChanged event to listen for changes to the current location, speed and course.

var geowatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High)
geowatcher.PositionChanged += watcher_PositionChanged;
geowatcher.Start();

In the event handler we can grab the latitude/longitude, project it to the map’s spatial reference and use the point to update a graphic in a graphics layer. Example:

private void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs e)
{
   GraphicsLayer gps = MyMap.Layers["gpsLayer"] as GraphicsLayer;
   if (gps == null) //First Time. Create layer
   {
      gps = new GraphicsLayer() { ID = gps };
      MyMap.Layers.Add(gps);
      Graphic g = new Graphic() { Symbol = new SimpleMarkerSymbol() };
      gps.Graphics.Add(g);
   }
   var coord = e.Position.Location;
   MapPoint p = new MapPoint(coord.Longitude, coord.Latitude);
   // Project point to Map's spatial reference, use ESRI.ArcGIS.Client.Projection.WebMercator or Geometry Service
   gps.Graphics[0].Geometry = p;
}

The GeoCoordinate object returned also contains information about Course, Speed and Accuracy. You can use these values to create an arrow that shows direction when speed is greater than 0, or display an “error circle” around the point using a Polygon to give the user an indication of the accuracy of the position.

We can create a new Layer Class that inherits from GraphicsLayer and encapsulates this. Below you can download an example of a GPS Layer that does exactly this, and implements the direction and error circle. The rest of this blog post talks about this layer.

To use the layer first add a reference to GpsLayer.dll included in the download as well as System.Device.dll. Second import the namespace in the page that contains the map:

xmlns:gps="clr-namespace:ESRI.ArcGIS.Samples;assembly=GpsLayer"

Next add the GPS layer to the map:

<esri:Map x:Name="MyMap" Loaded="MyMap_Loaded" >
	<esri:ArcGISTiledMapServiceLayer ID="BaseLayer"
              Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
	<gps:GpsLayer ID="gpsLayer"
              GeometryServiceUrl="http://sampleserver.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer" />
</esri:Map>

The layer has a geometry service url property to be able to project the point from WGS84 geographic coordinates to the map’s projection. If your map is already using WGS84 or is using the WebMercator projection, you do not need to set this since the projection is handled on the client.

When you run the app and zoom to your current location, you will see something like this:

The white triangle displays the course the phone is currently moving in, and the circle the accuracy of the measurement. As the GPS updates the location and error circle are smoothly animated. When the speed drops below 1m/s, the arrow automatically disappears. If you don’t like the symbols used, you can set your own MarkerSymbol for the location and fill symbol for the error circle. Example:

<gps:GpsLayer ID="gpsLayer">
	<gps:GpsLayer.LocationMarkerSymbol>
		<esriSymbols:SimpleMarkerSymbol />
	</gps:GpsLayer.LocationMarkerSymbol>
	<gps:GpsLayer.AccuracyCircleSymbol>
		<esriSymbols:SimpleFillSymbol Fill="#22FF4532" />
	</gps:GpsLayer.AccuracyCircleSymbol>
</gps:GpsLayer>

There’re two events on the layer that are useful: GeoCoordinateChanged and PositionChanged. GeoCoordinateChanged is fired when Layer.GeoCoordinate is updated. PositionChanged is fired when the point you see on the map has been projected and animated to the new location. By using these events we can automatically recenter the map, rotate the map based on the direction, or display information to the user about location, speed etc. The included sample application has a “Follow Me” option that enables auto-recenter and rotate.

GPS Simulation

If you are using the Windows Phone emulator, or you are inside and get poor GPS reception, testing a GPS layer is not really possible. The GpsLayer includes a GPS Simulator that is automatically used when you use the emulator. The included sample starts out at ESRI and moves west, constantly randomizing the distance travelled and course. If you need it to start it elsewhere, open the source for the GpsLayer and change the initial values used when constructing  the GeoCoordinateSimulator at line 100.

Download the sample

Morten Nielsen
Senior Software Engineer
Silverlight/WPF, Windows Phone

This entry was posted in Web and tagged , , , . Bookmark the permalink.

Leave a Reply

2 Comments

  1. merrill757 says:

    In your second example about getting the users current position from the position changed event handler you say “…we can grab the latitude/longitude, project it to the map’s spatial reference…” then add it to the map. How exactly are you projected the point? I didn’t see it in the code examples given, thanks.

    Matt

  2. rexhansen says:

    Matt -

    Good catch. I’ve updated the code snippet to indicate where the reprojection would take place, but didn’t include the actual code since it may overshadow the general purpose of the snippet. In the sample download, this code is tucked in the GpsLayer’s UpdateLocation method. Basically if projecting to Web Mercator, it’s done on the client. All other projections go through an ArcGIS Server geometry service.

    -Rex