I add 2 objects to the QuadTree but when I look through the whole list for the objects I can only find 1 object. Why is this and what can I do to fix it?
from pygame import draw
class QuadTree(object):
def __init__(self, box, current_level, max_level=3):# box (top_left_x, top_left_y, size_x, size_y)
self.location = (box[0], box[1])
self.size = (box[2], box[3])
self.current_level = current_level
self.max_level = max_level
self.objects = []
self.__setupchirldren__()
def __setupchirldren__(self):
self.top_right = None
self.top_left = None
self.bottom_right = None
self.bottom_left = None
def elements(self):
if self.current_level == self.max_level:
for x in self.objects:
print x, x.rect
else:
if self.bottom_left != None:
self.bottom_left.elements()
if self.bottom_right != None:
self.bottom_right.elements()
if self.top_left != None:
self.top_left.elements()
if self.top_right != None:
self.top_right.elements()
def add_object(self, new_object, rect):
if self.current_level == self.max_level:
#print new_object, rect
self.objects.append(new_object)
#print self.objects
else:
half_size = (self.size[0]/2, self.size[1]/2)
if rect.colliderect(self.location, half_size):
self.top_left = QuadTree((self.location[0], self.location[1], half_size[0], half_size[1]), self.current_level+1, self.max_level)
self.top_left.add_object(new_object, rect)
if rect.colliderect((self.location[0]+half_size[0], self.location[1]), half_size):
self.top_right = QuadTree((self.location[0]+half_size[0], self.location[1], half_size[0], half_size[1]), self.current_level+1, self.max_level)
self.top_right.add_object(new_object, rect)
if rect.colliderect((self.location[0], self.location[1]+half_size[1]), half_size):
self.bottom_left = QuadTree((self.location[0], self.location[1]+half_size[1], half_size[0], half_size[1]), self.current_level+1, self.max_level)
self.bottom_left.add_object(new_object, rect)
if rect.colliderect((self.location[0]+half_size[0], self.location[1]+half_size[1]), half_size):
self.bottom_right = QuadTree((self.location[0]+half_size[0], self.location[1]+half_size[1], half_size[0], half_size[1] ), self.current_level+1, self.max_level)
self.bottom_right.add_object(new_object, rect)
def draw(self, screen):
#if self.current_level == self.max_level:
draw.line(screen, (255, 0, 0), self.location, (self.location[0]+self.size[0], self.location[1]))
draw.line(screen, (255, 0, 0), self.location, (self.location[0], self.location[1]+self.size[1]))
draw.line(screen, (255, 0, 0), (self.location[0]+self.size[0], self.location[1]+self.size[1]), (self.location[0]+self.size[0], self.location[1]))
draw.line(screen, (255, 0, 0), (self.location[0]+self.size[0], self.location[1]+self.size[1]), (self.location[0], self.location[1]+self.size[1]))
if self.current_level != self.max_level:
if self.bottom_left != None:
self.bottom_left.draw(screen)
if self.bottom_right != None:
self.bottom_right.draw(screen)
if self.top_left != None:
self.top_left.draw(screen)
if self.top_right != None:
self.top_right.draw(screen)
def get_elements(self, rect):
#ret = self.objects
if self.current_level == self.max_level:
#print self.objects
return self.objects
else:
half_size = (self.size[0]/2, self.size[1]/2)
if self.top_left!= None and rect.colliderect((self.location, half_size)):
return self.top_left.get_elements(rect)
#for x in self.top_left.get_elements(rect):
# ret.append(x)
if self.top_right!= None and rect.colliderect(((self.location[0]+self.size[0]/2, self.location[1]), half_size)):
return self.top_right.get_elements(rect)
#for x in self.top_right.get_elements(rect):
# ret.append(x)
if self.bottom_left!= None and rect.colliderect(((self.location[0], self.location[1]+self.size[1]/2), half_size)):
return self.bottom_left.get_elements(rect)
#for x in self.bottom_left.get_elements(rect):
# ret.append(x)
if self.bottom_right!= None and rect.colliderect(((self.location[0]+self.size[0]/2, self.location[1]+self.size[1]/2), half_size)):
return self.bottom_right.get_elements(rect)
#for x in self.bottom_right.get_elements(rect):
# ret.append(x)
#print ret
return []
When I insert objects it prints out
platform.Platforms object at 0x0236F950 platform.Platforms object at
0x0236F950 platform.Platforms object at 0x0236F950 platform.Platforms
object at 0x0236F950 platform.Platforms object at 0x0236FAB0
platform.Platforms object at 0x0236FAB0 platform.Platforms object at
0x0236FAB0 platform.Platforms object at 0x0236FAB0
which is good I want two distinct objects in mutable trees
but when I call it it only has the second one in the list
so i made a function
def elements(self):
if self.current_level == self.max_level:
for x in self.objects:
print x, x.rect
else:
if self.bottom_left != None:
self.bottom_left.elements()
if self.bottom_right != None:
self.bottom_right.elements()
if self.top_left != None:
self.top_left.elements()
if self.top_right != None:
self.top_right.elements()
which prints out
platform.Platforms object at 0x02320A70 rect(350, 630, 110, 110)
platform.Platforms object at 0x02320A70 rect(350, 630, 110, 110)
platform.Platforms object at 0x02320A70 rect(350, 630, 110, 110)
platform.Platforms object at 0x02320A70 rect(350, 630, 110, 110)
Your
add_objectclass makes a new lower-level quadtree every time, even if there is already one there.I was going to suggest this on your earlier quadtree question (pretty sure that was you) but you removed it before I had a chance: you’ll probably be better off if the QuadTree class has a method that finds-or-creates the appropriate sub-tree given a location (what you call
rectin bothadd_objectsandget_elements). Note that this assumes that each object lives entirely within one sub-tree, which is true for points but not for arbitrary rectangles. (The most obvious case is that a very large rectangle—one that covers the entire field—occupies all four sub-trees of any given level of quadtree.)Assuming that the logic in
get_elementsis basically correct, for instance, you might define something like:This gives you a way to find the containing quadtree (returning None if it does not exist) or, for adding objects, creating it (returning the existing max-level quadtree, or creating a new max-level quadtree in the appropriate quadrant).
The
getattrandsetattroperations let you use thenameyou computed to get and set self.top_left, self.top_right, and so on.Adding an object is then pretty trivial:
There’s a better way to handle the location computation-and-test as well but I leave that as an exercise. (And, of course, if
rects can span multiple sub-trees—if they are not points—you’ll need to compute a list of all the appropriate sub-trees, rather than the single appropriate top-left / top-right / bottom-left / bottom-right sub-tree.)