// 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 GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.IO; namespace SharpMap.Converters.WellKnownBinary { /// /// Converts Well-known Binary representations to a instance. /// /// /// The Well-known Binary Representation for (WKBGeometry) provides a portable /// representation of a value as a contiguous stream of bytes. It permits /// values to be exchanged between an ODBC client and an SQL database in binary form. /// The Well-known Binary Representation for is obtained by serializing a /// instance as a sequence of numeric types drawn from the set {Unsigned Integer, Double} and /// then serializing each numeric type as a sequence of bytes using one of two well defined, /// standard, binary representations for numeric types (NDR, XDR). The specific binary encoding /// (NDR or XDR) used for a geometry byte stream is described by a one byte tag that precedes /// the serialized bytes. The only difference between the two encodings of geometry is one of /// byte order, the XDR encoding is Big Endian, the NDR encoding is Little Endian. /// public class GeometryFromWKB { /// /// Creates a from the supplied byte[] containing the Well-known Binary representation. /// /// byte[] containing the Well-known Binary representation. /// A bases on the supplied Well-known Binary representation. public static IGeometry Parse(byte[] bytes) { return new WKBReader().Read(bytes); // // Create a memory stream using the suppiled byte array. // using (MemoryStream ms = new MemoryStream(bytes)) // { // // Create a new binary reader using the newly created memorystream. // using (BinaryReader reader = new BinaryReader(ms)) // { // // Call the main create function. // return Parse(reader); // } // } } /// /// Creates a based on the Well-known binary representation. /// /// A BinaryReader used to read the Well-known binary representation. /// A based on the Well-known binary representation. // public static Geometry Parse(BinaryReader reader) // { // // Get the first byte in the array. This specifies if the WKB is in // // XDR (big-endian) format of NDR (little-endian) format. // byte byteOrder = reader.ReadByte(); // // if (!Enum.IsDefined(typeof(WkbByteOrder), byteOrder)) // { // throw new ArgumentException("Byte order not recognized"); // } // // // Get the type of this geometry. // uint type = (uint)ReadUInt32(reader, (WkbByteOrder)byteOrder); // // if (!Enum.IsDefined(typeof(WKBGeometryType), type)) // throw new ArgumentException("Geometry type not recognized"); // // switch((WKBGeometryType)type) // { // case WKBGeometryType.wkbPoint: // return CreateWKBPoint(reader, (WkbByteOrder)byteOrder); // // case WKBGeometryType.wkbLineString: // return CreateWKBLineString(reader, (WkbByteOrder)byteOrder); // // case WKBGeometryType.wkbPolygon: // return CreateWKBPolygon(reader, (WkbByteOrder)byteOrder); // // case WKBGeometryType.wkbMultiPoint: // return CreateWKBMultiPoint(reader, (WkbByteOrder)byteOrder); // // case WKBGeometryType.wkbMultiLineString: // return CreateWKBMultiLineString(reader, (WkbByteOrder)byteOrder); // // case WKBGeometryType.wkbMultiPolygon: // return CreateWKBMultiPolygon(reader, (WkbByteOrder)byteOrder); // // case WKBGeometryType.wkbGeometryCollection: // return CreateWKBGeometryCollection(reader, (WkbByteOrder)byteOrder); // // default: // throw new NotSupportedException("Geometry type '" + type.ToString() + "' not supported"); // } // } // // private static Point CreateWKBPoint(BinaryReader reader, WkbByteOrder byteOrder) // { // // Create and return the point. // return new Point(ReadDouble(reader, byteOrder), ReadDouble(reader, byteOrder)); // } // // private static Point[] ReadCoordinates(BinaryReader reader, WkbByteOrder byteOrder) // { // // Get the number of points in this linestring. // int numPoints = (int)ReadUInt32(reader, byteOrder); // // // Create a new array of coordinates. // Point[] coords = new Point[numPoints]; // // // Loop on the number of points in the ring. // for (int i = 0; i < numPoints; i++) // { // // Add the coordinate. // coords[i] = new Point(ReadDouble(reader, byteOrder), ReadDouble(reader, byteOrder)); // } // return coords; // } // // private static LineString CreateWKBLineString(BinaryReader reader, WkbByteOrder byteOrder) // { // SharpMap.Geometries.LineString l = new SharpMap.Geometries.LineString(); // //l.Vertices.AddRange(ReadCoordinates(reader, byteOrder)); // Point[] arrPoint = ReadCoordinates(reader, byteOrder); // for (int i = 0; i < arrPoint.Length; i++) // l.Vertices.Add(arrPoint[i]); // // return l; // // // } // // private static LinearRing CreateWKBLinearRing(BinaryReader reader, WkbByteOrder byteOrder) // { // SharpMap.Geometries.LinearRing l = new SharpMap.Geometries.LinearRing(); // //l.Vertices.AddRange(ReadCoordinates(reader, byteOrder)); // Point[] arrPoint = ReadCoordinates(reader, byteOrder); // for (int i = 0; i < arrPoint.Length; i++) // l.Vertices.Add(arrPoint[i]); // // //if polygon isn't closed, add the first point to the end (this shouldn't occur for correct WKB data) // if (l.Vertices[0].X != l.Vertices[l.Vertices.Count - 1].X || l.Vertices[0].Y != l.Vertices[l.Vertices.Count - 1].Y) // l.Vertices.Add(new Point(l.Vertices[0].X, l.Vertices[0].Y)); // return l; // } // // private static Polygon CreateWKBPolygon(BinaryReader reader, WkbByteOrder byteOrder) // { // // Get the Number of rings in this Polygon. // int numRings = (int)ReadUInt32(reader, byteOrder); // // Debug.Assert(numRings >= 1, "Number of rings in polygon must be 1 or more."); // // Polygon shell = new Polygon(CreateWKBLinearRing(reader, byteOrder)); // // // Create a new array of linearrings for the interior rings. // for (int i = 0; i < (numRings - 1); i++) // shell.InteriorRings.Add(CreateWKBLinearRing(reader, byteOrder)); // // // Create and return the Poylgon. // return shell; // } // // private static MultiPoint CreateWKBMultiPoint(BinaryReader reader, WkbByteOrder byteOrder) // { // // Get the number of points in this multipoint. // int numPoints = (int)ReadUInt32(reader, byteOrder); // // // Create a new array for the points. // MultiPoint points = new MultiPoint(); // // // Loop on the number of points. // for (int i = 0; i < numPoints; i++) // { // // Read point header // reader.ReadByte(); // ReadUInt32(reader, byteOrder); // // // TODO: Validate type // // // Create the next point and add it to the point array. // points.Points.Add(CreateWKBPoint(reader, byteOrder)); // } // return points; // } // // private static MultiLineString CreateWKBMultiLineString(BinaryReader reader, WkbByteOrder byteOrder) // { // // Get the number of linestrings in this multilinestring. // int numLineStrings = (int)ReadUInt32(reader, byteOrder); // // // Create a new array for the linestrings . // MultiLineString mline = new MultiLineString(); // // // Loop on the number of linestrings. // for (int i = 0; i < numLineStrings; i++) // { // // Read linestring header // reader.ReadByte(); // ReadUInt32(reader, byteOrder); // // // Create the next linestring and add it to the array. // mline.LineStrings.Add(CreateWKBLineString(reader, byteOrder)); // } // // // Create and return the MultiLineString. // return mline; // } // // private static MultiPolygon CreateWKBMultiPolygon(BinaryReader reader, WkbByteOrder byteOrder) // { // // Get the number of Polygons. // int numPolygons = (int)ReadUInt32(reader, byteOrder); // // // Create a new array for the Polygons. // MultiPolygon polygons = new MultiPolygon(); // // // Loop on the number of polygons. // for (int i = 0; i < numPolygons; i++) // { // // read polygon header // reader.ReadByte(); // ReadUInt32(reader, byteOrder); // // // TODO: Validate type // // // Create the next polygon and add it to the array. // polygons.Polygons.Add(CreateWKBPolygon(reader, byteOrder)); // } // // //Create and return the MultiPolygon. // return polygons; // } // // private static Geometry CreateWKBGeometryCollection(BinaryReader reader, WkbByteOrder byteOrder) // { // // The next byte in the array tells the number of geometries in this collection. // int numGeometries = (int)ReadUInt32(reader, byteOrder); // // // Create a new array for the geometries. // GeometryCollection geometries = new GeometryCollection(); // // // Loop on the number of geometries. // for (int i = 0; i < numGeometries; i++) // { // // Call the main create function with the next geometry. // geometries.Collection.Add(Parse(reader)); // } // // // Create and return the next geometry. // return geometries; // } // // //NOT USED // //private static int ReadInt32(BinaryReader reader, WKBByteOrder byteOrder) // //{ // // if (byteOrder == WKBByteOrder.Xdr) // // { // // byte[] bytes = BitConverter.GetBytes(reader.ReadInt32()); // // Array.Reverse(bytes); // // return BitConverter.ToInt32(bytes, 0); // // } // // else // // return reader.ReadInt32(); // //} // // private static uint ReadUInt32(BinaryReader reader, WkbByteOrder byteOrder) // { // if (byteOrder == WkbByteOrder.Xdr) // { // byte[] bytes = BitConverter.GetBytes(reader.ReadUInt32()); // Array.Reverse(bytes); // return BitConverter.ToUInt32(bytes, 0); // } // else // return reader.ReadUInt32(); // } // // private static double ReadDouble(BinaryReader reader, WkbByteOrder byteOrder) // { // if (byteOrder == WkbByteOrder.Xdr) // { // byte[] bytes = BitConverter.GetBytes(reader.ReadDouble()); // Array.Reverse(bytes); // return BitConverter.ToDouble(bytes, 0); // } // else // return reader.ReadDouble(); // } } }