Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Phone

Sensors and Services - Using a Map Service

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
3/13/2011 4:44:29 PM
Of course, most people curious about their location prefer to see a map rather than numeric coordinates. The Silverlight demonstration of the location service displays a map that comes to the program in the form of bitmaps.

In a real phone application, you’d probably be using Bing Maps, particularly considering the existence of a Bing Maps Silverlight Control tailored for the phone. Unfortunately, making use of Bing Maps in a program involves opening a developer account, and getting a maps key and a credential token. This is all free and straightforward but it doesn’t work well for a program that will be shared among all the readers of a book.

For that reason, I’ll be using an alternative that doesn’t require keys or tokens. This alternative is Microsoft Research Maps, which you can learn all about at msrmaps.com. The aerial images are provided by the United States Geological Survey (USGS). Microsoft Research Maps makes these images available through a web service called MSR Maps Service, but still sometimes referred to by its old name of TerraService.

The downside is that the images are not quite state-of-the-art and the service doesn’t always seem entirely reliable.

MSR Maps Service is a SOAP (Simple Object Access Protocol) service with the transactions described in a WSDL (Web Services Description Language) file. Behind the scenes, all the transactions between your program and the web service are in the form of XML files. However, to avoid programmer anguish, generally the WSDL file is used to generate a proxy, which is a collection of classes and structures that allow your program to communicate with the web service with method calls and events.

You can generate this proxy right in Visual Studio. Here’s how I did it: I first created an Windows Phone 7 project in Visual Studio called SilverlightLocationMapper. In the Solution Explorer, I right-clicked the project name and selected Add Service Reference. In the Address field I entered the URL of the MSR Maps Service WSDL file: http://MSRMaps.com/TerraService2.asmx.

(You might wonder if the URL should be http://msrmaps.com/TerraService2.asmx?WSDL because that’s how WSDL files are often referenced. That address will actually seem to work at first, but you’ll get files containing obsolete URLs.)

After you’ve entered the URL in the Address field, press Go. Visual Studio will access the site and report back what it finds. There will be one service, called by the old name of TerraService.

Next you’ll want to enter a name in the Namespace field to replace the generic ServiceReference1. I used MsrMapsService and pressed OK.

You’ll then see MsrMapsService show up under the project in the Solution Explorer. If you click the little Show All Files icon at the top of the Solution Explorer, you can view the generated files. In particular, nested under MsrMapsService and Reference.svcmap, you’ll see Reference.cs, a big file (over 4000 lines) with a namespace of XnaLocationMapper.MsrMapsService, which combines the original project name and the name you selected for the web service.

This Reference.cs file contains all the classes and structures you need to access the web service, and which are documented on the msrmaps.com web site. To access these classes in your program, add a using direction:

using SilverlightLocationMapper.MsrMapsService;

You also need a reference to the System.Device assembly and using directives for the System.Device.Location, System.IO, and System.Windows.Media.Imaging namespacess.

In the MainPage.xaml file, I left the SupportedOrientations property at its default setting of Portrait, I removed the page title to free up more space, and I moved the title panel below the content grid just in case there was a danger of something spilling out of the content grid and obscuring the title. Moving the title panel below the content grid in the XAML file ensures that it will be visually on top.

Here’s the content grid:

Example 1. Silverlight Project: SilverlightLocationMapper File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock Name="statusText"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextWrapping="Wrap" />

<Image Source="Images/usgslogoFooter.png"
Stretch="None"
HorizontalAlignment="Right"
VerticalAlignment="Bottom" />
</Grid>

The TextBlock is used to display status and (possibly) errors; the Image displays a logo of the United States Geological Survey.

The map bitmaps will be inserted between the TextBlock and Image so they obscure the TextBlock but the Image remains on top.

The code-behind file has just two fields, one for the GeoCoordinateWatcher that supplies the location information, and the other for the proxy class created when the web service was added:

Example 2. Silverlight Project: SilverlightLocationMapper File: MainPage.xaml.cs (excerpt)
public partial class MainPage : PhoneApplicationPage
{
GeoCoordinateWatcher geoWatcher = new GeoCoordinateWatcher();
TerraServiceSoapClient proxy = new TerraServiceSoapClient();
...
}

You use the proxy by calling its methods, which make network requests. All these methods are asynchronous. For each method you call, you must also supply a handler for a completion event that is fired when the information you requested has been transferred to your application.

The completion event is accompanied by event arguments: a Cancelled property of type bool, an Error property that is null if there is no error, and a Result property that depends on the request.

I wanted the process to begin after the program was loaded and displayed, so I set a handler for the Loaded event. That Loaded handler sets the handlers for the two completion events I’ll require of the proxy, and also starts up the GeoCoordinateWatcher:

Example 3. Silverlight Project: SilverlightLocationMapper File: MainPage.xaml.cs (excerpt)
public MainPage()
{
InitializeComponent();
Loaded += OnMainPageLoaded;
}

void OnMainPageLoaded(object sender, RoutedEventArgs args)
{
// Set event handlers for TerraServiceSoapClient proxy
proxy.GetAreaFromPtCompleted += OnProxyGetAreaFromPtCompleted;
proxy.GetTileCompleted += OnProxyGetTileCompleted;

// Start GeoCoordinateWatcher going
statusText.Text = "Obtaining geographic location...";
geoWatcher.PositionChanged += OnGeoWatcherPositionChanged;
geoWatcher.Start();
}

When coordinates are obtained, the following OnGeoWatcherPositionChanged method is called. This method begins by turning off the GeoCoordinateWatcher. The program is not equipped to continuously update the display, so it can’t do anything with any additional location information. It appends the longitude and latitude to the TextBlock called ApplicationTitle displayed at the top of the screen.

Example 4. Silverlight Project: SilverlightLocationMapper File: MainPage.xaml.cs (excerpt)
void OnGeoWatcherPositionChanged(object sender,
GeoPositionChangedEventArgs<GeoCoordinate> args)
{
// Turn off GeoWatcher
geoWatcher.PositionChanged -= OnGeoWatcherPositionChanged;
geoWatcher.Stop();

// Set coordinates to title text
GeoCoordinate coord = args.Position.Location;
ApplicationTitle.Text += ": " + String.Format("{0:F2}°{1} {2:F2}°{3}",
Math.Abs(coord.Latitude),
coord.Latitude > 0 ? 'N' : 'S',
Math.Abs(coord.Longitude),
coord.Longitude > 0 ? 'E' : 'W');
// Query proxy for AreaBoundingBox
LonLatPt center = new LonLatPt();
center.Lon = args.Position.Location.Longitude;
center.Lat = args.Position.Location.Latitude;

statusText.Text = "Accessing Microsoft Research Maps Service...";
proxy.GetAreaFromPtAsync(center, 1, Scale.Scale16m,
(int)ContentPanel.ActualWidth,

(int)ContentPanel.ActualHeight);
}


The method concludes by making its first call to the proxy. The GetAreaFromPtAsync call requires a longitude and latitude as a center point, but some other information as well. The second argument is 1 to get an aerial view and 2 for a map . The third argument is the desired scale, a member of the Scale enumeration. The member I’ve chosen means that each pixel of the returned bitmaps is equivalent to 16 meters.

Watch out: Some scaling factors—in particular, Scale2m, Scale8m, and Scale32m—result in GIF files being returned. Remember, remember, remember that Silverlight doesn’t do GIF! For the other scaling factors, JPEGS are returned.

The final arguments to GetAreaFromPtAsync are the width and height of the area you wish to cover with the map.

All the bitmaps you get back from the MSR Maps Service are 200 pixels square. Almost always, you’ll need multiple bitmaps to tile a complete area. For example, if the last two arguments to GetAreaFromPtAsync are 400 and 600, you’ll need 6 bitmaps to tile the area.

Well, actually not: An area of 400 pixels by 600 pixels will require 12 bitmaps, 3 horizontally and 4 vertically.

Here’s the catch: These bitmaps aren’t specially created when a program requests them. They already exist on the server in all the various scales. The geographic coordinates where these bitmaps begin and end are fixed. So if you want to cover a particular area of your display with a tiled map, and you want the center of this area to be precisely the coordinate you specify, the existing tiles aren’t going to fit exactly. You want sufficient tiles to cover your area, but the tiles around the boundary are going to hang over the edges.

What you get back from the GetAreaFromPtAsync call (in the following OnProxyGetAreaFromPtCompleted method) is an object of type AreaBoundingBox. This is a rather complex structure that nonetheless has all the information required to request the individual tiles you need and then assemble them together in a grid.

Example 5. Silverlight Project: SilverlightLocationMapper File: MainPage.xaml.cs (excerpt)
void OnProxyGetAreaFromPtCompleted(object sender, GetAreaFromPtCompletedEventArgs
args)
{
if (args.Error != null)
{
statusText.Text = args.Error.Message;
return;
}

statusText.Text = "Getting map tiles...";

AreaBoundingBox box = args.Result;
int xBeg = box.NorthWest.TileMeta.Id.X;
int yBeg = box.NorthWest.TileMeta.Id.Y;
int xEnd = box.NorthEast.TileMeta.Id.X;
int yEnd = box.SouthWest.TileMeta.Id.Y;

// Loop through the tiles
for (int x = xBeg; x <= xEnd; x++)
for (int y = yBeg; y >= yEnd; y--)
{
// Create Image object to display tile
Image img = new Image();
img.Stretch = Stretch.None;
img.HorizontalAlignment = HorizontalAlignment.Left;
img.VerticalAlignment = VerticalAlignment.Top;
img.Margin = new Thickness((x - xBeg) * 200 -
box.NorthWest.Offset.XOffset,
(yBeg - y) * 200 -
box.NorthWest.Offset.YOffset,
0, 0);

// Insert after TextBlock but before Image with logo
ContentPanel.Children.Insert(1, img);

// Define the tile ID
TileId tileId = box.NorthWest.TileMeta.Id;
tileId.X = x;
tileId.Y = y;

// Call proxy to get the tile (Notice that Image is user object)
proxy.GetTileAsync(tileId, img);
}
}


I won’t discuss the intricacies of AreaBoundingBox because it’s more or less documented on the msrmaps.com web site, and I was greatly assisted by some similar logic on the site written for Windows Forms (which I suppose dates it a bit).

Notice that the loop creates each Image object to display each tile. Each of these Image objects has the same Stretch, HorizontalAlignment, and VerticalAlignmentMargin properties, but a different . This Margin is how the individual tiles are positioned within the content grid. The XOffset and YOffset values cause the tiles to hang off the top and left edges of the content grid. The content grid doesn’t clip its contents, so these tiles possibly extend to the top of the program’s page.

Notice also that each Image object is passed as a second argument to the proxy’s GetTileAsync method. This is called the UserState argument. The proxy doesn’t do anything with this argument except return it as the UserState property of the completion arguments, as shown here:

Example 6. Silverlight Project: SilverlightLocationManager File: MainPage.xaml.cs (excerpt)
void OnProxyGetTileCompleted(object sender, GetTileCompletedEventArgs args)
{
if (args.Error != null)
{
return;
}

Image img = args.UserState as Image;
BitmapImage bmp = new BitmapImage();
bmp.SetSource(new MemoryStream(args.Result));
img.Source = bmp;
}

That’s how the method links up the particular bitmap tile with the particular Image element already in place in the content grid.

It is my experience that in most cases, the program doesn’t get all the tiles it requests. If you’re very lucky—and you happen to be running the program somewhere in my neighborhood—your display might look like this:



If you change the second argument of the proxy.GetAreaFromPtAsync call from a 1 to a 2, you get back images of an actual map rather than an aerial view:



It has a certain retro charm—and I love the watercolor look—but I’m afraid that modern users are accustomed to something just a little more 21st century.

Other -----------------
- Sensors and Services - Geographic Location
- Sensors and Services : A Simple Bubble Level
- Sensors and Services : Accelerometer
- Programming Windows Phone 7 : The Intricacies of Layout - The Mighty Grid
- Programming Windows Phone 7 : The Intricacies of Layout - The Canvas and Touch
- Programming Windows Phone 7 : The Intricacies of Layout - The Retro Canvas
- Programming Windows Phone 7 : The Intricacies of Layout - A Custom Vertical StackPanel
- Programming Windows Phone 7 : The Intricacies of Layout - A Single-Cell Grid Clone
- Programming Windows Phone 7 : The Intricacies of Layout - The Mechanism of Layout
- Programming Windows Phone 7 : The Intricacies of Layout - Two ScrollViewer Applications
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server