Beispiel #1
0
    def range(self, event):
        """Initiate a range search using a selected rectangular region."""

        p = (event.x, self.toCartesian(event.y))

        if self.selectedRegion is None:
            self.selectedStart = Region(p[X], p[Y], p[X], p[Y])
        self.selectedRegion = self.selectedStart.unionPoint(p)

        self.paint()

        # return (node,0,True) where status is True if draining entire tree rooted at node. If False,
        # then (rect,id,False). Draw these
        # as shaded red rectangle to identify whole sub-tree is selected.
        for triple in self.tree.range(self.selectedRegion):
            if triple[2]:
                r = triple[0].region
                self.canvas.create_rectangle(r.x_min,
                                             self.toTk(r.y_min),
                                             r.x_max,
                                             self.toTk(r.y_max),
                                             fill='Red',
                                             stipple='gray12')
            else:
                r = triple[0]
                self.canvas.create_rectangle(r.x_min,
                                             self.toTk(r.y_min),
                                             r.x_max,
                                             self.toTk(r.y_max),
                                             fill='Red')
Beispiel #2
0
 def test_adding(self):
     print ("Starting generation.");
     for _ in range(25):
         print ("Added " + str(_))
         self.quad.add((random.randint(25,225), random.randint(25,225)))
         
         
     print ("Done with generation.");
     
     # make sure not to overlap!
     q_ne = self.expand(Region(128, 128, 256, 256))
     q_nw = self.expand(Region(0, 128, 128, 256))
     q_sw = self.expand(Region(0, 0, 128, 128))
     q_se = self.expand(Region(128, 0, 256, 128))
     
     q_all = self.expand(Region(0,0, 256, 256))
     
     # quick check to see if any were missing
     combined = q_ne + q_nw + q_sw + q_se
     for q in q_all:
         if q not in combined:
             print (q, " missing ")
             
     # check duplicates
     for i in range(len(combined)):
         for j in range(len(combined)):
             if j <= i:
                 pass
             else:
                 if combined[i] == combined[j]:
                     print ("Duplicate:", combined[i])
     
     self.assertEquals(len(q_all), len(combined))
Beispiel #3
0
 def test_adding(self):
     for _ in range(5000):
         self.kd.add((random.randint(250,750), random.randint(250,750)))
     
     # make sure not to overlap!
     q_ne = self.expand(Region(500, 500, 1000, 1000))
     q_nw = self.expand(Region(0, 500, 499, 1000))
     q_sw = self.expand(Region(0, 0, 499, 499))
     q_se = self.expand(Region(500, 0, 1000, 499))
     
     q_all = self.expand(Region(0,0, 1000, 1000))
     
     # quick check to see if any were missing
     combined = q_ne + q_nw + q_sw + q_se
     for q in q_all:
         if q not in combined:
             print (q, " missing ")
     
     self.assertEquals(len(q_all), len(combined))
     
     # validate searches are true
     for p in combined:
         self.assertTrue(self.kd.find(p))
         
     # validate can't add these points anymore
     for p in combined:
         self.assertFalse(self.kd.add(p))
Beispiel #4
0
    def subdivide(self):
        """Add four children nodes to node and reassign existing circles."""
        r = self.region
        self.children[NE] = QuadNode(
            Region(self.origin[X], self.origin[Y], r.x_max, r.y_max))
        self.children[NW] = QuadNode(
            Region(r.x_min, self.origin[Y], self.origin[X], r.y_max))
        self.children[SW] = QuadNode(
            Region(r.x_min, r.y_min, self.origin[X], self.origin[Y]))
        self.children[SE] = QuadNode(
            Region(self.origin[X], r.y_min, r.x_max, self.origin[Y]))

        # go through completely contained circles and try to push to lowest
        # children. If intersect 2 or more quadrants then we must keep.
        update = self.circles
        self.circles = []
        for circle in update:
            quads = self.quadrants(circle)

            # If circle intersects multiple quadrants, must add to self, and mark
            # as MULTIPLE, otherwise only add to that individual quadrant
            if len(quads) == 1:
                self.children[quads[0]].add(circle)
                circle[MULTIPLE] = False
            else:
                self.circles.append(circle)
                circle[MULTIPLE] = True
Beispiel #5
0
 def range(self, event):
     """Initiate a range search using a selected rectangular region."""
     
     p = (event.x, self.toCartesian(event.y))
      
     if self.selectedRegion is None:
         self.selectedStart = Region(p[X],p[Y],  p[X],p[Y])
     self.selectedRegion = self.selectedStart.unionPoint(p)
     
     self.paint()
     
     # return (node,status) where status is True if draining entire tree rooted at node. Draw these
     # all in Yellow using another inorder traversal
     for pair in self.tree.range(self.selectedRegion):
         
         if pair[1]:
             self.canvas.create_rectangle(pair[0].region.x_min, self.toTk(pair[0].region.y_min), 
                                          pair[0].region.x_max, self.toTk(pair[0].region.y_max),
                                          fill='Red', stipple='gray12')
         else:
             p = pair[0][0]   # ignore data and grab point
             self.canvas.create_rectangle(p[X] - RectangleSize, self.toTk(p[Y]) - RectangleSize, 
                                          p[X] + RectangleSize, self.toTk(p[Y]) + RectangleSize, fill='Red')
     
     
     self.queryRect = self.canvas.create_rectangle(self.selectedRegion.x_min, self.toTk(self.selectedRegion.y_min),  
                                                  self.selectedRegion.x_max, self.toTk(self.selectedRegion.y_max), 
                                                  outline='Red', dash=(2, 4))
Beispiel #6
0
 def test_expand(self):
     r = Region(10,20,50,60)
     r2 = Region(30,60,70,80)
             
     self.tree.add(r, 99)
     self.tree.add(r2, 101)
                      
     self.assertEquals(Region(10,20,70,80), self.tree.root.region)
Beispiel #7
0
 def subquadrant(self, quad):
     """Create QuadNode associated with sub-quadrant for parent region."""
     r = self.region
     if quad == NE:
         return QuadNode(Region(self.origin[X], self.origin[Y], r.x_max,        r.y_max))
     elif quad == NW:
         return QuadNode(Region(r.x_min,        self.origin[Y], self.origin[X], r.y_max))
     elif quad == SW: 
         return QuadNode(Region(r.x_min,        r.y_min,        self.origin[X], self.origin[Y]))
     elif quad == SE:
         return QuadNode(Region(self.origin[X], r.y_min,        r.x_max,        self.origin[Y]))
Beispiel #8
0
 def subregion(self, quad):
     """Return region associated with given quadrant."""
     r = self.region
     if quad is NE:
         return Region(self.origin[X], self.origin[Y], r.x_max,        r.y_max)
     if quad is NW:
         return Region(r.x_min,        self.origin[Y], self.origin[X], r.y_max)
     if quad is SW:
         return Region(r.x_min,        r.y_min,        self.origin[X], self.origin[Y])
     if quad is SE:
         return Region(self.origin[X], r.y_min,        r.x_max,        self.origin[Y])
Beispiel #9
0
 def test_tiling(self):
     # create evenly placed rectangles (s=16_ and validate queries
     for x in range(1,8):
         for y in range(1,8):
             self.tree.add(Region(x*64,y*64, x*64+32,y*64+32))
 
     for x in range(1,5):
         for y in range(1,5):
             s = Region(x*64, y*64, x*64+255, y*64+127)   # includes 2x4 selection or 8
             match = self.expand(s)
         
             self.assertEquals(8, len(match))
Beispiel #10
0
 def test_verticalSlices(self):
     # check case of vertical rectangles all in a row. This forces regular extensions.
     # Make sure bounding rectangles are computed properly.
     for x in range(1,50):
         self.tree.add(Region(x*6,10, x*6+3,100))
         
     # sliding window always grabs eight of them since there is one rect every 6 pixels and query width is 47
     for x in range(1, 40):
         s = Region(x*6, 2, x*6+47, 100)
         match = self.expand(s)
         
         self.assertEquals(8, len(match))
     
     self.ensure_maxBounding(self.tree.root)
Beispiel #11
0
    def test_split(self):
        r1 = Region(10,20,50,60)
        r2 = Region(30,60,70,80)
        r3 = Region(-30,60,70,80)
        r4 = Region(40,70,60,100)
           
        self.tree.add(r1, 99)
        self.tree.add(r2, 101)
        self.tree.add(r3, 103)
        self.tree.add(r4, 105)
        
        self.assertEquals(Region(-30,20,70,100), self.tree.root.region)
        
        r5 = Region(10,60,0,90)
        
        self.tree.add(r5, 107)

        self.assertEquals(Region(-30,20,70,100), self.tree.root.region)
        
        # finds all rectangles.
        r_ids = []
        for triple in self.tree.range(Region(-100, -100, 200, 200)):
            if triple[2]:
                for d in triple[0].leafOrder():
                    r_ids.append(d[1])
            else:
                r_ids.append(triple[1])
        r_ids.sort()
        self.assertEquals ([99,101,103,105,107], r_ids)
Beispiel #12
0
    def test_deleteOnlyOne(self):
        r = Region(10,20,50,60)
                
        self.tree.add(r, 99)
                         
        self.assertTrue(self.tree.search(r))
        self.assertEquals(Region(10,20,50,60), self.tree.root.region)
        
        # not in tree.
        self.assertFalse(self.tree.remove(Region(2,4,22,50)))
        
        self.assertTrue(self.tree.remove(r))

        # Not present.
        self.assertTrue(self.tree.search(r) is None)
Beispiel #13
0
 def test_deleteFive(self):
     r1 = Region(38,148  , 300,288)
     r2 = Region(164,384 , 432,428)
     r3 = Region(316,342 , 456,392)
     r4 = Region(12,242  , 172,484)
     r5 = Region(324,200 , 494,276)
     for r in [r1,r2,r3,r4,r5]:
         self.tree.add(r)
         
     for r in [r1,r2,r3,r4,r5]:
         self.assertTrue(self.tree.search(r))
         self.tree.remove(r)
         self.assertFalse(self.tree.search(r))
         
     self.assertTrue (self.tree.root == None)
Beispiel #14
0
def table(n):
    """Generate tables for book."""
    items = []
    for r in range(int(n**0.5)):
        for c in range(int(n**0.5)):
            items.append(Region(c * 10, r * 10, c * 10 + 7, r * 10 + 7))

    conductTrial("non intersecting rectangles", items)

    items = []
    for _ in range(n):
        items.append(
            Region(random.random(), random.random(), random.random(),
                   random.random()))

    conductTrial("random rectangles in unit square", items)
Beispiel #15
0
 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()
Beispiel #16
0
def conductTrial(label, items):
    samples = 128
    n = len(items)
    rt = RTree(m=2, M=4)
    for r in items:
        rt.add(r)

    box = rt.root.region
    width = box.x_max - box.x_min
    height = box.y_max - box.y_min

    # can compute density for any tree, samples at 128 random spots
    ct = 0
    for _ in range(samples):
        x = box.x_min + random.random() * width
        y = box.y_min + random.random() * height
        for triple in rt.range(Region(x, y, x, y)):
            assert (triple[2] == False)
            ct += 1

    print("Density", n, "{:.2f}%".format(100 * ct / (n * samples)),
          "intersect random point in ", str(box))

    trials(n, items, BUILD, "Build")
    trials(n, items, SEARCH, "Search")
    trials(n, items, DELETE, "Delete")
Beispiel #17
0
def randomRectangle():
    """Random rectangle in unit square whose width/height is no greater than 0.5"""
    xmin = 0.5 * random.random()
    ymin = 0.5 * random.random()
    xmax = xmin + 0.5 * random.random()
    ymax = ymin + 0.5 * random.random()
    return Region(xmin, ymin, xmax, ymax)
Beispiel #18
0
    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)
Beispiel #19
0
    def updateLocations(self):
        """Move all circles, reconstruct QuadTree and repaint."""
        if self.ship is None:
            self.init()

        # schedule next update if we are still playing
        if self.status == PLAYING:
            self.master.after(frameDelay, self.updateLocations)

        if self.tree.root is None:
            self.bullets = []
            self.status = WON
            self.canvas.delete(BULLET)
            self.updateShip()
            return

        # check if any bullet has hit an asteroid. If so, remove and add two
        for idx in range(len(self.bullets) - 1, -1, -1):
            b = self.bullets[idx]
            for c in self.tree.collide(b):
                if b:
                    del self.bullets[idx]
                    b = None
                    self.tree.remove(c)
                    c[RADIUS] = c[RADIUS] // 2
                    if c[RADIUS] >= 8:
                        # perturb to avoid unique coordinates
                        c2 = [
                            c[X] + c[DY], c[Y], c[RADIUS], False, False, c[DY],
                            c[DX]
                        ]
                        c3 = [
                            c[X] - c[DY], c[Y], c[RADIUS], False, False,
                            -c[DY], c[DX]
                        ]
                        self.tree.add(c2)
                        self.tree.add(c3)

        # Destroy tree each time and reinsert all circles with new locations
        nodes = self.tree.root.preorder()
        self.tree = QuadTree(Region(0, 0, 512, 512))
        for n in nodes:
            for c in n.circles:

                # Move from one side to the other, top and bottom
                self.updateShape(c)
                self.tree.add(c)

        # Update our location and the bullets
        self.updateShip()
        self.updateBullets()

        # Final check to see if any asteroid intersects our ship
        for c in self.tree.collide(self.ship):
            self.status = DESTROYED

        # Redraw all asteroids
        self.canvas.delete(ASTEROID)
        self.visit(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 setUp(self):
        self.qt = QuadTree(Region(0, 0, 1024, 1024))

        self.qt.add([22, 40, 10, False, False])
        self.qt.add([13, 59, 20, False, False])
        self.qt.add([57, 37, 30, False, False])
        self.qt.add([43, 21, 20, False, False])
        self.qt.add([33, 11, 10, False, False])
Beispiel #22
0
 def test_iterator(self):
     # rectangles have all even numbered coordinates
     for _ in range(500):
         self.tree.add(Region(2*random.randint(2,250), 2*random.randint(2,250), 2*random.randint(2,250), 2*random.randint(2,250)))
     
     count = 0
     for _ in self.tree:
         count = count + 1
     self.assertEquals(500, count)
Beispiel #23
0
    def extendAdd(self, event):
        """End of range search."""
        if self.newRegionStart:
            x = event.x
            y = self.toCartesian(event.y)

            self.newRegion = Region(x, y, x, y).unionPoint(self.newRegionStart)

            self.paint()
Beispiel #24
0
 def test_basic(self):
     r = Region(10,20,50,60)
     
     self.tree.add(r, 99)
                      
     for node,_,status in self.tree.range(r):
         self.assertTrue(status)
         for rect, ident in node.leafOrder():
             self.assertEquals(99, ident)
             self.assertEquals(r, rect)
Beispiel #25
0
    def test_delete(self):
        r = Region(10,20,50,60)
        r2 = Region(30,60,70,80)
                
        self.tree.add(r, 99)
        self.tree.add(r2, 101)
                         
        self.assertTrue(self.tree.search(r))
        self.assertTrue(self.tree.search(r2))
        self.assertEquals(Region(10,20,70,80), self.tree.root.region)
        
        # not in tree.
        self.assertFalse(self.tree.remove(Region(2,4,22,50)))
        
        self.assertTrue(self.tree.remove(r2))

        # one is in, other is out
        self.assertTrue(self.tree.search(r))
        self.assertTrue(self.tree.search(r2) is None)
 def pause(self, event):
     """Pause or Reset to start state (if already paused)."""
     if self.paused:
         self.tree = QuadTree(Region(0, 0, 512, 512))
         self.canvas.delete(ALL)
         self.visit(self.tree.root)
         self.viz.clear()
         self.restart()
     else:
         self.paused = True
         self.master.title(QuadTreeFixedApp.pausedTitle)
    def test_iteration_more(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)
Beispiel #28
0
    def test_adding(self):
        # rectangles have all even numbered coordinates. Doesn't really matter since
        # range returns regions that intersect target, rather than being wholly contained
        for _ in range(500):
            self.tree.add(Region(2*random.randint(2,250), 2*random.randint(2,250), 2*random.randint(2,250), 2*random.randint(2,250)))
        
        # make sure not to overlap!
        q_ne = self.expand(Region(125, 125, 501, 501))
        q_nw = self.expand(Region(1, 125, 125, 501))
        q_sw = self.expand(Region(1, 1, 125, 125))
        q_se = self.expand(Region(125, 1, 511, 125))
        
        q_all = self.expand(Region(1,1, 501, 501))
        
        # quick check to see if any were missing
        combined = []
        for r in q_ne + q_nw + q_sw + q_se:
            if r not in combined:
                combined.append(r)

        for q in q_all:
            if q not in combined:
                print (q, " missing ")
                
        # check duplicates
        for i in range(len(combined)):
            for j in range(len(combined)):
                if j <= i:
                    pass
                else:
                    if combined[i] == combined[j]:
                        print ("Duplicate:", combined[i])
        
        self.assertEquals(len(q_all), len(combined))
    def test_remove_less_than_four(self):
        self.qt = QuadTree(Region(0, 0, 1024, 1024))

        self.qt.add([22, 40, 10, False, False])
        self.qt.add([13, 59, 20, False, False])
        self.qt.add([57, 37, 30, False, False])

        self.assertTrue(self.qt.remove([57, 37, 30]))
        self.assertTrue(self.qt.remove([13, 59, 20]))
        self.assertTrue(self.qt.remove([22, 40, 10]))

        self.assertFalse(self.qt.remove([57, 37, 30]))
        self.assertFalse(self.qt.remove([13, 59, 20]))
        self.assertFalse(self.qt.remove([22, 40, 10]))
Beispiel #30
0
 def __init__(self, master):
     """App for creating Quad tree dynamically with fixed circles that detect collisions."""
     
     master.title("Click to add fixed circles for QuadTree collision detection.") 
     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 range(self, event):
     """Initiate a range search using a selected rectangular region."""
     
     p = (event.x, self.toCartesian(event.y))
      
     if self.selectedRegion is None:
         self.selectedStart = Region(p[X],p[Y],  p[X],p[Y])
     self.selectedRegion = self.selectedStart.unionPoint(p)
     
     self.paint()
     
     # return (node,0,True) where status is True if draining entire tree rooted at node. If False,
     # then (rect,id,False). Draw these
     # as shaded red rectangle to identify whole sub-tree is selected.
     for triple in self.tree.range(self.selectedRegion):
         if triple[2]:
             r = triple[0].region
             self.canvas.create_rectangle(r.x_min, self.toTk(r.y_min), r.x_max, self.toTk(r.y_max),
                                          fill='Red', stipple='gray12')
         else:
             r = triple[0]
             self.canvas.create_rectangle(r.x_min, self.toTk(r.y_min), r.x_max, self.toTk(r.y_max), 
                                          fill='Red')
class KDTreeApp:
    
    def __init__(self):
        """App for creating KD tree dynamically and executing range queries."""
        
        self.tree = KDTree()
        self.static = False
        
        # for range query
        self.selectedRegion = None
        self.queryRect = None
        
        self.master = tkinter.Tk()
        self.master.title('KD Tree Range Query Application')
        self.w = tkinter.Frame(self.master, width=410, height=410)
        self.canvas = tkinter.Canvas(self.w, width=400, height=400)        
                        
        self.paint()

        self.canvas.bind("<Button-1>", self.click)
        self.canvas.bind("<Motion>", self.moved)
        self.canvas.bind("<Button-3>", self.range)   # when right mouse clicked
        self.canvas.bind("<ButtonRelease-3>", self.clear)
        self.canvas.bind("<B3-Motion>", self.range)  # only when right mouse dragged
        self.w.pack()
        

    def toCartesian(self, y):
        """Convert tkinter point into Cartesian."""
        return self.w.winfo_height() - y

    def toTk(self,y):
        """Convert Cartesian into tkinter point."""
        if y == maxValue: return 0
        tk_y = self.w.winfo_height()
        if y != minValue:
            tk_y -= y
        return tk_y
         
    def clear(self, event):
        """End of range search."""
        self.selectedRegion = None
        self.paint()
        
    def range(self, event):
        """Initiate a range search using a selected rectangular region."""
        
        p = (event.x, self.toCartesian(event.y))
         
        if self.selectedRegion is None:
            self.selectedStart = Region(p[X],p[Y],  p[X],p[Y])
        self.selectedRegion = self.selectedStart.unionPoint(p)
        
        self.paint()
        
        # return (node,status) where status is True if draining entire tree rooted at node. Draw these
        # as shaded red rectangle to identify whole sub-tree is selected.
        for pair in self.tree.range(self.selectedRegion):
            p = pair[0].point
            
            if pair[1]:
                self.canvas.create_rectangle(pair[0].region.x_min, self.toTk(pair[0].region.y_min), 
                                             pair[0].region.x_max, self.toTk(pair[0].region.y_max),
                                             fill='Red', stipple='gray12')
            else:
                self.canvas.create_rectangle(p[X] - RectangleSize, self.toTk(p[Y]) - RectangleSize, 
                                             p[X] + RectangleSize, self.toTk(p[Y]) + RectangleSize, fill='Red')
        
        self.queryRect = self.canvas.create_rectangle(self.selectedRegion.x_min, self.toTk(self.selectedRegion.y_min),  
                                                     self.selectedRegion.x_max, self.toTk(self.selectedRegion.y_max), 
                                                     outline='Red', dash=(2, 4))
        
        
    def moved(self, event):
        """Only here for static option."""
        if self.static:
            self.paint()
        
    def click(self, event):
        """Add point to KDtree."""
        p = (event.x, self.toCartesian(event.y))
        
        self.tree.add(p)
             
        self.paint()

    def drawPartition (self, r, p, orient):
        """Draw partitioning line and points itself as a small square."""
        if orient == VERTICAL:
            self.canvas.create_line(p[X], self.toTk(r.y_min), p[X], self.toTk(r.y_max))
        else:
            xlow = r.x_min
            if r.x_min <= minValue: xlow = 0
            xhigh = r.x_max
            if r.x_max >= maxValue: xhigh = self.w.winfo_width()

            self.canvas.create_line(xlow, self.toTk(p[Y]), xhigh, self.toTk(p[Y]))

        self.canvas.create_rectangle(p[X] - RectangleSize, self.toTk(p[Y]) - RectangleSize,
                                     p[X] + RectangleSize, self.toTk(p[Y]) + RectangleSize, fill='Black')

    def visit (self, n):
        """ Visit node to paint properly."""
        if n == None: return

        self.drawPartition(n.region, n.point, n.orient)

        self.visit (n.below)
        self.visit (n.above)

    def prepare(self, event):
        """prepare to add points."""
        if self.label:
            self.label.destroy()
            self.label = None
            self.canvas.pack()
        
    def paint(self):
        """Paint quad tree by visiting all nodes, or show introductory message."""
        if self.tree.root:
            self.canvas.delete(tkinter.ALL)
            self.visit(self.tree.root)
        else:
            self.label = tkinter.Label(self.w, width=100, height = 40, text="Click To Add Points")
            self.label.bind("<Button-1>", self.prepare)
            self.label.pack()
class QuadTreeApp:
    
    def __init__(self):
        """App for creating Quad tree dynamically and executing range queries."""
        
        self.tree = QuadTree(Region(0,0,W,H))
        self.match = None
        
        # for range query
        self.selectedRegion = None
        self.queryRect = None
        
        self.master = tkinter.Tk()
        self.master.title('Quad Tree Range Application')
        self.w = tkinter.Frame(self.master, width=W, height=H)
        self.canvas = tkinter.Canvas(self.w, width=W, height=H)        
                        
        self.paint()

        self.canvas.bind("<Button-1>", self.click)
        self.canvas.bind("<Button-3>", self.range)   # when right mouse clicked
        self.canvas.bind("<ButtonRelease-3>", self.clear)
        self.canvas.bind("<B3-Motion>", self.range)  # only when right mouse dragged
        self.w.pack()
        

    def toCartesian(self, y):
        """Convert tkinter point into Cartesian"""
        return self.w.winfo_height() - y

    def toTk(self,y):
        """Convert Cartesian into tkinter point."""
        if y == maxValue: return 0
        tk_y = self.w.winfo_height()
        if y != minValue:
            tk_y -= y
        return tk_y
         
    def clear(self, event):
        """End of range search."""
        self.selectedRegion = None
        self.paint()
        
    def range(self, event):
        """Initiate a range search using a selected rectangular region."""
        
        p = (event.x, self.toCartesian(event.y))
         
        if self.selectedRegion is None:
            self.selectedStart = Region(p[X],p[Y],  p[X],p[Y])
        self.selectedRegion = self.selectedStart.unionPoint(p)
        
        self.paint()
        
        # return (node,status) where status is True if draining entire tree rooted at node. Draw these
        # all in Yellow using another inorder traversal
        for pair in self.tree.range(self.selectedRegion):
            
            if pair[1]:
                self.canvas.create_rectangle(pair[0].region.x_min, self.toTk(pair[0].region.y_min), 
                                             pair[0].region.x_max, self.toTk(pair[0].region.y_max),
                                             fill='Red', stipple='gray12')
            else:
                p = pair[0][0]   # ignore data and grab point
                self.canvas.create_rectangle(p[X] - RectangleSize, self.toTk(p[Y]) - RectangleSize, 
                                             p[X] + RectangleSize, self.toTk(p[Y]) + RectangleSize, fill='Red')
        
        
        self.queryRect = self.canvas.create_rectangle(self.selectedRegion.x_min, self.toTk(self.selectedRegion.y_min),  
                                                     self.selectedRegion.x_max, self.toTk(self.selectedRegion.y_max), 
                                                     outline='Red', dash=(2, 4))
        
    def click(self, event):
        """Add point to QuadTree."""
        p = (event.x, self.toCartesian(event.y))
        
        self.tree.add(p)
             
        self.paint()

         
    def visit (self, node):
        """ Visit node to paint properly."""
        if node == None: return

        if node.points is None: 
            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]),
                                    fill='black', dash=(2, 4)) 
            self.canvas.create_line(node.origin[X], self.toTk(r.y_min), node.origin[X], self.toTk(r.y_max),
                                    fill='black', dash=(2, 4))
            for n in node.children:
                self.visit(n)
        else:
            for p in node.points:
                self.canvas.create_rectangle(p[X] - RectangleSize, self.toTk(p[Y]) - RectangleSize, 
                                             p[X] + RectangleSize, self.toTk(p[Y]) + RectangleSize, fill='Black')
        
    def prepare(self, event):
        """prepare to add points."""
        if self.label:
            self.label.destroy()
            self.label = None
            self.canvas.pack()
        
    def paint(self):
        """Paint Quad tree by visiting all nodes, or show introductory message."""
        if self.tree.root:
            self.canvas.delete(tkinter.ALL)
            self.visit(self.tree.root)
        else:
            self.label = tkinter.Label(self.w, width=100, height = 40, text="Click To Add Points")
            self.label.bind("<Button-1>", self.prepare)
            self.label.pack()
class RTreeApp:
    
    def __init__(self):
        """App for creating R tree dynamically and executing range queries"""
        
        self.tree = RTree(m=2, M=4)
        self.ready = False
        
        # for range query
        self.selectedRegion = None
        self.newRegionStart = None
        self.newRegion      = None
        
        # for identifiers
        self.counter = 0
        
        self.master = tkinter.Tk()
        self.master.title('R Tree Range Query Application')
        self.w = tkinter.Frame(self.master, width=512, height=512)
        self.canvas = tkinter.Canvas(self.w, width=512, height=512)        
                        
        self.paint()

        self.canvas.bind("<Button-1>", self.startAdd)
        self.canvas.bind("<B1-Motion>", self.extendAdd)  # only when right mouse dragged
        self.canvas.bind("<ButtonRelease-1>", self.endAdd)
        
        self.canvas.bind("<Button-3>", self.range)   # when right mouse clicked
        self.canvas.bind("<ButtonRelease-3>", self.clear)
        self.canvas.bind("<B3-Motion>", self.range)  # only when right mouse dragged
        self.w.pack()
        
    def startAdd(self, event):
        """End of range search."""
        x = event.x
        y = self.toCartesian(event.y)
        self.newRegionStart = (x,y)
        
    def extendAdd(self, event):
        """End of range search."""
        if self.newRegionStart:
            x = event.x
            y = self.toCartesian(event.y)
            
            self.newRegion = Region (x,y,x,y).unionPoint(self.newRegionStart) 
            
            self.paint()
        
    def endAdd(self, event):
        """End of range search."""
        if self.newRegionStart:
            self.newRegionStart = None
            self.counter += 1
            
            if self.newRegion:
                self.tree.add(self.newRegion, str(self.counter))
                
            self.newRegion = None
            self.paint()

    def toCartesian(self, y):
        """Convert tkinter point into Cartesian."""
        return self.w.winfo_height() - y

    def toTk(self,y):
        """Convert Cartesian into tkinter point."""
        if y == maxValue: return 0
        tk_y = self.w.winfo_height()
        if y != minValue:
            tk_y -= y
        return tk_y
         
    def clear(self, event):
        """End of range search."""
        self.selectedRegion = None
        self.paint()
        
    def range(self, event):
        """Initiate a range search using a selected rectangular region."""
        
        p = (event.x, self.toCartesian(event.y))
         
        if self.selectedRegion is None:
            self.selectedStart = Region(p[X],p[Y],  p[X],p[Y])
        self.selectedRegion = self.selectedStart.unionPoint(p)
        
        self.paint()
        
        # return (node,0,True) where status is True if draining entire tree rooted at node. If False,
        # then (rect,id,False). Draw these
        # as shaded red rectangle to identify whole sub-tree is selected.
        for triple in self.tree.range(self.selectedRegion):
            if triple[2]:
                r = triple[0].region
                self.canvas.create_rectangle(r.x_min, self.toTk(r.y_min), r.x_max, self.toTk(r.y_max),
                                             fill='Red', stipple='gray12')
            else:
                r = triple[0]
                self.canvas.create_rectangle(r.x_min, self.toTk(r.y_min), r.x_max, self.toTk(r.y_max), 
                                             fill='Red')
        
    def click(self, event):
        """Add point to KDtree."""
        p = (event.x, self.toCartesian(event.y))
        
        self.tree.add(p)
             
        self.paint()

    def visit (self, n):
        """ Visit node to paint properly."""
        if n == None: return

        if n.level == 0:
            for idx in range(n.count):
                r = n.children[idx].region
                self.canvas.create_rectangle(r.x_min, self.toTk(r.y_min), r.x_max, self.toTk(r.y_max),
                                     fill='Gray')    
            
        for idx in range(n.count):
            self.visit(n.children[idx])

        # Do after all children so we can see interior nodes, too.
        r = n.region
        self.canvas.create_rectangle(r.x_min, self.toTk(r.y_min), r.x_max, self.toTk(r.y_max),
                                     outline='Black', dash=(2, 4))
        color = 'Gray'
        if n.level == 0:
            color='Black'  
        self.canvas.create_text(r.x_max - 16*len(n.id), self.toTk(r.y_max) + 16, anchor = tkinter.W, 
                                font = "Times 16 bold", fill=color, text=n.id)

    def prepare(self, event):
        """prepare to add points."""
        if self.label:
            self.label.destroy()
            self.label = None
            self.canvas.pack()
        
    def paint(self):
        """Paint R tree by visiting all nodes, or show introductory message."""
        if self.ready:
            self.canvas.delete(tkinter.ALL)
            self.visit(self.tree.root)
            
            if self.newRegion:
                self.canvas.create_rectangle(self.newRegion.x_min, self.toTk(self.newRegion.y_min),
                                         self.newRegion.x_max, self.toTk(self.newRegion.y_max), 
                                         outline='Black', dash=(2, 4))
                
            if self.selectedRegion:
                self.canvas.create_rectangle(self.selectedRegion.x_min, self.toTk(self.selectedRegion.y_min),
                                         self.selectedRegion.x_max, self.toTk(self.selectedRegion.y_max), 
                                         outline='Red', dash=(2, 4))
        else:
            self.label = tkinter.Label(self.w, width=100, height = 40, text="Click To Add Points")
            self.label.bind("<Button-1>", self.prepare)
            self.label.pack()
            self.ready = True