Advertisement
Guest User

donky

a guest
Oct 14th, 2008
319
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.42 KB | None | 0 0
  1. #
  2.  
  3. # Initial octree covers (0, 0, 0) to (63999, 63999, 63999)
  4.  
  5. BASE_SIZE = 64000
  6.  
  7.  
  8. class Octree:
  9.     def __init__(self):
  10.         self.outer_calls = 0
  11.         self.max_outer_calls = 4
  12.         self.octree = OctreeLevel(self, size=64000, pos0=(0, 0, 0))
  13.  
  14.     def get_outer_level(self, level, pos, value, idxs):
  15.         self.outer_calls += 1
  16.         if self.outer_calls > self.max_outer_calls:
  17.             raise RuntimeError("Too deep")
  18.  
  19.         outerSize = level.size * 2
  20.  
  21.         # We want to set the outer corner of the new outer box to
  22.         # encompass the existing quadrant, but expanding in the
  23.         # direction of the position we wish to insert at.
  24.         outerPos0 = []
  25.         for i, offset in enumerate(level.pos0):
  26.             sign = idxs[i]
  27.             if sign < 0:
  28.                 # Extend in the negative direction one quadrant
  29.                 # meaning we keep the child quadrant within us.
  30.                 outerPos0.append(offset + sign * level.size)
  31.             else:
  32.                 # We naturally extend in the positive direction
  33.                 # by having double the size of the child quadrant,
  34.                 # so we can just share this axis' base offset.
  35.                 outerPos0.append(offset)
  36.  
  37.         outerLevel = OctreeLevel(self, outerSize, tuple(outerPos0))
  38.         outerLevel.insert_existing_quadrant(level)
  39.         self.octree = outerLevel
  40.         return outerLevel
  41.        
  42.     def __getattr__(self, attrName):
  43.         return getattr(self.octree, attrName)
  44.  
  45. class OctreeLevel:
  46.     def __init__(self, parent, size=None, pos0=None):
  47.         self.parent = parent
  48.    
  49.         self.size = size
  50.         self.pos0 = pos0
  51.         self.posC = (pos0[0] + size/2, pos0[1] + size/2, pos0[2] + size/2)
  52.        
  53.         self.quadrants = None
  54.         self.values = {}
  55.  
  56.     def insert_existing_quadrant(self, level):
  57.         if self.quadrants is None:
  58.             self.quadrants = [ None for i in range(8) ]
  59.         # Validate that this level is a sub-quadrant of ours.
  60.         for i, offset in enumerate(level.pos0):
  61.             if offset < self.pos0[i] or offset >= self.pos0[i] + self.size:
  62.                 raise RuntimeError("Bad sub-quadrant")
  63.         idx = calc_quadrant_index(self.posC, level.posC)
  64.         self.quadrants[idx] = level
  65.  
  66.     def insert(self, pos, value):
  67.         # Detect the case where we are outside of this level.
  68.         idxs = []
  69.         for i, offset in enumerate(pos):
  70.             # If this is the case, we want to know the axis and the
  71.             # direction we need to expand (i and sign respectively).
  72.             sign = 0
  73.             if offset < self.pos0[i]:
  74.                 sign = -1
  75.             elif offset >= self.pos0[i] + self.size:
  76.                 sign = 1
  77.             idxs.append(sign)
  78.  
  79.         # Check if the position falls outside any of the box walls.
  80.         if idxs != [0,0,0]:
  81.             print "getting outer level", pos, value, "level was", (self.pos0, self.size), "indicator", idxs
  82.             level = self.parent.get_outer_level(self, pos, value, idxs)
  83.             return level.insert(pos, value)
  84.  
  85.         if self.size != BASE_SIZE:
  86.             idx = calc_quadrant_index(self.posC, pos)
  87.             if self.quadrants is None:
  88.                 self.quadrants = [ None for i in range(8) ]
  89.             quadrant = self.quadrants[idx]
  90.             if quadrant is None:
  91.                 innerSize = self.size / 2
  92.                 # We need to work out where the outer corner of the sub-quadrant
  93.                 # the position falls into is, so we can create it properly.  Our
  94.                 # quadrant index is a reverse bit field of axis sign, so we can
  95.                 # use that to help us.            
  96.                 innerPos0 = list(self.pos0)
  97.                 for i in range(3):
  98.                     if idx & (1 << i):
  99.                         innerPos0[i] += innerSize
  100.                 print "CREATE-QUADRANT", self.pos0, innerPos0
  101.                 self.quadrants[idx] = quadrant = OctreeLevel(self, innerSize, tuple(innerPos0))
  102.             else:
  103.                 print "EXISTS-QUADRANT", self.pos0, quadrant.pos0
  104.  
  105.             print "level is", (self.pos0, self.size), "idx", idx, "getting inner level of", (quadrant.pos0, quadrant.size)
  106.             return quadrant.insert(pos, value)
  107.  
  108.         if self.values is None:
  109.             self.values = {}
  110.  
  111.         xValue = pos[0] - self.pos0[0]
  112.         if xValue < 0 or xValue >= BASE_SIZE: raise RuntimeError("Bad value")
  113.         if xValue not in self.values:
  114.             self.values[xValue] = {}
  115.  
  116.         yValue = pos[1] - self.pos0[1]
  117.         if yValue < 0 or yValue >= BASE_SIZE: raise RuntimeError("Bad value")
  118.         if yValue not in self.values[xValue]:
  119.             self.values[xValue][yValue] = {}
  120.  
  121.         zValue = pos[2] - self.pos0[2]
  122.         if zValue < 0 or zValue >= BASE_SIZE: raise RuntimeError("Bad value")
  123.         if zValue not in self.values[xValue][yValue]:
  124.             self.values[xValue][yValue][zValue] = value
  125.  
  126.         print "inserted", value, "at", pos, "level was", (self.pos0, self.size)
  127.  
  128.     def lookup(self, pos):
  129.         pass
  130.  
  131.  
  132. def calc_quadrant_index(vec1, vec2):
  133.     bits = 0
  134.     for i in range(3):
  135.         v = vec2[i] - vec1[i]
  136.         if v >= 0:
  137.             bits |= 1 << i
  138.     return bits
  139.  
  140. if __name__ == "__main__":
  141.     print "BEGIN"
  142.     o = Octree()
  143.     o.insert((100000, 100, 100), "TEST-VALUE")
  144.     o.insert((-100000, 100, 100), "TEST-VALUE")
  145.     print "END"
  146.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement