Sometimes it can be helpful to hold geospatial data locally and to distribute it with the application. In this example, we will use SQLite to store geospatial information and visualize it as a layer in the Bing Maps Control for Windows Store Apps.
SQLite is a software library that implements a self-contained, server-less, zero-configuration, transactional SQL database engine.
Preparing the Data
For this example we will be using trails which we retrieved from the King County GIS Data Portal. This data is available in Esri Shapefile format with coordinates in the North American Datum 1983 (NAD83) system. I converted them into a SQLite database with coordinates described as latitudes and longitudes with decimal degrees in the World Geodetic System 1984 (GS84) using the ogr2ogr command-line tool from Geospatial Data Abstraction Library (GDAL). The command for this conversion is:
ogr2ogr.exe -f sqlite -lco FORMAT=WKT "D:\Downloads\GeoData\King County\trail_SHP\trail.db" "D:\Downloads\GeoData\King County\trail_SHP\trail.shp" -t_srs EPSG:4326
Prerequisites
Since we are developing a Windows Store App, we need access to a Windows 8 machine as well as Visual Studio 2012. A free version of Visual Studio Express 2012 for Windows 8 is available here.
For this project we require the “Bing Maps SDK for Windows Store Apps” as well as “SQLite for Windows Runtime” you can install both from Visual Studio 2012 by selecting “Extensions and Updates” from the menu “Tools” and searching for the respective SDKs in the online gallery.
We will also require a Bing Maps Key. If you don’t have one yet, you can follow the instructions to get a free trial or basic key.
Preparing the Project
Let’s start by creating a new project using the blank Visual C# template for Windows Store Apps.
Next we add references to the Bing Maps SDK, the Visual C++ Runtime and SQLite.
The Bing Maps SDK requires that we compile separately for each processor architecture. So we need to open the “Configuration Manager” and change the platform from “Any CPU” to a specific one – here “x64”.
We also require the “sqlite-net” library and we can add this from NuGet by opening the menu “Tools” →“Library Package Manager” →“Manage NuGet Packages for Solution” and searching for “sqlite-net”.
Finally we add the SQLite database trail.db to the folder “Assets” of the project, set the property “Build Action” to “Content” and “Copy to Output Directory” to “Copy if Newer”.
Adding the Application Markup
Now that our project is prepared, we open the MainPage.xaml add the namespace for the Bing Maps control and define the user interface. In the user interface, we load Bing Maps centered to a location in King County at zoom-level 13 and specify that we want to display the aerial imagery.
<Pagex:Class="SQLite_Blog.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:SQLite_Blog"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:bm="using:Bing.Maps"mc:Ignorable="d"><GridBackground="{StaticResourceApplicationPageBackgroundThemeBrush}"><Grid.RowDefinitions><RowDefinitionHeight="140"/><RowDefinitionHeight="*"/> <RowDefinitionHeight="Auto"/></Grid.RowDefinitions><TextBlockx:Name="pageTitle"Text="WinRT and Spatial Data from SQLite"IsHitTestVisible="false"Style="{StaticResourcePageHeaderTextStyle}"VerticalAlignment="Center"Margin="30,0,30,40"/><bm:Mapx:Name="myMap"Grid.Row="1"MapType="Aerial"ZoomLevel="13"Credentials="Your_Bing_Maps_Key"><bm:Map.Center><bm:LocationLatitude="47.702894"Longitude="-122.054860" /></bm:Map.Center></bm:Map><TextBlockx:Name="myAttribution"Text="Data provided by permission of King County"Grid.Row="2"/></Grid></Page>
Adding the Code-Behind
In the code-file MainPage.xaml.cs we define a class that describes the SQLite table.
public class trail { public string OGC_FID { get; set; } public string WKT_GEOMETRY { get; set; } public string kc_fac_fid { get; set; }public string trail_name { get; set; }public string trail_type { get; set; }public string surf_type { get; set; }public string sitefacfid { get; set; }public string sitename { get; set; }public string sitetype { get; set; }public string owner { get; set; }public string ownertype { get; set; }public string manager { get; set; }public string managertype { get; set; }public string maintd_by { get; set; }public string mainttype { get; set; } public string shape_len { get; set; } }
For the class that will actually read the data and display it on the map, we import three libraries:
using Bing.Maps;using Windows.Storage;using Windows.UI.Popups;
The class that reads the trail-database copies it first in the local application directory. It creates a MapShapeLayer, reads through the table-records and adds the records for the trails to the layer before it adds the entire layer to the map.
One point to call out here is that the data is stored as Well Known Text (WKT) in SQLite. The WKT has the coordinates in the order Longitude and then Latitude while Bing Maps expects them in the order Latitude and then Longitude. So we have to swap the order of the coordinates.
public async void GetTrails() {var uri = newUri("ms-appx:///Assets/trail.db"); var file = awaitStorageFile.GetFileFromApplicationUriAsync(uri);var destinationFolder = ApplicationData.Current.LocalFolder;//local appdata dir try {await file.CopyAsync(destinationFolder); //copied application local folder}} }catch { }var dbpath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "trail.db");var db = new SQLite.SQLiteConnection(dbpath);var trails = db.Table<trail>();MapShapeLayer shapeLayer = newMapShapeLayer();int numLocs = 0;int numTrails = 0;foreach (trail thisTrail in trails) {var wkt = thisTrail.WKT_GEOMETRY.Replace("LINESTRING (" , "").Replace(")", "");string[] wktArray = wkt.Split(',');LocationCollection bmPolylineLocs = newLocationCollection();for (var i = 0; i < wktArray.Length; i++) { var loc = wktArray[i];var locArray = loc.Split(' '); bmPolylineLocs.Add(new Location(Convert.ToDouble(locArray[1]), Convert.ToDouble(locArray[0]))); numLocs = numLocs + 1; }MapPolyline bmPolyline = newMapPolyline(); bmPolyline.Locations = bmPolylineLocs; bmPolyline.Color = Windows.UI.Colors.Red; bmPolyline.Width = 5; shapeLayer.Shapes.Add(bmPolyline); numTrails = numTrails + 1; }myMap.ShapeLayers.Add(shapeLayer);var myMsg = newMessageDialog("Loaded " + numTrails.ToString() + " with " + numLocs.ToString() + " locations" );await myMsg.ShowAsync(); }
Finally we add a call to this new class right after we initialize the app.
public MainPage() {this.InitializeComponent();GetTrails(); }
And that’s it. Below you see a screenshot of the trails in King County on top of Bing Maps.
Happy Coding! ☺