// Ported from PostGIS: // http://svn.refractions.net/postgis/trunk/java/jdbc/src/org/postgis/binary/BinaryParser.java using System; using System.IO; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Geometries; namespace GisSharpBlog.NetTopologySuite.IO { /// /// Converts a PostGIS binary data to a Geometry. /// public class PostGisReader { private IGeometryFactory factory = null; /// /// Geometry builder. /// protected IGeometryFactory Factory { get { return factory; } } /// /// Initialize reader with a standard GeometryFactory. /// public PostGisReader() : this(GeometryFactory.Default) { } /// /// Initialize reader with the given GeometryFactory. /// /// public PostGisReader(IGeometryFactory factory) { this.factory = factory; } /// /// /// /// /// public IGeometry Read(byte[] data) { using (Stream stream = new MemoryStream(data)) return Read(stream); } /// /// /// /// /// public IGeometry Read(Stream stream) { BinaryReader reader = null; ByteOrder byteOrder = (ByteOrder) stream.ReadByte(); // "Rewind" to let Read(BinaryReader) skip this byte // in collection and non-collection geometries. stream.Position = 0; try { if (byteOrder == ByteOrder.BigEndian) reader = new BEBinaryReader(stream); else reader = new BinaryReader(stream); return Read(reader); } finally { if (reader != null) reader.Close(); } } /// /// /// /// /// protected IGeometry Read(BinaryReader reader) { // Dummy read, just for bytes compatibility. // The byte order is determined only once. reader.ReadByte(); int typeword = reader.ReadInt32(); // cut off high flag bits PostGisGeometryType geometryType = (PostGisGeometryType)(typeword & 0x1FFFFFFF); bool hasZ = (typeword & 0x80000000) != 0; bool hasM = (typeword & 0x40000000) != 0; bool hasS = (typeword & 0x20000000) != 0; int srid = -1; if (hasS) srid = reader.ReadInt32(); IGeometry result; switch (geometryType) { case PostGisGeometryType.Point: result = ReadPoint(reader, hasZ, hasM); break; case PostGisGeometryType.LineString: result = ReadLineString(reader, hasZ, hasM); break; case PostGisGeometryType.Polygon: result = ReadPolygon(reader, hasZ, hasM); break; case PostGisGeometryType.MultiPoint: result = ReadMultiPoint(reader); break; case PostGisGeometryType.MultiLineString: result = ReadMultiLineString(reader); break; case PostGisGeometryType.MultiPolygon: result = ReadMultiPolygon(reader); break; case PostGisGeometryType.GeometryCollection: result = ReadGeometryCollection(reader); break; default: throw new ArgumentException("Geometry type not recognized. GeometryCode: " + geometryType); } result.SRID = hasS ? srid : -1; return result; } /// /// /// /// /// protected ICoordinate ReadCoordinate(BinaryReader reader, bool hasZ, bool hasM) { double X = reader.ReadDouble(); double Y = reader.ReadDouble(); ICoordinate result; if (hasZ) { double Z = reader.ReadDouble(); result = new Coordinate(X, Y, Z); } else result = new Coordinate(X, Y); if (hasM) { double M = reader.ReadDouble(); //result.setM(M); } return result; } /// /// /// /// /// protected IPoint ReadPoint(BinaryReader reader, bool hasZ, bool hasM) { return Factory.CreatePoint(ReadCoordinate(reader, hasZ, hasM)); } /// /// /// /// /// protected ICoordinate[] ReadCoordinateArray(BinaryReader reader, bool hasZ, bool hasM) { int numPoints = reader.ReadInt32(); ICoordinate[] coordinates = new ICoordinate[numPoints]; for (int i = 0; i < numPoints; i++) coordinates[i] = ReadCoordinate(reader, hasZ, hasM); return coordinates; } /// /// /// /// /// protected ILineString ReadLineString(BinaryReader reader, bool hasZ, bool hasM) { ICoordinate[] coordinates = ReadCoordinateArray(reader, hasZ, hasM); return Factory.CreateLineString(coordinates); } /// /// /// /// /// protected ILinearRing ReadLinearRing(BinaryReader reader, bool hasZ, bool hasM) { ICoordinate[] coordinates = ReadCoordinateArray(reader, hasZ, hasM); return Factory.CreateLinearRing(coordinates); } /// /// /// /// /// protected IPolygon ReadPolygon(BinaryReader reader, bool hasZ, bool hasM) { int numRings = reader.ReadInt32(); ILinearRing exteriorRing = ReadLinearRing(reader, hasZ, hasM); ILinearRing[] interiorRings = new ILinearRing[numRings - 1]; for (int i = 0; i < numRings - 1; i++) interiorRings[i] = ReadLinearRing(reader, hasZ, hasM); return Factory.CreatePolygon(exteriorRing, interiorRings); } /// /// /// /// /// protected void ReadGeometryArray(BinaryReader reader, IGeometry[] container) { for (int i = 0; i < container.Length; i++) container[i] = Read(reader); } /// /// /// /// /// protected IMultiPoint ReadMultiPoint(BinaryReader reader) { int numGeometries = reader.ReadInt32(); IPoint[] points = new IPoint[numGeometries]; ReadGeometryArray(reader, points); return Factory.CreateMultiPoint(points); } /// /// /// /// /// protected IMultiLineString ReadMultiLineString(BinaryReader reader) { int numGeometries = reader.ReadInt32(); ILineString[] strings = new ILineString[numGeometries]; ReadGeometryArray(reader, strings); return Factory.CreateMultiLineString(strings); } /// /// /// /// /// protected IMultiPolygon ReadMultiPolygon(BinaryReader reader) { int numGeometries = reader.ReadInt32(); IPolygon[] polygons = new IPolygon[numGeometries]; ReadGeometryArray(reader, polygons); return Factory.CreateMultiPolygon(polygons); } /// /// /// /// /// protected IGeometryCollection ReadGeometryCollection(BinaryReader reader) { int numGeometries = reader.ReadInt32(); IGeometry[] geometries = new IGeometry[numGeometries]; ReadGeometryArray(reader, geometries); return Factory.CreateGeometryCollection(geometries); } } }