PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/branch/futaba/library/NetTopologySuite_Silverlight/Geometries/CoordinateArrays.cs

#
C# | 416 lines | 206 code | 32 blank | 178 comment | 57 complexity | 71456945d8baa2211d0bbd7a43daedf4 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, MPL-2.0-no-copyleft-exception
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using GeoAPI.Geometries;
  5. namespace GisSharpBlog.NetTopologySuite.Geometries
  6. {
  7. /// <summary>
  8. /// Useful utility functions for handling Coordinate arrays.
  9. /// </summary>
  10. public static class CoordinateArrays
  11. {
  12. /// <summary>
  13. /// Finds a <see cref="Coordinate "/> in a list of <see cref="Coordinate "/>s
  14. /// which is not contained in another list of <see cref="Coordinate "/>s.
  15. /// </summary>
  16. /// <param name="testPts">The <see cref="Coordinate" />s to test.</param>
  17. /// <param name="pts">An array of <see cref="Coordinate" />s to test the input points against.</param>
  18. /// <returns>
  19. /// A <see cref="Coordinate" /> from <paramref name="testPts" />
  20. /// which is not in <paramref name="pts" />, or <c>null</c>.
  21. /// </returns>
  22. public static ICoordinate PointNotInList(ICoordinate[] testPts, ICoordinate[] pts)
  23. {
  24. for (var i = 0; i < testPts.Length; i++)
  25. {
  26. var testPt = testPts[i];
  27. if (IndexOf(testPt, pts) < 0)
  28. return testPt;
  29. }
  30. return null;
  31. }
  32. /// <summary>
  33. /// Compares two <see cref="Coordinate" /> arrays
  34. /// in the forward direction of their coordinates,
  35. /// using lexicographic ordering.
  36. /// </summary>
  37. /// <param name="pts1"></param>
  38. /// <param name="pts2"></param>
  39. /// <returns></returns>
  40. public static int Compare(ICoordinate[] pts1, ICoordinate[] pts2)
  41. {
  42. var i = 0;
  43. while (i < pts1.Length && i < pts2.Length)
  44. {
  45. var compare = pts1[i].CompareTo(pts2[i]);
  46. if (compare != 0)
  47. return compare;
  48. i++;
  49. }
  50. // handle situation when arrays are of different length
  51. if (i < pts2.Length)
  52. return -1;
  53. if (i < pts1.Length)
  54. return 1;
  55. return 0;
  56. }
  57. /// <summary>
  58. /// Determines which orientation of the <see cref="Coordinate" /> array is (overall) increasing.
  59. /// In other words, determines which end of the array is "smaller"
  60. /// (using the standard ordering on <see cref="Coordinate" />).
  61. /// Returns an integer indicating the increasing direction.
  62. /// If the sequence is a palindrome, it is defined to be
  63. /// oriented in a positive direction.
  64. /// </summary>
  65. /// <param name="pts">The array of Coordinates to test.</param>
  66. /// <returns>
  67. /// <c>1</c> if the array is smaller at the start or is a palindrome,
  68. /// <c>-1</c> if smaller at the end.
  69. /// </returns>
  70. public static int IncreasingDirection(ICoordinate[] pts)
  71. {
  72. for (var i = 0; i < pts.Length / 2; i++)
  73. {
  74. var j = pts.Length - 1 - i;
  75. // skip equal points on both ends
  76. var comp = pts[i].CompareTo(pts[j]);
  77. if (comp != 0)
  78. return comp;
  79. }
  80. // array must be a palindrome - defined to be in positive direction
  81. return 1;
  82. }
  83. /// <summary>
  84. /// Determines whether two <see cref="Coordinate" /> arrays of equal length
  85. /// are equal in opposite directions.
  86. /// </summary>
  87. /// <param name="pts1"></param>
  88. /// <param name="pts2"></param>
  89. /// <returns></returns>
  90. private static bool IsEqualReversed(ICoordinate[] pts1, ICoordinate[] pts2)
  91. {
  92. for (var i = 0; i < pts1.Length; i++)
  93. {
  94. var p1 = pts1[i];
  95. var p2 = pts2[pts1.Length - i - 1];
  96. if (p1.CompareTo(p2) != 0)
  97. return false;
  98. }
  99. return true;
  100. }
  101. /// <summary>
  102. /// Creates a deep copy of the argument <c>Coordinate</c> array.
  103. /// </summary>
  104. /// <param name="coordinates">Array of Coordinates.</param>
  105. /// <returns>Deep copy of the input.</returns>
  106. public static ICoordinate[] CopyDeep(ICoordinate[] coordinates)
  107. {
  108. var copy = new ICoordinate[coordinates.Length];
  109. for(var i = 0; i < coordinates.Length; i++)
  110. copy[i] = new Coordinate(coordinates[i]);
  111. return copy;
  112. }
  113. /// <summary>
  114. /// Converts the given <see cref="IList" /> of
  115. /// <see cref="Coordinate" />s into a <see cref="Coordinate" /> array.
  116. /// </summary>
  117. /// <param name="coordList"><see cref="IList" /> of coordinates.</param>
  118. /// <returns></returns>
  119. /// <exception cref="InvalidCastException">
  120. /// If <paramref name="coordList"/> contains not only <see cref="Coordinate" />s.
  121. /// </exception>
  122. [Obsolete("Use generic method instead")]
  123. public static ICoordinate[] ToCoordinateArray(ICollection coordList)
  124. {
  125. var tempList = new List<ICoordinate>(coordList.Count);
  126. foreach (ICoordinate coord in coordList)
  127. tempList.Add(coord);
  128. return tempList.ToArray();
  129. }
  130. /// <summary>
  131. /// Converts the given <see cref="IList" /> of
  132. /// <see cref="Coordinate" />s into a <see cref="Coordinate" /> array.
  133. /// </summary>
  134. /// <param name="coordList"><see cref="IList" /> of coordinates.</param>
  135. /// <returns></returns>
  136. public static ICoordinate[] ToCoordinateArray(ICollection<ICoordinate> coordList)
  137. {
  138. var tempList = new List<ICoordinate>(coordList.Count);
  139. foreach (var coord in coordList)
  140. tempList.Add(coord);
  141. return tempList.ToArray();
  142. }
  143. /// <summary>
  144. /// Returns whether Equals returns true for any two consecutive
  145. /// coordinates in the given array.
  146. /// </summary>
  147. /// <param name="coord">Array of Coordinates.</param>
  148. /// <returns>true if coord has repeated points; false otherwise.</returns>
  149. public static bool HasRepeatedPoints(ICoordinate[] coord)
  150. {
  151. for(var i = 1; i < coord.Length; i++)
  152. if(coord[i - 1].Equals(coord[i]))
  153. return true;
  154. return false;
  155. }
  156. /// <summary>
  157. /// Returns either the given coordinate array if its length is greater than
  158. /// the given amount, or an empty coordinate array.
  159. /// </summary>
  160. /// <param name="n">Length amount.</param>
  161. /// <param name="c">Array of Coordinates.</param>
  162. /// <returns>New Coordinate array.</returns>
  163. public static ICoordinate[] AtLeastNCoordinatesOrNothing(int n, ICoordinate[] c)
  164. {
  165. return (c.Length >= n) ? (c) : (new ICoordinate[] { });
  166. }
  167. /// <summary>
  168. /// If the coordinate array argument has repeated points,
  169. /// constructs a new array containing no repeated points.
  170. /// Otherwise, returns the argument.
  171. /// </summary>
  172. /// <param name="coord"></param>
  173. /// <returns></returns>
  174. public static ICoordinate[] RemoveRepeatedPoints(ICoordinate[] coord)
  175. {
  176. if (!HasRepeatedPoints(coord))
  177. return coord;
  178. var coordList = new CoordinateList(coord, false);
  179. return coordList.ToCoordinateArray();
  180. }
  181. /// <summary>
  182. /// Reverses the coordinates in an array in-place.
  183. /// </summary>
  184. /// <param name="coord">Array of Coordinates.</param>
  185. public static void Reverse(ICoordinate[] coord)
  186. {
  187. // This implementation uses FCL capabilities
  188. Array.Reverse(coord);
  189. /* Old code from JTS
  190. int last = coord.Length - 1;
  191. int mid = last / 2;
  192. for (int i = 0; i <= mid; i++)
  193. {
  194. Coordinate tmp = coord[i];
  195. coord[i] = coord[last - i];
  196. coord[last - i] = tmp;
  197. }
  198. */
  199. }
  200. /// <summary>
  201. /// Returns <c>true</c> if the two arrays are identical, both <c>null</c>, or pointwise
  202. /// equal (as compared using Coordinate.Equals).
  203. /// </summary>
  204. /// <param name="coord1">First array of Coordinates.</param>
  205. /// <param name="coord2">Second array of Coordinates.</param>
  206. /// <returns><c>true</c> if two Coordinates array are equals; false otherwise</returns>
  207. public static bool Equals(ICoordinate[] coord1, ICoordinate[] coord2)
  208. {
  209. if (coord1 == coord2)
  210. return true;
  211. if (coord1 == null || coord2 == null)
  212. return false;
  213. if (coord1.Length != coord2.Length)
  214. return false;
  215. for (var i = 0; i < coord1.Length; i++)
  216. if (!coord1[i].Equals(coord2[i]))
  217. return false;
  218. return true;
  219. }
  220. /// <summary>
  221. /// Compares two <see cref="Coordinate" /> arrays
  222. /// in the forward direction of their coordinates,
  223. /// using lexicographic ordering.
  224. /// </summary>
  225. public class ForwardComparator : IComparer<ICoordinate[]>
  226. {
  227. /// <summary>
  228. /// Compares the specified <see cref="Coordinate" />s arrays.
  229. /// </summary>
  230. /// <param name="pts1"></param>
  231. /// <param name="pts2"></param>
  232. /// <returns></returns>
  233. public int Compare(ICoordinate[] pts1, ICoordinate[] pts2)
  234. {
  235. return CoordinateArrays.Compare(pts1, pts2);
  236. }
  237. }
  238. /// <summary>
  239. /// A comparator for <see cref="Coordinate" /> arrays modulo their directionality.
  240. /// E.g. if two coordinate arrays are identical but reversed
  241. /// they will compare as equal under this ordering.
  242. /// If the arrays are not equal, the ordering returned
  243. /// is the ordering in the forward direction.
  244. /// </summary>
  245. public class BidirectionalComparator : IComparer<ICoordinate[]>
  246. {
  247. /// <summary>
  248. ///
  249. /// </summary>
  250. /// <param name="pts1"></param>
  251. /// <param name="pts2"></param>
  252. /// <returns></returns>
  253. public int Compare(ICoordinate[] pts1, ICoordinate[] pts2)
  254. {
  255. if (pts1.Length < pts2.Length)
  256. return -1;
  257. if (pts1.Length > pts2.Length)
  258. return 1;
  259. if (pts1.Length == 0)
  260. return 0;
  261. var forwardComp = CoordinateArrays.Compare(pts1, pts2);
  262. var isEqualRev = IsEqualReversed(pts1, pts2);
  263. if (isEqualRev)
  264. return 0;
  265. return forwardComp;
  266. }
  267. /// <summary>
  268. ///
  269. /// </summary>
  270. /// <param name="pts1"></param>
  271. /// <param name="pts2"></param>
  272. /// <returns></returns>
  273. public int OLDcompare(ICoordinate[] pts1, ICoordinate[] pts2)
  274. {
  275. if (pts1.Length < pts2.Length)
  276. return -1;
  277. if (pts1.Length > pts2.Length)
  278. return 1;
  279. if (pts1.Length == 0)
  280. return 0;
  281. var dir1 = IncreasingDirection(pts1);
  282. var dir2 = IncreasingDirection(pts2);
  283. var i1 = dir1 > 0 ? 0 : pts1.Length - 1;
  284. var i2 = dir2 > 0 ? 0 : pts1.Length - 1;
  285. for (var i = 0; i < pts1.Length; i++)
  286. {
  287. var comparePt = pts1[i1].CompareTo(pts2[i2]);
  288. if (comparePt != 0)
  289. return comparePt;
  290. i1 += dir1;
  291. i2 += dir2;
  292. }
  293. return 0;
  294. }
  295. }
  296. /// <summary>
  297. /// Returns <c>true</c> if the two arrays are identical, both <c>null</c>, or pointwise
  298. /// equal, using a user-defined <see cref="IComparer" />
  299. /// for <see cref="Coordinate" />s.
  300. /// </summary>
  301. /// <param name="coord1">An array of <see cref="Coordinate" />s.</param>
  302. /// <param name="coord2">Another array of <see cref="Coordinate" />s.</param>
  303. /// <param name="coordinateComparer">
  304. /// A <see cref="IComparer" /> for <see cref="Coordinate" />s.
  305. /// </param>
  306. /// <returns></returns>
  307. public static bool Equals(ICoordinate[] coord1, ICoordinate[] coord2,
  308. IComparer<ICoordinate[]> coordinateComparer)
  309. {
  310. if (coord1 == coord2)
  311. return true;
  312. if (coord1 == null || coord2 == null)
  313. return false;
  314. if (coord1.Length != coord2.Length)
  315. return false;
  316. if (coordinateComparer.Compare(coord1, coord2) != 0)
  317. return false;
  318. return true;
  319. }
  320. /// <summary>
  321. /// Returns the minimum coordinate, using the usual lexicographic comparison.
  322. /// </summary>
  323. /// <param name="coordinates">Array to search.</param>
  324. /// <returns>The minimum coordinate in the array, found using <c>CompareTo</c>.</returns>
  325. public static ICoordinate MinCoordinate(ICoordinate[] coordinates)
  326. {
  327. ICoordinate minCoord = null;
  328. for (var i = 0; i < coordinates.Length; i++)
  329. if (minCoord == null || minCoord.CompareTo(coordinates[i]) > 0)
  330. minCoord = coordinates[i];
  331. return minCoord;
  332. }
  333. /// <summary>
  334. /// Shifts the positions of the coordinates until <c>firstCoordinate</c> is first.
  335. /// </summary>
  336. /// <param name="coordinates">Array to rearrange.</param>
  337. /// <param name="firstCoordinate">Coordinate to make first.</param>
  338. public static void Scroll(ICoordinate[] coordinates, ICoordinate firstCoordinate)
  339. {
  340. var i = IndexOf(firstCoordinate, coordinates);
  341. if (i < 0)
  342. return;
  343. var newCoordinates = new ICoordinate[coordinates.Length];
  344. Array.Copy(coordinates, i, newCoordinates, 0, coordinates.Length - i);
  345. Array.Copy(coordinates, 0, newCoordinates, coordinates.Length - i, i);
  346. Array.Copy(newCoordinates, 0, coordinates, 0, coordinates.Length);
  347. }
  348. /// <summary>
  349. /// Returns the index of <paramref name="coordinate" /> in <paramref name="coordinates" />.
  350. /// The first position is 0; the second is 1; etc.
  351. /// </summary>
  352. /// <param name="coordinate">A <see cref="Coordinate" /> to search for.</param>
  353. /// <param name="coordinates">A <see cref="Coordinate" /> array to search.</param>
  354. /// <returns>The position of <c>coordinate</c>, or -1 if it is not found.</returns>
  355. public static int IndexOf(ICoordinate coordinate, ICoordinate[] coordinates)
  356. {
  357. for (var i = 0; i < coordinates.Length; i++)
  358. if (coordinate.Equals(coordinates[i]))
  359. return i;
  360. return -1;
  361. }
  362. /// <summary>
  363. /// Extracts a subsequence of the input <see cref="Coordinate" /> array
  364. /// from indices <paramref name="start" /> to <paramref name="end"/> (inclusive).
  365. /// </summary>
  366. /// <param name="pts">The input array.</param>
  367. /// <param name="start">The index of the start of the subsequence to extract.</param>
  368. /// <param name="end">The index of the end of the subsequence to extract.</param>
  369. /// <returns>A subsequence of the input array.</returns>
  370. public static ICoordinate[] Extract(ICoordinate[] pts, int start, int end)
  371. {
  372. // Code using FLC features
  373. var len = end - start + 1;
  374. var extractPts = new ICoordinate[len];
  375. Array.Copy(pts, start, extractPts, 0, len);
  376. /* Original JTS code
  377. int iPts = 0;
  378. for (int i = start; i <= end; i++)
  379. extractPts[iPts++] = pts[i];
  380. */
  381. return extractPts;
  382. }
  383. }
  384. }