diff --git a/ChangeLog b/ChangeLog index 15c3b2cc9..4bc05d36b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2006-04-10 Martin Hawlisch + * src/DataViews/_MapView.py: Reworked to display multiple smaller + tiled map images + * src/images/mk_blue_marble.py: Script to create the map tiles out of + the nasa blue marble image + * src/images/Makefile.am: Add map tile images and bootstrap them using + mk_blue_marble.py + 2006-04-10 Nathan Bullock * src/GrampsDb/_ReadGedcom.py: LDS fixes. * src/Editors/_EditLdsOrd.py: LDS fixes. diff --git a/src/DataViews/_MapView.py b/src/DataViews/_MapView.py index 9b486ae9a..19bb66d8b 100644 --- a/src/DataViews/_MapView.py +++ b/src/DataViews/_MapView.py @@ -30,6 +30,7 @@ import gc import re import logging import os +import math log = logging.getLogger(".") @@ -51,6 +52,7 @@ import RelLib import PageView import const +# Some initial places for debugging glob_loc_data = [ # (Name, longitude, latitude) ("_Center", 0,0), ("_North",0,90), @@ -67,7 +69,12 @@ glob_loc_data = [ # (Name, longitude, latitude) ("Rio de Janeiro",-43.28,-22.88), ("Tokyo",139.75,35.67), ("Cape Town",18.47,-33.93), - ("Anchorage",-150.00,61.17)] + ("Anchorage",-150.00,61.17), + ("Mannheim-Wallstadt",8.55,49.48), + ("Mannheim-Neckarau",8.48,49.45), + ("Gorxheimertal",8.73,49.53)] + +enable_debug = False # Draws a map image and tries to allocate space in the correct aspect ratio @@ -79,13 +86,19 @@ class GuideMap(gtk.DrawingArea): self.connect("size-allocate", self.size_allocate_cb) self.gc = None self.current_area = None + self.current_spot = None self.old_size = (-1,-1) # Set hightlight region def hightlight_area( self, area): self.current_area = area self.queue_draw() - + + # Set hightlight region + def hightlight_spot( self, spot): + self.current_spot = spot + self.queue_draw() + # Redraw the image def expose_cb(self,widget,event): if not self.gc: @@ -101,6 +114,14 @@ class GuideMap(gtk.DrawingArea): self.current_area[3]) self.window.draw_rectangle( self.gc, False, r[0],r[1],r[2],r[3]) + if self.current_spot: + r = self.map_to_screen(self.current_spot[0], + self.current_spot[1]) + self.window.draw_line( self.gc,0,r[1], + self.backbuf.get_width(),r[1]) + self.window.draw_line( self.gc,r[0],0, + r[0],self.backbuf.get_height()) + # Scale backbuffer def size_allocate_cb(self,widget,allocation): @@ -118,32 +139,117 @@ class GuideMap(gtk.DrawingArea): gtk.gdk.INTERP_BILINEAR) gc.collect() - def map_to_screen( self, x,y,w,h): + def map_to_screen( self, x,y,w=None,h=None): px = int((float(x) + 180.0) / 360.0 * self.backbuf.get_width()) py = int((90-float(y)) / 180.0 * self.backbuf.get_height()) - pw = int(float(w) / 360.0 * self.backbuf.get_width()) - ph = int(float(h) / 180.0 * self.backbuf.get_height()) - - return (px,py,pw,ph) + if w and h: + pw = int(float(w) / 360.0 * self.backbuf.get_width()) + ph = int(float(h) / 180.0 * self.backbuf.get_height()) + return (px,py,pw,ph) + return (px,py) +# Map tile files used by the ZoomMap +class MapTile: + def __init__( self, filename, x, y, w, h, pw, ph): + self.filename = filename + self.full_path = os.path.join(const.image_dir,filename) + self.map_x = float(x) + self.map_y = float(y) + self.map_width = float(w) + self.map_height = float(h) + self.map_pixel_width = float(pw) + self.map_pixel_height = float(ph) + self.source_pixbuf = None + self.source_scale = self.map_pixel_width / self.map_width + self.scale = None + self.scaled_pixbuf = None + self.scaled_map_x = None + self.scaled_map_y = None + + def set_viewport( self, target_scale, x_in, y_in, w_in, h_in): + # intersect viewport with map area + x = max(self.map_x, max(-180.0,x_in)) + y = min(self.map_y, min( 90.0,y_in)) + xmax = min( min(180.0,x_in+w_in), self.map_x+self.map_width) + ymin = max( max(-90.0,y_in-h_in), self.map_y-self.map_width) + w = xmax-x + h = y-ymin + + if w > 0.0 and h > 0.0: + # crop source tile to not scale the whole image_dir + xoffset = max(0,math.floor((x - self.map_x) * self.source_scale)) + xmax = max(0,math.ceil((x+w - self.map_x) * self.source_scale)) + yoffset = min(self.map_pixel_width,math.floor(-(y - self.map_y) * self.source_scale)) + ymax = min(self.map_pixel_height,math.ceil(-(y-h - self.map_y) * self.source_scale)) + + rescale = target_scale / self.source_scale + if int((xmax-xoffset)*rescale) > 0 and int((ymax-yoffset)*rescale) > 0: + self.scaled_map_x = self.map_x + xoffset / self.source_scale + self.scaled_map_y = self.map_y - yoffset / self.source_scale + self.scaled_map_pixel_w = int((xmax-xoffset)*rescale) + self.scaled_map_pixel_h = int((ymax-yoffset)*rescale) + + if enable_debug: + print + print "Source-Map origin: %f x %f, %f, %f" % (self.map_x,self.map_y,self.map_width,self.map_height) + print "Source-Map pixels: %f x %f" % (self.map_pixel_width,self.map_pixel_height) + print "Source-Map scale: %f" % self.source_scale + print "Target origin: %f x %f, %f, %f" % (x,y,w,h) + print "Target scale: %f" % target_scale + print "Target crop: %f x %f, %f x %f" % (xoffset,yoffset,xmax,ymax) + print "Origin of crop: %f x %f" % (self.scaled_map_x,self.scaled_map_y) + print "scaled tile size: %f x %f pix" % (self.scaled_map_pixel_w,self.scaled_map_pixel_h) + + try: + if not self.source_pixbuf: + self.source_pixbuf = gtk.gdk.pixbuf_new_from_file( self.full_path) + + clip_pixbuf = self.source_pixbuf.subpixbuf(int(xoffset),int(yoffset),int(xmax-xoffset),int(ymax-yoffset)) + + self.scale = target_scale + self.scaled_pixbuf = clip_pixbuf.scale_simple( int((xmax-xoffset)*rescale), int((ymax-yoffset)*rescale), gtk.gdk.INTERP_BILINEAR) + clip_pixbuf = None + except: + pass + + else: + self.scale = None + self.scaled_pixbuf = None + else: + self.scale = None + self.scaled_pixbuf = None + + def free(self): + self.scale = None + self.scaled_pixbuf = None + + # Zoomable map image class ZoomMap( gtk.DrawingArea): - def __init__(self, map_pixbuf, place_marker_pixbuf, - hightlight_marker_pixbuf): + def __init__( self, place_marker_pixbuf, hightlight_marker_pixbuf): gtk.DrawingArea.__init__(self) - self.map_pixbuf = map_pixbuf self.place_marker_pixbuf = place_marker_pixbuf self.hightlight_marker_pixbuf = hightlight_marker_pixbuf + self.add_events(gtk.gdk.POINTER_MOTION_MASK) # position overlay self.connect("expose-event", self.expose_cb) self.connect("size-allocate", self.size_allocate_cb) + if enable_debug: + self.connect("motion-notify-event", self.motion_notify_event_cb) self.gc = None - self.old_size = (-1,-1) + self.current_pixel_size = (-1,-1) self.zoom_pos = (0,0) - self.current_area = (0,0,0,0) - self.magnifer = 0.5 + self.magnifer = 0.0 # in pixel per degree self.guide = None self.textlayout = self.create_pango_layout("") - + self.map_sources = {} + self.initial_exposed = False + + def add_map_source( self,filename, x, y, w, h,pw,ph): + tile = MapTile( filename, x, y, w, h, pw, ph) + if not tile.source_scale in self.map_sources: + self.map_sources[tile.source_scale] = [] + self.map_sources[tile.source_scale].append( tile) + # Set the guide map that should follow the zoom area def set_guide( self, guide): self.guide = guide @@ -154,6 +260,21 @@ class ZoomMap( gtk.DrawingArea): self.idx_long = idx_long self.idx_lat = idx_lat + def motion_notify_event_cb(self,widget,event): + self.textlayout.set_text( "Position: %03.0f,%03.0f pixel" % (event.x,event.y)) + (w,h) = self.textlayout.get_pixel_size() + self.gc.set_foreground( self.get_colormap().alloc_color("white")) + self.window.draw_rectangle( self.gc, True, 10,50,w,h) + self.gc.set_foreground( self.get_colormap().alloc_color("red")) + self.window.draw_layout( self.gc, 10, 50, self.textlayout) + (lon,lat) = self.screen_to_map(event.x,event.y) + self.textlayout.set_text( "Position: %03.0f,%03.0f degree" % (lon,lat)) + (w,h) = self.textlayout.get_pixel_size() + self.gc.set_foreground( self.get_colormap().alloc_color("white")) + self.window.draw_rectangle( self.gc, True, 10,70,w,h) + self.gc.set_foreground( self.get_colormap().alloc_color("red")) + self.window.draw_layout( self.gc, 10, 70, self.textlayout) + # Redraw the image def expose_cb(self,widget,event): if not self.gc: @@ -163,15 +284,28 @@ class ZoomMap( gtk.DrawingArea): if not self.backbuf: self.size_allocate_cb( self,self.get_allocation()) if self.backbuf and self.gc: - self.window.draw_pixbuf( self.gc, self.backbuf, 0,0, 0,0, -1,-1) - + #draw all maps + scales = self.map_sources.keys() + scales.sort() + for scale in scales: + for map in self.map_sources[scale]: + if map.scaled_pixbuf: + (px,py) = self.map_to_screen( map.scaled_map_x, map.scaled_map_y) + self.window.draw_pixbuf( self.gc, map.scaled_pixbuf, 0,0, px,py) + if enable_debug: + self.window.draw_rectangle( self.gc, False, px,py,map.scaled_map_pixel_w,map.scaled_map_pixel_h) + self.window.draw_line( self.gc, px,py,px+map.scaled_map_pixel_w,py+map.scaled_map_pixel_h) + self.window.draw_line( self.gc, px,py+map.scaled_map_pixel_h,px+map.scaled_map_pixel_w,py) + gc.collect() + + # draw all available locations if self.location_model: iter = self.location_model.get_iter_first() while iter: (n,x,y) = self.location_model.get( iter, self.idx_name, self.idx_long, self.idx_lat) (px,py) = self.map_to_screen( x, y) - if px > 0 and py > 0 and px < self.backbuf.get_width() and py < self.backbuf.get_height(): + #if px > 0 and py > 0 and px < self.backbuf.get_width() and py < self.backbuf.get_height(): # draw only visible markers #self.window.draw_pixbuf( # self.gc, @@ -180,11 +314,11 @@ class ZoomMap( gtk.DrawingArea): # px-self.place_marker_pixbuf.get_width()/2, # py-self.place_marker_pixbuf.get_height()/2, # -1,-1) - self.textlayout.set_text(n) - self.window.draw_layout( - self.gc, - px,py, - self.textlayout) + self.textlayout.set_text(n) + self.window.draw_layout( + self.gc, + px,py, + self.textlayout) iter = self.location_model.iter_next( iter) # hightlight current location @@ -197,78 +331,100 @@ class ZoomMap( gtk.DrawingArea): py-self.hightlight_marker_pixbuf.get_height()/2, -1,-1) #self.window.draw_rectangle( self.gc, False, px-3,py-3, 6,6) + + #(px1,py1) = self.map_to_screen(-180, 90) + #(px2,py2) = self.map_to_screen( 180,-90) + #self.window.draw_rectangle( self.gc, False, px1,py1,px2-px1,py2-py1) + #self.window.draw_line( self.gc, px1,py1,px2,py2) + #self.window.draw_line( self.gc, px1,py2,px2,py1) + if enable_debug: + # Output debugging info + self.textlayout.set_text( "Magnifer: %f pixel per degree" % self.magnifer) + self.window.draw_layout( self.gc, 10, 10, self.textlayout) + self.textlayout.set_text( "Current map: %f pixel per degree" % self.selected_map_scale) + self.window.draw_layout( self.gc, 10, 30, self.textlayout) - def map_to_screen( self, long, lat): - px = int(self.backbuf.get_width() / self.current_map_area[2] * - (float(long) - self.current_map_area[0])) - py = int(self.backbuf.get_height() / self.current_map_area[3] * - (-float(lat) + self.current_map_area[1])) + def map_to_screen( self, lon, lat): + px = int(self.current_pixel_size[0] / 2.0 + (lon - self.zoom_pos[0]) * self.magnifer) + py = int(self.current_pixel_size[1] / 2.0 - (lat - self.zoom_pos[1]) * self.magnifer) return( px, py) - + + def screen_to_map( self, px, py): + px = float(px) + py = float(py) + lon = (px - self.current_pixel_size[0]/2) / self.magnifer + self.zoom_pos[0]; + lat = -(py - self.current_pixel_size[1]/2) / self.magnifer + self.zoom_pos[1]; + return( lon, lat) + # Scale backbuffer def size_allocate_cb(self,widget,allocation): # only create new backbuffer if size is different new_size = (allocation.width,allocation.height) - if new_size is not self.old_size or not self.backbuf: - self.old_size = new_size + if new_size is not self.current_pixel_size or not self.backbuf: + self.backbuf = True + self.current_pixel_size = new_size + if self.magnifer == 0.0: + # scale map to full width + self.magnifer = self.current_pixel_size[0] / 360.0 + x0,y0 = self.screen_to_map( 0, 0) + x1,y1 = self.screen_to_map( new_size[0], new_size[1]) + self.guide.hightlight_area( (x0,y0,x1-x0, y0-y1)) - # Desired midpoint in map - pw = int(self.old_size[0]*self.magnifer) - ph = int(self.old_size[1]*self.magnifer) + def cmpfunc(s): + return((self.magnifer-s)*(self.magnifer-s)) + + # select best matching tile set + self.selected_map_scale = None + smallest_scale = None + largest_scale = None + for s in self.map_sources.keys(): + if not self.selected_map_scale or cmpfunc(s) < cmpfunc(self.selected_map_scale): + self.selected_map_scale = s + if not smallest_scale or s < smallest_scale: + smallest_scale = s + if not largest_scale or s > largest_scale: + largest_scale = s + if enable_debug: + print "scale of display: %f" % self.magnifer + print "available map scales:" + print self.map_sources.keys() + print "largest scale: %f" % largest_scale + print "smallest scale: %f" % smallest_scale + print "selected scale: %f" % self.selected_map_scale - px = int((float(self.zoom_pos[0]) + 180.0) / 360.0 - * self.map_pixbuf.get_width()) - py = int((90-float(self.zoom_pos[1])) / 180.0 - * self.map_pixbuf.get_height()) - - px = max( pw/2, px) - py = max( ph/2, py) - - px = min( px, self.map_pixbuf.get_width()-1-pw/2) - py = min( py, self.map_pixbuf.get_height()-1-ph/2) - - try: - zoomebuf = self.map_pixbuf.subpixbuf( max(0,int(px-pw/2)),max(0,int(py-ph/2)), - min(self.map_pixbuf.get_width(),pw), - min(self.map_pixbuf.get_height(),ph)) - self.backbuf = zoomebuf.scale_simple(self.old_size[0], - self.old_size[1], - gtk.gdk.INTERP_BILINEAR) - gc.collect() - mx = 360.0 / self.map_pixbuf.get_width() * (px-pw/2.0) - 180.0 - my = 90.0 - 180.0 / self.map_pixbuf.get_height() * (py-ph/2.0) - mw = 360.0 / self.map_pixbuf.get_width() * pw - mh = 180.0 / self.map_pixbuf.get_height() * ph - self.current_area = (px-pw/2, py-ph/2, pw,ph) - self.current_map_area = (mx, my, mw, mh) - if self.guide: - self.guide.hightlight_area( (mx,my,mw,mh)) - except: - pass + for s in self.map_sources.keys(): + for map in self.map_sources[s]: + if s == self.selected_map_scale or s == smallest_scale: + map.set_viewport( self.magnifer, x0, y0, x1-x0, y0-y1) + else: + map.free() # Scroll to requested position def scroll_to( self, long, lat): - self.zoom_pos = ( min(180,(max(-180,long))), min(90,(max(-90,lat)))) + self.zoom_pos = (float( min(180,(max(-180,long)))), float(min(90,(max(-90,lat))))) self.backbuf = None + if self.guide: + self.guide.hightlight_spot( self.zoom_pos) self.queue_draw() def zoom_out(self): - self.magnifer = min( 10, self.magnifer * 1.5) + self.magnifer = max( 1.0, self.magnifer * 2.0/3.0) self.backbuf = None self.queue_draw() def zoom_in(self): - self.magnifer = max( 0.1, self.magnifer * 0.75) + self.magnifer = min( 500.0, self.magnifer * 1.5) self.backbuf = None self.queue_draw() def zoom_normal(self): - self.magnifer = 1 + self.magnifer = 1.0 + self.magnifer = self.selected_map_scale self.backbuf = None self.queue_draw() def zoom_fit(self): - self.magnifer = 2 + self.magnifer = self.current_pixel_size[0] / 360.0 self.backbuf = None self.queue_draw() @@ -400,10 +556,54 @@ class MapView(PageView.PageView): no = gtk.Image() # The large zoomable map - self.zoom_map = ZoomMap( - gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"land_shallow_topo_2048.jpg")), + self.zoom_map = ZoomMap( gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"bad.png")), gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"good.png"))) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_0.jpg', -180,90, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_1.jpg', -135,90, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_2.jpg', -90,90, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_3.jpg', -45,90, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_4.jpg', 0,90, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_5.jpg', 45,90, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_6.jpg', 90,90, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_0_7.jpg', 135,90, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_0.jpg', -180,45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_1.jpg', -135,45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_2.jpg', -90,45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_3.jpg', -45,45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_4.jpg', 0,45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_5.jpg', 45,45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_6.jpg', 90,45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_1_7.jpg', 135,45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_0.jpg', -180,0, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_1.jpg', -135,0, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_2.jpg', -90,0, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_3.jpg', -45,0, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_4.jpg', 0,0, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_5.jpg', 45,0, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_6.jpg', 90,0, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_2_7.jpg', 135,0, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_0.jpg', -180,-45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_1.jpg', -135,-45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_2.jpg', -90,-45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_3.jpg', -45,-45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_4.jpg', 0,-45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_5.jpg', 45,-45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_6.jpg', 90,-45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x3200x1600_tile_3_7.jpg', 135,-45, 45,45, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_0_0.jpg', -180,90, 90,90, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_0_1.jpg', -90,90, 90,90, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_0_2.jpg', 0,90, 90,90, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_0_3.jpg', 90,90, 90,90, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_1_0.jpg', -180,0, 90,90, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_1_1.jpg', -90,0, 90,90, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_1_2.jpg', 0,0, 90,90, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x1600x800_tile_1_3.jpg', 90,0, 90,90, 400,400) + self.zoom_map.add_map_source('world.topo.200407.3x800x400.jpg', -180,90, 360,180, 800,400) + self.zoom_map.add_map_source('world.topo.200407.3x400x200.jpg', -180,90, 360,180, 400,200) + self.zoom_map.add_map_source('world.topo.200407.3x128x60.jpg', -180,90, 360,180, 128,60) + + #self.zoom_map.add_map_source("europe_2_0.jpg",0,90,90,90,1024,1024) self.zoom_map.set_size_request(300,300) hbox.pack_start( self.zoom_map, True, True, 0) @@ -413,7 +613,7 @@ class MapView(PageView.PageView): # The small guide map self.guide_map = GuideMap( - gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"land_shallow_topo_350.jpg"))) + gtk.gdk.pixbuf_new_from_file(os.path.join(const.image_dir,"world.topo.200407.3x128x60.jpg"))) self.guide_map.set_size_request(128,64) vbox.pack_start( self.guide_map, False, True, 0) diff --git a/src/images/Makefile.am b/src/images/Makefile.am index 97d49699e..cc6f4c899 100644 --- a/src/images/Makefile.am +++ b/src/images/Makefile.am @@ -12,8 +12,6 @@ dist_pkgdata_DATA = \ flist.svg\ good.png\ gramps.png\ - land_shallow_topo_2048.jpg\ - land_shallow_topo_350.jpg\ locked.png\ logo.png\ media.svg\ @@ -32,6 +30,55 @@ dist_pkgdata_DATA = \ stock_lock.png\ tools.png\ somerights20.gif \ - document.png + document.png\ + world.topo.200407.3x128x60.jpg\ + world.topo.200407.3x400x200.jpg\ + world.topo.200407.3x800x400.jpg\ + world.topo.200407.3x1600x800_tile_0_0.jpg\ + world.topo.200407.3x1600x800_tile_0_1.jpg\ + world.topo.200407.3x1600x800_tile_0_2.jpg\ + world.topo.200407.3x1600x800_tile_0_3.jpg\ + world.topo.200407.3x1600x800_tile_1_0.jpg\ + world.topo.200407.3x1600x800_tile_1_1.jpg\ + world.topo.200407.3x1600x800_tile_1_2.jpg\ + world.topo.200407.3x1600x800_tile_1_3.jpg\ + world.topo.200407.3x3200x1600_tile_0_0.jpg\ + world.topo.200407.3x3200x1600_tile_0_1.jpg\ + world.topo.200407.3x3200x1600_tile_0_2.jpg\ + world.topo.200407.3x3200x1600_tile_0_3.jpg\ + world.topo.200407.3x3200x1600_tile_0_4.jpg\ + world.topo.200407.3x3200x1600_tile_0_5.jpg\ + world.topo.200407.3x3200x1600_tile_0_6.jpg\ + world.topo.200407.3x3200x1600_tile_0_7.jpg\ + world.topo.200407.3x3200x1600_tile_1_0.jpg\ + world.topo.200407.3x3200x1600_tile_1_1.jpg\ + world.topo.200407.3x3200x1600_tile_1_2.jpg\ + world.topo.200407.3x3200x1600_tile_1_3.jpg\ + world.topo.200407.3x3200x1600_tile_1_4.jpg\ + world.topo.200407.3x3200x1600_tile_1_5.jpg\ + world.topo.200407.3x3200x1600_tile_1_6.jpg\ + world.topo.200407.3x3200x1600_tile_1_7.jpg\ + world.topo.200407.3x3200x1600_tile_2_0.jpg\ + world.topo.200407.3x3200x1600_tile_2_1.jpg\ + world.topo.200407.3x3200x1600_tile_2_2.jpg\ + world.topo.200407.3x3200x1600_tile_2_3.jpg\ + world.topo.200407.3x3200x1600_tile_2_4.jpg\ + world.topo.200407.3x3200x1600_tile_2_5.jpg\ + world.topo.200407.3x3200x1600_tile_2_6.jpg\ + world.topo.200407.3x3200x1600_tile_2_7.jpg\ + world.topo.200407.3x3200x1600_tile_3_0.jpg\ + world.topo.200407.3x3200x1600_tile_3_1.jpg\ + world.topo.200407.3x3200x1600_tile_3_2.jpg\ + world.topo.200407.3x3200x1600_tile_3_3.jpg\ + world.topo.200407.3x3200x1600_tile_3_4.jpg\ + world.topo.200407.3x3200x1600_tile_3_5.jpg\ + world.topo.200407.3x3200x1600_tile_3_6.jpg\ + world.topo.200407.3x3200x1600_tile_3_7.jpg + + EXTRA_DIST = gramps.svg + +world.topo.200407.3x800x400.jpg: mk_blue_marble.py + python mk_blue_marble.py + diff --git a/src/images/mk_blue_marble.py b/src/images/mk_blue_marble.py new file mode 100644 index 000000000..55c82b93f --- /dev/null +++ b/src/images/mk_blue_marble.py @@ -0,0 +1,100 @@ +#!/usr/bin/python + +# Script to create smaller map tiles for use in the GRAMPS MapView. +# (c) Martin Hawlisch, martin.hawlisch@gmx.de, 2006. +# I hereby put this script into the public domain. + + +# Images are generated by using the NASA Blue Marble next generation images. +# http://visibleearth.nasa.gov/view_set.php?categoryID=2355 +# July, Blue Marble Next Generation w/ Topography and Bathymetry: +# http://visibleearth.nasa.gov/view_rec.php?id=7106 +# 5400 pixel jpeg file: +# http://veimages.gsfc.nasa.gov/7106/world.topo.bathy.200407.3x5400x2700.jpg +# This images are public domain. + +import os + +tile_defines = [] + +def process_file( imagefile, image_width, image_height, map_x, map_y, map_width, outfilepattern, tile_size): + y = 0 + while (y*tile_size) < image_height: + x = 0 + while (x*tile_size) < image_width: + outfile = outfilepattern % (y,x) + if not os.path.isfile( outfile): + cmd = "jpegtran -optimize -crop %dx%d+%d+%d -outfile %s %s" %\ + (tile_size,tile_size,x*tile_size,y*tile_size,outfile,imagefile) + print cmd + if os.system( cmd): + print "ERROR" + else: + print "tile %s already exists" % outfile + tile_width = map_width/(image_width/tile_size) + tile_x = map_x + tile_width * x + tile_y = map_y - tile_width * y + print "location: %dx%d" % (tile_x,tile_y) + tile_defines.append("self.zoom_map.add_map_source('%s', %d,%d, %d,%d, %d,%d)" %\ + (outfile,tile_x,tile_y,tile_width,tile_width,tile_size,tile_size)) + x = x + 1 + y = y + 1 + pass + +def scale_down( infile, outfile, new_width): + if not os.path.isfile( outfile): + cmd = "convert %s -resize %d %s" % (infile,new_width,outfile) + print cmd + if os.system( cmd): + print "ERROR" + else: + print "scaled down image %s already exists" % outfile + +def fetch_image( server, filename): + if not os.path.isfile( sourcemap_midres): + print "downloading map file %s" % filename + cmd = "wget -v %s/%s" % (server, sourcemap_midres) + print cmd + if os.system( cmd): + print "ERROR" + + else: + print "mapfile %s already downloaded" % filename + +server = "http://veimages.gsfc.nasa.gov/7130" + +# Step 1: Fetch mid-res image +sourcemap_midres = "world.topo.200407.3x5400x2700.jpg" +fetch_image( server, sourcemap_midres) + + +# Step 2: Scale that down a bit (to a multiple of 16 pixels) +sourcemap_lowres = "world.topo.200407.3x3200x1600.jpg" +scale_down(sourcemap_midres,sourcemap_lowres,3200) + +# Step 3: Create tiles +process_file( sourcemap_lowres, 3200, 1600, -180, 90, 360, "world.topo.200407.3x3200x1600_tile_%d_%d.jpg",400) + +# Step 4: Scale down mid-res image to 2048x1024 +sourcemap_lowres = "world.topo.200407.3x1600x800.jpg" +scale_down(sourcemap_midres,sourcemap_lowres,1600) + +# Step 4: Tile low-res image +process_file( sourcemap_lowres, 1600, 800, -180, 90, 360, "world.topo.200407.3x1600x800_tile_%d_%d.jpg",400) + +# Step 5: Scale down once more +sourcemap_thumb = "world.topo.200407.3x800x400.jpg" +scale_down(sourcemap_lowres,sourcemap_thumb,800) + +# Step 5: Scale down thumb-scale image +sourcemap_thumb = "world.topo.200407.3x400x200.jpg" +scale_down(sourcemap_lowres,sourcemap_thumb,400) + +# Step 5: Scale down thumb-scale image +sourcemap_thumb = "world.topo.200407.3x128x60.jpg" +scale_down(sourcemap_lowres,sourcemap_thumb,128) + + +for d in tile_defines: + print d +