GeometryFromWKB.cs
上传用户:sex100000
上传日期:2013-11-09
资源大小:1377k
文件大小:12k
源码类别:

GIS编程

开发平台:

C#

  1. // Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
  2. //
  3. // This file is part of SharpMap.
  4. // SharpMap is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation; either version 2 of the License, or
  7. // (at your option) any later version.
  8. // 
  9. // SharpMap is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. // GNU Lesser General Public License for more details.
  13. // You should have received a copy of the GNU Lesser General Public License
  14. // along with SharpMap; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  16. // SOURCECODE IS MODIFIED FROM ANOTHER WORK AND IS ORIGINALLY BASED ON GeoTools.NET:
  17. /*
  18.  *  Copyright (C) 2002 Urban Science Applications, Inc. 
  19.  *
  20.  *  This library is free software; you can redistribute it and/or
  21.  *  modify it under the terms of the GNU Lesser General Public
  22.  *  License as published by the Free Software Foundation; either
  23.  *  version 2.1 of the License, or (at your option) any later version.
  24.  *
  25.  *  This library is distributed in the hope that it will be useful,
  26.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  27.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  28.  *  Lesser General Public License for more details.
  29.  *
  30.  *  You should have received a copy of the GNU Lesser General Public
  31.  *  License along with this library; if not, write to the Free Software
  32.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  33.  *
  34.  */
  35. using System;
  36. using System.IO;
  37. using System.Collections;
  38. using System.Diagnostics;
  39. using SharpMap.Geometries;
  40. namespace SharpMap.Converters.WellKnownBinary
  41. {
  42. /// <summary>
  43. ///  Converts Well-known Binary representations to a <see cref="SharpMap.Geometries.Geometry"/> instance.
  44. /// </summary>
  45. /// <remarks>
  46. /// <para>The Well-known Binary Representation for <see cref="SharpMap.Geometries.Geometry"/> (WKBGeometry) provides a portable 
  47. /// representation of a <see cref="SharpMap.Geometries.Geometry"/> value as a contiguous stream of bytes. It permits <see cref="SharpMap.Geometries.Geometry"/> 
  48. /// values to be exchanged between an ODBC client and an SQL database in binary form.</para>
  49. /// <para>The Well-known Binary Representation for <see cref="SharpMap.Geometries.Geometry"/> is obtained by serializing a <see cref="SharpMap.Geometries.Geometry"/>
  50. /// instance as a sequence of numeric types drawn from the set {Unsigned Integer, Double} and
  51. /// then serializing each numeric type as a sequence of bytes using one of two well defined,
  52. /// standard, binary representations for numeric types (NDR, XDR). The specific binary encoding
  53. /// (NDR or XDR) used for a geometry byte stream is described by a one byte tag that precedes
  54. /// the serialized bytes. The only difference between the two encodings of geometry is one of
  55. /// byte order, the XDR encoding is Big Endian, the NDR encoding is Little Endian.</para>
  56. /// </remarks> 
  57. public class GeometryFromWKB
  58. {
  59. /// <summary>
  60. /// Creates a <see cref="SharpMap.Geometries.Geometry"/> from the supplied byte[] containing the Well-known Binary representation.
  61. /// </summary>
  62. /// <param name="bytes">byte[] containing the Well-known Binary representation.</param>
  63. /// <returns>A <see cref="SharpMap.Geometries.Geometry"/> bases on the supplied Well-known Binary representation.</returns>
  64. public static Geometry Parse(byte[] bytes)
  65. {
  66. // Create a memory stream using the suppiled byte array.
  67. using (MemoryStream ms = new MemoryStream(bytes))
  68. {
  69. // Create a new binary reader using the newly created memorystream.
  70. using (BinaryReader reader = new BinaryReader(ms))
  71. {
  72. // Call the main create function.
  73. return Parse(reader);
  74. }
  75. }
  76. }
  77. /// <summary>
  78. /// Creates a <see cref="SharpMap.Geometries.Geometry"/> based on the Well-known binary representation.
  79. /// </summary>
  80. /// <param name="reader">A <see cref="System.IO.BinaryReader">BinaryReader</see> used to read the Well-known binary representation.</param>
  81. /// <returns>A <see cref="SharpMap.Geometries.Geometry"/> based on the Well-known binary representation.</returns>
  82. public static Geometry Parse(BinaryReader reader)
  83. {
  84. // Get the first byte in the array.  This specifies if the WKB is in
  85. // XDR (big-endian) format of NDR (little-endian) format.
  86. byte byteOrder = reader.ReadByte();
  87. if (!Enum.IsDefined(typeof(WkbByteOrder), byteOrder))
  88. {
  89. throw new ArgumentException("Byte order not recognized");
  90. }
  91. // Get the type of this geometry.
  92. uint type = (uint)ReadUInt32(reader, (WkbByteOrder)byteOrder);
  93. if (!Enum.IsDefined(typeof(WKBGeometryType), type))
  94. throw new ArgumentException("Geometry type not recognized");
  95. switch((WKBGeometryType)type)
  96. {
  97. case WKBGeometryType.wkbPoint:
  98. return CreateWKBPoint(reader, (WkbByteOrder)byteOrder);
  99. case WKBGeometryType.wkbLineString:
  100.     return CreateWKBLineString(reader, (WkbByteOrder)byteOrder);
  101. case WKBGeometryType.wkbPolygon:
  102.     return CreateWKBPolygon(reader, (WkbByteOrder)byteOrder);
  103. case WKBGeometryType.wkbMultiPoint:
  104. return CreateWKBMultiPoint(reader, (WkbByteOrder)byteOrder);
  105. case WKBGeometryType.wkbMultiLineString:
  106.     return CreateWKBMultiLineString(reader, (WkbByteOrder)byteOrder);
  107. case WKBGeometryType.wkbMultiPolygon:
  108.     return CreateWKBMultiPolygon(reader, (WkbByteOrder)byteOrder);
  109. case WKBGeometryType.wkbGeometryCollection:
  110.     return CreateWKBGeometryCollection(reader, (WkbByteOrder)byteOrder);
  111. default:
  112. throw new NotSupportedException("Geometry type '" + type.ToString() + "' not supported");
  113. }
  114. }
  115. private static Point CreateWKBPoint(BinaryReader reader, WkbByteOrder byteOrder)
  116. {
  117. // Create and return the point.
  118. return new Point(ReadDouble(reader, byteOrder), ReadDouble(reader, byteOrder));
  119. }
  120. private static Point[] ReadCoordinates(BinaryReader reader, WkbByteOrder byteOrder)
  121. {
  122. // Get the number of points in this linestring.
  123. int numPoints = (int)ReadUInt32(reader, byteOrder);
  124. // Create a new array of coordinates.
  125. Point[] coords = new Point[numPoints];
  126. // Loop on the number of points in the ring.
  127. for (int i = 0; i < numPoints; i++)
  128. {
  129. // Add the coordinate.
  130. coords[i] = new Point(ReadDouble(reader, byteOrder), ReadDouble(reader, byteOrder));
  131. }
  132. return coords;
  133. }
  134. private static LineString CreateWKBLineString(BinaryReader reader, WkbByteOrder byteOrder)
  135. {
  136.     SharpMap.Geometries.LineString l = new SharpMap.Geometries.LineString();
  137.             //l.Vertices.AddRange(ReadCoordinates(reader, byteOrder));
  138.             Point[] arrPoint = ReadCoordinates(reader, byteOrder);
  139.             for (int i = 0; i < arrPoint.Length; i++)
  140.                 l.Vertices.Add(arrPoint[i]);
  141.     
  142.     return l;
  143.             
  144. }
  145. private static LinearRing CreateWKBLinearRing(BinaryReader reader, WkbByteOrder byteOrder)
  146. {
  147. SharpMap.Geometries.LinearRing l = new SharpMap.Geometries.LinearRing();
  148. //l.Vertices.AddRange(ReadCoordinates(reader, byteOrder));
  149.             Point[] arrPoint = ReadCoordinates(reader, byteOrder);
  150.             for (int i = 0; i < arrPoint.Length; i++)
  151.                 l.Vertices.Add(arrPoint[i]);
  152. //if polygon isn't closed, add the first point to the end (this shouldn't occur for correct WKB data)
  153. if (l.Vertices[0].X != l.Vertices[l.Vertices.Count - 1].X || l.Vertices[0].Y != l.Vertices[l.Vertices.Count - 1].Y)
  154. l.Vertices.Add(new Point(l.Vertices[0].X, l.Vertices[0].Y));
  155. return l;
  156. }
  157. private static Polygon CreateWKBPolygon(BinaryReader reader, WkbByteOrder byteOrder)
  158. {
  159. // Get the Number of rings in this Polygon.
  160. int numRings = (int)ReadUInt32(reader, byteOrder);
  161. Debug.Assert(numRings >= 1, "Number of rings in polygon must be 1 or more.");
  162. Polygon shell = new Polygon(CreateWKBLinearRing(reader, byteOrder));
  163. // Create a new array of linearrings for the interior rings.
  164. for (int i = 0; i < (numRings - 1); i++)
  165. shell.InteriorRings.Add(CreateWKBLinearRing(reader, byteOrder));
  166. // Create and return the Poylgon.
  167. return shell;
  168. }
  169. private static MultiPoint CreateWKBMultiPoint(BinaryReader reader, WkbByteOrder byteOrder)
  170. {
  171. // Get the number of points in this multipoint.
  172. int numPoints = (int)ReadUInt32(reader, byteOrder);
  173. // Create a new array for the points.
  174. MultiPoint points = new MultiPoint();
  175. // Loop on the number of points.
  176. for (int i = 0; i < numPoints; i++)
  177. {
  178. // Read point header
  179. reader.ReadByte();
  180. ReadUInt32(reader, byteOrder);
  181. // TODO: Validate type
  182. // Create the next point and add it to the point array.
  183. points.Points.Add(CreateWKBPoint(reader, byteOrder));
  184. }
  185. return points;
  186. }
  187. private static MultiLineString CreateWKBMultiLineString(BinaryReader reader, WkbByteOrder byteOrder)
  188. {
  189. // Get the number of linestrings in this multilinestring.
  190. int numLineStrings = (int)ReadUInt32(reader, byteOrder);
  191. // Create a new array for the linestrings .
  192. MultiLineString mline = new MultiLineString();
  193. // Loop on the number of linestrings.
  194. for (int i = 0; i < numLineStrings; i++)
  195. {
  196. // Read linestring header
  197. reader.ReadByte();
  198. ReadUInt32(reader, byteOrder);
  199. // Create the next linestring and add it to the array.
  200. mline.LineStrings.Add(CreateWKBLineString(reader, byteOrder));
  201. }
  202. // Create and return the MultiLineString.
  203. return mline;
  204. }
  205. private static MultiPolygon CreateWKBMultiPolygon(BinaryReader reader, WkbByteOrder byteOrder)
  206. {
  207. // Get the number of Polygons.
  208. int numPolygons = (int)ReadUInt32(reader, byteOrder);
  209. // Create a new array for the Polygons.
  210. MultiPolygon polygons = new MultiPolygon();
  211. // Loop on the number of polygons.
  212. for (int i = 0; i < numPolygons; i++)
  213. {
  214. // read polygon header
  215. reader.ReadByte();
  216. ReadUInt32(reader, byteOrder);
  217. // TODO: Validate type
  218. // Create the next polygon and add it to the array.
  219. polygons.Polygons.Add(CreateWKBPolygon(reader, byteOrder));
  220. }
  221. //Create and return the MultiPolygon.
  222. return polygons;
  223. }
  224. private static Geometry CreateWKBGeometryCollection(BinaryReader reader, WkbByteOrder byteOrder)
  225. {
  226. // The next byte in the array tells the number of geometries in this collection.
  227. int numGeometries = (int)ReadUInt32(reader, byteOrder);
  228. // Create a new array for the geometries.
  229. GeometryCollection geometries = new GeometryCollection();
  230. // Loop on the number of geometries.
  231. for (int i = 0; i < numGeometries; i++)
  232. {
  233. // Call the main create function with the next geometry.
  234. geometries.Collection.Add(Parse(reader));
  235. }
  236. // Create and return the next geometry.
  237. return geometries;
  238. }
  239. //NOT USED
  240. //private static int ReadInt32(BinaryReader reader, WKBByteOrder byteOrder)
  241. //{
  242. //    if (byteOrder == WKBByteOrder.Xdr)
  243. //    {
  244. //        byte[] bytes = BitConverter.GetBytes(reader.ReadInt32()); 
  245. //        Array.Reverse(bytes);
  246. //        return BitConverter.ToInt32(bytes, 0);
  247. //    }
  248. //    else
  249. //        return reader.ReadInt32();
  250. //}
  251. private static uint ReadUInt32(BinaryReader reader, WkbByteOrder byteOrder)
  252. {
  253. if (byteOrder == WkbByteOrder.Xdr)
  254. {
  255. byte[] bytes = BitConverter.GetBytes(reader.ReadUInt32()); 
  256. Array.Reverse(bytes);
  257. return BitConverter.ToUInt32(bytes, 0);
  258. }
  259. else
  260. return reader.ReadUInt32();
  261. }
  262. private static double ReadDouble(BinaryReader reader, WkbByteOrder byteOrder)
  263. {
  264. if (byteOrder == WkbByteOrder.Xdr)
  265. {
  266. byte[] bytes = BitConverter.GetBytes(reader.ReadDouble()); 
  267. Array.Reverse(bytes);
  268. return BitConverter.ToDouble(bytes, 0);
  269. }
  270. else
  271. return reader.ReadDouble();
  272. }
  273. }
  274. }