def closest(self, point, sidx=si.StorageIndex()): """ Returns a list of unique keys that fell within the BoundingBox that contained the point. :param point: the point of interest >>> print(tree.closest([7,2])) <<< [5 6] """ # Return found points if "elements" in self.storage[sidx.storage()]: return self.storage[sidx.storage()]["elements"] else: # Or continue recursive seeking # > obtain axis and partition. # axis: In which axis is the partition located axis = self.storage[sidx.storage()]["axis"] # partition: the coordinate of split point in the given axis partition = self.storage[sidx.storage()]["partition"] boxes = [] # search for the closest point by comparing coordinate of point # in the given axis and partition if point[axis] <= partition: boxes.extend(self.closest(point, sidx.left())) if partition < point[axis]: boxes.extend(self.closest(point, sidx.right())) return boxes
def traverse(self, mtrx, depth=0, sidx=si.StorageIndex()): """ Internal used method for creating the QuadTree. This method will be called recursively until the maximum depth is reached. In every step it will split the data along a certain axis into two equal sized (median) partitions. Technically the partion function only needs to be called once, but is done repeatedly for clarity. """ axis = depth % 2 self.storage[sidx.storage()]["index"] = sidx.tree() self.storage[sidx.storage()]["depth"] = depth self.storage[sidx.storage()]["axis"] = axis # if no more splitting, store ids from the matrix if len(mtrx) == 1 or depth + 1 == self.max_depth: self.storage[sidx.storage()]["elements"] = mtrx[:, 0] else: # order the matrix, and partition order = np.array_split(self.partition(mtrx, axis + 1), 2) self.storage[sidx.storage()]["partition"] = mtrx[order[0][-1], axis + 1] self.traverse(mtrx[order[0], :], depth + 1, sidx.left()) self.traverse(mtrx[order[1], :], depth + 1, sidx.right())
def rquery(self, bbox=[], sidx=si.StorageIndex()): """ Returns a list of unique keys that fell within the provided BoundingBox. :param bbox: the current BoundingBox that will be searched :param sidx: helper class for Binary Tree traversal >>> bbox = bb.BoundingBox(1,2,1,2) >>> print(tree.rquery(bbox)) <<< [1, 2] >>> print(database.query(tree.rquery(bbox))) <<< [[1, 2, 3], [2, 5, 4]] """ if "elements" in self.storage[sidx.storage()]: return self.storage[sidx.storage()]["elements"] else: axis = self.storage[sidx.storage()]["axis"] partition = self.storage[sidx.storage()]["partition"] lr = bbox.partition(partition, axis) boxes = [] if lr[0]: boxes.extend(self.rquery(bbox, sidx.left())) if lr[1]: boxes.extend(self.rquery(bbox, sidx.right())) return boxes
def closest(self, point, sidx=si.StorageIndex()): """ Returns a list of unique keys that fell within the BoundingBox that contained the point. :param point: the point of interest >>> print(tree.closest([7,2])) <<< [5 6] :To be implemented by the student: """ if "elements" in self.storage[sidx.storage()]: return self.storage[sidx.storage()]["elements"] else: axis = self.storage[sidx.storage()]["axis"] partition = self.storage[sidx.storage()]["partition"] # lr = ((point[axis] <= partition) or (point[axis]<=partition), (point[axis] > partition) or (point[axis] > partition)) boxes = [] if point[axis] <= partition: boxes.extend(self.closest(point, sidx.left())) if point[axis] > partition: boxes.extend(self.closest(point, sidx.right())) return boxes
def closest(self, point, sidx=si.StorageIndex()): """ Returns a list of unique keys that fell within the BoundingBox that contained the point. :param point: the point of interest """ # When the condition is satisfied the recurssion is stopped. if "elements" in self.storage[sidx.storage()]: return self.storage[sidx.storage()]["elements"] else: """ Get the axis and the partition number Axis - is the orientations, like x-axis (0) or y-axis (1) Partition - is the element where the KDTree was split or partitioned. """ axis = self.storage[sidx.storage()]["axis"] partition = self.storage[sidx.storage()]["partition"] """ traversal_direction - determines the direction of traversal (Left/Right). If the point is less than or equal to the partition value traverse left else traverse right. The axis == 0 or axis == 1 ensure that we are comparing the partition value against either x or y respectively. """ traversal_direction = (point[axis] <= partition, point[axis] > partition) """ Perform recursion until closest leaf node is reached. Store the data points in that leaf node in boxes and return the boxes. """ boxes = [] if traversal_direction[0]: # Recursion/Traverse towards left child boxes.extend(self.closest(point, sidx.left())) if traversal_direction[1]: # Recursion/Traverse towards right child boxes.extend(self.closest(point, sidx.right())) return boxes
def partitions(self): """ Returns a dictionary containing lists of BoundingBoxes. { 0 : [ 1 x BoundingBox] 1 : [ 2 x BoundingBox] 2 : [ 4 x BoundingBox] } where the key represents the depth, and the collection of BoundingBoxes make up the entire space containing this KDTree :Example: >>> for k,v in tree.partitions().items(): >>> print(k,len(v)) <<< (0, 1) <<< (1, 2) <<< (2, 4) """ bounding_boxes = {} sidx = si.StorageIndex() self.traverse_partition(0, sidx, bounding_boxes, self.bb) return bounding_boxes
def closest(self, point, sidx=si.StorageIndex()): # :To be implemented by the student: pass