Following up on my post a few months back about GeoJSON and SharpMap; here is the code to the converter as it stands so far. I have mentioned recently that things have been pretty busy at work so I have progressed on this more slowly than I had wished. I have yet to insert code to handle CRS but I thought it would be better to post something than nothing.
Basically, I just had to do some modifications to Morten’s original code for handling WKT. It was pretty straightforward owing mainly to the quality of Morten’s code. So here it is. Enjoy…
[sourcecode language=”csharp”]
// Copyright 2008 – William Dollins
// GeometryToGeoJson converter by William Dollins (bill@zekiah.com / www.zekiah.com)
//
// Date 2008-09-25
//
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// SharpMap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//SOURCECODE IS MODIFIED FROM ANOTHER WORK AND IS ORIGINALLY BASED ON THE
//GeometryToWKT class of SharpMap which was in turn was based on GeoTools.NET (see below):
// Copyright 2005, 2006 – Morten Nielsen (www.iter.dk)
//
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// SharpMap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// SOURCECODE IS MODIFIED FROM ANOTHER WORK AND IS ORIGINALLY BASED ON GeoTools.NET:
/*
* Copyright (C) 2002 Urban Science Applications, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
using System;
using System.IO;
using System.Text;
using SharpMap.Geometries;
namespace SharpMap.Converters.GeoJson
{
///
///
///
///
/// sutiable for use my Javascript mapping clients that support GeoJSON, such as OpenLayers.
/// conversion routines. These examples are originally from the geojson.org site and were used for testing.
///
public class GeometryToGeoJson
{
#region Methods
///
///
/// A Geometry to write.
///
/// Specification)
public static string Write(IGeometry geometry)
{
StringWriter sw = new StringWriter();
Write(geometry, sw);
return sw.ToString();
}
///
///
/// A geometry to process.
/// Stream to write out the geometry’s text representation.
///
/// Geometry is written to the output stream as a GeoJSON geometry string (see the GeoJSON
/// Specification).
///
public static void Write(IGeometry geometry, StringWriter writer)
{
AppendGeometryTaggedText(geometry, writer);
}
///
///
/// The Geometry to process.
/// The output stream to Append to.
private static void AppendGeometryTaggedText(IGeometry geometry, StringWriter writer)
{
if (geometry == null)
throw new NullReferenceException(“Cannot write GeoJSON: geometry was null”); ;
if (geometry is Point)
{
Point point = geometry as Point;
AppendPointTaggedText(point, writer);
}
else if (geometry is LineString)
AppendLineStringTaggedText(geometry as LineString, writer);
else if (geometry is Polygon)
AppendPolygonTaggedText(geometry as Polygon, writer);
else if (geometry is MultiPoint)
AppendMultiPointTaggedText(geometry as MultiPoint, writer);
else if (geometry is MultiLineString)
AppendMultiLineStringTaggedText(geometry as MultiLineString, writer);
else if (geometry is MultiPolygon)
AppendMultiPolygonTaggedText(geometry as MultiPolygon, writer);
else if (geometry is GeometryCollection)
AppendGeometryCollectionTaggedText(geometry as GeometryCollection, writer);
else
throw new NotSupportedException(“Unsupported Geometry implementation:” + geometry.GetType().Name);
}
///
/// then Appends it to the writer.
///
/// the Coordinate
to process
/// the output writer to Append to
private static void AppendPointTaggedText(Point coordinate, StringWriter writer)
{
writer.WriteLine(“{“);
writer.WriteLine(“”type”: “Point”,”);
writer.Write(“”coordinates”: “);
AppendPointText(coordinate, writer);
writer.WriteLine(“}”);
}
///
///
/// The LineString to process.
/// The output stream writer to Append to.
private static void AppendLineStringTaggedText(LineString lineString, StringWriter writer)
{
writer.WriteLine(“{“);
writer.WriteLine(“”type”: “LineString”,”);
writer.WriteLine(“”coordinates”: “);
AppendLineStringText(lineString, writer);
//writer.WriteLine(“]”);
writer.WriteLine(“}”);
}
///
/// then Appends it to the writer.
///
/// Th Polygon to process.
/// The stream writer to Append to.
private static void AppendPolygonTaggedText(Polygon polygon, StringWriter writer)
{
//{
// “type”: “Polygon”,
// “coordinates”: [
// [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]
// ]
//}
// with holes (inner rings)
//{
// “type”: “Polygon”,
// “coordinates”: [
// [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ],
// [ [100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2] ]
// ]
//}
//{
//”type”: “Polygon”,
//”coordinates”:
//[ [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[5, 5], [7, 5], [7, 7], [5, 7], [5, 5]]] ]
//}
writer.WriteLine(“{“);
writer.WriteLine(“”type”: “Polygon”,”);
writer.WriteLine(“”coordinates”: “);
//writer.Write(“[ “);
AppendPolygonText(polygon, writer);
//writer.WriteLine(” ]”);
//writer.WriteLine(“]”);
writer.WriteLine(“}”);
}
///
/// format, then Appends it to the writer.
///
/// The MultiPoint to process.
/// The output writer to Append to.
private static void AppendMultiPointTaggedText(MultiPoint multipoint, StringWriter writer)
{
//{
// “type”: “MultiPoint”,
// “coordinates”: [
// [100.0, 0.0], [101.0, 1.0]
// ]
//}
writer.WriteLine(“{“);
writer.WriteLine(“”type”: “MultiPoint”,”);
writer.WriteLine(“”coordinates”: “);
AppendMultiPointText(multipoint, writer);
writer.WriteLine(“}”);
}
///
/// Text> format, then Appends it to the writer.
///
/// The MultiLineString to process
/// The output stream writer to Append to.
private static void AppendMultiLineStringTaggedText(MultiLineString multiLineString, StringWriter writer)
{
//{
// “type”: “MultiLineString”,
// “coordinates”: [
// [ [100.0, 0.0], [101.0, 1.0] ],
// [ [102.0, 2.0], [103.0, 3.0] ]
// ]
//}
writer.WriteLine(“{“);
writer.WriteLine(“”type”: “MultiLineString”,”);
writer.WriteLine(“”coordinates”: “);
AppendMultiLineStringText(multiLineString, writer);
writer.WriteLine(“}”);
}
///
/// Text> format, then Appends it to the writer.
///
/// The MultiPolygon to process
/// The output stream writer to Append to.
private static void AppendMultiPolygonTaggedText(MultiPolygon multiPolygon, StringWriter writer)
{
//{
// “type”: “MultiPolygon”,
// “coordinates”: [
// [
// [ [102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0] ]
// ],
// [
// [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ],
// [ [100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2] ]
// ]
// ]
//}
writer.WriteLine(“{“);
writer.WriteLine(“”type”: “MultiPolygon”,”);
writer.WriteLine(“”coordinates”: “);
AppendMultiPolygonText(multiPolygon, writer);
writer.WriteLine(“}”);
}
///
/// Text> format, then Appends it to the writer.
///
/// The GeometryCollection to process
/// The output stream writer to Append to.
private static void AppendGeometryCollectionTaggedText(GeometryCollection geometryCollection, StringWriter writer)
{
//{
// “type”: “GeometryCollection”,
// “members”: [
// {
// “type”: “Point”,
// “coordinates”: [100.0, 0.0]
// },
// {
// “type”: “LineString”,
// “coordinates”: [
// [101.0, 0.0], [102.0, 1.0]
// ]
// }
// ]
//}
writer.WriteLine(“{“);
writer.WriteLine(“”type”: “GeometryCollection”,”);
writer.WriteLine(“”geometries”: “);
AppendGeometryCollectionText(geometryCollection, writer);
writer.WriteLine(“}”);
}
///
///
/// The Coordinate to process.
/// The output stream writer to Append to.
private static void AppendPointText(Point coordinate, StringWriter writer)
{
if (coordinate == null || coordinate.IsEmpty())
writer.Write(“EMPTY”);
else
{
writer.Write(“[“);
AppendCoordinate(coordinate, writer);
writer.Write(“]”);
}
}
///
/// it to the writer.
///
/// The Coordinate to process.
/// The output writer to Append to.
private static void AppendCoordinate(Point coordinate, StringWriter writer)
{
for (uint i = 0; i < coordinate.NumOrdinates; i++)
writer.Write(WriteNumber(coordinate[i]) + (i < coordinate.NumOrdinates - 1 ? ", " : ""));
}
///
///
/// The double to convert.
///
private static string WriteNumber(double d)
{
return d.ToString(SharpMap.Map.numberFormat_EnUS);
}
///
/// Appends it to the writer.
///
/// The LineString to process.
/// The output stream to Append to.
private static void AppendLineStringText(LineString lineString, StringWriter writer)
{
if (lineString == null || lineString.IsEmpty())
writer.Write(“EMPTY”);
else
{
writer.Write(“[“);
for (int i = 0; i < lineString.NumPoints; i++)
{
if (i > 0)
writer.Write(“, “);
writer.Write(“[“);
AppendCoordinate(lineString.Vertices[i], writer);
writer.Write(“]”);
}
writer.Write(“]”);
}
}
///
/// Appends it to the writer.
///
/// The Polygon to process.
///
private static void AppendPolygonText(Polygon polygon, StringWriter writer)
{
if (polygon == null || polygon.IsEmpty())
writer.Write(“EMPTY”);
else
{
writer.Write(“[“);
AppendLineStringText(polygon.ExteriorRing, writer);
for (int i = 0; i < polygon.InteriorRings.Count; i++)
{
writer.Write(", ");
AppendLineStringText(polygon.InteriorRings[i], writer);
}
writer.Write("]");
}
}
///
/// Appends it to the writer.
///
/// The MultiPoint to process.
/// The output stream writer to Append to.
private static void AppendMultiPointText(MultiPoint multiPoint, StringWriter writer)
{
if (multiPoint == null || multiPoint.IsEmpty())
writer.Write(“EMPTY”);
else
{
writer.Write(“[“);
for (int i = 0; i < multiPoint.Points.Count; i++)
{
if (i > 0)
writer.Write(“, “);
writer.Write(“[“);
AppendCoordinate(multiPoint[i], writer);
writer.Write(“]”);
}
writer.Write(“]”);
}
}
///
/// format, then Appends it to the writer.
///
/// The MultiLineString to process.
/// The output stream writer to Append to.
private static void AppendMultiLineStringText(MultiLineString multiLineString, StringWriter writer)
{
if (multiLineString == null || multiLineString.IsEmpty())
writer.Write(“EMPTY”);
else
{
writer.Write(“[“);
for (int i = 0; i < multiLineString.LineStrings.Count; i++)
{
if (i > 0)
writer.Write(“, “);
AppendLineStringText(multiLineString[i], writer);
}
writer.Write(“]”);
}
}
///
///
/// The MultiPolygon to process.
/// The output stream to Append to.
private static void AppendMultiPolygonText(MultiPolygon multiPolygon, StringWriter writer)
{
if (multiPolygon == null || multiPolygon.IsEmpty())
writer.Write(“EMPTY”);
else
{
writer.Write(“[“);
for (int i = 0; i < multiPolygon.Polygons.Count; i++)
{
if (i > 0)
writer.Write(“, “);
AppendPolygonText(multiPolygon[i], writer);
}
writer.Write(“]”);
}
}
///
///
/// The GeometryCollection to process.
/// The output stream writer to Append to.
private static void AppendGeometryCollectionText(GeometryCollection geometryCollection, StringWriter writer)
{
if (geometryCollection == null || geometryCollection.IsEmpty())
writer.Write(“EMPTY”);
else
{
writer.Write(“[“);
for (int i = 0; i < geometryCollection.Collection.Count; i++)
{
if (i > 0)
writer.Write(“, “);
AppendGeometryTaggedText(geometryCollection[i], writer);
}
writer.Write(“]”);
}
}
#endregion
}
}
[/sourcecode]
Great post!
I miss one point:
How can i turn the string returned from webservice to a Json object to be used in Open layers?
In my client-side code, I have the following javascript function:
function addGeoJson(gj) {
var geojson_format = new OpenLayers.Format.GeoJSON();
var vector_layer = new OpenLayers.Layer.Vector();
map.addLayer(vector_layer);
//vector_layer.addFeatures(geojson_format.read(featurecollection));
vector_layer.addFeatures(geojson_format.read(gj));
}
In this function, the parameter gj represents the GeoJSON string.
Ok, no worries. Mostly I’m just amused to see how far the JTS code travels!
Martin,
I’ll have to defer to Morten on that since I just tacked my stuff onto the header he already had in the code. You will see the “Urban Science Applications, Inc.” notation in the header. It credits GeoTools.NET as his source. I am unaware if GeoTools sourced JTS but I have tried to leave the lineage described in the SharpMap code in tact.
Thanks for the head’s up.
Bill
You might want to credit JTS and Jon Aquino for the “clean original code”, since if I’m not mistaken this is a direct port from the JTS WKTWriter!
Sweet. You should propably replace “EMPTY” with “null” or nothing though.
Yeah, that’s a good point. Thank you.