PageRenderTime 28ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/HydroModeler/Utilities/OpenMI/sdk/Backup/Spatial/XYPolygon.cs

#
C# | 359 lines | 220 code | 23 blank | 116 comment | 42 complexity | 6fb89bfe875ecc940b2e03b40632ab65 MD5 | raw file
Possible License(s): MIT
  1. #region Copyright
  2. /*
  3. * Copyright (c) 2005,2006,2007, OpenMI Association
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * * Neither the name of the OpenMI Association nor the
  14. * names of its contributors may be used to endorse or promote products
  15. * derived from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY "OpenMI Association" ``AS IS'' AND ANY
  18. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. * DISCLAIMED. IN NO EVENT SHALL "OpenMI Association" BE LIABLE FOR ANY
  21. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #endregion
  29. using System;
  30. using System.Collections;
  31. namespace Oatc.OpenMI.Sdk.Spatial
  32. {
  33. /// <summary>
  34. /// <p>The XYPolygon class defines a polygon in the XY plane (no z coordinate)</p>
  35. /// <p></p>
  36. /// <p>The XYPolygon class has a number of usefull methods and XYPolygon objects
  37. /// are used as argument in a number of the methods in the Oatc.OpenMI.Sdk.Spatial
  38. /// namespace.</p>
  39. /// <p></p>
  40. /// <p>The XYPolygon class is inhereted from the org.OpenMI.Utilities.BackBone.Element class.</p>
  41. /// <p></p>
  42. /// <p>It is possible to upcaste the XYPoint objects to Element objects.</p>
  43. /// <p></p>
  44. /// <p>If you already have a Element object that defines a polygon you can construct
  45. /// a new XYPoint using the Element objects as argument in the constructor.</p>
  46. ///
  47. /// </summary>
  48. public class XYPolygon : XYPolyline
  49. {
  50. /// <summary>
  51. /// Constructor.
  52. /// </summary>
  53. public XYPolygon()
  54. {
  55. }
  56. /// <summary>
  57. /// Constructor. Copies the contents of the xyPolygon parameter.
  58. /// </summary>
  59. /// <param name="xyPolygon">Polygon to copy.</param>
  60. /// <returns>None</returns>
  61. public XYPolygon(XYPolygon xyPolygon)
  62. {
  63. // Points = new ArrayList();
  64. foreach (XYPoint xypoint in xyPolygon.Points)
  65. {
  66. Points.Add(new XYPoint(xypoint.X, xypoint.Y));
  67. }
  68. }
  69. /// <summary>
  70. /// Calcualtes area of polygon.
  71. /// </summary>
  72. /// <returns>Polygon area.</returns>
  73. public double GetArea()
  74. {
  75. double x1, x2, y1, y2, xN, x0, yN, y0, area;
  76. area = 0;
  77. for (int i = 0; i < Points.Count - 1; i++)
  78. {
  79. x1 = ((XYPoint) Points[i]).X;
  80. x2 = ((XYPoint) Points[i+1]).X;
  81. y1 = ((XYPoint) Points[i]).Y;
  82. y2 = ((XYPoint) Points[i+1]).Y;
  83. area += x1*y2 - x2*y1;
  84. }
  85. xN = ((XYPoint) Points[Points.Count - 1]).X;
  86. x0 = ((XYPoint) Points[0]).X;
  87. yN = ((XYPoint) Points[Points.Count - 1]).Y;
  88. y0 = ((XYPoint) Points[0]).Y;
  89. area += xN * y0 - x0 * yN;
  90. area = 0.5 * area;
  91. return area;
  92. }
  93. /// <summary>
  94. /// Returns the XYline that connects XYPoint LineNumber and the next
  95. /// number (i.e. LineNumber+1 or 0).</summary>
  96. /// <param name="lineNumber">0-based line number.</param>
  97. /// <returns>
  98. /// The XYLine starting at node lineNumber.
  99. /// </returns>
  100. public new XYLine GetLine(int lineNumber)
  101. {
  102. int index2;
  103. if (lineNumber == Points.Count - 1)
  104. {
  105. index2 = 0;
  106. }
  107. else
  108. {
  109. index2 = lineNumber + 1;
  110. }
  111. return new XYLine(((XYPoint) Points[lineNumber]).X, ((XYPoint) Points[lineNumber]).Y, ((XYPoint) Points[index2]).X, ((XYPoint) Points[index2]).Y);
  112. }
  113. /// <summary>
  114. /// Finds a set of three concecutive points that form a triangle, that
  115. /// is not intersected by other parts of the polygon.
  116. /// </summary>
  117. /// <param></param>
  118. /// <returns>
  119. /// <p>i: Index for the "midlle" point of triangle that forms an ear.
  120. /// The ear is formed by P(i-1), P(i) and P(i+1), where P are points
  121. /// included in the polygon.</p>
  122. /// </returns>
  123. protected int FindEar()
  124. {
  125. int i = 0;
  126. int n = Points.Count - 1;
  127. bool found = false;
  128. while ((i < n-1) && (!found))
  129. {
  130. if ((IsConvex(i) == true) && (IsIntersected(i) == false))
  131. {
  132. found = true;
  133. }
  134. else
  135. {
  136. i++;
  137. }
  138. }
  139. return i;
  140. }
  141. /// <summary>
  142. /// The method decides if the triangle formed by P(i-1), P(i) and
  143. /// P(i+1) from Polygon are intersected by any of the other points
  144. /// of the polygon.
  145. /// </summary>
  146. /// <param name="i">Middle index for the three points that forms the triangle</param>
  147. /// <returns>
  148. /// <p>true: If the triangle P(i-1), P(i), P(i+1) is intersected by other parts of Polygon</p>
  149. /// <p>false: otherwise</p>
  150. /// </returns>
  151. protected bool IsIntersected(int i)
  152. {
  153. double x = 0;
  154. double y = 0;
  155. int n = Points.Count;
  156. int im1 = i-1;
  157. int ip1 = i+1;
  158. if (i == 0)
  159. {
  160. im1 = n-1;
  161. }
  162. else if (i == n-1)
  163. {
  164. ip1 = 0;
  165. }
  166. XYPoint nodeim1 = new XYPoint((XYPoint) Points[im1]);
  167. XYPoint nodei = new XYPoint((XYPoint) Points[i]);
  168. XYPoint nodeip1 = new XYPoint((XYPoint) Points[ip1]);
  169. XYPolygon localPolygon = new XYPolygon();
  170. localPolygon.Points.Add(nodeim1);
  171. localPolygon.Points.Add(nodei);
  172. localPolygon.Points.Add(nodeip1);
  173. int j = 0;
  174. bool intersected = false;
  175. while (((j < n-1) && (!intersected)))
  176. {
  177. x = ((XYPoint) Points[j]).X;
  178. y = ((XYPoint) Points[j]).Y;
  179. if (((((j!=im1) && (j!=i)) && (j!=ip1)) && XYGeometryTools.IsPointInPolygon(x,y,localPolygon)))
  180. {
  181. return true;
  182. }
  183. else
  184. {
  185. j++;
  186. }
  187. }
  188. return false;
  189. }
  190. /// <summary>
  191. /// Returns an ArrayList of triangles of type XYPolygon describing the
  192. /// triangalation of the polygon.
  193. /// </summary>
  194. /// <param></param>
  195. /// <returns>
  196. /// A triangulation of the polygon.
  197. /// </returns>
  198. public ArrayList GetTriangulation()
  199. {
  200. int i = 0;
  201. int im1 = 0;
  202. int ip1 = 0;
  203. int n = 0;
  204. XYPolygon LocalPolygon = new XYPolygon(this);
  205. ArrayList TriangleList = new ArrayList();
  206. while (LocalPolygon.Points.Count > 3)
  207. {
  208. i = LocalPolygon.FindEar();
  209. n = LocalPolygon.Points.Count;
  210. im1 = i-1;
  211. ip1 = i+1;
  212. if (i == 0)
  213. {
  214. im1 = n-1;
  215. }
  216. else if (i == n-1)
  217. {
  218. ip1 = 0;
  219. }
  220. XYPoint Nodeim1 = new XYPoint((XYPoint)LocalPolygon.Points[im1]);
  221. XYPoint Nodei = new XYPoint((XYPoint)LocalPolygon.Points[i]);
  222. XYPoint Nodeip1 = new XYPoint((XYPoint)LocalPolygon.Points[ip1]);
  223. XYPolygon Triangle = new XYPolygon();
  224. Triangle.Points.Add(Nodeim1);
  225. Triangle.Points.Add(Nodei);
  226. Triangle.Points.Add(Nodeip1);
  227. TriangleList.Add(Triangle);
  228. LocalPolygon.Points.RemoveAt(i);
  229. }
  230. TriangleList.Add(LocalPolygon);
  231. return TriangleList;
  232. }
  233. /// <summary>
  234. /// Decides if the angle at i´th point is convex or concave.
  235. /// </summary>
  236. /// <param name="pointIndex">Index</param>
  237. /// <returns>
  238. /// <p>True if angle at the i´th point is convex.</p>
  239. /// <p>False if angle at the i´th point is concave.</p>
  240. /// </returns>
  241. protected bool IsConvex(int pointIndex)
  242. {
  243. bool isConvex = true;
  244. int im1 = pointIndex - 1 < 0 ? Points.Count - 1 : pointIndex - 1; //previous point index
  245. int ip1 = pointIndex + 1 > Points.Count - 1 ? 0 : pointIndex + 1; //next point index
  246. double xim1 = ((XYPoint) Points[im1]).X;
  247. double yim1 = ((XYPoint) Points[im1]).Y;
  248. double xi = ((XYPoint) Points[pointIndex]).X;
  249. double yi = ((XYPoint) Points[pointIndex]).Y;
  250. double xip1 = ((XYPoint) Points[ip1]).X;
  251. double yip1 = ((XYPoint) Points[ip1]).Y;
  252. if ((xip1-xim1)*(yi-yim1)-(xi-xim1)*(yip1-yim1)>0)
  253. {
  254. isConvex = false;
  255. }
  256. else
  257. {
  258. isConvex = true;
  259. }
  260. return isConvex;
  261. }
  262. /// <summary>
  263. /// Compares the object type and the coordinates of the object and the
  264. /// object passed as parameter.
  265. /// </summary>
  266. /// <returns>True if object type is XYPolygon and the coordinates are
  267. /// equal to to the coordinates of the current object. False otherwise.</returns>
  268. public override bool Equals(Object obj)
  269. {
  270. if (obj == null || GetType() != obj.GetType())
  271. {
  272. return false;
  273. }
  274. XYPolyline e = (XYPolygon) obj;
  275. if (Points.Count!=e.Points.Count)
  276. {
  277. return false;
  278. }
  279. for (int i=0;i<Points.Count;i++)
  280. {
  281. if (!((XYPoint) Points[i]).Equals(e.Points[i]))
  282. {
  283. return false;
  284. }
  285. }
  286. return true;
  287. }
  288. /// <summary>
  289. /// Get hash code.
  290. /// </summary>
  291. /// <returns>Hash Code for the current instance.</returns>
  292. public override int GetHashCode()
  293. {
  294. return base.GetHashCode();
  295. }
  296. /// <summary>
  297. /// The validate method check if the XYPolyline is valid. The checks
  298. /// made are:
  299. /// - is number of points >= 3
  300. /// - is the length of all line segments positiv
  301. /// - do any lines cross
  302. /// - is the area positiv
  303. /// Exception is raised if the constraints are not met.
  304. /// </summary>
  305. public new void Validate()
  306. {
  307. if(Points.Count < 3)
  308. {
  309. throw new System.Exception("Number of vertices in polygon element is less than 3.");
  310. }
  311. if (GetArea() <= 0)
  312. {
  313. throw new System.Exception("Area of polygon is negative or zero. XYPolygons must be ordered counter clockwise.");
  314. }
  315. for (int j = 0; j < Points.Count; j++)
  316. {
  317. if (GetLine(j).GetLength() == 0)
  318. {
  319. throw new System.Exception("Length of line segment no: "+
  320. j.ToString()+" (0-based) of XYPolygon is zero.");
  321. }
  322. }
  323. for (int j = 0; j < Points.Count; j++)
  324. {
  325. for (int m = 0; m < j; m++)
  326. {
  327. if (XYGeometryTools.DoLineSegmentsIntersect(GetLine(j),GetLine(m)))
  328. {
  329. throw new System.Exception("Line no: "+j.ToString()+" and line no: "+
  330. m.ToString()+" of XYPolygon crosses.");
  331. }
  332. }
  333. }
  334. }
  335. }
  336. }