BadTriQueue.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // -----------------------------------------------------------------------
  2. // <copyright file="BadTriQueue.cs">
  3. // Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
  4. // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
  5. // </copyright>
  6. // -----------------------------------------------------------------------
  7. namespace UnityEngine.U2D.Animation.TriangleNet
  8. .Meshing.Data
  9. {
  10. using Animation.TriangleNet.Geometry;
  11. using Animation.TriangleNet.Topology;
  12. /// <summary>
  13. /// A (priority) queue for bad triangles.
  14. /// </summary>
  15. /// <remarks>
  16. // The queue is actually a set of 4096 queues. I use multiple queues to
  17. // give priority to smaller angles. I originally implemented a heap, but
  18. // the queues are faster by a larger margin than I'd suspected.
  19. /// </remarks>
  20. class BadTriQueue
  21. {
  22. const double SQRT2 = 1.4142135623730950488016887242096980785696718753769480732;
  23. public int Count { get { return this.count; } }
  24. // Variables that maintain the bad triangle queues. The queues are
  25. // ordered from 4095 (highest priority) to 0 (lowest priority).
  26. BadTriangle[] queuefront;
  27. BadTriangle[] queuetail;
  28. int[] nextnonemptyq;
  29. int firstnonemptyq;
  30. int count;
  31. public BadTriQueue()
  32. {
  33. queuefront = new BadTriangle[4096];
  34. queuetail = new BadTriangle[4096];
  35. nextnonemptyq = new int[4096];
  36. firstnonemptyq = -1;
  37. count = 0;
  38. }
  39. /// <summary>
  40. /// Add a bad triangle data structure to the end of a queue.
  41. /// </summary>
  42. /// <param name="badtri">The bad triangle to enqueue.</param>
  43. public void Enqueue(BadTriangle badtri)
  44. {
  45. double length, multiplier;
  46. int exponent, expincrement;
  47. int queuenumber;
  48. int posexponent;
  49. int i;
  50. this.count++;
  51. // Determine the appropriate queue to put the bad triangle into.
  52. // Recall that the key is the square of its shortest edge length.
  53. if (badtri.key >= 1.0)
  54. {
  55. length = badtri.key;
  56. posexponent = 1;
  57. }
  58. else
  59. {
  60. // 'badtri.key' is 2.0 to a negative exponent, so we'll record that
  61. // fact and use the reciprocal of 'badtri.key', which is > 1.0.
  62. length = 1.0 / badtri.key;
  63. posexponent = 0;
  64. }
  65. // 'length' is approximately 2.0 to what exponent? The following code
  66. // determines the answer in time logarithmic in the exponent.
  67. exponent = 0;
  68. while (length > 2.0)
  69. {
  70. // Find an approximation by repeated squaring of two.
  71. expincrement = 1;
  72. multiplier = 0.5;
  73. while (length * multiplier * multiplier > 1.0)
  74. {
  75. expincrement *= 2;
  76. multiplier *= multiplier;
  77. }
  78. // Reduce the value of 'length', then iterate if necessary.
  79. exponent += expincrement;
  80. length *= multiplier;
  81. }
  82. // 'length' is approximately squareroot(2.0) to what exponent?
  83. exponent = 2 * exponent + (length > SQRT2 ? 1 : 0);
  84. // 'exponent' is now in the range 0...2047 for IEEE double precision.
  85. // Choose a queue in the range 0...4095. The shortest edges have the
  86. // highest priority (queue 4095).
  87. if (posexponent > 0)
  88. {
  89. queuenumber = 2047 - exponent;
  90. }
  91. else
  92. {
  93. queuenumber = 2048 + exponent;
  94. }
  95. // Are we inserting into an empty queue?
  96. if (queuefront[queuenumber] == null)
  97. {
  98. // Yes, we are inserting into an empty queue.
  99. // Will this become the highest-priority queue?
  100. if (queuenumber > firstnonemptyq)
  101. {
  102. // Yes, this is the highest-priority queue.
  103. nextnonemptyq[queuenumber] = firstnonemptyq;
  104. firstnonemptyq = queuenumber;
  105. }
  106. else
  107. {
  108. // No, this is not the highest-priority queue.
  109. // Find the queue with next higher priority.
  110. i = queuenumber + 1;
  111. while (queuefront[i] == null)
  112. {
  113. i++;
  114. }
  115. // Mark the newly nonempty queue as following a higher-priority queue.
  116. nextnonemptyq[queuenumber] = nextnonemptyq[i];
  117. nextnonemptyq[i] = queuenumber;
  118. }
  119. // Put the bad triangle at the beginning of the (empty) queue.
  120. queuefront[queuenumber] = badtri;
  121. }
  122. else
  123. {
  124. // Add the bad triangle to the end of an already nonempty queue.
  125. queuetail[queuenumber].next = badtri;
  126. }
  127. // Maintain a pointer to the last triangle of the queue.
  128. queuetail[queuenumber] = badtri;
  129. // Newly enqueued bad triangle has no successor in the queue.
  130. badtri.next = null;
  131. }
  132. /// <summary>
  133. /// Add a bad triangle to the end of a queue.
  134. /// </summary>
  135. /// <param name="enqtri"></param>
  136. /// <param name="minedge"></param>
  137. /// <param name="apex"></param>
  138. /// <param name="org"></param>
  139. /// <param name="dest"></param>
  140. public void Enqueue(ref Otri enqtri, double minedge, Vertex apex, Vertex org, Vertex dest)
  141. {
  142. // Allocate space for the bad triangle.
  143. BadTriangle newbad = new BadTriangle();
  144. newbad.poortri = enqtri;
  145. newbad.key = minedge;
  146. newbad.apex = apex;
  147. newbad.org = org;
  148. newbad.dest = dest;
  149. Enqueue(newbad);
  150. }
  151. /// <summary>
  152. /// Remove a triangle from the front of the queue.
  153. /// </summary>
  154. /// <returns></returns>
  155. public BadTriangle Dequeue()
  156. {
  157. // If no queues are nonempty, return NULL.
  158. if (firstnonemptyq < 0)
  159. {
  160. return null;
  161. }
  162. this.count--;
  163. // Find the first triangle of the highest-priority queue.
  164. BadTriangle result = queuefront[firstnonemptyq];
  165. // Remove the triangle from the queue.
  166. queuefront[firstnonemptyq] = result.next;
  167. // If this queue is now empty, note the new highest-priority
  168. // nonempty queue.
  169. if (result == queuetail[firstnonemptyq])
  170. {
  171. firstnonemptyq = nextnonemptyq[firstnonemptyq];
  172. }
  173. return result;
  174. }
  175. }
  176. }