]> git.itanic.dy.fi Git - sdl-planets/commitdiff
planet.c: Optimize moving of planets within thetree
authorTimo Kokkonen <kaapeli@itanic.dy.fi>
Sun, 11 Apr 2010 09:13:55 +0000 (12:13 +0300)
committerTimo Kokkonen <kaapeli@itanic.dy.fi>
Sun, 11 Apr 2010 09:18:38 +0000 (12:18 +0300)
If there is no changes in the tree topology when a planet is moved,
there is no need to do any tree operations. This will decrease tree
maintenance overhead especially with large trees.

Signed-off-by: Timo Kokkonen <kaapeli@itanic.dy.fi>
planet.c

index da83d3a1d491762fb1ae8cbe0196bbae10fd9e06..de0e49fa2d2bdb3138ed46e9aec54e15fc85232d 100644 (file)
--- a/planet.c
+++ b/planet.c
@@ -207,17 +207,97 @@ struct planet *merge_planets(struct planet *a, struct planet *b)
        return a;
 }
 
        return a;
 }
 
+static int planet_search_when_moving(struct quadtree *node,
+                                    struct quadtree_iterator *itr)
+{
+       struct planet *p = tree_to_planet(node);
+       struct planet_search_iterator *it = qt_itr_to_planet_itr(itr);
+       int direction = 0, i;
+       int up = 0, left = 0, right = 0, down = 0;
+
+       for (i = 0; i < 2; i++) {
+               if (it->limit[i].x < p->pos.x)
+                       left = 1;
+               else
+                       right = 1;
+               if (it->limit[i].y < p->pos.y)
+                       up = 1;
+               else
+                       down = 1;
+       }
+
+       if (left || up)
+               direction |= QUADTREE_UPLEFT;
+       if (right || up)
+               direction |= QUADTREE_UPRIGHT;
+       if (left || down)
+               direction |= QUADTREE_DOWNLEFT;
+       if (right || down)
+               direction |= QUADTREE_DOWNRIGHT;
+       if ((left && right) || (up && down))
+               direction |= QUADTREE_SELF;
+
+       return direction;
+}
+
+void planet_move_iterator(struct quadtree *node, struct quadtree_iterator *it)
+{
+       struct quadtree *parent;
+
+       parent = quadtree_del(node, planet_spatial_compare);
+       quadtree_add(parent, node, planet_spatial_compare);
+}
+
 struct planet *move_planet(struct planet *p, const double time)
 {
 struct planet *move_planet(struct planet *p, const double time)
 {
-       struct vector tmp;
-       struct quadtree *tree_parent;
+       struct vector tmp, new_pos;
+       struct quadtree *parent, *tree_parent;
+       struct planet *pa;
+       struct planet_search_iterator it;
+
+       int modify = 0;
 
        vector_scale(&p->speed, time, &tmp);
 
        vector_scale(&p->speed, time, &tmp);
-       vector_add(&p->pos, &tmp, &p->pos);
+       vector_add(&p->pos, &tmp, &new_pos);
+
+       /* Check if we have crossed any of the parents */
+       parent = p->tree.parent;
+       while (parent) {
+               pa = tree_to_planet(parent);
+               if (p->pos.x < pa->pos.x && new_pos.x > pa->pos.x)
+                       modify = 1;
+               if (p->pos.x > pa->pos.x && new_pos.x < pa->pos.x)
+                       modify = 1;
+               if (p->pos.y < pa->pos.y && new_pos.y > pa->pos.y)
+                       modify = 1;
+               if (p->pos.y > pa->pos.y && new_pos.y < pa->pos.y)
+                       modify = 1;
+
+               if (!modify) {
+                       parent = parent->parent;
+                       continue;
+               }
+
+               tree_parent = quadtree_del(&p->tree, planet_spatial_compare);
+               p->pos = new_pos;
+               quadtree_add(tree_parent, &p->tree, planet_spatial_compare);
+               return tree_to_planet(tree_parent);
+       }
+
+       /*
+        * Now, search the subtree for any crossed children and move
+        * them into correct place within the tree.
+        */
+       it.qt_iterator.head = &p->tree;
+       it.limit[0] = p->pos;
+       it.limit[1] = new_pos;
+       it.qt_iterator.direction = planet_search_when_moving;
+       it.qt_iterator.callback = planet_move_iterator;
+       walk_quadtree(&it.qt_iterator);
+
+       p->pos = new_pos;
 
 
-       tree_parent = quadtree_del(&p->tree, planet_spatial_compare);
-       quadtree_add(tree_parent, &p->tree, planet_spatial_compare);
-       return tree_to_planet(tree_parent);
+       return tree_to_planet(quadtree_find_parent(&p->tree));
 }
 
 void print_planet(const struct planet *p)
 }
 
 void print_planet(const struct planet *p)