Polygon.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /* Poly2Tri
  2. * Copyright (c) 2009-2010, Poly2Tri Contributors
  3. * http://code.google.com/p/poly2tri/
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without modification,
  8. * are permitted provided that the following conditions are met:
  9. *
  10. * * Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation
  14. * and/or other materials provided with the distribution.
  15. * * Neither the name of Poly2Tri nor the names of its contributors may be
  16. * used to endorse or promote products derived from this software without specific
  17. * prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. // Changes from the Java version
  32. // Polygon constructors sprused up, checks for 3+ polys
  33. // Naming of everything
  34. // getTriangulationMode() -> TriangulationMode { get; }
  35. // Exceptions replaced
  36. // Future possibilities
  37. // We have a lot of Add/Clear methods -- we may prefer to just expose the container
  38. // Some self-explanitory methods may deserve commenting anyways
  39. using System;
  40. using System.Collections.Generic;
  41. using System.Linq;
  42. using Poly2Tri.Triangulation.Delaunay;
  43. namespace Poly2Tri.Triangulation.Polygon
  44. {
  45. public class Polygon : Triangulatable
  46. {
  47. protected List<Polygon> _holes;
  48. protected PolygonPoint _last;
  49. protected List<TriangulationPoint> _points = new List<TriangulationPoint>();
  50. protected List<TriangulationPoint> _steinerPoints;
  51. protected List<DelaunayTriangle> _triangles;
  52. /// <summary>
  53. /// Create a polygon from a list of at least 3 points with no duplicates.
  54. /// </summary>
  55. /// <param name="points">A list of unique points</param>
  56. public Polygon(IList<PolygonPoint> points)
  57. {
  58. if (points.Count < 3) throw new ArgumentException("List has fewer than 3 points", "points");
  59. // Lets do one sanity check that first and last point hasn't got same position
  60. // Its something that often happen when importing polygon data from other formats
  61. if (points[0].Equals(points[points.Count - 1])) points.RemoveAt(points.Count - 1);
  62. _points.AddRange(points.Cast<TriangulationPoint>());
  63. }
  64. /// <summary>
  65. /// Create a polygon from a list of at least 3 points with no duplicates.
  66. /// </summary>
  67. /// <param name="points">A list of unique points.</param>
  68. public Polygon(IEnumerable<PolygonPoint> points) : this((points as IList<PolygonPoint>) ?? points.ToArray())
  69. {
  70. }
  71. public Polygon()
  72. {
  73. }
  74. public IList<Polygon> Holes
  75. {
  76. get { return _holes; }
  77. }
  78. #region Triangulatable Members
  79. public TriangulationMode TriangulationMode
  80. {
  81. get { return TriangulationMode.Polygon; }
  82. }
  83. public IList<TriangulationPoint> Points
  84. {
  85. get { return _points; }
  86. }
  87. public IList<DelaunayTriangle> Triangles
  88. {
  89. get { return _triangles; }
  90. }
  91. public void AddTriangle(DelaunayTriangle t)
  92. {
  93. _triangles.Add(t);
  94. }
  95. public void AddTriangles(IEnumerable<DelaunayTriangle> list)
  96. {
  97. _triangles.AddRange(list);
  98. }
  99. public void ClearTriangles()
  100. {
  101. if (_triangles != null) _triangles.Clear();
  102. }
  103. /// <summary>
  104. /// Creates constraints and populates the context with points
  105. /// </summary>
  106. /// <param name="tcx">The context</param>
  107. public void PrepareTriangulation(TriangulationContext tcx)
  108. {
  109. if (_triangles == null)
  110. {
  111. _triangles = new List<DelaunayTriangle>(_points.Count);
  112. }
  113. else
  114. {
  115. _triangles.Clear();
  116. }
  117. // Outer constraints
  118. for (int i = 0; i < _points.Count - 1; i++)
  119. {
  120. tcx.NewConstraint(_points[i], _points[i + 1]);
  121. }
  122. tcx.NewConstraint(_points[0], _points[_points.Count - 1]);
  123. tcx.Points.AddRange(_points);
  124. // Hole constraints
  125. if (_holes != null)
  126. {
  127. foreach (Polygon p in _holes)
  128. {
  129. for (int i = 0; i < p._points.Count - 1; i++)
  130. {
  131. tcx.NewConstraint(p._points[i], p._points[i + 1]);
  132. }
  133. tcx.NewConstraint(p._points[0], p._points[p._points.Count - 1]);
  134. tcx.Points.AddRange(p._points);
  135. }
  136. }
  137. if (_steinerPoints != null)
  138. {
  139. tcx.Points.AddRange(_steinerPoints);
  140. }
  141. }
  142. #endregion
  143. public void AddSteinerPoint(TriangulationPoint point)
  144. {
  145. if (_steinerPoints == null)
  146. {
  147. _steinerPoints = new List<TriangulationPoint>();
  148. }
  149. _steinerPoints.Add(point);
  150. }
  151. public void AddSteinerPoints(List<TriangulationPoint> points)
  152. {
  153. if (_steinerPoints == null)
  154. {
  155. _steinerPoints = new List<TriangulationPoint>();
  156. }
  157. _steinerPoints.AddRange(points);
  158. }
  159. public void ClearSteinerPoints()
  160. {
  161. if (_steinerPoints != null)
  162. {
  163. _steinerPoints.Clear();
  164. }
  165. }
  166. /// <summary>
  167. /// Add a hole to the polygon.
  168. /// </summary>
  169. /// <param name="poly">A subtraction polygon fully contained inside this polygon.</param>
  170. public void AddHole(Polygon poly)
  171. {
  172. if (_holes == null) _holes = new List<Polygon>();
  173. _holes.Add(poly);
  174. // XXX: tests could be made here to be sure it is fully inside
  175. // addSubtraction( poly.getPoints() );
  176. }
  177. /// <summary>
  178. /// Inserts newPoint after point.
  179. /// </summary>
  180. /// <param name="point">The point to insert after in the polygon</param>
  181. /// <param name="newPoint">The point to insert into the polygon</param>
  182. public void InsertPointAfter(PolygonPoint point, PolygonPoint newPoint)
  183. {
  184. // Validate that
  185. int index = _points.IndexOf(point);
  186. if (index == -1)
  187. throw new ArgumentException(
  188. "Tried to insert a point into a Polygon after a point not belonging to the Polygon", "point");
  189. newPoint.Next = point.Next;
  190. newPoint.Previous = point;
  191. point.Next.Previous = newPoint;
  192. point.Next = newPoint;
  193. _points.Insert(index + 1, newPoint);
  194. }
  195. /// <summary>
  196. /// Inserts list (after last point in polygon?)
  197. /// </summary>
  198. /// <param name="list"></param>
  199. public void AddPoints(IEnumerable<PolygonPoint> list)
  200. {
  201. PolygonPoint first;
  202. foreach (PolygonPoint p in list)
  203. {
  204. p.Previous = _last;
  205. if (_last != null)
  206. {
  207. p.Next = _last.Next;
  208. _last.Next = p;
  209. }
  210. _last = p;
  211. _points.Add(p);
  212. }
  213. first = (PolygonPoint) _points[0];
  214. _last.Next = first;
  215. first.Previous = _last;
  216. }
  217. /// <summary>
  218. /// Adds a point after the last in the polygon.
  219. /// </summary>
  220. /// <param name="p">The point to add</param>
  221. public void AddPoint(PolygonPoint p)
  222. {
  223. p.Previous = _last;
  224. p.Next = _last.Next;
  225. _last.Next = p;
  226. _points.Add(p);
  227. }
  228. /// <summary>
  229. /// Removes a point from the polygon.
  230. /// </summary>
  231. /// <param name="p"></param>
  232. public void RemovePoint(PolygonPoint p)
  233. {
  234. PolygonPoint next, prev;
  235. next = p.Next;
  236. prev = p.Previous;
  237. prev.Next = next;
  238. next.Previous = prev;
  239. _points.Remove(p);
  240. }
  241. }
  242. }