/NetTopologySuite.Converter/NetTopologySuite.Converter.DotSpatial/GeometryConverterToGeoAPI.cs

http://nettopologysuite.googlecode.com/ · C# · 583 lines · 386 code · 66 blank · 131 comment · 71 complexity · bc0d83301663d4b4c33d8038a968cd8b MD5 · raw file

  1. // Copyright 2012 - Felix Obermaier (www.ivv-aachen.de)
  2. //
  3. // This file is part of DotSpatial.Topology.GeoAPIConverter.
  4. // DotSpatial.Topology.GeoAPIConverter 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. // DotSpatial.Topology.GeoAPIConverter 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. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with SharpMap; if not, write to the Free Software
  16. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. // The conversion code for GeoAPI to DotSpatial.Data.Shape was taken and enhanced
  18. // from DotSpatial.Data.Shape.
  19. using System;
  20. using System.Collections.Generic;
  21. using System.Linq;
  22. namespace DotSpatial.Topology
  23. {
  24. using GeoAPICoordinate = GeoAPI.Geometries.Coordinate;
  25. using GeoAPIEnvelope = GeoAPI.Geometries.Envelope;
  26. using GeoAPIGeometry = GeoAPI.Geometries.IGeometry;
  27. using GeoAPIGeometryCollection = GeoAPI.Geometries.IGeometryCollection;
  28. using GeoAPIGeometryFactory = GeoAPI.Geometries.IGeometryFactory;
  29. using GeoAPILinearRing = GeoAPI.Geometries.ILinearRing;
  30. using GeoAPILineString = GeoAPI.Geometries.ILineString;
  31. using GeoAPIMultiLineString = GeoAPI.Geometries.IMultiLineString;
  32. using GeoAPIMultiPoint = GeoAPI.Geometries.IMultiPoint;
  33. using GeoAPIMultiPolygon = GeoAPI.Geometries.IMultiPolygon;
  34. using GeoAPIPoint = GeoAPI.Geometries.IPoint;
  35. using GeoAPIPolygon = GeoAPI.Geometries.IPolygon;
  36. using GeoAPIPrecisionModel = GeoAPI.Geometries.IPrecisionModel;
  37. public static class GeometryConverter
  38. {
  39. private static readonly Dictionary<PrecisionModelType, GeoAPIPrecisionModel> ConvertedPrecisionModels =
  40. new Dictionary<PrecisionModelType, GeoAPIPrecisionModel>();
  41. private static readonly Dictionary<IGeometryFactory, GeoAPIGeometryFactory> ConvertedGeometryFactories =
  42. new Dictionary<IGeometryFactory, GeoAPIGeometryFactory>();
  43. public static GeoAPIPrecisionModel ToGeoAPI(this PrecisionModelType model)
  44. {
  45. GeoAPIPrecisionModel geoAPIPrecisionModel;
  46. if (ConvertedPrecisionModels.TryGetValue(model, out geoAPIPrecisionModel))
  47. return geoAPIPrecisionModel;
  48. var geoService = GeoAPI.GeometryServiceProvider.Instance;
  49. switch (model)
  50. {
  51. case PrecisionModelType.Floating:
  52. geoAPIPrecisionModel = geoService.CreatePrecisionModel(GeoAPI.Geometries.PrecisionModels.Floating);
  53. break;
  54. case PrecisionModelType.FloatingSingle:
  55. geoAPIPrecisionModel = geoService.CreatePrecisionModel(GeoAPI.Geometries.PrecisionModels.FloatingSingle);
  56. break;
  57. case PrecisionModelType.Fixed:
  58. geoAPIPrecisionModel = geoService.CreatePrecisionModel(GeoAPI.Geometries.PrecisionModels.Fixed);
  59. break;
  60. }
  61. ConvertedPrecisionModels.Add(model, geoAPIPrecisionModel);
  62. return geoAPIPrecisionModel;
  63. }
  64. public static GeoAPIGeometryFactory ToGeoAPI(this IGeometryFactory factory)
  65. {
  66. GeoAPIGeometryFactory geoAPIFactory;
  67. if (ConvertedGeometryFactories.TryGetValue(factory, out geoAPIFactory))
  68. return geoAPIFactory;
  69. var geoAPIPrecisionModel = factory.PrecisionModel.ToGeoAPI();
  70. var geoService = GeoAPI.GeometryServiceProvider.Instance;
  71. geoAPIFactory = geoService.CreateGeometryFactory(geoAPIPrecisionModel, factory.Srid);
  72. ConvertedGeometryFactories.Add(factory, geoAPIFactory);
  73. return geoAPIFactory;
  74. }
  75. /// <summary>
  76. /// Converts a <see cref="IGeometry"/> to a <see cref="GeoAPIGeometry"/>
  77. /// </summary>
  78. /// <param name="self">The <see cref="IGeometry"/> to convert</param>
  79. /// <param name="factory">The factory to create the <see cref="GeoAPIGeometry"/></param>
  80. /// <param name="setUserData">Sets the <see cref="GeoAPIGeometry.UserData"/> to <paramref name="self"/>.UserData</param>
  81. /// <returns>The converted geometry</returns>
  82. public static GeoAPIGeometry ToGeoAPI(this IGeometry self, GeoAPIGeometryFactory factory = null, bool setUserData = false)
  83. {
  84. var useFactory = factory ?? self.Factory.ToGeoAPI();
  85. return FromGeometry(self, useFactory, setUserData);
  86. }
  87. /// <summary>
  88. /// Converts a <see cref="IPoint"/> to a <see cref="GeoAPIPoint"/>
  89. /// </summary>
  90. /// <param name="self">The <see cref="IPoint"/> to convert</param>
  91. /// <param name="factory">The factory to create the <see cref="GeoAPIPoint"/></param>
  92. /// <param name="setUserData">Sets the <see cref="GeoAPIGeometry.UserData"/> to <paramref name="self"/>.UserData</param>
  93. /// <returns>The converted geometry</returns>
  94. public static GeoAPIPoint ToGeoAPI(this IPoint self, GeoAPIGeometryFactory factory = null, bool setUserData = false)
  95. {
  96. var useFactory = factory ?? self.Factory.ToGeoAPI();
  97. return FromPoint(self, useFactory, setUserData);
  98. }
  99. /// <summary>
  100. /// Converts a <see cref="ILineString"/> to a <see cref="GeoAPILineString"/>
  101. /// </summary>
  102. /// <param name="self">The <see cref="ILineString"/> to convert</param>
  103. /// <param name="factory">The factory to create the <see cref="GeoAPILineString"/></param>
  104. /// <param name="setUserData">Sets the <see cref="GeoAPIGeometry.UserData"/> to <paramref name="self"/>.UserData</param>
  105. /// <returns>The converted geometry</returns>
  106. public static GeoAPILineString ToGeoAPI(this ILineString self, GeoAPIGeometryFactory factory = null, bool setUserData = false)
  107. {
  108. var useFactory = factory ?? self.Factory.ToGeoAPI();
  109. return FromLineString(self, useFactory, setUserData);
  110. }
  111. /// <summary>
  112. /// Converts a <see cref="ILinearRing"/> to a <see cref="GeoAPILinearRing"/>
  113. /// </summary>
  114. /// <param name="self">The <see cref="ILinearRing"/> to convert</param>
  115. /// <param name="factory">The factory to create the <see cref="GeoAPILinearRing"/></param>
  116. /// <param name="setUserData">Sets the <see cref="GeoAPIGeometry.UserData"/> to <paramref name="self"/>.UserData</param>
  117. /// <returns>The converted geometry</returns>
  118. public static GeoAPILinearRing ToGeoAPI(this ILinearRing self, GeoAPIGeometryFactory factory = null, bool setUserData = false)
  119. {
  120. var useFactory = factory ?? self.Factory.ToGeoAPI();
  121. return (GeoAPILinearRing)FromLineString(self, useFactory, setUserData);
  122. }
  123. /// <summary>
  124. /// Converts a <see cref="IPolygon"/> to a <see cref="GeoAPIPolygon"/>
  125. /// </summary>
  126. /// <param name="self">The <see cref="IPolygon"/> to convert</param>
  127. /// <param name="factory">The factory to create the <see cref="GeoAPIPolygon"/></param>
  128. /// <param name="setUserData">Sets the <see cref="GeoAPIGeometry.UserData"/> to <paramref name="self"/>.UserData</param>
  129. /// <returns>The converted geometry</returns>
  130. public static GeoAPIPolygon ToGeoAPI(this IPolygon self, GeoAPIGeometryFactory factory = null, bool setUserData = false)
  131. {
  132. var useFactory = factory ?? self.Factory.ToGeoAPI();
  133. return FromPolygon(self, useFactory, setUserData);
  134. }
  135. /// <summary>
  136. /// Converts a <see cref="IMultiPoint"/> to a <see cref="GeoAPIMultiPoint"/>
  137. /// </summary>
  138. /// <param name="self">The <see cref="IMultiPoint"/> to convert</param>
  139. /// <param name="factory">The factory to create the <see cref="GeoAPIMultiPoint"/></param>
  140. /// <param name="setUserData">Sets the <see cref="GeoAPIGeometry.UserData"/> to <paramref name="self"/>.UserData</param>
  141. /// <returns>The converted geometry</returns>
  142. public static GeoAPIMultiPoint ToGeoAPI(this IMultiPoint self, GeoAPIGeometryFactory factory = null, bool setUserData = false)
  143. {
  144. var useFactory = factory ?? self.Factory.ToGeoAPI();
  145. return FromMultiPoint(self, useFactory, setUserData);
  146. }
  147. /// <summary>
  148. /// Converts a <see cref="IMultiLineString"/> to a <see cref="GeoAPIMultiLineString"/>
  149. /// </summary>
  150. /// <param name="self">The <see cref="IMultiLineString"/> to convert</param>
  151. /// <param name="factory">The factory to create the <see cref="GeoAPIMultiLineString"/></param>
  152. /// <param name="setUserData">Sets the <see cref="GeoAPIGeometry.UserData"/> to <paramref name="self"/>.UserData</param>
  153. /// <returns>The converted geometry</returns>
  154. public static GeoAPIMultiLineString ToGeoAPI(this IMultiLineString self, GeoAPIGeometryFactory factory = null, bool setUserData = false)
  155. {
  156. var useFactory = factory ?? self.Factory.ToGeoAPI();
  157. return FromMultiLineString(self, useFactory, setUserData);
  158. }
  159. /// <summary>
  160. /// Converts a <see cref="IMultiLineString"/> to a <see cref="GeoAPIMultiLineString"/>
  161. /// </summary>
  162. /// <param name="self">The <see cref="IMultiLineString"/> to convert</param>
  163. /// <param name="factory">The factory to create the <see cref="GeoAPIMultiLineString"/></param>
  164. /// <param name="setUserData">Sets the <see cref="GeoAPIGeometry.UserData"/> to <paramref name="self"/>.UserData</param>
  165. /// <returns>The converted geometry</returns>
  166. public static GeoAPIMultiPolygon ToGeoAPI(this IMultiPolygon self, GeoAPIGeometryFactory factory = null, bool setUserData = false)
  167. {
  168. var useFactory = factory ?? self.Factory.ToGeoAPI();
  169. return FromMultiPolygon(self, useFactory, setUserData);
  170. }
  171. /// <summary>
  172. /// Converts a <see cref="IGeometryCollection"/> to a <see cref="GeoAPIGeometryCollection"/>
  173. /// </summary>
  174. /// <param name="self">The <see cref="IGeometryCollection"/> to convert</param>
  175. /// <param name="factory">The factory to create the <see cref="GeoAPIGeometryCollection"/></param>
  176. /// <param name="setUserData">Sets the <see cref="GeoAPIGeometry.UserData"/> to <paramref name="self"/>.UserData</param>
  177. /// <returns>The converted geometry</returns>
  178. public static GeoAPIGeometryCollection ToGeoAPI(this IGeometryCollection self, GeoAPIGeometryFactory factory = null, bool setUserData = false)
  179. {
  180. var useFactory = factory ?? self.Factory.ToGeoAPI();
  181. return FromGeometryCollection(self, useFactory, setUserData);
  182. }
  183. public static IList<GeoAPIGeometry> ToGeoAPI(this IList<IGeometry> geometries, GeoAPIGeometryFactory factory = null, bool setUserData = false)
  184. {
  185. return geometries.Select(geometry => FromGeometry(geometry, factory, setUserData)).ToList();
  186. }
  187. private static GeoAPIGeometry FromGeometry(IGeometry geometry, GeoAPIGeometryFactory factory, bool copyUserData)
  188. {
  189. var point = geometry as IPoint;
  190. if (point != null)
  191. return FromPoint(point, factory, copyUserData);
  192. var lineString = geometry as ILineString;
  193. if (lineString != null)
  194. return FromLineString(lineString, factory, copyUserData);
  195. var polygon = geometry as IPolygon;
  196. if (polygon != null)
  197. return FromPolygon(polygon, factory, copyUserData);
  198. var multiPoint = geometry as IMultiPoint;
  199. if (multiPoint != null)
  200. return FromMultiPoint(multiPoint, factory, copyUserData);
  201. var multiLineString = geometry as IMultiLineString;
  202. if (multiLineString != null)
  203. return FromMultiLineString(multiLineString, factory, copyUserData);
  204. var multiPolygon = geometry as IMultiPolygon;
  205. if (multiPolygon != null)
  206. return FromMultiPolygon(multiPolygon, factory, copyUserData);
  207. var geometryCollection = geometry as IGeometryCollection;
  208. if (geometryCollection != null)
  209. return FromGeometryCollection(geometryCollection, factory, copyUserData);
  210. throw new ArgumentException();
  211. }
  212. private static GeoAPICoordinate FromCoordinate(Coordinate coordinate)
  213. {
  214. return new GeoAPICoordinate(coordinate.X, coordinate.Y, coordinate.Z);
  215. }
  216. private static GeoAPICoordinate[] FromCoordinates(IList<Coordinate> coordinates)
  217. {
  218. var ret = new GeoAPICoordinate[coordinates.Count];
  219. for (var i = 0; i < coordinates.Count; i++)
  220. ret[i] = FromCoordinate(coordinates[i]);
  221. return ret;
  222. }
  223. /*
  224. private static DSCoordinateSequence FromCoordinateSequence(ICoordinateSequence coordinateSequence, DSCoordinateSequenceFactory factory)
  225. {
  226. var coordinates = FromCoordinates(coordinateSequence.ToCoordinateArray());
  227. return factory.Create(coordinates);
  228. }
  229. */
  230. private static GeoAPIPoint FromPoint(IPoint geometry, GeoAPIGeometryFactory factory, bool copyUserData)
  231. {
  232. var coord = FromCoordinate(geometry.Coordinate);
  233. var point = factory.CreatePoint(coord);
  234. if (copyUserData)
  235. point.UserData = geometry.UserData;
  236. return point;
  237. }
  238. private static GeoAPILineString FromLineString(ILineString geometry, GeoAPIGeometryFactory factory, bool copyUserData)
  239. {
  240. var coordinates = FromCoordinates(geometry.Coordinates);
  241. var result = (geometry is ILinearRing)
  242. ? factory.CreateLinearRing(coordinates)
  243. : factory.CreateLineString(coordinates);
  244. if (copyUserData)
  245. result.UserData = geometry.UserData;
  246. return result;
  247. }
  248. private static GeoAPIPolygon FromPolygon(IPolygon geometry, GeoAPIGeometryFactory factory, bool copyUserData)
  249. {
  250. var shell = (GeoAPILinearRing)FromLineString(geometry.Shell, factory, copyUserData);
  251. GeoAPILinearRing[] holes = null;
  252. if (geometry.Holes != null && geometry.Holes.Length > 0)
  253. {
  254. holes = new GeoAPILinearRing[geometry.Holes.Length];
  255. for (var i = 0; i < holes.Length; i++)
  256. holes[i] = (GeoAPILinearRing)FromLineString(geometry.Holes[i], factory, copyUserData);
  257. }
  258. return factory.CreatePolygon(shell, holes);
  259. }
  260. private static GeoAPIMultiPoint FromMultiPoint(IMultiPoint geometry, GeoAPIGeometryFactory factory, bool copyUserData)
  261. {
  262. var result = factory.CreateMultiPoint(FromCoordinates(geometry.Coordinates));
  263. if (copyUserData)
  264. result.UserData = geometry.UserData;
  265. return result;
  266. }
  267. private static GeoAPIMultiLineString FromMultiLineString(IMultiLineString geometry, GeoAPIGeometryFactory factory, bool copyUserData)
  268. {
  269. var dsLineStrings = new GeoAPILineString[geometry.NumGeometries];
  270. for (var i = 0; i < dsLineStrings.Length; i++)
  271. dsLineStrings[i] = FromLineString((ILineString)geometry.GetGeometryN(i), factory, copyUserData);
  272. var result = factory.CreateMultiLineString(dsLineStrings);
  273. if (copyUserData)
  274. result.UserData = geometry.UserData;
  275. return result;
  276. }
  277. private static GeoAPIMultiPolygon FromMultiPolygon(IMultiPolygon geometry, GeoAPIGeometryFactory factory, bool copyUserData)
  278. {
  279. var dsPolygons = new GeoAPI.Geometries.IPolygon[geometry.NumGeometries];
  280. for (var i = 0; i < dsPolygons.Length; i++)
  281. dsPolygons[i] = FromPolygon((IPolygon)geometry.GetGeometryN(i), factory, copyUserData);
  282. var result = factory.CreateMultiPolygon(dsPolygons);
  283. if (copyUserData)
  284. result.UserData = geometry.UserData;
  285. return result;
  286. }
  287. private static GeoAPIGeometryCollection FromGeometryCollection(IGeometryCollection geometry, GeoAPIGeometryFactory factory, bool copyUserData)
  288. {
  289. var dsGeometries = new GeoAPI.Geometries.IGeometry[geometry.NumGeometries];
  290. for (var i = 0; i < dsGeometries.Length; i++)
  291. dsGeometries[i] = FromGeometry(geometry.GetGeometryN(i), factory, copyUserData);
  292. var result = factory.CreateGeometryCollection(dsGeometries);
  293. if (copyUserData)
  294. result.UserData = geometry.UserData;
  295. return result;
  296. }
  297. public static GeoAPIEnvelope ToGeoAPI(this Data.Extent extent)
  298. {
  299. return new GeoAPIEnvelope(extent.MinX, extent.MaxX, extent.MinY, extent.MaxY);
  300. }
  301. public static GeoAPIEnvelope ToGeoAPI(this Envelope extent)
  302. {
  303. return new GeoAPIEnvelope(extent.Minimum.X, extent.Maximum.X, extent.Minimum.Y, extent.Maximum.Y);
  304. }
  305. public static GeoAPIGeometry ToGeoAPI(this Data.Shape shape, GeoAPI.Geometries.IGeometryFactory factory = null, bool copyAttributes = false)
  306. {
  307. var useFactory = factory ?? GeoAPI.GeometryServiceProvider.Instance.CreateGeometryFactory();
  308. if (shape.Range.FeatureType == FeatureType.Polygon)
  309. {
  310. return FromPolygonShape(shape, useFactory, copyAttributes);
  311. }
  312. if (shape.Range.FeatureType == FeatureType.Line)
  313. {
  314. return FromLineShape(shape, useFactory, copyAttributes);
  315. }
  316. if (shape.Range.FeatureType == FeatureType.MultiPoint)
  317. {
  318. return FromMultiPointShape(shape, useFactory, copyAttributes);
  319. }
  320. if (shape.Range.FeatureType == FeatureType.Point)
  321. {
  322. return FromPointShape(shape, useFactory, copyAttributes);
  323. }
  324. return null;
  325. }
  326. /// <summary>
  327. /// Get the point for this shape if this is a point shape.
  328. /// </summary>
  329. /// <param name="shape">The shape to convert</param>
  330. /// <param name="factory">The geometry factory to use.</param>
  331. /// <param name="copyAttributes">A value indicating whether or not to copy the <see cref="Data.Shape.Attributes"/> to <see cref="GeoAPIGeometry.UserData"/></param>
  332. /// <returns>The geometry representing the converted shape.</returns>
  333. private static GeoAPIGeometry FromPointShape(Data.Shape shape, GeoAPIGeometryFactory factory, bool copyAttributes)
  334. {
  335. var part = shape.Range.Parts[0];
  336. var i = part.StartIndex;
  337. var c = new GeoAPICoordinate(part.Vertices[0], part.Vertices[1]);
  338. //if (shape.HasM()) c.M = shape.M[i]
  339. if (shape.HasZ()) c.Z = shape.Z[i];
  340. var ret = factory.CreatePoint(c);
  341. if (copyAttributes)
  342. ret.UserData = shape.Attributes;
  343. return ret;
  344. }
  345. /// <summary>
  346. /// Creates a new MultiPoint geometry from a MultiPoint shape
  347. /// </summary>
  348. /// <param name="shape">The shape to convert</param>
  349. /// <param name="factory">The geometry factory to use.</param>
  350. /// <param name="copyAttributes">A value indicating whether or not to copy the <see cref="Data.Shape.Attributes"/> to <see cref="GeoAPIGeometry.UserData"/></param>
  351. /// <returns>The geometry representing the converted shape.</returns>
  352. /// <returns></returns>
  353. private static GeoAPIGeometry FromMultiPointShape(Data.Shape shape, GeoAPIGeometryFactory factory, bool copyAttributes)
  354. {
  355. var coords = new List<GeoAPICoordinate>();
  356. foreach (var part in shape.Range.Parts)
  357. {
  358. var i = part.StartIndex;
  359. foreach (var vertex in part)
  360. {
  361. var c = new GeoAPICoordinate(vertex.X, vertex.Y);
  362. coords.Add(c);
  363. //if (shape.HasM()) c.M = shape.M[i];
  364. if (shape.HasZ()) c.Z = shape.Z[i];
  365. i++;
  366. }
  367. }
  368. var ret = factory.CreateMultiPoint(coords.ToArray());
  369. if (copyAttributes)
  370. ret.UserData = shape.Attributes;
  371. return ret;
  372. }
  373. /// <summary>
  374. /// Gets the line for the specified index
  375. /// </summary>
  376. /// <param name="shape">The shape to convert</param>
  377. /// <param name="factory">The geometry factory to use.</param>
  378. /// <param name="copyAttributes">A value indicating whether or not to copy the <see cref="Data.Shape.Attributes"/> to <see cref="GeoAPIGeometry.UserData"/></param>
  379. /// <returns>The geometry representing the converted shape.</returns>
  380. private static GeoAPIGeometry FromLineShape(Data.Shape shape, GeoAPIGeometryFactory factory, bool copyAttributes)
  381. {
  382. var lines = new List<GeoAPILineString>();
  383. foreach (var part in shape.Range.Parts)
  384. {
  385. var i = part.StartIndex;
  386. var coords = new List<GeoAPICoordinate>();
  387. foreach (var d in part)
  388. {
  389. var c = new GeoAPICoordinate(d.X, d.Y);
  390. coords.Add(c);
  391. //if (shape.HasM()) c.M = M[i];
  392. if (shape.HasZ()) c.Z = shape.Z[i];
  393. i++;
  394. }
  395. lines.Add(factory.CreateLineString(coords.ToArray()));
  396. }
  397. if (lines.Count == 1)
  398. {
  399. if (copyAttributes)
  400. lines[0].UserData = shape.Attributes;
  401. return lines[0];
  402. }
  403. var ret = factory.CreateMultiLineString(lines.ToArray());
  404. if (copyAttributes)
  405. ret.UserData = shape.Attributes;
  406. return ret;
  407. }
  408. /// <summary>
  409. /// Creates a Polygon or MultiPolygon from this Polygon shape.
  410. /// </summary>
  411. /// <param name="shape">The shape to convert</param>
  412. /// <param name="factory">The geometry factory to use.</param>
  413. /// <param name="copyAttributes">A value indicating whether or not to copy the <see cref="Data.Shape.Attributes"/> to <see cref="GeoAPIGeometry.UserData"/></param>
  414. /// <returns>The geometry representing the converted shape.</returns>
  415. private static GeoAPIGeometry FromPolygonShape(Data.Shape shape, GeoAPIGeometryFactory factory, bool copyAttributes)
  416. {
  417. var shells = new List<GeoAPILinearRing>();
  418. var holes = new List<GeoAPILinearRing>();
  419. foreach (var part in shape.Range.Parts)
  420. {
  421. var coords = new List<GeoAPICoordinate>();
  422. var i = part.StartIndex;
  423. foreach (var d in part)
  424. {
  425. var c = new GeoAPICoordinate(d.X, d.Y);
  426. //if (shape.HasM()) c.M = M[i];
  427. if (shape.HasZ()) c.Z = shape.Z[i];
  428. i++;
  429. coords.Add(c);
  430. }
  431. var ring = factory.CreateLinearRing(coords.ToArray());
  432. if (shape.Range.Parts.Count == 1)
  433. {
  434. shells.Add(ring);
  435. }
  436. else
  437. {
  438. if (NetTopologySuite.Algorithm.CGAlgorithms.IsCCW(ring.Coordinates))
  439. {
  440. holes.Add(ring);
  441. }
  442. else
  443. {
  444. shells.Add(ring);
  445. }
  446. }
  447. }
  448. //// Now we have a list of all shells and all holes
  449. var holesForShells = new List<GeoAPILinearRing>[shells.Count];
  450. for (var i = 0; i < shells.Count; i++)
  451. {
  452. holesForShells[i] = new List<GeoAPILinearRing>();
  453. }
  454. // Find holes
  455. foreach (var testRing in holes)
  456. {
  457. GeoAPILinearRing minShell = null;
  458. GeoAPIEnvelope minEnv = null;
  459. var testEnv = testRing.EnvelopeInternal;
  460. var testPt = testRing.Coordinates[0];
  461. for (int j = 0; j < shells.Count; j++)
  462. {
  463. var tryRing = shells[j];
  464. var tryEnv = tryRing.EnvelopeInternal;
  465. if (minShell != null)
  466. minEnv = minShell.EnvelopeInternal;
  467. var isContained = tryEnv.Contains(testEnv)
  468. && (NetTopologySuite.Algorithm.CGAlgorithms.IsPointInRing(testPt, tryRing.Coordinates)
  469. || (PointInList(testPt, tryRing.Coordinates)));
  470. // Check if this new containing ring is smaller than the current minimum ring
  471. if (isContained)
  472. {
  473. if (minShell == null || minEnv.Contains(tryEnv))
  474. {
  475. minShell = tryRing;
  476. }
  477. holesForShells[j].Add(testRing);
  478. }
  479. }
  480. }
  481. var polygons = new GeoAPIPolygon[shells.Count];
  482. for (var i = 0; i < shells.Count; i++)
  483. {
  484. polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray());
  485. }
  486. if (polygons.Length == 1)
  487. {
  488. if (copyAttributes)
  489. polygons[0].UserData = shape.Attributes;
  490. return polygons[0];
  491. }
  492. // It's a multi part
  493. var ret = factory.CreateMultiPolygon(polygons);
  494. if (copyAttributes)
  495. ret.UserData = shape.Attributes;
  496. return ret;
  497. }
  498. private static bool HasM(this Data.Shape self)
  499. {
  500. return self.M != null && self.M.Length > 0;
  501. }
  502. private static bool HasZ(this Data.Shape self)
  503. {
  504. return self.Z != null && self.Z.Length > 0;
  505. }
  506. /// <summary>
  507. /// Test if a point is in a list of coordinates.
  508. /// </summary>
  509. /// <param name="testPoint">The point to test for.</param>
  510. /// <param name="pointList">The list of points to look through.</param>
  511. /// <returns>true if <paramref name="testPoint"/> is a point in the <paramref name="pointList"/> list.</returns>
  512. private static bool PointInList(GeoAPICoordinate testPoint, IEnumerable<GeoAPICoordinate> pointList)
  513. {
  514. return pointList.Any(p => p.Equals2D(testPoint));
  515. }
  516. }
  517. }