Advertisement
Guest User

Untitled

a guest
Jul 1st, 2015
204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.80 KB | None | 0 0
  1. from geometry import Point
  2.  
  3. class Rect:
  4. def __init__(self, *args):
  5. if len(args) == 4: #scalars
  6. self.left, self.top, self.right, self.bottom = args
  7. elif len(args) == 2: #Points
  8. self.__init__(*(args[0].tuple() + args[1].tuple()))
  9. else:
  10. raise Exception("Need 4 scalars or 2 points, got {}".format(len(args)))
  11.  
  12. @property
  13. def height(self):
  14. return self.bottom - self.top
  15. @property
  16. def width(self):
  17. return self.right - self.left
  18.  
  19. def contains(self, p):
  20. return self.left <= p.x < self.right and self.top <= p.y <= self.bottom
  21.  
  22. def overlaps(self, other):
  23. #returns true if line segment AB shares a common segment with line segment CD.
  24. def intersects(a,b,c,d):
  25. #returns true if x lies between a and b.
  26. def lies_between(x,a,b):
  27. return a <= x < b
  28. return lies_between(a, c, d) or lies_between(b, c, d) or lies_between(c, a, b) or lies_between(d, a, b)
  29. return intersects(self.left, self.right, other.left, other.right) and intersects(self.top, self.bottom, other.top, other.bottom)
  30.  
  31. def copy(self, **d):
  32. return Rect(*[d.get(attr, getattr(self, attr)) for attr in "left top right bottom".split()])
  33.  
  34. def corners(self):
  35. return (Point(self.left, self.top), Point(self.right, self.bottom))
  36. def tuple(self):
  37. return (self.left, self.top, self.right, self.bottom)
  38.  
  39. def map(self, f):
  40. new_corners = [p.map(f) for p in self.corners()]
  41. return Rect(*new_corners)
  42. def pmap(self, f):
  43. new_corners = [f(p) for p in self.corners()]
  44. return Rect(*new_corners)
  45.  
  46.  
  47.  
  48. def bisect(rect, p):
  49. if rect.height > rect.width:
  50. return [rect.copy(bottom=p.y), rect.copy(top=p.y)]
  51. else:
  52. return [rect.copy(left=p.x), rect.copy(right=p.x)]
  53.  
  54.  
  55. class KD_Tree:
  56. def __init__(self, rect):
  57. self.rect = rect
  58. self.p = None
  59. self.children = []
  60. def add(self, p):
  61. assert self.rect.contains(p)
  62. if self.p is None:
  63. self.p = p
  64. else:
  65. if not self.children:
  66. self.children = [KD_Tree(rect) for rect in bisect(self.rect, self.p)]
  67. for child in self.children:
  68. if child.rect.contains(p):
  69. child.add(p)
  70. return
  71. raise Exception("could not find branch for {}".format(p))
  72. def iter(self):
  73. if self.p is not None:
  74. yield self.p
  75. for child in self.children:
  76. for item in child.iter():
  77. yield item
  78. def iter_in_range(self, rect):
  79. if self.p is None:
  80. return
  81. if rect.contains(self.p):
  82. yield self.p
  83. for child in self.children:
  84. if rect.overlaps(child.rect):
  85. for item in child.iter_in_range(rect):
  86. yield item
  87.  
  88.  
  89. from PIL import Image, ImageDraw
  90.  
  91. def render(tree):
  92. #we want the resulting image to have at least one dimension that is this big
  93. target_size = 500
  94.  
  95. margin = 10
  96.  
  97. scale = target_size / float(max(tree.rect.width, tree.rect.height))
  98.  
  99. width = int(tree.rect.width * scale) + margin*2
  100. height = int(tree.rect.height * scale) + margin*2
  101. dx = tree.rect.left
  102. dy = tree.rect.top
  103. delta = Point(dx,dy)
  104.  
  105. img = Image.new("RGB", (width, height), "white")
  106. draw = ImageDraw.Draw(img)
  107.  
  108. def logical_to_screen(p):
  109. return (((p - delta) * scale) + Point(margin, margin)).map(int)
  110.  
  111. def dot(p, radius, **options):
  112. a = p - Point(radius, radius)
  113. b = p + Point(radius, radius)
  114. draw.chord(a.tuple() + b.tuple(), 0, 359, **options)
  115.  
  116. def box(rect, **options):
  117. draw.rectangle(rect.tuple(), **options)
  118.  
  119. def render_node(node):
  120. if node.p is not None:
  121. dot(logical_to_screen(node.p), 2, fill="black")
  122. for child in node.children:
  123. box(child.rect.pmap(logical_to_screen), outline="black")
  124. render_node(child)
  125.  
  126. render_node(tree)
  127. radius = 1
  128. search_vector = Point(radius, radius)
  129. for p in tree.iter():
  130. area = Rect(p - search_vector, p + search_vector)
  131. for neighbor in tree.iter_in_range(area):
  132. draw.line(logical_to_screen(p).tuple() + logical_to_screen(neighbor).tuple(), fill="red")
  133.  
  134. return img
  135.  
  136.  
  137. def render_random_tree():
  138. import random
  139. random.seed(0)
  140. def rand_point(field):
  141. return Point(random.uniform(field.left, field.right), random.uniform(field.top, field.bottom))
  142.  
  143. field = Rect(0,0,10,10)
  144. t = KD_Tree(field)
  145.  
  146. for i in range(100):
  147. t.add(rand_point(field))
  148. render(t).save("output.png")
  149.  
  150. render_random_tree()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement