b2VoronoiDiagram.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Copyright (c) 2013 Google, Inc.
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. * Permission is granted to anyone to use this software for any purpose,
  8. * including commercial applications, and to alter it and redistribute it
  9. * freely, subject to the following restrictions:
  10. * 1. The origin of this software must not be misrepresented; you must not
  11. * claim that you wrote the original software. If you use this software
  12. * in a product, an acknowledgment in the product documentation would be
  13. * appreciated but is not required.
  14. * 2. Altered source versions must be plainly marked as such, and must not be
  15. * misrepresented as being the original software.
  16. * 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include <Box2D/Particle/b2VoronoiDiagram.h>
  19. #include <Box2D/Particle/b2StackQueue.h>
  20. #include <Box2D/Collision/b2Collision.h>
  21. b2VoronoiDiagram::b2VoronoiDiagram(
  22. b2StackAllocator* allocator, int32 generatorCapacity)
  23. {
  24. m_allocator = allocator;
  25. m_generatorBuffer =
  26. (Generator*) allocator->Allocate(
  27. sizeof(Generator) * generatorCapacity);
  28. m_generatorCapacity = generatorCapacity;
  29. m_generatorCount = 0;
  30. m_countX = 0;
  31. m_countY = 0;
  32. m_diagram = NULL;
  33. }
  34. b2VoronoiDiagram::~b2VoronoiDiagram()
  35. {
  36. if (m_diagram)
  37. {
  38. m_allocator->Free(m_diagram);
  39. }
  40. m_allocator->Free(m_generatorBuffer);
  41. }
  42. void b2VoronoiDiagram::AddGenerator(
  43. const b2Vec2& center, int32 tag, bool necessary)
  44. {
  45. b2Assert(m_generatorCount < m_generatorCapacity);
  46. Generator& g = m_generatorBuffer[m_generatorCount++];
  47. g.center = center;
  48. g.tag = tag;
  49. g.necessary = necessary;
  50. }
  51. void b2VoronoiDiagram::Generate(float32 radius, float32 margin)
  52. {
  53. b2Assert(m_diagram == NULL);
  54. float32 inverseRadius = 1 / radius;
  55. b2Vec2 lower(+b2_maxFloat, +b2_maxFloat);
  56. b2Vec2 upper(-b2_maxFloat, -b2_maxFloat);
  57. for (int32 k = 0; k < m_generatorCount; k++)
  58. {
  59. Generator& g = m_generatorBuffer[k];
  60. if (g.necessary)
  61. {
  62. lower = b2Min(lower, g.center);
  63. upper = b2Max(upper, g.center);
  64. }
  65. }
  66. lower.x -= margin;
  67. lower.y -= margin;
  68. upper.x += margin;
  69. upper.y += margin;
  70. m_countX = 1 + (int32) (inverseRadius * (upper.x - lower.x));
  71. m_countY = 1 + (int32) (inverseRadius * (upper.y - lower.y));
  72. m_diagram = (Generator**)
  73. m_allocator->Allocate(sizeof(Generator*) * m_countX * m_countY);
  74. for (int32 i = 0; i < m_countX * m_countY; i++)
  75. {
  76. m_diagram[i] = NULL;
  77. }
  78. // (4 * m_countX * m_countY) is the queue capacity that is experimentally
  79. // known to be necessary and sufficient for general particle distributions.
  80. b2StackQueue<b2VoronoiDiagramTask> queue(
  81. m_allocator, 4 * m_countX * m_countY);
  82. for (int32 k = 0; k < m_generatorCount; k++)
  83. {
  84. Generator& g = m_generatorBuffer[k];
  85. g.center = inverseRadius * (g.center - lower);
  86. int32 x = (int32) g.center.x;
  87. int32 y = (int32) g.center.y;
  88. if (x >=0 && y >= 0 && x < m_countX && y < m_countY)
  89. {
  90. queue.Push(b2VoronoiDiagramTask(x, y, x + y * m_countX, &g));
  91. }
  92. }
  93. while (!queue.Empty())
  94. {
  95. int32 x = queue.Front().m_x;
  96. int32 y = queue.Front().m_y;
  97. int32 i = queue.Front().m_i;
  98. Generator* g = queue.Front().m_generator;
  99. queue.Pop();
  100. if (!m_diagram[i])
  101. {
  102. m_diagram[i] = g;
  103. if (x > 0)
  104. {
  105. queue.Push(b2VoronoiDiagramTask(x - 1, y, i - 1, g));
  106. }
  107. if (y > 0)
  108. {
  109. queue.Push(b2VoronoiDiagramTask(x, y - 1, i - m_countX, g));
  110. }
  111. if (x < m_countX - 1)
  112. {
  113. queue.Push(b2VoronoiDiagramTask(x + 1, y, i + 1, g));
  114. }
  115. if (y < m_countY - 1)
  116. {
  117. queue.Push(b2VoronoiDiagramTask(x, y + 1, i + m_countX, g));
  118. }
  119. }
  120. }
  121. for (int32 y = 0; y < m_countY; y++)
  122. {
  123. for (int32 x = 0; x < m_countX - 1; x++)
  124. {
  125. int32 i = x + y * m_countX;
  126. Generator* a = m_diagram[i];
  127. Generator* b = m_diagram[i + 1];
  128. if (a != b)
  129. {
  130. queue.Push(b2VoronoiDiagramTask(x, y, i, b));
  131. queue.Push(b2VoronoiDiagramTask(x + 1, y, i + 1, a));
  132. }
  133. }
  134. }
  135. for (int32 y = 0; y < m_countY - 1; y++)
  136. {
  137. for (int32 x = 0; x < m_countX; x++)
  138. {
  139. int32 i = x + y * m_countX;
  140. Generator* a = m_diagram[i];
  141. Generator* b = m_diagram[i + m_countX];
  142. if (a != b)
  143. {
  144. queue.Push(b2VoronoiDiagramTask(x, y, i, b));
  145. queue.Push(b2VoronoiDiagramTask(x, y + 1, i + m_countX, a));
  146. }
  147. }
  148. }
  149. while (!queue.Empty())
  150. {
  151. const b2VoronoiDiagramTask& task = queue.Front();
  152. int32 x = task.m_x;
  153. int32 y = task.m_y;
  154. int32 i = task.m_i;
  155. Generator* k = task.m_generator;
  156. queue.Pop();
  157. Generator* a = m_diagram[i];
  158. Generator* b = k;
  159. if (a != b)
  160. {
  161. float32 ax = a->center.x - x;
  162. float32 ay = a->center.y - y;
  163. float32 bx = b->center.x - x;
  164. float32 by = b->center.y - y;
  165. float32 a2 = ax * ax + ay * ay;
  166. float32 b2 = bx * bx + by * by;
  167. if (a2 > b2)
  168. {
  169. m_diagram[i] = b;
  170. if (x > 0)
  171. {
  172. queue.Push(b2VoronoiDiagramTask(x - 1, y, i - 1, b));
  173. }
  174. if (y > 0)
  175. {
  176. queue.Push(b2VoronoiDiagramTask(x, y - 1, i - m_countX, b));
  177. }
  178. if (x < m_countX - 1)
  179. {
  180. queue.Push(b2VoronoiDiagramTask(x + 1, y, i + 1, b));
  181. }
  182. if (y < m_countY - 1)
  183. {
  184. queue.Push(b2VoronoiDiagramTask(x, y + 1, i + m_countX, b));
  185. }
  186. }
  187. }
  188. }
  189. }
  190. void b2VoronoiDiagram::GetNodes(NodeCallback& callback) const
  191. {
  192. for (int32 y = 0; y < m_countY - 1; y++)
  193. {
  194. for (int32 x = 0; x < m_countX - 1; x++)
  195. {
  196. int32 i = x + y * m_countX;
  197. const Generator* a = m_diagram[i];
  198. const Generator* b = m_diagram[i + 1];
  199. const Generator* c = m_diagram[i + m_countX];
  200. const Generator* d = m_diagram[i + 1 + m_countX];
  201. if (b != c)
  202. {
  203. if (a != b && a != c &&
  204. (a->necessary || b->necessary || c->necessary))
  205. {
  206. callback(a->tag, b->tag, c->tag);
  207. }
  208. if (d != b && d != c &&
  209. (b->necessary || d->necessary || c->necessary))
  210. {
  211. callback(b->tag, d->tag, c->tag);
  212. }
  213. }
  214. }
  215. }
  216. }