How to Load Spatial Data from SQLite in a Windows Store App

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 or 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.

image

Next we add references to the Bing Maps SDK, the Visual C++ Runtime and SQLite.

image

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”.

image

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”.

image

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”.

image

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.

<Page
    x: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">

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="140"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <TextBlock x:Name="pageTitle" 
                   Text="WinRT and Spatial Data from SQLite" 
                   IsHitTestVisible="false" 
                   Style="{StaticResource PageHeaderTextStyle}" 
                   VerticalAlignment="Center" 
                   Margin="30,0,30,40"/>

        <bm:Map x:Name="myMap" 
                Grid.Row="1" 
                MapType="Aerial" 
                ZoomLevel="13" 
                Credentials="Your_Bing_Maps_Key">
            <bm:Map.Center>
                <bm:Location Latitude="47.702894" Longitude="-122.054860" />
            </bm:Map.Center>
        </bm:Map>

        <TextBlock x: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 = new Uri("ms-appx:///Assets/trail.db"); 
  var file = await StorageFile.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 = new MapShapeLayer();
  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 = new LocationCollection();
    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 = new MapPolyline();
    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 = new MessageDialog("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. You’ll find the complete source code here.

Happy Coding Smile

image

About these ads
This entry was posted in Bing Maps, SQLite, Windows Store and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s