Ignore:
Timestamp:
May 5, 2011, 7:43:13 AM (14 years ago)
Author:
rick
Message:

As Dennis proved during his experiments PyGame is _much_ faster than PIL
PyGame is using OpenGL acceleration in the background. So let's use PyGame
instead.

While we are here implement a more pretty signal/range function.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/django_gheat/website/tile.py

    r9147 r9148  
    1313import settings
    1414import sys
     15import pygame
     16import tempfile
    1517
    16 log = logging.getLogger('sample_tile')
    17 logging.basicConfig(level=logging.DEBUG)
    18 setup_environ(settings)
     18logging.basicConfig(level=logging.WARNING)
     19log = logging.getLogger('tile')
     20
     21class PyGamePicture():
     22  """ Basic PyGame class, allowing simple image manipulations """
     23  def __init__(self, method, size):
     24    self.surf = pygame.Surface(size,flags=pygame.SRCALPHA)
     25
     26  def write(self, fh,format='png'):
     27    # XXX: How to get a PNG stream directly to the output
     28    f = tempfile.NamedTemporaryFile(suffix=format)
     29    pygame.image.save(self.surf,f.name)
     30    f.seek(0)
     31    fh.write(f.read())
    1932
    2033
    21 def make_circle(draw, center, radius,colour=(0,255,0)):
    22   """ Cicle gradient is created by creating smaller and smaller cicles """
    23   (center_x, center_y) = center
    24   for i in range(0,radius):
    25     draw.ellipse(
    26       (center_x - radius + i,
    27        center_y - radius + i,
    28        center_x + radius - i,
    29        center_y + radius - i
    30       ),
    31       colour +(255 * i/(radius * 2),)
    32     )
     34  def add_circle(self, center, radius, colour=(255,0,0)):
     35    # Quirky hack to generate lineair gradient circles and merge them with the parent.
     36    new_surf = pygame.Surface((250,250),flags=pygame.SRCALPHA)
     37    for r in range(radius,1,-1):
     38      pygame.draw.circle(new_surf,colour + (255 - (r * (float(255)/radius)),),center,r,0)
     39    self.surf.blit(new_surf,(0,0),special_flags=pygame.BLEND_RGBA_MAX)
    3340
    3441
    35 class Picture():
    36   """ Basic class, allowing simple image manipulations """
     42class PILPicture():
     43  """ Basic PIL class, allowing simple image manipulations """
    3744  im = None
    3845  def __init__(self, method, size):
     
    4047    self.data = np.array(self.im)
    4148
    42   def save(self,*args, **kw):
    43         self.im.save(*args, **kw)
     49  def write(self,fh,format='png'):
     50        self.im.save(fh,format)
     51
     52  def make_circle(self,draw, center, radius,colour=(0,255,0)):
     53    """ Cicle gradient is created by creating smaller and smaller cicles """
     54    (center_x, center_y) = center
     55    for i in range(0,radius):
     56      draw.ellipse(
     57        (center_x - radius + i,
     58         center_y - radius + i,
     59         center_x + radius - i,
     60         center_y + radius - i
     61        ),
     62        colour +(255 * i/(radius * 2),)
     63      )
    4464
    4565  def add_circle(self, center, radius, colour):
     
    5272    im_new = Image.new("RGBA", self.im.size)
    5373    draw = ImageDraw.Draw(im_new)
    54     make_circle(draw, center, radius, colour)
     74    self.make_circle(draw, center, radius, colour)
    5575   
    5676    data2 = np.array(im_new)
     
    103123def make_tile(x,y,z):
    104124  """ Crude attempt to generate tiles, by placing a gradient circle on a
    105   coordinate point. Many stuff NOT implemented yet, like:
    106   * Caching Images
    107   * Behaviour around edges (generate larger imagea)
     125  coordinate point.
     126 
     127  Many stuff NOT implemented yet, like:
     128  - Caching Images
     129  - Generate a larger tile (300x300) at first and then crop it to the required
     130    size (250x250).
    108131  """
    109132  nw_deg,se_deg = boundbox_deg(x,y,z)
    110133 
     134  Picture = PyGamePicture
    111135  resolution_deg = nw_deg.deg_per_pixel(se_deg, 250)
    112136  im = Picture("RGBA",(250,250))
     
    119143     latitude__lte=nw_deg.lat,latitude__gte=se_deg.lat,
    120144     longitude__lte=se_deg.lon,longitude__gte=nw_deg.lon)
    121   if metingen.count() > 100:
    122     metingen = metingen[1:100]
    123145 
    124146  def dif(x,y):
    125147    return max(x,y) - min(x,y)
    126148 
     149  # Converting LatLon to Meters is discussed here:
     150  #  http://stackoverflow.com/questions/3024404/transform-longitude-latitude-into-meters
     151  tile_height = float(40008000) / (2 ** z)
     152  meters_per_pixel = float(tile_height) / 250
    127153  for meting in metingen:
    128154    lat_min = min(lat_min, meting.latitude)
     
    133159    ycoord = dif(nw_deg.lat,meting.latitude) / (resolution_deg.lat)
    134160    log.info(meting.accespoint.ssid, meting.latitude, meting.longitude, xcoord, ycoord)
    135     im.add_circle((xcoord,ycoord),z,(255,0,0))
     161    # The radius relates to the zoom-level we are in, and should represent
     162    # a fixed distance, given the scale. Assume signal/distance to be lineair
     163    # such that signal 100% = 100m and 1% = 1m.
     164    #
     165    # XXX: The relation is not lineair but from a more logeritmic scape, as we
     166    # are dealing with radio signals
     167    im.add_circle((xcoord,ycoord),float(meting.signaal) / meters_per_pixel,(255,0,0))
    136168 
    137169  log.info("BoundingBox NW: %s" % nw_deg)
     
    150182  im = make_tile(int(x),int(y),int(zoom))
    151183  response = HttpResponse(mimetype="image/png")
    152   im.save(response, 'PNG')
     184  im.write(response,'png')
    153185  return response
    154186
    155187if __name__ == '__main__':
     188  log.setLevel(logging.DEBUG)
    156189  x = int(sys.argv[1])
    157190  y = int(sys.argv[2])
     
    160193  im = make_tile(x,y,z)
    161194  filename = 'sample-gradient.png'
    162   im.save(filename)
    163   log.info("#INFO: Output saved as '%s'" % filename)
     195  im.write(open(filename,'w'))
     196  log.info("Output saved as '%s'" % filename)
Note: See TracChangeset for help on using the changeset viewer.