rtree.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. from extent import *
  2. from math import ceil
  3. class Entry:
  4. def __init__(self, extent = None, child = None, parent = None, node = None, id = None, geometry = None):
  5. self.MBR = extent
  6. self.child = child
  7. self.node = node
  8. self.id = id
  9. self.geometry = geometry
  10. def __repr__(self):
  11. return str(self.MBR)
  12. class RtreeNode:
  13. def __init__(self, M, parent = None):
  14. self.entries = []
  15. self.M = M
  16. self.parent = parent
  17. self.extent = None
  18. def __getitem__(self, i):
  19. if i >= self.M or i >= len(self.entries): return None
  20. return self.entries[i]
  21. def __repr__(self):
  22. return str(self.extent)
  23. # проверка на лист
  24. def is_leaf(self):
  25. for e in self.entries:
  26. if e.child is not None:
  27. return False
  28. return True
  29. # проверка на родителя
  30. def is_root(self):
  31. return self.parent is None
  32. # обновление MBR узла, чтобы он включал в себе все его объекты
  33. def update(self):
  34. if not len(self.entries):
  35. return
  36. if self.entries[0] is not None:
  37. self.extent = self.entries[0].MBR
  38. for e in self.entries[1:]:
  39. self.extent = union_extent(self.extent, e.MBR)
  40. # обновление всего дерева до корня
  41. def update_up(self):
  42. self.update()
  43. if self.is_root():
  44. return
  45. self.parent.MBR = self.extent
  46. self.parent.node.update_up()
  47. # получение MBR объектов в виде объекта класса Extent
  48. def union_extent(e1, e2):
  49. xmin = min(e1.xmin, e2.xmin)
  50. xmax = max(e1.xmax, e2.xmax)
  51. ymin = min(e1.ymin, e2.ymin)
  52. ymax = max(e1.ymax, e2.ymax)
  53. return Extent(xmin, xmax, ymin, ymax)
  54. # функция вставки
  55. def insert(node, e, child = None):
  56. for ent in node.entries: # если объект уже есть в узле, то возвращаем True
  57. if ent.MBR == e:
  58. return True
  59. # создание объекта класса Entry с переданными параметрами
  60. entry = Entry(extent = e, child = child, id = e.id, geometry = e.geometry)
  61. if len(node.entries) < node.M: # если в узле ещё есть место, то просто добавляем объект
  62. entry.node = node
  63. if entry.child is not None: # если у объекта есть потомки, то устанавливаем им объект в качестве родителя
  64. entry.child.parent = entry
  65. node.entries.append(entry) # добавляем объект
  66. node.update_up() # обновляем узел
  67. return True
  68. # если места нет, то необходимо разделить узел
  69. M = node.M # максимально возможное количество объектов
  70. m = ceil(float(M) / 2) # возможное количество объектов в новых узлах
  71. L1 = RtreeNode(M) # новые узлы
  72. L2 = RtreeNode(M)
  73. max_i, max_j = -1, -1 # переменные для получения 2 наиболее удаленных друг от друга MBR
  74. max_distance = 0.0 # максимальное расстояние между MBR
  75. tmp_entries = [ent for ent in node.entries] # временное хранилище объектов
  76. tmp_entries.append(entry) # добавление нового объекта во временное хранилище
  77. M1 = len(tmp_entries) # размер временного хранилища объектов
  78. # поиск 2 наиболее удаленных друг от друга MBR
  79. for i in range(M1):
  80. for j in range(i+1, M1):
  81. distance = tmp_entries[i].MBR.get_distance(tmp_entries[j].MBR)
  82. if distance > max_distance:
  83. max_distance = distance
  84. max_i = i
  85. max_j = j
  86. # запись 2 наиболее отдалённых друг от друга MBR
  87. e1 = tmp_entries[max_i]
  88. e2 = tmp_entries[max_j]
  89. all_exts = [] # массив для всех оставшихся объектов
  90. # добавление оставшихся объектов
  91. for ext in tmp_entries:
  92. if ext is not e1 and ext is not e2:
  93. all_exts.append(ext)
  94. # добавление в новые узлы полученных объектов и последующее обновление узлов
  95. L1.entries.append(e1)
  96. L2.entries.append(e2)
  97. L1.update()
  98. L2.update()
  99. # мы продолжаем вставлять остальные MBR в каждый из новых узлов, так чтобы увеличение общей площади MBR в каждом узле было минимально
  100. while len(all_exts):
  101. num_remained = len(all_exts)
  102. current_node = None
  103. if len(L1.entries) == (m - num_remained):
  104. current_node = L1
  105. elif len(L2.entries) == (m - num_remained):
  106. current_node = L2
  107. if current_node is not None:
  108. while len(all_exts):
  109. ext = all_exts.pop()
  110. current_node.entries.append(ext)
  111. else:
  112. minimal_area = union_extent(L1.extent, L2.extent).get_area()
  113. minimal_next = -1
  114. current_node = None
  115. for i in range(len(all_exts)):
  116. tmp_ext1 = union_extent(L1.extent, all_exts[i].MBR)
  117. tmp_area1 = tmp_ext1.get_area() - L1.extent.get_area()
  118. tmp_ext2 = union_extent(L2.extent, all_exts[i].MBR)
  119. tmp_area2 = tmp_ext2.get_area() - L2.extent.get_area()
  120. if min(tmp_area1, tmp_area2) > minimal_area:
  121. continue
  122. minimal_next = i
  123. if tmp_area1 < tmp_area2 and tmp_area1 < minimal_area:
  124. tmp_current_node = L1
  125. minimal_area = tmp_area1
  126. elif tmp_area1 > tmp_area2 and tmp_area2 < minimal_area:
  127. tmp_current_node = L2
  128. minimal_area = tmp_area2
  129. else:
  130. minimal_area = tmp_area1
  131. if L1.extent.get_area() < L2.extent.get_area():
  132. tmp_current_node = L1
  133. elif L1.extent.get_area() > L2.extent.get_area():
  134. tmp_current_node = L2
  135. else:
  136. if len(L1.entries) < len(L2.entries):
  137. tmp_current_node = L1
  138. else:
  139. tmp_current_node = L2
  140. if minimal_next != -1 and tmp_current_node is not None:
  141. ext = all_exts.pop(minimal_next)
  142. current_node = tmp_current_node
  143. current_node.entries.append(ext)
  144. current_node.update()
  145. for ent in L1.entries:
  146. ent.node = L1
  147. if ent.child is not None:
  148. ent.child.parent = ent
  149. # после вставки всех объектов
  150. split(node, L1, L2) # разделение узла
  151. # обновление полученных узлов
  152. L1.update_up()
  153. L2.update_up()
  154. return True
  155. def split(node, L1, L2):
  156. # получаем MBR узлов
  157. entry1 = Entry(L1.extent)
  158. entry2 = Entry(L2.extent)
  159. # если расщепляется корень, то удаляем текущие записи в корне и повторно заполняем его новыми записями
  160. if node.is_root():
  161. node.entries = []
  162. entry1.node = node
  163. entry2.node = node
  164. entry1.child = L1
  165. entry2.child = L2
  166. node.entries.append(entry1)
  167. node.entries.append(entry2)
  168. L1.parent = entry1
  169. L2.parent = entry2
  170. return
  171. else: # иначе один из узлов заменяется на новый, а другой вставляется в родительский узел через insert
  172. entry1.node = L1
  173. L1.parent = node.parent
  174. L1.parent.child = L1
  175. del node
  176. insert(L1.parent.node, L2.extent, L2)
  177. return
  178. def search_rtree_extent(node, e): # поиск по rtree через заданный MBR
  179. if node.is_leaf(): # если текущий узел - лист, то возвращаем его
  180. return node
  181. best_entry = None # MBR с наибольшим пересечением к заданному
  182. intersect_area = -1 # максимальная зона покрытия
  183. for ent in node.entries:
  184. tmp_area = ent.MBR.get_intersect(e) # зона покрытия между заданным MBR и текущим
  185. if tmp_area > intersect_area: # если полученная зона больше максимальной, то изменяем MBR с наибольшим покрытием и максимальную зону
  186. intersect_area = tmp_area
  187. best_entry = ent
  188. return search_rtree_extent(best_entry.child, e) # рекурсивно идём в следующий узел, который является потомком объекта с наибольшем MBR