Advertisement
JontePonte

Untitled

Nov 10th, 2024
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.39 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using Vector2 = UnityEngine.Vector2;
  4. using Particle = Simulation.Particle;
  5. public class QuadTree
  6. {
  7.     // Arbitrary constant to indicate how many elements can be stored in this quad
  8.     const int Capacity = 1;
  9.     const float MinSize = .1f;
  10.    
  11.     Vector2 centerOfMass;
  12.     float mass;
  13.    
  14.     // Axis-aligned bounding box stored as a center with half-dimensions
  15.     // to represent the boundaries of this quad tree
  16.     Rectangle boundary;
  17.    
  18.     //Objects in this quad tree node
  19.     readonly List<Particle> particles;
  20.    
  21.     // Children
  22.     QuadTree northWest;
  23.     QuadTree northEast;
  24.     QuadTree southWest;
  25.     QuadTree southEast;
  26.    
  27.     //True if the quad subdivides
  28.     bool divided;
  29.  
  30.     readonly float particleRadius;
  31.  
  32.     public QuadTree(Rectangle boundary, float particleRadius)
  33.     {
  34.         this.boundary = boundary;
  35.         this.particleRadius = particleRadius;
  36.         particles = new();
  37.         divided = false;
  38.     }
  39.  
  40.     public void DrawTree()
  41.     {
  42.         DrawRectangle(boundary.position, boundary.size);
  43.         Debug.DrawLine(centerOfMass, centerOfMass + new Vector2(0.1f, 0), Color.blue);
  44.        
  45.         if (divided)
  46.         {
  47.             northWest.DrawTree();
  48.             northEast.DrawTree();
  49.             southWest.DrawTree();
  50.             southEast.DrawTree();
  51.         }
  52.     }
  53.     static void DrawRectangle(Vector2 position, Vector2 size)
  54.     {
  55.         Debug.DrawLine(position, new Vector2(position.x, position.y + size.y), Color.red);
  56.         Debug.DrawLine(new Vector2(position.x, position.y + size.y), new Vector2(position.x + size.x, position.y + size.y), Color.red);
  57.         Debug.DrawLine(new Vector2(position.x + size.x, position.y + size.y), new Vector2(position.x + size.x, position.y), Color.red);
  58.         Debug.DrawLine(new Vector2(position.x + size.x, position.y), new Vector2(position.x, position.y), Color.red);
  59.     }
  60.  
  61.     public Particle UpdateVelocity(Particle particle, float timeStep)
  62.     {
  63.         //If the node hasn't been divided, calculate the force exerted by all particles in this node
  64.         if (!divided)
  65.         {
  66.             for (int i = 0; i < particles.Count; i++)
  67.             {
  68.                 if(particles[i].position == particle.position) continue;
  69.                 particle.velocity += CalculateAcceleration(particle, particles[i]) * timeStep;
  70.             }
  71.  
  72.             return particle;
  73.         }
  74.         //Otherwise, calculate the ratio s/d. If node is sufficiently far away, treat it as a single particle
  75.         float sd = boundary.size.x / (particle.position - centerOfMass).magnitude;
  76.         if (sd < 0.5f)
  77.         {
  78.             Particle particle2 = new(){ position = centerOfMass, mass = mass };
  79.             particle.velocity += CalculateAcceleration(particle, particle2) * timeStep;
  80.             return particle;
  81.         }
  82.         //Otherwise, check children if the node has been divided
  83.         particle = northWest.UpdateVelocity(particle, timeStep);
  84.         particle = northEast.UpdateVelocity(particle, timeStep);
  85.         particle = southWest.UpdateVelocity(particle, timeStep);
  86.         particle = southEast.UpdateVelocity(particle, timeStep);
  87.         return particle;
  88.     }
  89.    
  90.     Vector2 CalculateAcceleration(Particle p1, Particle p2)
  91.     {
  92.         Vector2 diff = p2.position - p1.position;
  93.         Vector2 forceDir = diff.normalized;
  94.         float sqrDst = Mathf.Max(diff.sqrMagnitude, 0.05f);
  95.         Vector2 force = forceDir * (p1.mass * p2.mass) / sqrDst;
  96.         Vector2 acceleration = force / p1.mass;
  97.  
  98.         return acceleration;
  99.     }
  100.  
  101.     public void CalculateMassAndCenterOfMass()
  102.     {
  103.         centerOfMass = new Vector2();
  104.        
  105.         for (int i = 0; i < particles.Count; i++)
  106.         {
  107.             mass += particles[i].mass;
  108.         }
  109.  
  110.         float x = 0;
  111.         float y = 0;
  112.        
  113.         for (int i = 0; i < particles.Count; i++)
  114.         {
  115.             x += particles[i].position.x * particles[i].mass;
  116.             y += particles[i].position.y * particles[i].mass;
  117.         }
  118.  
  119.         x /= mass;
  120.         y /= mass;
  121.         centerOfMass = new Vector2(x, y);
  122.  
  123.         if (divided)
  124.         {
  125.             northWest.CalculateMassAndCenterOfMass();
  126.             northEast.CalculateMassAndCenterOfMass();
  127.             southWest.CalculateMassAndCenterOfMass();
  128.             southEast.CalculateMassAndCenterOfMass();
  129.         }
  130.     }
  131.    
  132.     public void Insert(Particle particle)
  133.     {
  134.         //If the quad has already divided, insert it into on of the children
  135.         if (divided)
  136.         {
  137.             InsertIntoChildren(particle);
  138.         }
  139.         else
  140.         {
  141.             // Ignore objects that do not belong in this quad tree
  142.             if (!boundary.Intersects(particle)) return;
  143.            
  144.             // If there is space in this quad tree and if doesn't have subdivisions, add the object here
  145.             if (particles.Count < Capacity)
  146.             {
  147.                 particles.Add(particle);
  148.             }
  149.             // Otherwise, subdivide and then add the point to whichever node will accept it
  150.             else
  151.             {
  152.                 Subdivide(particle);
  153.             }
  154.  
  155.         }
  156.     }
  157.  
  158.     void Subdivide(Simulation.Particle particle)
  159.     {
  160.         float size = Mathf.Min(boundary.size.x, boundary.size.y) / 2;
  161.  
  162.         if (size > MinSize)
  163.         {
  164.             northWest = new(new Rectangle
  165.             {
  166.                 position = new Vector2(boundary.position.x, boundary.position.y + boundary.size.y / 2f),
  167.                 size = boundary.size / 2,
  168.                 pRadius = particleRadius
  169.             }, particleRadius);
  170.             northEast = new(new Rectangle
  171.             {
  172.                 position = new Vector2(boundary.position.x + boundary.size.x / 2, boundary.position.y + boundary.size.y / 2f),
  173.                 size = boundary.size / 2,
  174.                 pRadius = particleRadius
  175.             }, particleRadius);
  176.             southWest = new(new Rectangle
  177.             {
  178.                 position = new Vector2(boundary.position.x, boundary.position.y),
  179.                 size = boundary.size / 2,
  180.                 pRadius = particleRadius
  181.             }, particleRadius);
  182.             southEast = new(new Rectangle
  183.             {  
  184.                 position = new Vector2(boundary.position.x + boundary.size.x / 2, boundary.position.y),
  185.                 size = boundary.size / 2,
  186.                 pRadius = particleRadius
  187.             }, particleRadius);
  188.        
  189.             //Move all objects from this quad into children
  190.             InsertIntoChildren(particle);
  191.             for (int i = 0; i < particles.Count; i++)
  192.             {
  193.                 InsertIntoChildren(particles[i]);
  194.             }
  195.  
  196.             divided = true;
  197.         }
  198.     }
  199.  
  200.     void InsertIntoChildren(Simulation.Particle particle)
  201.     {
  202.         northWest.Insert(particle);
  203.         northEast.Insert(particle);
  204.         southWest.Insert(particle);
  205.         southEast.Insert(particle);
  206.     }
  207. }
  208.  
  209. public struct Rectangle
  210. {
  211.     //Bottom left of rectangle
  212.     public Vector2 position;
  213.     public Vector2 size;
  214.     public float pRadius;
  215.  
  216.     public bool Intersects(Simulation.Particle p)
  217.     {
  218.         return p.position.x > position.x - pRadius && p.position.x < position.x + size.x + pRadius &&
  219.                p.position.y > position.y - pRadius && p.position.y < position.y + size.y + pRadius;
  220.     }
  221. }
  222.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement