Advertisement
cookertron

Quadtree Query - Python Pygame

May 21st, 2020
1,561
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.57 KB | None | 0 0
  1. import pygame
  2. from pygame import gfxdraw
  3. import random
  4.  
  5. # quadTree constants
  6. CAPACITY = 4
  7.  
  8. # This breaks down the display area into populated rectangles. The population is based on points
  9. class quadTree:
  10.     def __init__(s, rect): # boundry is a rectangle
  11.         s.rect = rect
  12.         s.points = []
  13.         s.divided = False
  14.        
  15.     def insert(s, point):
  16.         global CAPACITY # maximum capacity on each quadrant
  17.  
  18.         # if the point inserted doesn't fit into this quadrant then don't add it to
  19.         # the points list. Exit insert()!
  20.         if not s.rect.collidepoint(int(point.x), int(point.y)): return False
  21.  
  22.         # check if the quadrant has room for more points
  23.         if len(s.points) < CAPACITY:
  24.             s.points.append(point) # if there's room add it to the points list
  25.             # return True to inform parent quadtree the point has been added
  26.             return True
  27.         else:
  28.             # if the quadrant is full then divide the quadrant into
  29.             # four parts north west, north east, south west, south east...
  30.             if not s.divided:
  31.                 s.subDivide()
  32.        
  33.             # ...and insert the point into one of the four new quadrants
  34.             if s.nw.insert(point):
  35.                 return True
  36.             elif s.ne.insert(point):
  37.                 return True
  38.             elif s.sw.insert(point):
  39.                 return True
  40.             elif s.se.insert(point):
  41.                 return True
  42.  
  43.     def subDivide(s):
  44.         # create four new quadtrees which belong to the parent quadtree
  45.         size = (s.rect.width / 2, s.rect.height / 2)
  46.         s.nw = quadTree(pygame.Rect(s.rect.topleft, size))
  47.         s.ne = quadTree(pygame.Rect(s.rect.midtop, size))
  48.         s.sw = quadTree(pygame.Rect(s.rect.midleft, size))
  49.         s.se = quadTree(pygame.Rect(s.rect.center, size))
  50.         s.divided = True # the parent quadtree can no longer be divided
  51.  
  52.     def query(s, rect, pointsArray = []):
  53.         # if the queried rect doesn't intersect with the quadrant
  54.         # exit query
  55.         if not s.rect.colliderect(rect): return
  56.  
  57.         # if it does then append points to the pointsArray
  58.         for p in s.points:
  59.             if rect.collidepoint(p): pointsArray.append(p)
  60.  
  61.         # because the quadtree is recursive we need to check its children
  62.         # to see if they're within the query parameters (rect)
  63.         if s.divided:
  64.             s.nw.query(rect, pointsArray)
  65.             s.ne.query(rect, pointsArray)
  66.             s.sw.query(rect, pointsArray)
  67.             s.se.query(rect, pointsArray)
  68.  
  69.     def show(s):
  70.         global PD # Primary Display
  71.  
  72.         if not s.points: return
  73.  
  74.         # draw all the points in this quadrant to the Primary Display
  75.         for p in s.points:
  76.             pygame.draw.circle(PD, (255, 0, 0), (int(p.x), int(p.y)), 3)
  77.  
  78.         # if the quadrant is divided then:
  79.         # 1. draw the division lines and then
  80.         # 2. get its children to draw their points and division lines
  81.         if s.divided:
  82.             # draw the boundry to help visualise what's going on
  83.             pygame.gfxdraw.hline(PD, int(s.rect.x), int(s.rect.right), int(s.rect.centery), (255, 255, 255))
  84.             pygame.gfxdraw.vline(PD, int(s.rect.centerx), int(s.rect.y), int(s.rect.bottom), (255, 255, 255))            
  85.  
  86.             s.nw.show()
  87.             s.ne.show()
  88.             s.sw.show()
  89.             s.se.show()
  90.  
  91. # pygame display settings
  92. DR = pygame.Rect((0, 0, 800, 600)) # Display Rectangle
  93. HDW, HDH = DR.center # H = half
  94.  
  95. # set up pygame
  96. pygame.init()
  97. PD = pygame.display.set_mode(DR.size) # primary display based of the size of Display Rect (800, 600)
  98.  
  99. # create a quadtree instance and initialise it with the display rectange (size of the display)
  100. QT = quadTree(DR)
  101.  
  102. # previous position of the mouse pointer
  103. px, py = -1, -1
  104.  
  105. # press ESC to exit
  106. while True:
  107.     # process events
  108.     e = pygame.event.get()
  109.     if pygame.key.get_pressed()[pygame.K_ESCAPE]: break
  110.  
  111.     # get position of the mouse
  112.     mx, my = pygame.mouse.get_pos()
  113.  
  114.  
  115.     # get the status of the mouse buttons
  116.     mb = pygame.mouse.get_pressed()
  117.    
  118.     # if left mouse button has been pressed then add randomised points
  119.     if mb[0]:
  120.         # if current mouse position is different to the previous mouse position
  121.         if (mx, my) != (px, py):
  122.             # set the previous mouse position to the current mouse position
  123.             px, py = (mx, my)
  124.  
  125.             # create a vector from the mouse location with a random offset on the x and y axis
  126.             rx, ry = (mx + random.randint(-40, 40), my + random.randint(-40, 40))
  127.  
  128.             # create a point using pygame's vector2
  129.             p = pygame.math.Vector2(rx, ry)
  130.  
  131.             # insert the point into the quadtree
  132.             QT.insert(p)
  133.  
  134.     # clear the primary display by filling it with black
  135.     PD.fill((0, 0, 0))
  136.     QT.show()
  137.  
  138.     # if right mouse button is pressed then query quadtree
  139.     if mb[2] and not mb[0]:
  140.         # the query will take the form of a pygame.Rect (x, y, w, h)
  141.         queryRect = pygame.Rect(mx - 100, my - 100, 200, 200)
  142.         points = [] # this list will contain the points returned by the query
  143.        
  144.         # query the quadtree :D
  145.         QT.query(queryRect, points)
  146.        
  147.         # draw query rectangle
  148.         pygame.draw.rect(PD, (0, 255, 0), queryRect, 1)
  149.        
  150.         # highlight the points by over writing QT.show() points with queried points
  151.         for p in points:
  152.             pygame.draw.circle(PD, (255, 0, 255), (int(p.x), int(p.y)), 3)
  153.    
  154.     pygame.display.update()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement