Simplifying Spatial Data while Preserving Topologies in C#

The data in a shape file is frequently too detailed for use over a web page / internet connection, as the amount of data being transferred is large, but the user typically views the data on a zoomed-out map, and isn’t in need of all the detail. MapShaper is a fantastic tool for converting shape files to other formats, while simplifying the shapes in the process. However, it’s either a manual process using their website, or there is a command line tool written in JavaScript. But can you do it in C#/.net?

One of the main challenges is to simplify the shapes together. Each shape in the shape file is a different record/row, and if you simplify them individually, the shared boundaries between the shapes will no longer be shared, and you will end up with overlapping boundaries or gaps.

Take the following code example:

The resulting GeoJson looks like the following:

If you Union (join) the shapes before simplifying, such as in this code:

Your GeoJson will be produced as follows:

enter image description here

The Union function actually merges the shapes, so you end up with a single overall shape that is then simplified.

So, how do you get the required result?

One approach is to convert the polygons and multipolygons into lines (LineStrings and MultiLineStrings), then simplify the lines (while preserving the topologies). Then you have to convert the areas between the lines back into polygons, and then re-attach any properties (e.g. the Id or Name of the shape).

The first few codes samples above made use of the spatial functions directly in SQL Server. However, a limitation in SQL Server is that you can’t (easily) convert from the simplified lines back to polygons. So our approach was to use NetTopologySuite, a C# library that is a direct port from Java Topology Suite, which offers a bit more functionality than what you get natively in SQL Server (using SqlGeometry etc.).

Here is a simplified(!) version of the code, in a console app:

Note that there are 3 items you’d need to replace:

  • YOUR_USERNAME: your windows username, or change the path to something suitable.
  • DC31_COORDINATESDC32_COORDINATES: this demo just uses two shapes/polygons: you can paste your co-ordinates into these placeholders, so that it uses inline well-known-text values, or you can populate the polygons in another way, e.g. from a database field, or a shape file.

The code will generate GeoJson files at multiple points in the processing. The last step produces results.json, which can be viewed in geojsonlint.com, as per the screenshot below.

You can see the two shapes (in this case districts DC31 & DC32) have been simplified, while the shared edge has been preserved (no overlaps or gaps), and the attributes (id) have also been retained.

The above code will need a bit of tweaking for more complex geometries, but it demonstrates the basic premise.

This webpage provided the basic solution in PostGIS.