def test(): pygame.init() screen = pygame.display.set_mode((W, H), 0) quadtree = Quadtree((0, 0, W, H)) triangles = [] p = (0, 0) while True: new_triangles = False new_point = False update = False events = pygame.event.get() for e in events: if e.type == pygame.QUIT: return elif e.type == pygame.KEYUP and e.key == pygame.K_ESCAPE: return elif e.type == pygame.KEYUP and e.key == pygame.K_SPACE: new_triangles = True elif e.type == pygame.KEYUP and e.key == pygame.K_RETURN: new_point = True elif e.type == pygame.MOUSEBUTTONUP: p = e.pos update = True print p if new_triangles: for i in range(N_triangles): quadtree.remove(i) print "foo" triangles = [] for i in range(N_triangles): triangles.append(get_random_triangle()) quadtree.add(i, triangles[-1]) print triangles[-1] if new_point: p = get_random_point() if new_point or new_triangles or update: screen.fill(BLACK) ids = quadtree.query(p) print ids for i in range(N_triangles): color = GREEN if i in ids else BLUE pygame.draw.lines(screen, color, True, triangles[i]) pygame.draw.line(screen, RED, (p[0]-2, p[1]-2), (p[0]+2, p[1]+2)) pygame.draw.line(screen, RED, (p[0]-2, p[1]+2), (p[0]+2, p[1]-2)) pygame.display.update()
def capgrids_tree(): tree = Quadtree((-180, -90, 180, 90)) keys = {} i = 0 for mapid in range(1, 100): mapid = str(mapid) for letter in 'abcdefghijklmnop': for num in range(1, 10): try: b = box(mapid, letter + str(num)) except IndexError: continue v = "%s/%s" % (mapid, (letter + str(num)).capitalize()) if v not in keys: tree.add(i, b) keys[i] = v i += 1 return keys, tree
class Map: def __init__(self, definition_file, points): # Open definition file and background image definition = ElementTree.parse(open(definition_file)).getroot() map_file = os.path.join(os.path.split(definition_file)[0], definition.attrib['bg']) self.background = Image.open(map_file) self.north = math.radians(float(definition.attrib['maxlat'])) self.south = math.radians(float(definition.attrib['minlat'])) self.west = math.radians(float(definition.attrib['minlon'])) self.east = math.radians(float(definition.attrib['maxlon'])) # Store ranges color and distance self.ranges = [(float(r.attrib['distance']), (int(r.attrib['red']), int(r.attrib['green']), int(r.attrib['blue']))) for r in definition.getiterator("range")] self.width, self.height = self.background.size self.points = points # Creating top quadtree element self.grid = Quadtree(self.north, self.south, self.west, self.east, 6) for point in points: self.grid.add(point) # Precompute latitude and longitude at each row and column self.pixel_lons = [self.west + (self.east-self.west)*(float(i)/float(self.width)) for i in range(self.width)] self.pixel_lats = [self.north - (self.north-self.south)*(float(j)/float(self.height)) for j in range(self.height)] def generate(self): "Generates the output image" ranges_image = Image.new('RGB', self.background.size) # Create a lists list with the distance from each pixel to its nearest point colors = [[self.color(self.distance(i,j)) for i in range(self.width)] for j in range(self.height)] # Flatten list colors = [item for sublist in colors for item in sublist] ranges_image.putdata(colors) return Image.blend(ranges_image, self.background.convert('RGB'), 0.5) def distance(self, i, j): lon = self.pixel_lons[i] lat = self.pixel_lats[j] point = Point(lat, lon) elements = PriorityQueue() elements.put_nowait((self.grid.distance(point), self.grid)) # We iterate over the priority queue until the nearest element is a point. While it isn't we add its children to the queue. while True: (distance, elem) = elements.get_nowait() #print "Iterating (%d, %d) distance: %f" % (i, j, distance) if isinstance(elem, Point): return distance else: for child in elem.children: elements.put_nowait((child.distance(point), child)) def color(self, distance): "Returns which color represents distance" return [c for (d,c) in self.ranges if d>distance][0]
class View(object): """ View class for gaphas.Canvas objects. """ def __init__(self, canvas=None): self._matrix = Matrix() self._painter = DefaultPainter(self) self._bounding_box_painter = BoundingBoxPainter(self) # Handling selections. ### TODO: Move this to a context? self._selected_items = set() self._focused_item = None self._hovered_item = None self._dropzone_item = None ###/ self._qtree = Quadtree() self._bounds = Rectangle(0, 0, 0, 0) self._canvas = None if canvas: self._set_canvas(canvas) matrix = property(lambda s: s._matrix, doc="Canvas to view transformation matrix") def _set_canvas(self, canvas): """ Use view.canvas = my_canvas to set the canvas to be rendered in the view. """ if self._canvas: self._qtree.clear() self._selected_items.clear() self._focused_item = None self._hovered_item = None self._dropzone_item = None self._canvas = canvas canvas = property(lambda s: s._canvas, _set_canvas) def emit(self, *args, **kwargs): """ Placeholder method for signal emission functionality. """ pass def queue_draw_item(self, *items): """ Placeholder for item redraw queueing. """ pass def select_item(self, item): """ Select an item. This adds @item to the set of selected items. """ self.queue_draw_item(item) if item not in self._selected_items: self._selected_items.add(item) self.emit('selection-changed', self._selected_items) def unselect_item(self, item): """ Unselect an item. """ self.queue_draw_item(item) if item in self._selected_items: self._selected_items.discard(item) self.emit('selection-changed', self._selected_items) def select_all(self): for item in self.canvas.get_all_items(): self.select_item(item) def unselect_all(self): """ Clearing the selected_item also clears the focused_item. """ self.queue_draw_item(*self._selected_items) self._selected_items.clear() self.focused_item = None self.emit('selection-changed', self._selected_items) selected_items = property(lambda s: s._selected_items, select_item, unselect_all, "Items selected by the view") def _set_focused_item(self, item): """ Set the focused item, this item is also added to the selected_items set. """ if not item is self._focused_item: self.queue_draw_item(self._focused_item, item) if item: self.select_item(item) if item is not self._focused_item: self._focused_item = item self.emit('focus-changed', item) def _del_focused_item(self): """ Items that loose focus remain selected. """ self._set_focused_item(None) focused_item = property(lambda s: s._focused_item, _set_focused_item, _del_focused_item, "The item with focus (receives key events a.o.)") def _set_hovered_item(self, item): """ Set the hovered item. """ if item is not self._hovered_item: self.queue_draw_item(self._hovered_item, item) self._hovered_item = item self.emit('hover-changed', item) def _del_hovered_item(self): """ Unset the hovered item. """ self._set_hovered_item(None) hovered_item = property(lambda s: s._hovered_item, _set_hovered_item, _del_hovered_item, "The item directly under the mouse pointer") def _set_dropzone_item(self, item): """ Set dropzone item. """ if item is not self._dropzone_item: self.queue_draw_item(self._dropzone_item, item) self._dropzone_item = item self.emit('dropzone-changed', item) def _del_dropzone_item(self): """ Unset dropzone item. """ self._set_dropzone_item(None) dropzone_item = property(lambda s: s._dropzone_item, _set_dropzone_item, _del_dropzone_item, 'The item which can group other items') def _set_painter(self, painter): """ Set the painter to use. Painters should implement painter.Painter. """ self._painter = painter painter.set_view(self) self.emit('painter-changed') painter = property(lambda s: s._painter, _set_painter) def _set_bounding_box_painter(self, painter): """ Set the painter to use for bounding box calculations. """ self._bounding_box_painter = painter painter.set_view(self) self.emit('painter-changed') bounding_box_painter = property(lambda s: s._bounding_box_painter, _set_bounding_box_painter) def get_item_at_point(self, pos, selected=True): """ Return the topmost item located at ``pos`` (x, y). Parameters: - selected: if False returns first non-selected item """ items = self._qtree.find_intersect((pos[0], pos[1], 1, 1)) for item in self._canvas.sort(items, reverse=True): if not selected and item in self.selected_items: continue # skip selected items v2i = self.get_matrix_v2i(item) ix, iy = v2i.transform_point(*pos) if item.point((ix, iy)) < 0.5: return item return None def get_handle_at_point(self, pos, distance=6): """ Look for a handle at ``pos`` and return the tuple (item, handle). """ def find(item): """ Find item's handle at pos """ v2i = self.get_matrix_v2i(item) d = v2i.transform_distance(distance, 0)[0] x, y = v2i.transform_point(*pos) for h in item.handles(): if not h.movable: continue hx, hy = h.pos if -d < (hx - x) < d and -d < (hy - y) < d: return h # The focused item is the prefered item for handle grabbing if self.focused_item: h = find(self.focused_item) if h: return self.focused_item, h # then try hovered item if self.hovered_item: h = find(self.hovered_item) if h: return self.hovered_item, h # Last try all items, checking the bounding box first x, y = pos items = self.get_items_in_rectangle((x - distance, y - distance, distance * 2, distance * 2), reverse=True) found_item, found_h = None, None for item in items: h = find(item) if h: return item, h return None, None def get_port_at_point(self, vpos, distance=10, exclude=None): """ Find item with port closest to specified position. List of items to be ignored can be specified with `exclude` parameter. Tuple is returned - found item - closest, connectable port - closest point on found port (in view coordinates) :Parameters: vpos Position specified in view coordinates. distance Max distance from point to a port (default 10) exclude Set of items to ignore. """ v2i = self.get_matrix_v2i vx, vy = vpos max_dist = distance port = None glue_pos = None item = None rect = (vx - distance, vy - distance, distance * 2, distance * 2) items = self.get_items_in_rectangle(rect, reverse=True) for i in items: if i in exclude: continue for p in i.ports(): if not p.connectable: continue ix, iy = v2i(i).transform_point(vx, vy) pg, d = p.glue((ix, iy)) if d >= max_dist: continue item = i port = p # transform coordinates from connectable item space to view # space i2v = self.get_matrix_i2v(i).transform_point glue_pos = i2v(*pg) return item, port, glue_pos def get_items_in_rectangle(self, rect, intersect=True, reverse=False): """ Return the items in the rectangle 'rect'. Items are automatically sorted in canvas' processing order. """ if intersect: items = self._qtree.find_intersect(rect) else: items = self._qtree.find_inside(rect) return self._canvas.sort(items, reverse=reverse) def select_in_rectangle(self, rect): """ Select all items who have their bounding box within the rectangle @rect. """ items = self._qtree.find_inside(rect) map(self.select_item, items) def zoom(self, factor): """ Zoom in/out by factor @factor. """ # TODO: should the scale factor be clipped? self._matrix.scale(factor, factor) # Make sure everything's updated #map(self.update_matrix, self._canvas.get_all_items()) self.request_update((), self._canvas.get_all_items()) def set_item_bounding_box(self, item, bounds): """ Update the bounding box of the item. ``bounds`` is in view coordinates. Coordinates are calculated back to item coordinates, so matrix-only updates can occur. """ v2i = self.get_matrix_v2i(item).transform_point ix0, iy0 = v2i(bounds.x, bounds.y) ix1, iy1 = v2i(bounds.x1, bounds.y1) self._qtree.add(item=item, bounds=bounds, data=Rectangle(ix0, iy0, x1=ix1, y1=iy1)) def get_item_bounding_box(self, item): """ Get the bounding box for the item, in view coordinates. """ return self._qtree.get_bounds(item) bounding_box = property(lambda s: s._bounds) def update_bounding_box(self, cr, items=None): """ Update the bounding boxes of the canvas items for this view, in canvas coordinates. """ painter = self._bounding_box_painter if items is None: items = self.canvas.get_all_items() # The painter calls set_item_bounding_box() for each rendered item. painter.paint(Context(cairo=cr, items=items, area=None)) # Update the view's bounding box with the rest of the items self._bounds = Rectangle(*self._qtree.soft_bounds) def paint(self, cr): self._painter.paint(Context(cairo=cr, items=self.canvas.get_all_items(), area=None)) def get_matrix_i2v(self, item): """ Get Item to View matrix for ``item``. """ if self not in item._matrix_i2v: self.update_matrix(item) return item._matrix_i2v[self] def get_matrix_v2i(self, item): """ Get View to Item matrix for ``item``. """ if self not in item._matrix_v2i: self.update_matrix(item) return item._matrix_v2i[self] def update_matrix(self, item): """ Update item matrices related to view. """ try: i2v = item._matrix_i2c.multiply(self._matrix) except AttributeError: # Fall back to old behaviour i2v = item._matrix_i2c * self._matrix item._matrix_i2v[self] = i2v v2i = Matrix(*i2v) v2i.invert() item._matrix_v2i[self] = v2i def _clear_matrices(self): """ Clear registered data in Item's _matrix{i2c|v2i} attributes. """ for item in self.canvas.get_all_items(): try: del item._matrix_i2v[self] del item._matrix_v2i[self] except KeyError: pass
class View(object): """ View class for gaphas.Canvas objects. """ def __init__(self, canvas=None): self._matrix = Matrix() self._painter = DefaultPainter(self) self._bounding_box_painter = BoundingBoxPainter(self) # Handling selections. ### TODO: Move this to a context? self._selected_items = set() self._focused_item = None self._hovered_item = None self._dropzone_item = None ###/ self._qtree = Quadtree() self._bounds = Rectangle(0, 0, 0, 0) self._canvas = None if canvas: self._set_canvas(canvas) matrix = property(lambda s: s._matrix, doc="Canvas to view transformation matrix") def _set_canvas(self, canvas): """ Use view.canvas = my_canvas to set the canvas to be rendered in the view. """ if self._canvas: self._qtree.clear() self._selected_items.clear() self._focused_item = None self._hovered_item = None self._dropzone_item = None self._canvas = canvas canvas = property(lambda s: s._canvas, _set_canvas) def emit(self, *args, **kwargs): """ Placeholder method for signal emission functionality. """ pass def queue_draw_item(self, *items): """ Placeholder for item redraw queueing. """ pass def select_item(self, item): """ Select an item. This adds @item to the set of selected items. """ self.queue_draw_item(item) if item not in self._selected_items: self._selected_items.add(item) self.emit('selection-changed', self._selected_items) def unselect_item(self, item): """ Unselect an item. """ self.queue_draw_item(item) if item in self._selected_items: self._selected_items.discard(item) self.emit('selection-changed', self._selected_items) def select_all(self): for item in self.canvas.get_all_items(): self.select_item(item) def unselect_all(self): """ Clearing the selected_item also clears the focused_item. """ self.queue_draw_item(*self._selected_items) self._selected_items.clear() self.focused_item = None self.emit('selection-changed', self._selected_items) selected_items = property(lambda s: s._selected_items, select_item, unselect_all, "Items selected by the view") def _set_focused_item(self, item): """ Set the focused item, this item is also added to the selected_items set. """ if not item is self._focused_item: self.queue_draw_item(self._focused_item, item) if item: self.select_item(item) if item is not self._focused_item: self._focused_item = item self.emit('focus-changed', item) def _del_focused_item(self): """ Items that loose focus remain selected. """ self._set_focused_item(None) focused_item = property(lambda s: s._focused_item, _set_focused_item, _del_focused_item, "The item with focus (receives key events a.o.)") def _set_hovered_item(self, item): """ Set the hovered item. """ if item is not self._hovered_item: self.queue_draw_item(self._hovered_item, item) self._hovered_item = item self.emit('hover-changed', item) def _del_hovered_item(self): """ Unset the hovered item. """ self._set_hovered_item(None) hovered_item = property(lambda s: s._hovered_item, _set_hovered_item, _del_hovered_item, "The item directly under the mouse pointer") def _set_dropzone_item(self, item): """ Set dropzone item. """ if item is not self._dropzone_item: self.queue_draw_item(self._dropzone_item, item) self._dropzone_item = item self.emit('dropzone-changed', item) def _del_dropzone_item(self): """ Unset dropzone item. """ self._set_dropzone_item(None) dropzone_item = property(lambda s: s._dropzone_item, _set_dropzone_item, _del_dropzone_item, 'The item which can group other items') def _set_painter(self, painter): """ Set the painter to use. Painters should implement painter.Painter. """ self._painter = painter painter.set_view(self) self.emit('painter-changed') painter = property(lambda s: s._painter, _set_painter) def _set_bounding_box_painter(self, painter): """ Set the painter to use for bounding box calculations. """ self._bounding_box_painter = painter painter.set_view(self) self.emit('painter-changed') bounding_box_painter = property(lambda s: s._bounding_box_painter, _set_bounding_box_painter) def get_item_at_point(self, pos, selected=True): """ Return the topmost item located at ``pos`` (x, y). Parameters: - selected: if False returns first non-selected item """ items = self._qtree.find_intersect((pos[0], pos[1], 1, 1)) for item in self._canvas.sort(items, reverse=True): if not selected and item in self.selected_items: continue # skip selected items v2i = self.get_matrix_v2i(item) ix, iy = v2i.transform_point(*pos) if item.point((ix, iy)) < 0.5: return item return None def get_handle_at_point(self, pos, distance=6): """ Look for a handle at ``pos`` and return the tuple (item, handle). """ def find(item): """ Find item's handle at pos """ v2i = self.get_matrix_v2i(item) d = v2i.transform_distance(distance, 0)[0] x, y = v2i.transform_point(*pos) for h in item.handles(): if not h.movable: continue hx, hy = h.pos if -d < (hx - x) < d and -d < (hy - y) < d: return h # The focused item is the prefered item for handle grabbing if self.focused_item: h = find(self.focused_item) if h: return self.focused_item, h # then try hovered item if self.hovered_item: h = find(self.hovered_item) if h: return self.hovered_item, h # Last try all items, checking the bounding box first x, y = pos items = self.get_items_in_rectangle( (x - distance, y - distance, distance * 2, distance * 2), reverse=True) found_item, found_h = None, None for item in items: h = find(item) if h: return item, h return None, None def get_port_at_point(self, vpos, distance=10, exclude=None): """ Find item with port closest to specified position. List of items to be ignored can be specified with `exclude` parameter. Tuple is returned - found item - closest, connectable port - closest point on found port (in view coordinates) :Parameters: vpos Position specified in view coordinates. distance Max distance from point to a port (default 10) exclude Set of items to ignore. """ v2i = self.get_matrix_v2i vx, vy = vpos max_dist = distance port = None glue_pos = None item = None rect = (vx - distance, vy - distance, distance * 2, distance * 2) items = self.get_items_in_rectangle(rect, reverse=True) for i in items: if i in exclude: continue for p in i.ports(): if not p.connectable: continue ix, iy = v2i(i).transform_point(vx, vy) pg, d = p.glue((ix, iy)) if d >= max_dist: continue item = i port = p # transform coordinates from connectable item space to view # space i2v = self.get_matrix_i2v(i).transform_point glue_pos = i2v(*pg) return item, port, glue_pos def get_items_in_rectangle(self, rect, intersect=True, reverse=False): """ Return the items in the rectangle 'rect'. Items are automatically sorted in canvas' processing order. """ if intersect: items = self._qtree.find_intersect(rect) else: items = self._qtree.find_inside(rect) return self._canvas.sort(items, reverse=reverse) def select_in_rectangle(self, rect): """ Select all items who have their bounding box within the rectangle @rect. """ items = self._qtree.find_inside(rect) map(self.select_item, items) def zoom(self, factor): """ Zoom in/out by factor @factor. """ # TODO: should the scale factor be clipped? self._matrix.scale(factor, factor) # Make sure everything's updated #map(self.update_matrix, self._canvas.get_all_items()) self.request_update((), self._canvas.get_all_items()) def set_item_bounding_box(self, item, bounds): """ Update the bounding box of the item. ``bounds`` is in view coordinates. Coordinates are calculated back to item coordinates, so matrix-only updates can occur. """ v2i = self.get_matrix_v2i(item).transform_point ix0, iy0 = v2i(bounds.x, bounds.y) ix1, iy1 = v2i(bounds.x1, bounds.y1) self._qtree.add(item=item, bounds=bounds, data=Rectangle(ix0, iy0, x1=ix1, y1=iy1)) def get_item_bounding_box(self, item): """ Get the bounding box for the item, in view coordinates. """ return self._qtree.get_bounds(item) bounding_box = property(lambda s: s._bounds) def update_bounding_box(self, cr, items=None): """ Update the bounding boxes of the canvas items for this view, in canvas coordinates. """ painter = self._bounding_box_painter if items is None: items = self.canvas.get_all_items() # The painter calls set_item_bounding_box() for each rendered item. painter.paint(Context(cairo=cr, items=items, area=None)) # Update the view's bounding box with the rest of the items self._bounds = Rectangle(*self._qtree.soft_bounds) def paint(self, cr): self._painter.paint( Context(cairo=cr, items=self.canvas.get_all_items(), area=None)) def get_matrix_i2v(self, item): """ Get Item to View matrix for ``item``. """ if self not in item._matrix_i2v: self.update_matrix(item) return item._matrix_i2v[self] def get_matrix_v2i(self, item): """ Get View to Item matrix for ``item``. """ if self not in item._matrix_v2i: self.update_matrix(item) return item._matrix_v2i[self] def update_matrix(self, item): """ Update item matrices related to view. """ try: i2v = item._matrix_i2c.multiply(self._matrix) except AttributeError: # Fall back to old behaviour i2v = item._matrix_i2c * self._matrix item._matrix_i2v[self] = i2v v2i = Matrix(*i2v) v2i.invert() item._matrix_v2i[self] = v2i def _clear_matrices(self): """ Clear registered data in Item's _matrix{i2c|v2i} attributes. """ for item in self.canvas.get_all_items(): try: del item._matrix_i2v[self] del item._matrix_v2i[self] except KeyError: pass
def main(): parser = argparse.ArgumentParser() parser.add_argument('-d', type=int, action='store', dest='data_num', help='choose which data set to use') if len(sys.argv) != 3: print 'Command e.g.: python findNearPlace.py -d 0(1,2)' sys.exit(1) para = parser.parse_args() if para.data_num == 0: location_infile = settings["ROOT_PATH"] + settings["SRC_DATA_FILE1_1"] nearplace_outfile = settings["ROOT_PATH"] + settings["NEAR_PLACE_FILE1"] elif para.data_num == 1: location_infile = settings["ROOT_PATH"] + settings["SRC_DATA_FILE2_1"] nearplace_outfile = settings["ROOT_PATH"] + settings["NEAR_PLACE_FILE2"] elif para.data_num == 2: location_infile = settings["ROOT_PATH"] + settings["SRC_DATA_FILE3_3"] nearplace_outfile = settings["ROOT_PATH"] + settings["NEAR_PLACE_FILE3"] else: print 'Invalid choice of data set' sys.exit(1) loc_latlng = {} try: for entry in csv.reader(open(location_infile, 'rU')): pid, lat, lng = int(entry[0]), float(entry[2]), float(entry[3]) loc_latlng[pid] = (lat, lng) except: print entry sys.exit(1) # directly scanning all POIs to get answer, which is too slow '''writer = csv.writer(open(nearplace_outfile, "w"), lineterminator="\r\n") pids = loc_latlng.keys() for i in xrange(len(pids)): pid1 = pids[i] near_place = [] for j in xrange(len(pids)): pid2 = pids[j] dis = distance.distance(loc_latlng[pid1], loc_latlng[pid2]).miles if dis < settings["DISTANCE_THRESHOLD"]: near_place.append(pid2) writer.writerow([pid1] + near_place) print i''' # quad tree index_extent = (-90, -180, 90, 180) index = Quadtree(index_extent) for pid in loc_latlng: index.add(pid, loc_latlng[pid]) for pid in loc_latlng: start_time = time.clock() pid_set = findNearPlaceByQuadtree(loc_latlng, loc_latlng[pid], index.struct(), settings["DISTANCE_THRESHOLD"]) end_time = time.clock() print "Time Cost: %f(s)" % (end_time-start_time) raw_input() print len(pid_set) raw_input()
class Map: def __init__(self, definition_file, points): # Open definition file and background image definition = ElementTree.parse(open(definition_file)).getroot() map_file = os.path.join( os.path.split(definition_file)[0], definition.attrib['bg']) self.background = Image.open(map_file) self.north = math.radians(float(definition.attrib['maxlat'])) self.south = math.radians(float(definition.attrib['minlat'])) self.west = math.radians(float(definition.attrib['minlon'])) self.east = math.radians(float(definition.attrib['maxlon'])) # Store ranges color and distance self.ranges = [(float(r.attrib['distance']), (int(r.attrib['red']), int(r.attrib['green']), int(r.attrib['blue']))) for r in definition.getiterator("range")] self.width, self.height = self.background.size self.points = points # Creating top quadtree element self.grid = Quadtree(self.north, self.south, self.west, self.east, 6) for point in points: self.grid.add(point) # Precompute latitude and longitude at each row and column self.pixel_lons = [ self.west + (self.east - self.west) * (float(i) / float(self.width)) for i in range(self.width) ] self.pixel_lats = [ self.north - (self.north - self.south) * (float(j) / float(self.height)) for j in range(self.height) ] def generate(self): "Generates the output image" ranges_image = Image.new('RGB', self.background.size) # Create a lists list with the distance from each pixel to its nearest point colors = [[self.color(self.distance(i, j)) for i in range(self.width)] for j in range(self.height)] # Flatten list colors = [item for sublist in colors for item in sublist] ranges_image.putdata(colors) return Image.blend(ranges_image, self.background.convert('RGB'), 0.5) def distance(self, i, j): lon = self.pixel_lons[i] lat = self.pixel_lats[j] point = Point(lat, lon) elements = PriorityQueue() elements.put_nowait((self.grid.distance(point), self.grid)) # We iterate over the priority queue until the nearest element is a point. While it isn't we add its children to the queue. while True: (distance, elem) = elements.get_nowait() #print "Iterating (%d, %d) distance: %f" % (i, j, distance) if isinstance(elem, Point): return distance else: for child in elem.children: elements.put_nowait((child.distance(point), child)) def color(self, distance): "Returns which color represents distance" return [c for (d, c) in self.ranges if d > distance][0]