TrianglePool.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // -----------------------------------------------------------------------
  2. // <copyright file="TrianglePool.cs" company="">
  3. // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
  4. // </copyright>
  5. // -----------------------------------------------------------------------
  6. namespace UnityEngine.U2D.Animation.TriangleNet
  7. {
  8. using System;
  9. using System.Collections.Generic;
  10. using Animation.TriangleNet.Geometry;
  11. using Animation.TriangleNet.Topology;
  12. internal class TrianglePool : ICollection<Triangle>
  13. {
  14. // Determines the size of each block in the pool.
  15. private const int BLOCKSIZE = 1024;
  16. // The total number of currently allocated triangles.
  17. int size;
  18. // The number of triangles currently used.
  19. int count;
  20. // The pool.
  21. Triangle[][] pool;
  22. // A stack of free triangles.
  23. Stack<Triangle> stack;
  24. public TrianglePool()
  25. {
  26. size = 0;
  27. // On startup, the pool should be able to hold 2^16 triangles.
  28. int n = Math.Max(1, 65536 / BLOCKSIZE);
  29. pool = new Triangle[n][];
  30. pool[0] = new Triangle[BLOCKSIZE];
  31. stack = new Stack<Triangle>(BLOCKSIZE);
  32. }
  33. /// <summary>
  34. /// Gets a triangle from the pool.
  35. /// </summary>
  36. /// <returns></returns>
  37. public Triangle Get()
  38. {
  39. Triangle triangle;
  40. if (stack.Count > 0)
  41. {
  42. triangle = stack.Pop();
  43. triangle.hash = -triangle.hash - 1;
  44. Cleanup(triangle);
  45. }
  46. else if (count < size)
  47. {
  48. triangle = pool[count / BLOCKSIZE][count % BLOCKSIZE];
  49. triangle.id = triangle.hash;
  50. Cleanup(triangle);
  51. count++;
  52. }
  53. else
  54. {
  55. triangle = new Triangle();
  56. triangle.hash = size;
  57. triangle.id = triangle.hash;
  58. int block = size / BLOCKSIZE;
  59. if (pool[block] == null)
  60. {
  61. pool[block] = new Triangle[BLOCKSIZE];
  62. // Check if the pool has to be resized.
  63. if (block + 1 == pool.Length)
  64. {
  65. Array.Resize(ref pool, 2 * pool.Length);
  66. }
  67. }
  68. // Add triangle to pool.
  69. pool[block][size % BLOCKSIZE] = triangle;
  70. count = ++size;
  71. }
  72. return triangle;
  73. }
  74. public void Release(Triangle triangle)
  75. {
  76. stack.Push(triangle);
  77. // Mark the triangle as free (used by enumerator).
  78. triangle.hash = -triangle.hash - 1;
  79. }
  80. /// <summary>
  81. /// Restart the triangle pool.
  82. /// </summary>
  83. public TrianglePool Restart()
  84. {
  85. foreach (var triangle in stack)
  86. {
  87. // Reset hash to original value.
  88. triangle.hash = -triangle.hash - 1;
  89. }
  90. stack.Clear();
  91. count = 0;
  92. return this;
  93. }
  94. /// <summary>
  95. /// Samples a number of triangles from the pool.
  96. /// </summary>
  97. /// <param name="k">The number of triangles to sample.</param>
  98. /// <param name="random"></param>
  99. /// <returns></returns>
  100. internal IEnumerable<Triangle> Sample(int k, Random random)
  101. {
  102. int i, count = this.Count;
  103. if (k > count)
  104. {
  105. // TODO: handle Sample special case.
  106. k = count;
  107. }
  108. Triangle t;
  109. // TODO: improve sampling code (to ensure no duplicates).
  110. while (k > 0)
  111. {
  112. i = random.Next(0, count);
  113. t = pool[i / BLOCKSIZE][i % BLOCKSIZE];
  114. if (t.hash >= 0)
  115. {
  116. k--;
  117. yield return t;
  118. }
  119. }
  120. }
  121. private void Cleanup(Triangle triangle)
  122. {
  123. triangle.label = 0;
  124. triangle.area = 0.0;
  125. triangle.infected = false;
  126. for (int i = 0; i < 3; i++)
  127. {
  128. triangle.vertices[i] = null;
  129. triangle.subsegs[i] = default(Osub);
  130. triangle.neighbors[i] = default(Otri);
  131. }
  132. }
  133. public void Add(Triangle item)
  134. {
  135. throw new NotImplementedException();
  136. }
  137. public void Clear()
  138. {
  139. stack.Clear();
  140. int blocks = (size / BLOCKSIZE) + 1;
  141. for (int i = 0; i < blocks; i++)
  142. {
  143. var block = pool[i];
  144. // Number of triangles in current block:
  145. int length = (size - i * BLOCKSIZE) % BLOCKSIZE;
  146. for (int j = 0; j < length; j++)
  147. {
  148. block[j] = null;
  149. }
  150. }
  151. size = count = 0;
  152. }
  153. public bool Contains(Triangle item)
  154. {
  155. int i = item.hash;
  156. if (i < 0 || i > size)
  157. {
  158. return false;
  159. }
  160. return pool[i / BLOCKSIZE][i % BLOCKSIZE].hash >= 0;
  161. }
  162. public void CopyTo(Triangle[] array, int index)
  163. {
  164. var enumerator = GetEnumerator();
  165. while (enumerator.MoveNext())
  166. {
  167. array[index] = enumerator.Current;
  168. index++;
  169. }
  170. }
  171. public int Count
  172. {
  173. get { return count - stack.Count; }
  174. }
  175. public bool IsReadOnly
  176. {
  177. get { return true; }
  178. }
  179. public bool Remove(Triangle item)
  180. {
  181. throw new NotImplementedException();
  182. }
  183. public IEnumerator<Triangle> GetEnumerator()
  184. {
  185. return new Enumerator(this);
  186. }
  187. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  188. {
  189. return GetEnumerator();
  190. }
  191. class Enumerator : IEnumerator<Triangle>
  192. {
  193. // TODO: enumerator should be able to tell if collection changed.
  194. int count;
  195. Triangle[][] pool;
  196. Triangle current;
  197. int index, offset;
  198. internal Enumerator(TrianglePool pool)
  199. {
  200. this.count = pool.Count;
  201. this.pool = pool.pool;
  202. index = 0;
  203. offset = 0;
  204. }
  205. public Triangle Current
  206. {
  207. get { return current; }
  208. }
  209. public void Dispose()
  210. {
  211. }
  212. object System.Collections.IEnumerator.Current
  213. {
  214. get { return current; }
  215. }
  216. public bool MoveNext()
  217. {
  218. while (index < count)
  219. {
  220. current = pool[offset / BLOCKSIZE][offset % BLOCKSIZE];
  221. offset++;
  222. if (current.hash >= 0)
  223. {
  224. index++;
  225. return true;
  226. }
  227. }
  228. return false;
  229. }
  230. public void Reset()
  231. {
  232. index = offset = 0;
  233. }
  234. }
  235. }
  236. }