Showing posts with label OpenStreetMap. Show all posts
Showing posts with label OpenStreetMap. Show all posts

Tuesday, June 8, 2010

Maps revisited

Last year I created a prototype map renderer in Silverlight using the OSM dataset. Since then I've been thinking about some of the issues with the design - especially:
  • the UI load time and
  • some specific issues with the Quad Store approach
  • Dataset size
  • Automated updates to the dataset, including taking differences
  • No Geograhic AI system
  • No animation engine in the renderer

I've decided that I will restart the renderer again, but with a new design, storage mechanism and using more mature agile approaches (i.e. TDD, Mocking, IoC etc). Also during this time silverlight has moved form version 2.0 to 4.0 which also offers some interesting capabilities, and .Net 4.0 now has support for memory mapped files. I also want to follow a more product management approach, with a proper backlog etc.


TDD Unit test for Strontium using Rhino Mocks
I've started writing new code, especially for the import routine using the full dataset rather than just London. As part of this I'm using PowerShell and the Pscx extensions - there seems to be some issues with handling large files, so hopefully when this gets fixed I can have a constantly updating system.

The prototype code was using the Project Cobalt name, this new effort will go under Project Strontium

Monday, June 1, 2009

Mapumental

Maps with travel information overlaid - very nice!

Mapumental

Tuesday, February 3, 2009

Terms of Service for Web Mapping providers

Interesting article on Terms of Service for Web Mapping providers and the dangers of clicking "I Agree" without actually reading the terms (apparently 50% don't read before agreeing)

Nice coverage of what people are signing up for when they use the various services and a bit of light shed on the Ordnance Survey "Show us a better way" fiasco.

Reminds of the Copyright article on uncyclopedia

though they do recommend reading the Wikipedia (a dangerous parody of Uncyclopedia):

Wednesday, January 28, 2009

Moonlight, Silverlight and OpenStreetMap

One of the nice things about creating the map in Silverlight has been the possibilty of using a Moonlight client to reach even more users..

however I seem to be causing problems in moonlight with my OpenStreetMap in Silverlight..

Bad me! I suspect this is because I am really pushing the Silverlight threading model - the application is very UI intensive, which is something that (ironically) Silverlight has problems with (You can't multi-thread UI calls, so everything bottlenecks waiting for Dispatch).

I will try and see if I can help the Moonlight guys with the fixin'

I've been a bit quite on the map front - mainly due to re-engineering the Quadstore to handle the whole planet - this is still ongoing (I'm trying to keep conversion time from OSM dataset to Quadstore to under an hour, and at the same time not use SQL Server)

I have updated the demo to improve a few things:
  • Points of Interest now supported (though theres not mainly in my test data set, my fault not OSM's - I filtered them out, next data upload will fix this) You can see them as blue/red triangles. Hopefully I should be able to start demonstrating the power of the dynamic approach by allowing users to select what POIs to show on the fly.
  • Where's FE? this is really me just playing - from my post on mobile location finding I've added the capability to the cobalt server to track users. My windows smartphnone mobile phone tells the server where it is and this is shown as a little icon - in the future a user can download this app and put their own details in. They can then show this on their own map, and if the choose allow other (selected users) to see their location. You will also be able to tell the system how accurate you want the position to be (so the icon can be placed anywhere within, 100, 10, 1, exact square meters.
  • Road smoothing - I've improved this algorithm to speed this up, mainly by reducing it from O(n2) to O(n) by using a "smarter" approach.
  • Performance - I did a lot of profiling combined with improving the road smoothing alg, has made the map faster, however I'm still unhappy with the 30sec draw time - faster computer do this in about 12-15 seconds. This is too slow, so performance is still on the agenda. I had some good feedback from emj on OpenStreetMap on this - thanks!
The next release of the map should support the full world and complete pan/zoom control..

Wednesday, December 31, 2008

2008: a long year

It's that time of year again, where we celebrate the significance of digit roll-over on a completely artificial counter for time - the New Year.

This year has (will) be a long one (BBC: New Year to arrive a tick later), and as is the custom I thought I betters have at least one resolution for the New Year:

  • Start doing more AI - this blog was meant to have more of this, but I seem to have spent most of the year learning technologies (Silverlight and OpenStreetMap - both fun of course!).
So next year I will have to dig out a good book on the subject (Artificial Intelligence in Geography)


And try and combine all three!

Thursday, December 18, 2008

OpenStreetMap rendering in Silverlight part XI

I had a look to see what was causing the serial drawing nature of the map, and it does appear to being caused by going via the Dispatcher. Silverlight supports multithreading, but any code that want to do UI work must do it in the main thread.

   // get the tile data
   quadrant = GetTileData();
   // we are creating UI elements, go via dispatcher
   map.Dispatcher.BeginInvoke(delegate()
   {
    Canvas canvas = new Canvas();

    Tile tile = new Tile(quadrant, canvas);

    // create instance of renderer
    ITileRenderer tileDrawer = RenderFactory.CreateRenderer(tile);

    // render the tile
    tileDrawer.Render();

    // tell the requester that the tile available to add to UI
    tileLoaded(quadrant.Path, tile);
   });
This means multithreading is great if you have complex calculations going in, and just need to update a simple UI. However for code where the complex work is the UI then you end up hitting a bottleneck. In the code for drawing London I am creating 24 tiles which in total contain about 60k poly-line/gons. I am effectively forced to create them in a serial fashion (my code is non-serial, but each tile has to wait for the last tile to stop using the Dispatcher).

On my PC it took about 30seconds to draw the map of London (once you have run it once all the data should be cached). I've made some changes to speed this up, so it now runs in 15 seconds. I updated the Silverlight Map demo to use this version (you may have to delete the XAP file from your cache to get the newer version)

For the production version I will not be trying to draw the whole of London like this, but it does suggest that progressive rendering will be needed to make the application more responsive. (Progressive as in only draw large items on the tile for the first pass, and then add detail in the subsequent background passes)

I'm not sure if this UI blocking issue will be a problem for other developers (most complex UIs are made using bitmap based tile operations so in this case they would only have 24 UI elements vs. my 60k) and for other non UI intensive applications the current threading model is fine. However it would be nice if this large block could be removed - for example only require the Dispatcher when the tile is added to a visible UI element...

Wednesday, December 17, 2008

OpenStreetMap rendering in Silverlight part X

Last few days were spent refactoring some of the design and data models. This has yielded some pretty impressive gains. Based on the UK data the following optimizations have been gained:

  • Original OSM data: 1.3gb
  • Import data into QuadStore: 367mb
  • QuadStore as binary: 97mb
  • QuadStore as compressed binary: 48mb
Yep that's right the whole of the OSM data for the UK has been compressed from 1.3gb into 48mb, or in other words its less than 5% of the original size. And the majority of this gain has delivered a geographically clustered data set, so it's fast as well.

I've also updated the map to cache data (it caches the compressed binary) into IsolatedStorage, though the default of 1mb is not enough for a mapping application, so it now requests the user to increase it to 10mb upfront. The nice thing about using the compressed binary is that we can cache twice us much as well!

To show the effect of all these optimizations I've changed the demo to show the whole of London (alá EastEnders)  on the fly:


The main bottle neck I have now is the requirement to go via the Dispatcher for drawing UI elements, this causes the "one at a time" display of tiles. I think I can get round this, but I will have to investigate further (it may just be my own code causing this!)

Given that the code is drawing a very detailed map of the whole of London it's very fast, however for a production version I would create lower resolution tiles first and replace them with higher resolutions in the background.

Friday, December 12, 2008

OpenStreetMap rendering in Silverlight part IX

From talking to people at the last London OSM meet it appears that large ways are not a good idea for performance reasons (the OSM database and editors). For example the River Thames is split into a number of ways, rather than being one big one.

Since I can cope with large ways, and there are performance gains and presentation gains from combining them I did a test applying two techniques.

The first was to "promote" low level tile feature that are deemed interesting at the time of OSM import. So for example I promoted all coastlines from level 12 to level 4, and major rivers from 12 to 9. The promotion level was gut feel.

I then applied the road junction method to coastline features. Then I applied this to the whole of the UK:


This reduced the draw data from 9k to 4k, with a smoother coastline. I applied the road junction method on the fly, however this would make more sense at the point of import for coastlines. This is because when drawing the map I want to know about the individuals roads, whilst for the coastline, rivers etc the split was artificial in the first place.

In the picture there are some lines outside the country which are mostly ferry routes, and the line of detail down the south-east of England is a tile border (there is also one horizontally in Scotland buts it's not so obvious). At this level of zoom the code needs to filter out such small features.

Wednesday, December 10, 2008

London is 80k polygons

Well I'll be, and I thought it was a city, instead its 80k polygons (actually its more than that, but some were optimized out)

Click to zoom:


[warning 500kb image!]

OpenStreetMap rendering in Silverlight part VIII

One of the issues that my current renderer has is that it's not as smooth as the raster versions used in the slippy map. One of the worst offenders was road junctions, where two roads meet. They looked something like this:


In the image you can see where the two roads meet there is a gap. This is due to my code drawing the two roads as separate polylines. I create a test renderer to see if this could be improved:


This version has joined the two roads together, drawing only one polyline for both of them. This results in a smooth join, and also a reduction in the number of objects. For example joining roads where they share a start and end point reduces the number of objects for south-west London from ~40k to ~30k. So not only does it create nicer looking maps, it makes them less memory intensive.

It occurs to me that this technique could be used for any Xaml consisting of multiple lines, as my findings suggest that Silverlight performs faster (one poly line with a 1,000 segments is faster than 1,000 single line segments)

My join algorithm is brute forced within a tile (creating an O(n2) complexity) which won't do for release code. So I will write a smarter version - hopefully of the order of O(3n).

I also spotted that a lot of ways within OSM are artificially split (the river Thames for example) I don't know if this is a feature of data collection or policy. My QuadStore design can cope with large entities like the river Thames quite easily - so applying this same technique at a higher level may generate smooth maps overall.

Tuesday, December 9, 2008

OpenStreetMap rendering in Silverlight part VII

I've been refactoring the application to tidy up handling of geography calculations and especially tile positioning, (drawing is now done using a visitor pattern). I've not released a new verison as it currently a step backwards (I've not yet worked out who should be reponsible for zoom and rotation, so I've left it out)

As a test of tile positioning I tried to render London at a high detail level, I used some simple colours (blue=water, green=leisure or natural, black for everything else). I manually selected the tiles, but the code places them correctly - what's nice about the picture is that it shows the high level of detail that is available due to everyone's contributions to OSM, (click to see detail)



see the previous zoom/rotation version of the Silverlight OpenStreetMap

Thursday, December 4, 2008

OpenStreetMap rendering in Silverlight part VI

I've spent some time looking at performance, using some of the tricks from Seema's blog - she also very helpfully sent me some helpful tips when trying to build applications with many complex shapes.

Changes to the version now include:
  • Speed/Memory improvement using feature clipping.
  • Tooltips tags for features, (mouse over a line or area to see)


The neeed for speed: performance investigation
This is where the ability to swap drawers has been helpful, I was able to create try out new ideas without having to worry about breaking the existing drawing system. One of the technique's I investigated was drawing using Silverlight's mini-language, this allows you to draw complex shapes using a LOGO like definition:

<Canvas>
<Path Stroke="Black" Fill="Gray"Data="M 10,100 C 10,300 300,-200 300,100" />
</Canvas>

Since I need to draw this dynamically I need to load the Path.Data from a string:

StringBuilder sb = new StringBuilder();
sb.Append("<Path xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"");
sb.Append(" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"");
sb.Append(" Data=\"");
sb.Append("");

ShowWay(sb, tileBorder);
foreach (var gpp in quadrant.GeoPolyPoints)
DrawFeature(sb, gpp);

sb.Append("\"/>");

GeometryGroup gg = new GeometryGroup();
Path uiPath = (Path)System.Windows.Markup.XamlReader.Load(sb.ToString());

using a helper function to turn a set of points into a set of draw instructions:

private void DrawFeature(StringBuilder sb, GeoPolyPoint gpp)
  {

   bool isFirst = true;
   foreach (GeoPoint geoPoint in gpp.GeoPoints)
   {
    int y = geoPoint.GetScaledX(viewport);
    int x = geoPoint.GetScaledY(viewport);

    if (isFirst)
    {
     isFirst = false;
     sb.Append(" M ");
    }
    else
     sb.Append("L ");

    sb.Append(x);
    sb.Append(',');
    sb.Append(y);
   }
   if (gpp.PolyConstruct == PolyConstruct.Polygon)
    sb.Append("Z ");

   return count;
  }

I then timed this against my previous attempt, and found hardly any difference - and I also tried create PathFigures, Geometries etc - these were painfully slow (mainly due to the need to create lots of LineSegment objects). So I am sticking with creating Shapes (Polygon and Polyline) as both of these take a collection of points, so no need to create lots of lines.

I then had a look at Seema's blog again and had a play with
<param name="enableRedrawRegions" value="true" />

This showed that I was updating a vast region of the screen, this seems to be related to clipping not behaving as expected - I've asked Seema for some clarification on this. However I also knew my draw routine was pretty lazy - it did not check when drawing a feature if it would even be visible on the tile (for example to the left of the tile).

I was relying on Silverlight clipping to do all the work. So I put in a simple check to only draw features that actually appear in the tile. This reduced the New Malden draw set from 26,038 features to 7,979. This means my code is drawing 3 times less shapes - a massive memory and speed improvement (10% faster), but more importantly ~20,000 shapes that Silverlight does not have to calculate, rotate, clip for no visible effect.

Once I get an answer from Seema on the clipping issue things should get even quicker!

Tuesday, December 2, 2008

OpenStreetMap rendering in Silverlight part V

Have released the first version of the map, its limited to just new malden and is still using a simple drawing plug-in.

You can play with it by clicking on the picture:

Its a very simple update from what I've been working with, but I spent most of the day fighting DNS, FTP, Visual Studio and my own stupidity ;-( However it now shows/does a number of things:
  • parallel downloading of tiles (still not predictively, but since you can see only new malden that's not going to hurt!). Tiles fade in for effect
  • fixed colour coding for tiles (red, green, blue and magenta for TR, TL, BL, BR tiles) and then colours the tiles according to size (small to large - orange, cyan, purple, brown and dark gray for everything else). This allows you to see how a tile is a mixture of data from different levels.
  • I extended the drawing to shade areas as its easier to work with the map (the non-shaded version was easy to get lost in)
  • drag and move: you can drag the map around
  • zoom: mouse wheel - you can zoom the map in and out
  • rotate: mouse wheen+ctrl - you can rotate the map (this is too slow at the moment I need to look at why, also there is some odd clipping going on if you turn clockwise)

Its all debug code, and we probably won't ever show tiles at this size and detail (i.e there's too much detail at this level of zoom). However there is certainly work to be done on improving the general speed of drawing...

Monday, December 1, 2008

OpenStreetMap rendering in Silverlight part IV

A critical part of be able to show the maps is putting tiles together, today the code base solved a number of problems:
  • downloading data asynchronously (though not yet predicatively, or in parallel)
  • reduced data set transmission sizes (from 367mb to 97mb for the UK) - no compression yet.
  • clipping of drawing to fit within tiles, (applying higher level data to tiles does not draw outside the tile) though this does not yet crop the drawing effort (performance to be gained here)
  • multi-tile support, the code can handle multiple tiles independently (though does not yet know how to stitch properly yet).
All of this yields a nice improvement in speed and appearance, hopefully I can post a live version tomorrow.


The colours above are used to show which level the data existed at (per tile, cross tile etc) so you can see how the image is made of four tiles, with large entities (i.e. across tiles) being in different colours.

Saturday, November 29, 2008

OpenStreetMap rendering in Silverlight part III

As part of writing the silverlight renderer I wanted to be able to "plug-in" different rendering engines - so you can change how the map looks depending on what you are using it for.

For the test and dev phase I've created a simple "sketch" renderer that's fast and uses different colours purely for tile differentiation.

Here's a snapshot of the sketch renderer drawing part of new malden:

Thursday, November 27, 2008

OpenStreetMap rendering in Silverlight part II

So I've been progressing quite quickly with the OSM data, I'm currently using the UK data set to trial stuff for a number of reasons - the biggest one being that for some reason I can't successfully unzip the full data set *grr* (I suspect this is my PC rather than anything else)

I've written a data store for project cobalt that allows me to restructure the OSM data into a format more suitable for realtime map generation - I'm calling it a QuadStore as its a geographically clustered XML data model and GCXDM does not sounds as good.

Throwing all 1.2gb of the UK data generates a QuadStore of 365mb which is a compression I get for free due to losing duplicated data in the OSM model. I'm also ignoring OSM "relationship" data at the moment as a) I don't know what it means yet b) I'm having to much fun with just "ways".

I've then updated the silverlight proof of concept to use the QuadStore via a webservice - this seriously kicks ass in performance terms (and the proof of concept just did not scale for multi tile retrieval). Using the QuadStore means that tile filling is 1 (yes) one cost - O(1) rather than O(n) where n=number of points in tile.

So for fun I ask the proof of concept to pull every tile and draw them out as rectangles - which looks something like this (the screen shot is halfway through the draw so you can see the progression)



There's quite a bit of performance to be gained from the webservice, for example by compressing the stream (though compressed streams are not available in silverlight). And also from returning multiple tiles per call rather than one at a time.

So the next step is to change the silverlight UI to manage tiles correctly, once it does this I will release a working version. One of the nice features I should be able to deliver is being able to rotate the map...

Friday, November 21, 2008

Proof Of Concept of OpenStreetMap in Silverlight

So I've put up the proof of concept I did to see what happens if you render OSM with Silverlight and it looks pretty neat. Its just the New Malden data (1.2mb OSM), you can pan around by dragging, and get tooltips on all the items on the map.

I need to revist how I'm going to model this in code, and how I am using MS SQL in the equation.

Thursday, November 20, 2008

OpenStreetMap rendering in Silverlight

So the other part of OSM I wanted to look at was the feasibility of writing a Silverlight client for the OSM data. So the OSM render of New Malden, UK looks likes:



and my first attempt (mostly guessing what things should look like and be layered) looks like:



which obviously is not as good as the XSLT/SVG renderer for OSM - however I only spent a day on it. A few things I learnt, 1) the OSM renderer is doing some nice joins on street junctions 2) the OSM format is not complex, but its not documented (not to a great detail).

The New Malden data set is 1.2mb, and the silverlight code generates 976 Polylines and 178 Polygons, and it renders in 0.11 seconds.

So what does this all mean? for one, I like the OSM format, and we can build primitive data type into the system based on Node, Way and Relation to makes life easy and consistent with the OSM view. However I need a higher level model to interpret this data. That way the primitives can stay flexible and "dumb", whilst the high level can focus on routes and joins etc.

The method I used to process the data into UI elements is based on the following concept. I create a top level tile to put all the items into, and then I create PolyLines or Polygons using just ways (I don't process relations yet). I use a simple fixed formulae to map the node GPS points into X,Y (not correct or proportional - but close enough to visualize). I use Polygons for ways the end at the same location as its start, and PolyLines for everything else. I use the tag field on the ways to decide the fill or stroke colour, and set the z-index based on the same model.

The effect of creating a top level tile is that I can pan the whole of New Malden but just moving the tile, rather than having to move each item individually. It also means I can use multiple tiles to build the map, and cache them for performance (data retrieve rather than draw as at 0.11 seconds/tile I'm not worried yet)

Once I have abstracted the code into the two clean levels (primitive and map) I will post the code - at the moment it's too much of a hack (and the GPS conversion is very, very wrong)

Sunday, November 16, 2008

OpenStreetMap into SQL Server 2008 first steps

So as I said in my previous post "OpenStreetMap - show me some data" the next step in evaluating the use of the OSM data was to see how SQL Server 2008 Spatial features might help.

The first thing I wanted to look at was how to define the structure in SQL and work with it from C#. This was mainly to get a feeling for the data types involved. In SQL I created a database (UKGeo) and a table:

CREATE TABLE [dbo].[Nodes](
 [id] [int] NOT NULL,
 [location] [geography] NOT NULL,
 CONSTRAINT [PK_Nodes] PRIMARY KEY CLUSTERED 
(
 [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

The key point is to note the datatype "geography" being used for the location field, this datatype can handle a number of GIS related structures. We also need a stored procedure to load the data:

CREATE PROCEDURE [dbo].[sp_NodeCreate]
 @id int, 
 @location geography
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

 INSERT INTO Nodes(id, location) VALUES (@id, @location);
END

Once again it's a simple enough procedure, with the use of "geography" being the only complexity. From C# we just need to create a command pointing to this stored procedure:

   string sql = "sp_NodeCreate";
   SqlCommand command = new SqlCommand(sql, connection);
   command.CommandType = CommandType.StoredProcedure;

and when setting up the parameters we need to specify that the @location parameter is a Udt (user defined type), in this case geography is already registered in SQL, so we can just name it:
   SqlParameter idParam = new SqlParameter("@id", SqlDbType.Int);
   SqlParameter geoParam = new SqlParameter("@location", SqlDbType.Udt);
   geoParam.UdtTypeName = "geography";
   command.Parameters.Add(idParam);
   command.Parameters.Add(geoParam);

and finally a function to call the procedure:
 private void CreateNodeInDatabase(string id, string longtitude, string latitude)
  {
   SqlGeographyBuilder builder = new SqlGeographyBuilder();
   builder.SetSrid(4326);

   builder.BeginGeography(OpenGisGeographyType.Point);

   builder.BeginFigure(double.Parse(longtitude), double.Parse(latitude));
   builder.EndFigure();

   builder.EndGeography();

   SqlGeography geo = builder.ConstructedGeography;

   command.Parameters["@id"].Value = id;
   command.Parameters["@location"].Value = geo;

   command.ExecuteNonQuery();
  }

This code uses the SqlGeographyBuilder to create an instance of type Point, which is what we want location to contain. I'm sure this code is not the best way to do this, but it serves as a starting point for understanding the relationship between SQL and CLR implementations of spatial information.

Thursday, November 13, 2008

OpenStreetMap - show me some data

Project Colbolt requires some understanding of space (actually another project does as well, but one thing at a time!) so I am going to use OpenStreetMap, as it gives me access to the underlying data. I'm not sure I can go the whole way using this - I will have to read the copyright and terms.
 
However, the first part of the plan is to take the OSM data and start to understand it. What I already like is that this is a real sized data set, the UK alone is ~1.2gb of XML, the world is 5.3gb as a zip file. So I'm looking forward to some proper coding. Since I worked in direct marketing a few years ago large geographical datasets are great fun for me (sad git).
 
The stats say that the dataset for the world contains :
  • nodes 278 millon;
  • ways 23 millon;
  • relations 41 thousand.
Node = GPS point (long/lat)
Way = a list of nodes describing a map feature (streets, fields etc)
Relation = a more complex grouping, normally of ways
 
My first step was to play with just the UK data, (always start with a small dataset that you know roughly what it should look like).
 
I wrote a little C# application to read the UK file, which gave me back some stats:
  • nodes 6,441,456;
  • ways 873,054;
  • relations 1,362
So this means we can apply a rough estimate that anything about the UK data can be sized up to the world by multiplying it by 42 (thanks for all the fish!).
Knowing there was no sensible way to try and load the whole XML file into memory (especially when we come back to the world data) I used an XmlReader to process the data. A quick scan which processed all the tags and added up these counts takes less than 30 secs for the UK - so the rule of 42 says it would take about 20 minutes to read the whole world.
 
A stripped down node (removing editing information) looks like:
 
<node id="int" lat="float" long="float">
 
In terms of trying to hold it in memory, stuffing the UK nodes into a List<float[2]> as a pair of floats required 150mb of memory, a sparse array fell over after 1gb and a Dictionary<int, float[2]> used 379 mb.
 
The List<float[2]> approach would lose the node id, which is not really a valid comparison, though I could just use a BitArray to hold the id (as big as the largest ID, a 1 indicating if its in the List<float[2]>, and the number of 1s before it indicating its offset) - this would require another 1mb of memory, but would be slower that the Dictionary approach (not validated this). In either case this is all moot as the rule of 42 shows we would need 7gb just to hold the nodes for the world - and at this stage I'm not doing that!. So we are going to need a storage system...
 
The code so far, is skeletal, but shows what we have to do to process the OSM format - note I could have skipped most of the data, but I wanted to get a fair idea of what reading the data takes:
 
 


static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(@"k:\geo\uk-081015.osm");

Importer importer = new Importer(reader);
}

and the Importer class:


public class Importer
{
int nodes = 0;
int ways = 0;
int relations = 0;

public Importer(XmlReader reader)
{
// skip boring stuff
reader.MoveToContent();

reader.ReadStartElement("osm");

while (reader.IsStartElement())
{
string name = reader.Name;

switch (name)
{
case "bounds":
ReadBound(reader);
break;
case "node":
ReadNode(reader);
break;
case "way":
ReadWay(reader);
break;
case "relation":
ReadRelation(reader);
break;
default:
throw new Exception("Unknown element encounterd " + name);
}
}

reader.ReadEndElement(); // osm

Console.WriteLine("nodes {0} ways {1} relations {2}", nodes, ways, relations);
}

private void ReadBound(XmlReader reader)
{
reader.ReadStartElement();
reader.Skip();
}

private void ReadNode(XmlReader reader)
{
// get attributes
string id = reader.GetAttribute("id");
string latitude = reader.GetAttribute("lat");
string longtitude = reader.GetAttribute("lon");

reader.ReadStartElement(); // node
reader.Skip();
nodes++;

while (reader.Name == "tag")
{
reader.ReadStartElement();
reader.Skip();
}

if (reader.NodeType == XmlNodeType.EndElement)
reader.ReadEndElement(); // node
}

private void ReadWay(XmlReader reader)
{
// get attributes
string id = reader.GetAttribute("id");

reader.ReadStartElement(); // way
reader.Skip();
ways++;

while (reader.Name == "nd")
{
reader.ReadStartElement();
reader.Skip();
}
while (reader.Name == "tag")
{
reader.ReadStartElement();
reader.Skip();
}

if (reader.NodeType == XmlNodeType.EndElement)
reader.ReadEndElement(); // way
}

private void ReadRelation(XmlReader reader)
{
// get attributes
string id = reader.GetAttribute("id");

reader.ReadStartElement(); // relation
reader.Skip();
relations++;

while (reader.Name == "member")
{
reader.ReadStartElement();
reader.Skip();
}
while (reader.Name == "tag")
{
reader.ReadStartElement();
reader.Skip();
}

if (reader.NodeType == XmlNodeType.EndElement)
reader.ReadEndElement(); // relation
}

So as a first pass I'm going to stick it into SQL Server 2008 and see what the spatial features can do...