Advertisement
JontePonte

Single threaded quadtree

Nov 17th, 2024
11
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.94 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using Unity.VisualScripting;
  3. using UnityEngine;
  4. using Unity.Mathematics;
  5. using Particle = Simulation.Particle;
  6.  
  7. struct Node
  8. {
  9. public Quad boundary;
  10. public float mass;
  11. public float2 centerOfMass;
  12. public int childIndex;
  13. public int next;
  14. }
  15. public struct Quad
  16. {
  17. //Bottom left of rectangle
  18. public Vector2 position;
  19. public float size;
  20.  
  21. public int FindNode(Vector2 pos)
  22. {
  23. bool wX = pos.x - position.x < size / 2;
  24. bool sY = pos.y - position.y < size / 2;
  25.  
  26. if (wX && !sY) return 0;
  27. if (!wX && !sY) return 1;
  28. if (wX && sY) return 2;
  29. if(!wX && sY) return 3;
  30.  
  31. return 0;
  32. }
  33. }
  34.  
  35. public class QuadTree
  36. {
  37. List<Node> quadTree;
  38.  
  39. public QuadTree()
  40. {
  41. quadTree = new();
  42. Quad boundary = new() { position = new Vector2(-5, -5), size = 10 };
  43. quadTree.Add(new Node
  44. {
  45. boundary = boundary,
  46. next = 0
  47. });
  48. }
  49.  
  50. public void DrawTree()
  51. {
  52. foreach (var node in quadTree)
  53. {
  54. DrawSquare(node.boundary.position, node.boundary.size);
  55. }
  56. }
  57. static void DrawSquare(Vector2 position, float size)
  58. {
  59. Debug.DrawLine(position, new Vector2(position.x, position.y + size), Color.red);
  60. Debug.DrawLine(new Vector2(position.x, position.y + size), new Vector2(position.x + size, position.y + size), Color.red);
  61. Debug.DrawLine(new Vector2(position.x + size, position.y + size), new Vector2(position.x + size, position.y), Color.red);
  62. Debug.DrawLine(new Vector2(position.x + size, position.y), new Vector2(position.x, position.y), Color.red);
  63. }
  64.  
  65. public Vector2 CalculateAcceleration(Particle particle, float theta, float epsilon, float deltaTime)
  66. {
  67. Vector2 acceleration = new();
  68. float thetaSqr = theta * theta;
  69. float epsilonSqr = epsilon * epsilon;
  70.  
  71. int nodeIndex = 0;
  72. while (true)
  73. {
  74. Node node = quadTree[nodeIndex];
  75. Vector2 diff = node.centerOfMass - particle.position;
  76. float sqrDst = Mathf.Max(diff.sqrMagnitude, 0.05f);
  77.  
  78. if (node.childIndex == 0 || node.boundary.size * node.boundary.size < sqrDst * thetaSqr)
  79. {
  80. float denom = (sqrDst + epsilonSqr) * Mathf.Sqrt(sqrDst);
  81. acceleration += diff * node.mass / denom * deltaTime;
  82.  
  83. if (node.next == 0) return acceleration;
  84. nodeIndex = node.next;
  85. }
  86. else nodeIndex = node.childIndex;
  87. }
  88. }
  89.  
  90. public void Propagate()
  91. {
  92. for (int i = quadTree.Count - 1; i > 0; i--)
  93. {
  94. if(quadTree[i].childIndex == 0) continue;
  95.  
  96. int child = quadTree[i].childIndex;
  97. Node node = quadTree[i];
  98.  
  99. node.centerOfMass = quadTree[child].centerOfMass * quadTree[child].mass
  100. + quadTree[child + 1].centerOfMass * quadTree[child + 1].mass
  101. + quadTree[child + 2].centerOfMass * quadTree[child + 2].mass
  102. + quadTree[child + 3].centerOfMass * quadTree[child + 3].mass;
  103. node.mass = quadTree[child].mass
  104. + quadTree[child + 1].mass
  105. + quadTree[child + 2].mass
  106. + quadTree[child + 3].mass;
  107. node.centerOfMass /= node.mass;
  108. quadTree[i] = node;
  109.  
  110. }
  111. }
  112.  
  113. public void Insert(Particle particle)
  114. {
  115. int nodeIndex = 0;
  116. while (quadTree[nodeIndex].childIndex != 0)
  117. {
  118. int quad = quadTree[nodeIndex].boundary.FindNode(particle.position);
  119. nodeIndex = quad + quadTree[nodeIndex].childIndex;
  120. }
  121.  
  122. if (quadTree[nodeIndex].mass == 0)
  123. {
  124. Node n = quadTree[nodeIndex];
  125. n.centerOfMass = particle.position;
  126. n.mass = particle.mass;
  127. quadTree[nodeIndex] = n;
  128. return;
  129. }
  130.  
  131. if (quadTree[nodeIndex].centerOfMass == particle.position)
  132. {
  133. Node n = quadTree[nodeIndex];
  134. n.mass += particle.mass;
  135. quadTree[nodeIndex] = n;
  136. return;
  137. }
  138.  
  139. Vector2 nodePos = quadTree[nodeIndex].centerOfMass;
  140. float nodeMass = quadTree[nodeIndex].mass;
  141. while (true)
  142. {
  143. Subdivide(nodeIndex);
  144. int childIndex = quadTree[nodeIndex].childIndex;
  145. int q1 = quadTree[nodeIndex].boundary.FindNode(nodePos);
  146. int q2 = quadTree[nodeIndex].boundary.FindNode(particle.position);
  147.  
  148. if (q1 == q2)
  149. {
  150. nodeIndex = q1 + childIndex;
  151. }
  152. else
  153. {
  154. int n1 = q1 + childIndex;
  155. int n2 = q2 + childIndex;
  156.  
  157. quadTree[n1] = new Node
  158. {
  159. centerOfMass = nodePos,
  160. mass = nodeMass,
  161. boundary = quadTree[n1].boundary,
  162. next = quadTree[n1].next
  163. };
  164. quadTree[n2] = new Node
  165. {
  166. centerOfMass = particle.position,
  167. mass = particle.mass,
  168. boundary = quadTree[n2].boundary,
  169. next = quadTree[n2].next
  170. };
  171. return;
  172. }
  173. }
  174. }
  175.  
  176. void Subdivide(int parentIndex)
  177. {
  178. Node parent = quadTree[parentIndex];
  179. parent.childIndex = quadTree.Count;
  180. quadTree[parentIndex] = parent;
  181. Vector2 parentPos = parent.boundary.position;
  182. Vector2 nwPosition = new(parentPos.x, parentPos.y + parent.boundary.size / 2);
  183. Vector2 nePosition = new(parentPos.x + parent.boundary.size / 2, parentPos.y + parent.boundary.size / 2);
  184. Vector2 swPosition = new(parentPos.x, parentPos.y);
  185. Vector2 sePosition = new(parentPos.x + parent.boundary.size / 2, parentPos.y);
  186.  
  187. Node nw = new()
  188. {
  189. boundary = new Quad { position = nwPosition, size = parent.boundary.size / 2 },
  190. next = parent.childIndex + 1
  191. };
  192. Node ne = new()
  193. {
  194. boundary = new Quad { position = nePosition, size = parent.boundary.size / 2 },
  195. next = parent.childIndex + 2
  196. };
  197. Node sw = new()
  198. {
  199. boundary = new Quad { position = swPosition, size = parent.boundary.size / 2 },
  200. next = parent.childIndex + 3
  201. };
  202. Node se = new()
  203. {
  204. boundary = new Quad { position = sePosition, size = parent.boundary.size / 2 },
  205. next = parent.next
  206. };
  207.  
  208. quadTree.Add(nw);
  209. quadTree.Add(ne);
  210. quadTree.Add(sw);
  211. quadTree.Add(se);
  212. }
  213. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement