def reset(self, event): """Reset to start state.""" self.tree = QuadTree( Region(0, 0, 512 // self.factor, 512 // self.factor)) self.canvas.delete(ALL) self.visit(self.tree.root) self.viz.clear()
def zoom(self, key): """ Zoom in (+) and Zoom out (-) with key events. In rebuilding tree, some points may get lost when zooming in. """ factor = self.factor if key.char == '+': factor = min(factor * 2, 256) elif key.char == '-': factor = max(factor // 2, 1) if factor != self.factor: self.factor = factor self.canvas.delete(ALL) oldTree = self.tree self.tree = QuadTree(Region(0, 0, 512 // factor, 512 // factor)) self.master.title("Click to add/remove points: [0,0] - (" + str(512 // factor) + "," + str(512 // self.factor) + ")") for pt in oldTree: self.tree.add(pt) self.visit(self.tree.root) self.viz.plot(self.tree.root)
def setUp(self): self.qt = QuadTree(Region(0, 0, 1024, 1024)) self.qt.add((22, 40)) self.qt.add((13, 59)) self.qt.add((57, 37)) self.qt.add((43, 21)) self.qt.add((33, 11))
def test_iteration(self): self.qt = QuadTree(Region(0, 0, 1024, 1024)) points = [] for _ in range(100): x = random.randint(0, 1021) y = random.randint(0, 1021) points.append((x, y)) self.qt.add((x, y)) for pt in self.qt: self.assertTrue(pt in points)
def __init__(self, master): """App for creating Quad tree dynamically with fixed circles that ALMOST ALWAYS detect collisions.""" master.title("Click to add fixed circles for ALMOST detecting collisions.") self.master = master # QuadTree holds the events self.tree = QuadTree(Region(0,0,512,512)) self.canvas = Canvas(master, width=512, height=512) self.canvas.bind("<Button-1>", self.click) self.canvas.bind("<Button-2>", self.reset) # needed for Mac self.canvas.bind("<Button-3>", self.reset) # this is PC self.canvas.pack()
class TestQuadPointMethods(unittest.TestCase): def setUp(self): self.qt = QuadTree(Region(0, 0, 1024, 1024)) self.qt.add((22, 40)) self.qt.add((13, 59)) self.qt.add((57, 37)) self.qt.add((43, 21)) self.qt.add((33, 11)) def tearDown(self): self.qt = None def test_basic(self): self.assertTrue((43, 21) in self.qt) self.assertFalse((21, 43) in self.qt) def test_adding(self): for _ in range(1000): # make sure these are even (within 0..1023, even incremented ones) x = random.randint(0, 1021) if x % 2 == 1: x += 1 y = random.randint(0, 1021) if y % 2 == 1: y += 1 pt = (x, y) badpt = (x + 1, y + 1) self.qt.add(pt) self.assertTrue(pt in self.qt) # (x,y) is there self.assertFalse(badpt in self.qt) # different indices not present def test_iteration(self): self.qt = QuadTree(Region(0, 0, 1024, 1024)) points = [] for _ in range(100): x = random.randint(0, 1021) y = random.randint(0, 1021) points.append((x, y)) self.qt.add((x, y)) for pt in self.qt: self.assertTrue(pt in points)
def __init__(self, master, factor): """App for creating point-based quadtree dynamically.""" master.title("Click to add/remove points: [0,0] - (" + str(512 // factor) + "," + str(512 // factor) + ")") self.master = master self.factor = factor # QuadTree holds the events self.tree = QuadTree(Region(0, 0, 512 // factor, 512 // factor)) self.canvas = Canvas(master, width=512, height=512) self.canvas.bind("<Button-1>", self.click) self.canvas.bind("<Button-2>", self.reset) # Needed for Mac self.canvas.bind("<Button-3>", self.reset) # This is PC master.bind("<Key>", self.zoom) self.canvas.pack() # no visualization just yet self.viz = None
class QuadTreePointApp: def __init__(self, master, factor): """App for creating point-based quadtree dynamically.""" master.title("Click to add/remove points: [0,0] - (" + str(512 // factor) + "," + str(512 // factor) + ")") self.master = master self.factor = factor # QuadTree holds the events self.tree = QuadTree(Region(0, 0, 512 // factor, 512 // factor)) self.canvas = Canvas(master, width=512, height=512) self.canvas.bind("<Button-1>", self.click) self.canvas.bind("<Button-2>", self.reset) # Needed for Mac self.canvas.bind("<Button-3>", self.reset) # This is PC master.bind("<Key>", self.zoom) self.canvas.pack() # no visualization just yet self.viz = None def zoom(self, key): """ Zoom in (+) and Zoom out (-) with key events. In rebuilding tree, some points may get lost when zooming in. """ factor = self.factor if key.char == '+': factor = min(factor * 2, 256) elif key.char == '-': factor = max(factor // 2, 1) if factor != self.factor: self.factor = factor self.canvas.delete(ALL) oldTree = self.tree self.tree = QuadTree(Region(0, 0, 512 // factor, 512 // factor)) self.master.title("Click to add/remove points: [0,0] - (" + str(512 // factor) + "," + str(512 // self.factor) + ")") for pt in oldTree: self.tree.add(pt) self.visit(self.tree.root) self.viz.plot(self.tree.root) def toCartesian(self, y): """Convert tkinter point into Cartesian.""" return self.canvas.winfo_height() - y def toTk(self, y): """Convert Cartesian into tkinter point.""" if y == maxValue: return 0 tk_y = self.canvas.winfo_height() if y != minValue: tk_y -= y return tk_y def click(self, event): """Add point to quadtree, based on factor.""" pt = [event.x // self.factor, self.toCartesian(event.y) // self.factor] if pt in self.tree: self.tree.remove(pt) else: self.tree.add(pt) self.canvas.delete(ALL) self.visit(self.tree.root) self.viz.plot(self.tree.root) def reset(self, event): """Reset to start state.""" self.tree = QuadTree( Region(0, 0, 512 // self.factor, 512 // self.factor)) self.canvas.delete(ALL) self.visit(self.tree.root) self.viz.clear() def visit(self, node): """Visit nodes recursively.""" if node == None: return # draw rectangular region with criss-crossed hashed lines r = node.region self.canvas.create_rectangle(self.factor * r.x_min, self.factor * self.toTk(r.y_min), self.factor * r.x_max, self.factor * self.toTk(r.y_max)) self.canvas.create_line(self.factor * r.x_min, self.toTk(self.factor * node.origin[Y]), self.factor * r.x_max, self.toTk(self.factor * node.origin[Y]), dash=(2, 4)) self.canvas.create_line(self.factor * node.origin[X], self.toTk(self.factor * r.y_min), self.factor * node.origin[X], self.toTk(self.factor * r.y_max), dash=(2, 4)) if node.points: for pt in node.points: self.canvas.create_rectangle(self.factor * pt[X], self.toTk(self.factor * pt[Y]), self.factor * (pt[X] + 1), self.toTk(self.factor * (pt[Y] + 1)), fill='black') for n in node.children: self.visit(n)
def reset(self, event): """Reset to start state.""" self.tree = QuadTree(Region(0,0,512,512)) self.canvas.delete(ALL) self.visit(self.tree.root)
class QuadTreeInvalidApp: def __init__(self, master): """App for creating Quad tree dynamically with fixed circles that ALMOST ALWAYS detect collisions.""" master.title("Click to add fixed circles for ALMOST detecting collisions.") self.master = master # QuadTree holds the events self.tree = QuadTree(Region(0,0,512,512)) self.canvas = Canvas(master, width=512, height=512) self.canvas.bind("<Button-1>", self.click) self.canvas.bind("<Button-2>", self.reset) # needed for Mac self.canvas.bind("<Button-3>", self.reset) # this is PC self.canvas.pack() def toCartesian(self, y): """Convert tkinter point into Cartesian.""" return self.canvas.winfo_height() - y def toTk(self,y): """Convert Cartesian into tkinter point.""" if y == maxValue: return 0 tk_y = self.canvas.winfo_height() if y != minValue: tk_y -= y return tk_y def click(self, event): """Add circle to QuadTree with random radius.""" circle = [event.x, self.toCartesian(event.y), Radius, False, False] # To find all collisions, take advantage of the fact that circles # can neither be modified nor deleted, so any new collisions are # solely between the new circle and existing circles in the QuadTree. for circ in collide(self.tree.root, circle): circ[HIT] = 1 circle[HIT] = 1 self.tree.add(circle) self.canvas.delete(ALL) self.visit(self.tree.root) def reset(self, event): """Reset to start state.""" self.tree = QuadTree(Region(0,0,512,512)) self.canvas.delete(ALL) self.visit(self.tree.root) def visit (self, node): """Visit nodes recursively.""" if node == None: return # draw rectangular region with criss-crossed hashed lines r = node.region self.canvas.create_rectangle(r.x_min, self.toTk(r.y_min), r.x_max, self.toTk(r.y_max)) self.canvas.create_line(r.x_min, self.toTk(node.origin[Y]), r.x_max, self.toTk(node.origin[Y]), dash=(2, 4)) self.canvas.create_line(node.origin[X], self.toTk(r.y_min), node.origin[X], self.toTk(r.y_max), dash=(2, 4)) if node.points: for circle in node.points: markColor = 'black' if circle[HIT]: markColor = 'red' self.canvas.create_oval(circle[X] - circle[RADIUS], self.toTk(circle[Y]) - circle[RADIUS], circle[X] + circle[RADIUS], self.toTk(circle[Y]) + circle[RADIUS], fill=markColor) for n in node.children: self.visit(n)