I just read this days newsletter from OGC, containing some news on the release of a simple profile of the GML v3.1.1 standard. From the standard one can read the following in the introduction:
This profile defines a restricted but useful subset of XML-Schema and GML to lower the “implementation bar” of time and resources required for an organization to commit for developing software that supports GML. [...] this profile facilitates the ability to use WFS for interoperable feature data exchange with much less software development investment.
The GML standard is a big and complex standard, and I really think this is a great move by the OGC. This is a 30 page long specification (well 117 if you include the annex), and it's nothing compared to the 267 (601) pages full GML spec.
Hopefully we'll see more GML support in the future. At least this finally got me started with implementing GML/WFS support into SharpMap.
Well, while I'm at it, if you want to know more on the GML specification, I can recommend the book "Geography Markup Language, Foundation for the Geo-Web" by Ron Lake from Wiley.
A couple of days ago, Ubikcan wrote about a set of county maps with voting results compiled by Anthony Robinson. I had a look at the data myself and discovered that they contain a bunch of interesting statistical data.
I tried creating various thematic maps and ended up with this little web-app where you can pan and zoom all the data.
Christian Graefe recently posted an update on his additions to the GDAL/OGR C# wrapper and his OGR provider for SharpMap.
Apart from the data sources that SharpMap already supports, Christians OGR provider adds support for "MapInfo File", "TIGER", "S57", "DGN", "Memory", "CSV", "GML", "Interlis 1", "Interlis 2", "SQLite" and "ODBC". If I'm not completely wrong he is also working on a GDAL raster layer as well...
Look at http://www.volley-boy.de/home/sharpmap.aspx
You will need to install FWTools to use it.
Great work Christian !
I've created a small demo showing how to utilize NetTopologySuite in SharpMap. The great thing about NetTopologySuite is that is has a bunch of geoprocessing methods that SharpMap doesn't have (yet anyway). The demo uses the NetTopologySuite library for the following:
- Apply some geoprocessing to the geometries (in this case it puts a buffer on all rivers)
- Uses NTS for making exact intersection queries. By clicking on an object the buffered feature(s) are highlighted and attribute data shown beneath.
The basics are:
Create a NTS datasource based on another datasource which takes a delegate to apply to all geometries:
NtsProvider ntsDataSource = new NtsProvider(myShapeFileDatasource, CreateBuffers);
Create the geometry-operation delegate method which should be applied to all features:
private void CreateBuffers(List<GisSharpBlog.NetTopologySuite.Features.Feature> features)
foreach (GisSharpBlog.NetTopologySuite.Features.Feature feature in features)
feature.Geometry = feature.Geometry.Buffer(0.5);
The 'ntsDataSource' object can then be assigned as datasource to a vectorlayer.
Clicking and highlighting features are done by reacting to a click-event on an ImageButton (in ASP.NET) or a PictureBox (in Windows.Forms).
protected void imgMap_Click(object sender, ImageClickEventArgs e)
//Convert click-point in image coordinates to world coordinates
Point ClickPnt = myMap.ImageToWorld(new System.Drawing.Point(e.X, e.Y));
SharpMap.Data.FeatureDataSet ds = new SharpMap.Data.FeatureDataSet();
//Execute click-query on first layer in layers collection
(myMap.Layers as SharpMap.Layers.VectorLayer).DataSource.ExecuteIntersectionQuery(ClickPnt, ds);
if (ds.Tables.Count > 0) //We have a result
//Add clicked features to a new selection layer
SharpMap.Layers.VectorLayer laySelected = new SharpMap.Layers.VectorLayer("Selection");
laySelected.DataSource = new GeometryProvider(ds.Tables);
laySelected.Style.Fill = new System.Drawing.SolidBrush(System.Drawing.Color.Yellow);
//Call method that renders a new map and displays it to the user
Download NetTopologySuite_Demo.zip (544,32 KB)
SharpMap v0.9RC1 is now available for download from the SharpMap website.
Thanks to all the people who kept sending feedback and bug reports!
I've resolved a lot of bugs since beta 1, as well as added some obviously missing properties and methods in the API. Especially the Shapefile reader has been enhanced to handle a lot of special cases (in one case it was even able to render a file that ArcGIS claimed to be corrupt). On-the-fly transformation has also been completed and now supports transformation between geographic and projected coordinate systems.
Thanks to Humberto Ferreira for providing us with an Oracle Spatial provider as well. SharpMap now supports data from ESRI Shapefiles, PostGIS, Oracle, Microsoft SQL Server, Access and ECW raster.
Last but not least, I've spent a great deal of time enhancing the documentation, so go take a look at that as well. There are lots of code-samples hidden in there as well.
I’ve always thought that on the spatial support, MSSQL was way behind many of the other database servers, in its lack of supporting storage of geometry. With the new .NET CLR you can actually add your own .NET-based object types and I’ve also tried implementing the Simple Features Specification in SQL Server. There are some limitations that made me give this up though. First of all, a user data type cannot be more than 8000 bytes. That is at most no more than 500 vertices in a geometry object, which is far too little for an accurate coastline for instance. Another problem is that SQL Server doesn’t support inheritance chains, so you can’t make a good object-oriented implementation of your datatype either.
…so yesterday I went for a completely different and much simpler approach. I decided to just store the geometry as Well-Known Binary in an image column. The reason for using an image column is that it can hold up to 2Gb of data, which should be sufficient for most geometry objects ;-). A binary field has the same 8000 byte limitation as UDT so this is no good. In addition to the geometry field, I create four real-type fields, holding the min/max values of the geometry envelope. This makes it efficient to do boundingbox based queries on the data. Any additional fields would be attributes for the geometry object.
I implemented the whole thing using SharpMap. First I created a small upload application that takes a shapefile, creates a table in the database and uploads the geometry and attributes to it. SharpMap has the necessary data readers and WKB formatters for this. The second part was to create a data provider from which SharpMap could draw from. I more or less based this on the PostGreSQL/PostGIS data provider for SharpMap, by changing the boundingbox query to use the four envelope fields. All this was not much more than an hour’s work, so it is very simple to accomplish.
I must say I was very surprised by the performance of the approach. It is just slightly faster than the shapefile data provider, which used to be the fastest data provider for SharpMap. In comparison the PostGreSQL/PostGIS is generally 4-6 times slower.
I have created a small demo web-application you can download from here. It contains two pages: one for uploading to the database, and one for rendering a layer from the database. All you need to do is to add an empty SQL Server 2005 Express database to the \App_Data\ folder and name id "GeoDatabase.mdf".
Download SharpMapSqlServer.zip (181,74 KB) (updated May 20, 2006)
Update: The MsSqlProvider is now also included in v0.9RC1, including a method for uploading from any of the SharpMap datasources to MS SQL.
The last couple of days I've been working on doing on-the-fly transformations in SharpMap. I started out by implementing all the interfaces in the OGC "Coordinate Transformation Services" specification. These specifications are just great and makes my work of designing APIs so much eaier. Anyway when I started at the actual implementation I also looked at NetTopologySuite (which is a .NET port of Java Topology Suite and GeoTools.NET for a little help on the more complex transformation formulas.
It didn't really work out. All my results was either wrong, resulted in Overflow and DivisionByZero exceptions and NaN values. All I could then do was working through the EPSG transformation formulas, which was I was trying to avoid in the first place (oh by the way, EPSG recently released v7.10 of their coordinate system database).
Well I finally hacked it, and my conclusion is that there are several problems in the NTS code that causes very inaccurate (if not completely wrong) transformations. Problems like an incorrect constant for converting between radians and degrees, transformation formulas that are wrong (at least the Mercator projection - haven't checked the others yet), transformation-factories that doesn't respect the order of source and target coordinate systems (it will always transform from geographic to projected coordsys), and using the TransformList(array-of-points) method in many cases gives a different result than Transform(point).
I emailed my findings to Diego and Andrew who's doing a great job on NTS, so that they can benefit from this work well, but this is just to warn you people out there that NTS is probably giving your incorrect or inaccurate transformation results, until the bug is corrected. This is by no means Diego's fault; I guess he just copied it from GeoTools.NET (since the code is more or less the same), but this reminds me why we always use the national cadastras transformation libraries for transforming data...
Oh well as you can probably understand from this post, SharpMap now supports on-the-fly transforrmation! How cool is that? :-) If you can't wait for the next release, grap the source from the GotDotNet workspace. Warning though: I haven't checked the rest of the formulas thoroughly yet, but Mercator projection is checked and corrected and UTM seems to be working...
One of the things that SharpMap at the current stage lacks most is probably a relation model, making for instance intersectiontests possible (unless you use the PostGIS provider which uses its built-in relation model). This is important to be able to select features within a certain distance, which features intersects the point that was clicked on the map or features that intersect other features. At the current stage most intersection-tests are only done on bounding-box level, which - although very fast - isn't very precise.
NetTopologySuite is another great .NET library that among other does a lot of the things that SharpMap not (yet) can do. Fortunately Diego from the NTS team has made a link between NTS and SharpMap making this possible. They have posted an example on the NTS website showing how to check for exact intersection in SharpMap. Check it out. It is very cool and very powerful.
Charlie Savage has a great post introducing coordinate systems in his blog. I too have had many questions on coordinate systems, projections and datums, and Charlie have made a great introduction to the world of "spatial reference systems". He promises to post some more on the topic, so keep track of his blog if you find these topics confusing (I know I did when I first was told about datums and coordinate systems).
Here is a small C# method for calculating distances between two longitude/latitude points based on Movable Type's article on the subject. Since the earth isn't perfectly round, and since I've found several values for the approximate radius of the earth, this method is only approximate, but should be sufficiently accurate for most applications.
/// Calculates the distance between to lat/long points and returns the approximate distance in kilometers
/// <param name="from">Point in long/lat decimal degrees</param>
/// <param name="to">Point in long/lat decimal degrees</param>
/// <returns>Distance in kilometers</returns>
private double CalcDistance(Point from, Point to)
double rad = 6371; //Earth radius in Km
//Convert to radians
double p1X = from.X / 180 * Math.PI;
double p1Y = from.Y / 180 * Math.PI;
double p2X = to.X / 180 * Math.PI;
double p2Y = to.Y / 180 * Math.PI;
return Math.Acos(Math.Sin(p1Y) * Math.Sin(p2Y) +
Math.Cos(p1Y) * Math.Cos(p2Y) * Math.Cos(p2X - p1X)) * rad;
If you want the distance returned in something else than kilometers, change the radius to whatever unit you would like the output unit to be in.
I have successfully incorporated this in a SharpMap-based application for doing nearest-object searches in a map. It is fun to see how the earth-curvate is taken into account; -this is particularily visible towards the poles in a flat projected map.