Guest User

Untitled

a guest
Nov 20th, 2024
25
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /// Quadtree
  2.  
  3. function initTree(max_nodes) {
  4.     global.nodes = array_create(max_nodes)
  5.     for (var i = 0; i < max_nodes; i++) {
  6.         global.nodes[i] = {
  7.             x: 0,
  8.             y: 0,
  9.             width: 0,
  10.             height: 0,
  11.             divided: false,
  12.             bodies: [],
  13.             mass: 0,
  14.             center_x: 0,
  15.             center_y: 0,
  16.             northwest_index: -1,
  17.             northeast_index: -1,
  18.             southwest_index: -1,
  19.             southeast_index: -1
  20.         };
  21.     }
  22.     global.node_index = 0
  23. }
  24.  
  25. function createNode(_x, _y, _width, _height) {
  26.     if (global.node_index >= array_length(global.nodes)) {
  27.         show_error("Превышено количество узлов дерева: " + string(global.node_index), true);
  28.     }
  29.     var node = global.nodes[global.node_index];
  30.     global.node_index += 1;
  31.  
  32.     node.x = _x;
  33.     node.y = _y;
  34.     node.width = _width;
  35.     node.height = _height;
  36.     resetNode(node);
  37.  
  38.     return node;
  39. }
  40.  
  41. function insertNode(node, body) {
  42.     if (!containsNode(node, body)) {
  43.         return false;
  44.     }
  45.  
  46.     if (!node.divided && array_length(node.bodies) < 1) {
  47.         array_push(node.bodies, body);
  48.         return true;
  49.     }
  50.  
  51.     if (!node.divided) {
  52.         subdivideNode(node);
  53.     }
  54.  
  55.     if (insertNode(global.nodes[node.northwest_index], body)) return true;
  56.     if (insertNode(global.nodes[node.northeast_index], body)) return true;
  57.     if (insertNode(global.nodes[node.southwest_index], body)) return true;
  58.     if (insertNode(global.nodes[node.southeast_index], body)) return true;
  59.  
  60.     return false;
  61. }
  62.  
  63. function resetTree() {
  64.     for (var i = 0; i < global.node_index; i++) {
  65.         resetNode(global.nodes[i]);
  66.     }
  67.     global.node_index = 1;
  68. }
  69.  
  70. function resetNode(node) {
  71.     node.bodies = [];
  72.     node.mass = 0;
  73.     node.center_x = 0;
  74.     node.center_y = 0;
  75.     node.divided = false;
  76.     node.northwest_index = -1;
  77.     node.northeast_index = -1;
  78.     node.southwest_index = -1;
  79.     node.southeast_index = -1;
  80. }
  81.    
  82. function computeMassDistribution(node) {
  83.     if (!node.divided) {
  84.         if (array_length(node.bodies) == 1) {
  85.             var body = node.bodies[0];
  86.             node.mass = body.mass;
  87.             node.center_x = body.x;
  88.             node.center_y = body.y;
  89.         } else {
  90.             node.mass = 0;
  91.             node.center_x = node.x + node.width / 2;
  92.             node.center_y = node.y + node.height / 2;
  93.         }
  94.     } else {
  95.         computeMassDistribution(global.nodes[node.northwest_index]);
  96.         computeMassDistribution(global.nodes[node.northeast_index]);
  97.         computeMassDistribution(global.nodes[node.southwest_index]);
  98.         computeMassDistribution(global.nodes[node.southeast_index]);
  99.  
  100.         var nw = global.nodes[node.northwest_index];
  101.         var ne = global.nodes[node.northeast_index];
  102.         var sw = global.nodes[node.southwest_index];
  103.         var se = global.nodes[node.southeast_index];
  104.  
  105.         node.mass = nw.mass + ne.mass + sw.mass + se.mass;
  106.         if (node.mass > 0) {
  107.             node.center_x = (nw.center_x * nw.mass +
  108.                                 ne.center_x * ne.mass +
  109.                                 sw.center_x * sw.mass +
  110.                                 se.center_x * se.mass) / node.mass;
  111.             node.center_y = (nw.center_y * nw.mass +
  112.                                 ne.center_y * ne.mass +
  113.                                 sw.center_y * sw.mass +
  114.                                 se.center_y * se.mass) / node.mass;
  115.         }
  116.     }
  117. }
  118.  
  119. function containsNode(node, body) {
  120.     return (body.x >= node.x) && (body.x < node.x + node.width) &&
  121.             (body.y >= node.y) && (body.y < node.y + node.height);
  122. }
  123.  
  124. function subdivideNode(node) {
  125.     static tempBodies = [];
  126.  
  127.     var half_width = node.width / 2;
  128.     var half_height = node.height / 2;
  129.  
  130.     node.northwest_index = global.node_index;
  131.     createNode(node.x, node.y, half_width, half_height);
  132.  
  133.     node.northeast_index = global.node_index;
  134.     createNode(node.x + half_width, node.y, half_width, half_height);
  135.  
  136.     node.southwest_index = global.node_index;
  137.     createNode(node.x, node.y + half_height, half_width, half_height);
  138.  
  139.     node.southeast_index = global.node_index;
  140.     createNode(node.x + half_width, node.y + half_height, half_width, half_height);
  141.  
  142.     node.divided = true;
  143.  
  144.     tempBodies = node.bodies;
  145.     node.bodies = [];
  146.  
  147.     for (var i = 0; i < array_length(tempBodies); i++) {
  148.         var body = tempBodies[i];
  149.         if (insertNode(global.nodes[node.northwest_index], body)) continue;
  150.         if (insertNode(global.nodes[node.northeast_index], body)) continue;
  151.         if (insertNode(global.nodes[node.southwest_index], body)) continue;
  152.         if (insertNode(global.nodes[node.southeast_index], body)) continue;
  153.     }
  154. }
  155.  
  156. // slower?
  157. function calculateForce(node, body, theta) {
  158.     if (!node.divided && array_length(node.bodies) == 1 && node.bodies[0] == body) {
  159.         return;
  160.     }
  161.  
  162.     if (node.mass == 0) {
  163.         return;
  164.     }
  165.  
  166.     var dx = node.center_x - body.x;
  167.     var dy = node.center_y - body.y;
  168.     var distance = sqrt(dx * dx + dy * dy) + 0.0001;
  169.  
  170.     if (distance == 0) {
  171.         return;
  172.     }
  173.  
  174.     var s = node.width;
  175.     var d = distance;
  176.  
  177.     if (!node.divided || (s / d) < theta) {
  178.         var force = (obj_controller.G * node.mass * body.mass) / (distance * distance);
  179.         var fx = force * (dx / distance);
  180.         var fy = force * (dy / distance);
  181.         body.force_x += fx;
  182.         body.force_y += fy;
  183.     } else {
  184.         calculateForce(global.nodes[node.northwest_index], body, theta);
  185.         calculateForce(global.nodes[node.northeast_index], body, theta);
  186.         calculateForce(global.nodes[node.southwest_index], body, theta);
  187.         calculateForce(global.nodes[node.southeast_index], body, theta);
  188.     }
  189.    
  190. }
  191.  
  192. // faster?
  193. function calculateForceIterative(node, body, theta) {
  194.     var stack = [];
  195.     array_push(stack, node);
  196.  
  197.     while (array_length(stack) > 0) {
  198.         var current = array_pop(stack);
  199.  
  200.         if (!current.divided && array_length(current.bodies) == 1 && current.bodies[0] == body) {
  201.             continue;
  202.         }
  203.  
  204.         if (current.mass == 0) {
  205.             continue;
  206.         }
  207.  
  208.         var dx = current.center_x - body.x;
  209.         var dy = current.center_y - body.y;
  210.         var distance = sqrt(dx * dx + dy * dy) + 0.0001;
  211.  
  212.         if (distance == 0) {
  213.             continue;
  214.         }
  215.  
  216.         var s = current.width;
  217.         var d = distance;
  218.  
  219.         if (!current.divided || (s / d) < theta) {
  220.             var force = (obj_controller.G * current.mass * body.mass) / (distance * distance);
  221.             var fx = force * (dx / distance);
  222.             var fy = force * (dy / distance);
  223.             body.force_x += fx;
  224.             body.force_y += fy;
  225.         } else {
  226.             array_push(stack, global.nodes[current.northwest_index]);
  227.             array_push(stack, global.nodes[current.northeast_index]);
  228.             array_push(stack, global.nodes[current.southwest_index]);
  229.             array_push(stack, global.nodes[current.southeast_index]);
  230.         }
  231.     }
  232. }
  233.  
  234. function applyForce(body) {
  235.     body.velocity_x += (body.force_x / body.mass);
  236.     body.velocity_y += (body.force_y / body.mass);
  237.     body.x += body.velocity_x;
  238.     body.y += body.velocity_y;
  239. }
  240.  
  241. function drawTree(node) {
  242.     with (node) {
  243.         draw_set_color(c_green);
  244.         draw_line(x, y, x + width, y)
  245.         draw_line(x + width, y, x + width, y + height)
  246.         draw_line(x + width, y + height, x, y + height)
  247.         draw_line(x, y + height, x, y)
  248.         if (divided) {
  249.             drawTree(global.nodes[node.northwest_index]);
  250.             drawTree(global.nodes[node.northeast_index]);
  251.             drawTree(global.nodes[node.southwest_index]);
  252.             drawTree(global.nodes[node.southeast_index]);
  253.         }
  254.     }
  255.        
  256. }
Advertisement
Add Comment
Please, Sign In to add comment