/Branches/0.9.5-DeltaShell/src/Common/NetTopologySuite/IO/ShapeWriter.cs

# · C# · 357 lines · 189 code · 42 blank · 126 comment · 32 complexity · 2f51f132b0730e6cdf2408ec186697cc MD5 · raw file

  1. using System;
  2. using System.IO;
  3. using GeoAPI.Geometries;
  4. namespace GisSharpBlog.NetTopologySuite.IO
  5. {
  6. /// <summary>
  7. /// Contains methods for writing a single <c>Geometry</c> in binary ESRI shapefile format.
  8. /// </summary>
  9. public class ShapeWriter
  10. {
  11. /// <summary>
  12. /// Standard byte size for each complex point.
  13. /// Each complex point (LineString, Polygon, ...) contains
  14. /// 4 bytes for ShapeTypes and
  15. /// 32 bytes for Boundingbox.
  16. /// </summary>
  17. protected const int InitCount = 36;
  18. /// <summary>
  19. /// Creates a <coordinate>ShapeWriter</coordinate> that creates objects using a basic GeometryFactory.
  20. /// </summary>
  21. public ShapeWriter() { }
  22. /// <summary>
  23. ///
  24. /// </summary>
  25. /// <param name="coordinate"></param>
  26. /// <param name="writer"></param>
  27. public void Write(ICoordinate coordinate, BinaryWriter writer)
  28. {
  29. writer.Write((double) coordinate.X);
  30. writer.Write((double) coordinate.Y);
  31. }
  32. /// <summary>
  33. ///
  34. /// </summary>
  35. /// <param name="point"></param>
  36. /// <param name="writer"></param>
  37. public void Write(IPoint point, BinaryWriter writer)
  38. {
  39. writer.Write((int) ShapeGeometryType.Point);
  40. writer.Write((double) point.X);
  41. writer.Write((double) point.Y);
  42. }
  43. /// <summary>
  44. ///
  45. /// </summary>
  46. /// <param name="lineString"></param>
  47. /// <param name="writer"></param>
  48. public void Write(ILineString lineString, BinaryWriter writer)
  49. {
  50. writer.Write((int) ShapeGeometryType.LineString);
  51. // Write BoundingBox
  52. WriteBoundingBox(lineString, writer);
  53. // Write NumParts and NumPoints
  54. writer.Write((int) 1);
  55. writer.Write((int) lineString.NumPoints);
  56. // Write IndexParts
  57. writer.Write((int) 0);
  58. // Write Coordinates
  59. for (int i = 0; i < lineString.NumPoints; i++)
  60. Write(lineString.Coordinates[i], writer);
  61. }
  62. /// <summary>
  63. ///
  64. /// </summary>
  65. /// <param name="polygon"></param>
  66. /// <param name="writer"></param>
  67. public void Write(IPolygon polygon, BinaryWriter writer)
  68. {
  69. writer.Write((int) ShapeGeometryType.Polygon);
  70. // Write BoundingBox
  71. WriteBoundingBox(polygon, writer);
  72. // Write NumParts and NumPoints
  73. writer.Write((int) (polygon.NumInteriorRings + 1));
  74. writer.Write((int) polygon.NumPoints);
  75. // Write IndexParts
  76. int count = 0;
  77. writer.Write((int) count);
  78. if (polygon.NumInteriorRings != 0)
  79. {
  80. // Write external shell index
  81. count += polygon.ExteriorRing.NumPoints;
  82. writer.Write((int) count);
  83. for (int i = 1; i < polygon.NumInteriorRings; i++)
  84. {
  85. // Write internal holes index
  86. count += polygon.GetInteriorRingN(i - 1).NumPoints;
  87. writer.Write((int) count);
  88. }
  89. }
  90. // Write Coordinates
  91. for (int i = 0; i < polygon.NumPoints; i++)
  92. Write(polygon.Coordinates[i], writer);
  93. }
  94. /// <summary>
  95. ///
  96. /// </summary>
  97. /// <param name="multiPoint"></param>
  98. /// <param name="writer"></param>
  99. public void Write(IMultiPoint multiPoint, BinaryWriter writer)
  100. {
  101. writer.Write((int) ShapeGeometryType.MultiPoint);
  102. // Write BoundingBox
  103. WriteBoundingBox(multiPoint, writer);
  104. // Write NumPoints
  105. writer.Write((int) multiPoint.NumPoints);
  106. // Write Coordinates
  107. for (int i = 0; i < multiPoint.NumPoints; i++)
  108. Write(multiPoint.Coordinates[i], writer);
  109. }
  110. /// <summary>
  111. ///
  112. /// </summary>
  113. /// <param name="multiLineString"></param>
  114. /// <param name="writer"></param>
  115. public void Write(IMultiLineString multiLineString, BinaryWriter writer)
  116. {
  117. writer.Write((int) ShapeGeometryType.LineString);
  118. // Write BoundingBox
  119. WriteBoundingBox(multiLineString, writer);
  120. // Write NumParts and NumPoints
  121. writer.Write((int) multiLineString.NumGeometries);
  122. writer.Write((int) multiLineString.NumPoints);
  123. // Write IndexParts
  124. int count = 0;
  125. writer.Write((int) count);
  126. // Write linestrings index
  127. for (int i = 0; i < multiLineString.NumGeometries; i++)
  128. {
  129. // Write internal holes index
  130. count += multiLineString.GetGeometryN(i).NumPoints;
  131. if (count == multiLineString.NumPoints)
  132. break;
  133. writer.Write((int) count);
  134. }
  135. // Write Coordinates
  136. for (int i = 0; i < multiLineString.NumPoints; i++)
  137. Write(multiLineString.Coordinates[i], writer);
  138. }
  139. /// <summary>
  140. ///
  141. /// </summary>
  142. /// <param name="multiPolygon"></param>
  143. /// <param name="writer"></param>
  144. public void Write(IMultiPolygon multiPolygon, BinaryWriter writer)
  145. {
  146. writer.Write((int) ShapeGeometryType.Polygon);
  147. // Write BoundingBox
  148. WriteBoundingBox(multiPolygon, writer);
  149. // Write NumParts and NumPoints
  150. int numParts = multiPolygon.NumGeometries; // Exterior rings count
  151. for (int i = 0; i < multiPolygon.NumGeometries; i++) // Adding interior rings count
  152. numParts += ((IPolygon) multiPolygon.GetGeometryN(i)).NumInteriorRings;
  153. writer.Write((int) numParts);
  154. writer.Write((int) multiPolygon.NumPoints);
  155. // Write IndexParts
  156. int count = 0;
  157. writer.Write((int) count);
  158. for (int i = 0; i < multiPolygon.NumGeometries; i++)
  159. {
  160. IPolygon polygon = (IPolygon) multiPolygon.GetGeometryN(i);
  161. ILineString shell = polygon.ExteriorRing;
  162. count += shell.NumPoints;
  163. if (count == multiPolygon.NumPoints)
  164. break;
  165. writer.Write((int) count);
  166. for (int j = 0; j < polygon.NumInteriorRings; j++)
  167. {
  168. ILineString hole = (ILineString) polygon.GetInteriorRingN(j);
  169. count += hole.NumPoints;
  170. if (count == multiPolygon.NumPoints)
  171. break;
  172. writer.Write((int) count);
  173. }
  174. }
  175. // Write Coordinates
  176. for (int i = 0; i < multiPolygon.NumPoints; i++)
  177. Write(multiPolygon.Coordinates[i], writer);
  178. }
  179. /// <summary>
  180. ///
  181. /// </summary>
  182. /// <param name="geometry"></param>
  183. /// <param name="writer"></param>
  184. public void WriteBoundingBox(IGeometry geometry, BinaryWriter writer)
  185. {
  186. IEnvelope boundingBox = geometry.EnvelopeInternal;
  187. writer.Write((double) boundingBox.MinX);
  188. writer.Write((double) boundingBox.MinY);
  189. writer.Write((double) boundingBox.MaxX);
  190. writer.Write((double) boundingBox.MaxY);
  191. }
  192. /// <summary>
  193. /// Sets correct length for Byte Stream.
  194. /// </summary>
  195. /// <param name="geometry"></param>
  196. /// <returns></returns>
  197. public byte[] GetBytes(IGeometry geometry)
  198. {
  199. return new byte[GetBytesLength(geometry)];
  200. }
  201. /// <summary>
  202. /// Return correct length for Byte Stream.
  203. /// </summary>
  204. /// <param name="geometry"></param>
  205. /// <returns></returns>
  206. public int GetBytesLength(IGeometry geometry)
  207. {
  208. if (geometry is IPoint)
  209. return SetByteStreamLength(geometry as IPoint);
  210. else if (geometry is ILineString)
  211. return SetByteStreamLength(geometry as ILineString);
  212. else if (geometry is IPolygon)
  213. return SetByteStreamLength(geometry as IPolygon);
  214. else if (geometry is IMultiPoint)
  215. return SetByteStreamLength(geometry as IMultiPoint);
  216. else if (geometry is IMultiLineString)
  217. return SetByteStreamLength(geometry as IMultiLineString);
  218. else if (geometry is IMultiPolygon)
  219. return SetByteStreamLength(geometry as IMultiPolygon);
  220. else if (geometry is IGeometryCollection)
  221. throw new NotSupportedException("GeometryCollection not supported!");
  222. else throw new ArgumentException("ShouldNeverReachHere!");
  223. }
  224. /// <summary>
  225. ///
  226. /// </summary>
  227. /// <param name="multiPolygon"></param>
  228. /// <returns></returns>
  229. protected int SetByteStreamLength(IMultiPolygon multiPolygon)
  230. {
  231. int numParts = multiPolygon.NumGeometries; // Exterior rings count
  232. foreach (IPolygon polygon in multiPolygon.Geometries) // Adding interior rings count
  233. numParts += polygon.NumInteriorRings;
  234. int numPoints = multiPolygon.NumPoints;
  235. return CalculateLength(numParts, numPoints);
  236. }
  237. /// <summary>
  238. ///
  239. /// </summary>
  240. /// <param name="multiLineString"></param>
  241. /// <returns></returns>
  242. protected int SetByteStreamLength(IMultiLineString multiLineString)
  243. {
  244. int numParts = multiLineString.NumGeometries;
  245. int numPoints = multiLineString.NumPoints;
  246. return CalculateLength(numParts, numPoints);
  247. }
  248. /// <summary>
  249. ///
  250. /// </summary>
  251. /// <param name="multiPoint"></param>
  252. /// <returns></returns>
  253. protected int SetByteStreamLength(IMultiPoint multiPoint)
  254. {
  255. int numPoints = multiPoint.NumPoints;
  256. return CalculateLength(numPoints);
  257. }
  258. /// <summary>
  259. ///
  260. /// </summary>
  261. /// <param name="polygon"></param>
  262. /// <returns></returns>
  263. protected int SetByteStreamLength(IPolygon polygon)
  264. {
  265. int numParts = polygon.InteriorRings.Length + 1;
  266. int numPoints = polygon.NumPoints;
  267. return CalculateLength(numParts, numPoints);
  268. }
  269. /// <summary>
  270. ///
  271. /// </summary>
  272. /// <param name="lineString"></param>
  273. /// <returns></returns>
  274. protected int SetByteStreamLength(ILineString lineString)
  275. {
  276. int numPoints = lineString.NumPoints;
  277. return CalculateLength(1, numPoints); // ASSERT: IndexParts.Length == 1;
  278. }
  279. /// <summary>
  280. ///
  281. /// </summary>
  282. /// <param name="point"></param>
  283. /// <returns></returns>
  284. protected int SetByteStreamLength(IPoint point)
  285. {
  286. return 20;
  287. }
  288. /// <summary>
  289. ///
  290. /// </summary>
  291. /// <param name="numParts"></param>
  292. /// <param name="numPoints"></param>
  293. /// <returns></returns>
  294. private static int CalculateLength(int numParts, int numPoints)
  295. {
  296. int count = InitCount;
  297. count += 8; // NumParts and NumPoints
  298. count += 4 * numParts;
  299. count += 8 * 2 * numPoints;
  300. return count;
  301. }
  302. /// <summary>
  303. ///
  304. /// </summary>
  305. /// <param name="numPoints"></param>
  306. /// <returns></returns>
  307. private static int CalculateLength(int numPoints)
  308. {
  309. int count = InitCount;
  310. count += 4; // NumPoints
  311. count += 8 * 2 * numPoints;
  312. return count;
  313. }
  314. }
  315. }