C# open source GIS is alive

A few weeks ago a number of developers around C# open source GIS came together when we all visited the MapWindow conference. There were also five contributers to SharpMap, Felix, Gena, Peter, Frank en me. We had the opportunity to meet with some of the MapWindow people like Dan Ames, Paul Meems and Matthew Klein. I think a lot of positive energy came out of it.

SharpMap itself has been in an impasse for a while. The SharpMap trunk has been stuck at version 0.9 for years now, even though new functionality was added. At the same time various other versions were in the making. There is now work going on to integrate the various version of SharpMap. The choice was made to focus on the SharpMap trunk. We will try to move the good parts of other branches/versions there. Another step towards integration has been taken by Felix when he replaced SharpMap geometries with NTS. We hope DotSpatial could start to use this same version so we are one step closer.

For my own client Mapsui I need support for various platforms like Silverlight, Windows Phone, WinRT and the PixelSense. This won’t change. My approach will be to adapt NTS and parts of SharpMap so that it can be used cross platform, probably by creating Portable Class Library versions. This will be slow process because we will need consent on everything. But at least we are now moving forwards, and moving as a community.

Projecting from WGS84 to SphericalMercator

Projecting from one coordinate system to another is a big topic in the geo bizz. Most apps use comprehensive libraries to deal with all possible projections. These days 90% of the projections that I see are from WGS84 to SphericalMercator. Mostly this is GPS coordinates projected to a Google, Bing or OpenStreetMap tile background. If you would like to keep it simple the code below would suffice (Thanks to Steven Fruijtier for sharing the code).


using System;
using SharpMap.Geometries;

namespace Projection
{
public static class SphericalMercator
{
private readonly static double radius = 6378137;
private static double D2R = Math.PI / 180;
private static double HALF_PI = Math.PI / 2;

public static Point FromLonLat(double lon, double lat)
{
double lonRadians = (D2R * lon);
double latRadians = (D2R * lat);

double x = radius * lonRadians;
double y = radius * Math.Log(Math.Tan(Math.PI * 0.25 + latRadians * 0.5));

return new Point((float)x, (float)y);
}

public static Point ToLonLat(double x, double y)
{
double ts;
ts = Math.Exp(-y / (radius));
double latRadians = HALF_PI - 2 * Math.Atan(ts);

double lonRadians = x / (radius);

double lon = (lonRadians / D2R);
double lat = (latRadians / D2R);

return new Point((float)lon, (float)lat);
}
}
}

Tile schema compatibility

How easy is it to combine different tile services in one map? For instance, how easy is it to combine Google Maps aerial photos with a roads overlay from a TMS. Well this depends on two things, 1) how smart is the client, and 2) how compatible are the tile schemas. Here we look at several levels of compatibility taking the TMS specification as an example.
In TMS a tile schema is described in a TileMap. The main parameters involved are:
  • Origin: the coordinate where the first tile starts. It is the bottom left corner of tile (0, 0).
  • BoundingBox: the extent in which tiles are available. The BoudingBox’s bottom left coordinate is often identical to the origin but doesn’t have to be.
  • TileSets (levels): a list of the available tile levels and their resolutions.
1) Identical
Okay, lets keep this short, sometimes the schema’s are just the same.
2) Common tile system
When the BoundingBox’s are different but the Origin and TileSets are the same a tile in one schema will have the same x ,y and level as it’s corresponding tile in the other schema. The only difference between the schema’s is that some tiles can be available in one scheme but not in the other.
The two schemas can be said to be in the same tile system. If the TileSets are perceived as a Z-axis it forms a kind of three dimensional coordinate system for tiles. The origin of that space is defined by Origin.X, Origin.Y and the resolution of the first TileSet. The steps are defined by the tile width, tile height, the step size between resolutions (which can be irregular to complicate things).
3) Projectable to another tile system
When the tile system differs it is sometimes possible to transform a tile in one tile system to the other tile system. For instance when in one schema the Y-Axis is inverted with respect to the other it is easy to see how tile (0, 0) can be mapped to tile (0, count – 1). Such a trick is sometimes used in simple cases. I have not seen it done for more complicated relations. In this case the boundingboxes are the same, but the x, y and level identifiers are not.
4) Projectable to the map coordinate system
When the above methods fail because the TileSets are too different it is not possible to project one tile to another but it is still possible to project the tiles to a single map coordinator system, thus combining two totally different tile layers. The downside is that you can not use performance optimizations where you combine tiles of several sources into a single tile. This can cost more memory and may be somewhat slower.

Porting SharpMap to Silverlight – first attempts

Over the last week I spend some time porting open source GIS library SharpMap V1 to Silverlight. My intent was to go straight towards a working version in the easiest and quickest way and try to suppress my urge to redesign. Below is how I worked through it. It might be relevant for those who have to do a similar port.

First, I removed all the files that I didn’t need. I included only those that I needed to retrieve data (shapefiles) and render a map.
System.Drawing
Silverlight has no System.Drawing (GDI), so my next goal was to move this into a separate dll while maintaining all functionality. I created an IRenderer interface in SharpMap and used the existing GDI rendering for the implementation. I put this in a separate assembly called GdiRendering.dll.

The IStyle class in SharpMap also depended on System.Drawing. I replaced all the System.Drawing classes in IStyle with implementation independent classes. These were converted to System.Drawing classes in the GdiRenderer.

For raster renderers there was no separation between data retrieval and rendering at all. So I introduced an IRasterProvider and an IRaster class. In the GdiRenderer this IRaster type was treated in the same way as the geometry types.

At that point all GDI was contained in the GdiRenderer.dll and I could remove the System.Drawing dll from SharpMap. Everything worked like at the start. There was no WPF or Silverlight yet.

System.Data
Next was System.Data. There is none in Silverlight, so no DataTable or DataRow, yet the IProvider interface heavily depends on it. I spend some time looking for a good solution here. I was expecting to find some simple grid-like data structure, but I ended up using a List of FeatureDataRow for the table and derived FeatureDataRow from Dictionary. The downside here is there is no restriction on adding columns, you could add anything you like to it. I am open for better (and simple) solutions.

System.Xml
With that settled I was about to set up a Silverlight data provider so I could start on my SilverlightRendering.dll. But which provider? It turns out that the current SharpMap data providers fall in into three categories:

  1. Raster. This would work just fine but my purpose was to implement vector rendering to SL, I had raster already working in BruTile.
  2. Vectors read from db or file. This is not allowed from the SL sandbox.
  3. Vectors retrieved from web. That’s what I need but it turns out they all depend on XmlDocument which is not part of Silverlight.

I worked around this problem by using WPF rendering and a file based data provider. I created two project files for my SilverlightRendering.dll, one SL, one WPF, that share the same files. I developed my renderer using the WPF version. So far I have only compiled my SL version, I have yet to find out if it actually works.

Finally Rendering
With the WPF version of the SilverlightRendering.dll I managed to render Points, MultiPoints, LineStrings, MultiLineStrings, Polygons and MultiPolygons. I was happy to see that it is also possible to render Polygons with holes, this could have been a been a show stopper for a proper gis lib. The renderer currently ignores projections but there is a Silverlight version of proj.net on http://projnet.codeplex.com.

So far it seems there are not many complications. I am currently investigating how I could use System.Data for the file and db data providers, while having a System.Data free Silverlight version. I believe it is possible to also support WPF and WinForms without too much maintenance. Support for Windows Phone 7 should be easy.

BruTile’s async tile fetcher

This morning I had some time to play around with powerpoint. Below is a diagram depicting how BruTile’s tile fetcher works. The tile fetcher runs on a worker thread and fetches tiles from the web or the disk. The idea behind its setup was that the direct communication between the UI thread and the fetcher thread would be minimized. The only direct communication is a ViewChanged call to the fetcher, telling it the user is panning or zooming and a DataChanged callback telling the UI it should render. The fetcher dumps incoming tiles into the MemoryCache, which is just a big bag of tiles. The UI renderer retrieves whichever tiles it needs.

Both the fetcher and the renderer can use all kinds of smart tricks. The fetcher can pre-fetch tiles based on its current view, or on the way the view changes over time. The renderer could search for alternative tiles (higher or lower levels) when the optimal tiles are not available. Those strategies should be tuned to support each other. For instance, in the current implementation the renderer uses higher level tiles when the optimal tiles are not available, and the fetcher pre-fetches higher level tiles to assist the renderer. But the way they play together is not specified in the interface. This loose coupling keeps things simple and flexible and the renderer never has to wait for the fetcher which results in a smooth (perceived) performance.

ArcBruTile released

Last week Bert Temme released ArcBruTile 0.1.6. This is a plugin for ArcGIS which uses BruTile to show tile layers in ArcGIS. This allows for an easy way to show openstreetmap data in ArcGIS which became very relevant due to it use in the Haiti crisis.

What I like so much about ArcBruTile is that it is connecting OSS to the ESRI/Microsoft world. That was one of the purposes we had in mind when creating BruTile and this is the perfect example. An added bonus is that we can now use the projection capabilities in ArcGIS on our tile layers, something that won’t be possible with our C# OSS tools soon.