def get_next_maplet(self, fullpathname, dX, dY): """Given a maplet's pathname, get the next or previous one. Does not currently work for jumps more than 1 in any direction. Returns pixbuf, newpath (either may be None). """ pathname, filename = os.path.split(fullpathname) if (self.Debug): print "Generic get_next_maplet", filename, dX, dY name, ext = os.path.splitext(filename) # traceback.print_stack() mapb = int(name[-self.numdigits:]) if self.usedash: mapa = int(name[-self.numdigits * 2 - 1: -self.numdigits - 1]) else: mapa = int(name[-self.numdigits * 2: -self.numdigits]) if self.latfirst: newa = MapUtils.ohstring(mapa + dX, self.numdigits) newb = MapUtils.ohstring(mapb + dY, self.numdigits) else: newa = MapUtils.ohstring(mapa + dY, self.numdigits) newb = MapUtils.ohstring(mapb + dX, self.numdigits) if self.usedash: newname = self.prefix + newa + "-" + newb else: newname = self.prefix + newa + newb newpath = os.path.join(self.location, newname + ext) if filename is None or not os.access(filename, os.R_OK): return None, newpath pixbuf = MapWindow.load_image_from_file(newpath) return pixbuf, newpath
def coords_to_filename(self, longitude, latitude): """Given coordinates in decimal degrees, map to the closest filename""" if self.left_longitude > longitude or self.top_latitude < latitude: return None x_grid = MapUtils.int_trunc((longitude - self.left_longitude) * self.xscale / self.img_width) y_grid = MapUtils.int_trunc((self.top_latitude - latitude) * self.yscale / self.img_height) if not self.latfirst: temp = x_grid x_grid = y_grid y_grid = temp retstr = os.path.join(self.location, self.prefix + MapUtils.ohstring(x_grid, self.numdigits)) if self.usedash: retstr = retstr + "-" retstr = retstr + MapUtils.ohstring(y_grid, self.numdigits) + self.ext return retstr
def coords_to_filename(self, longitude, latitude): """Given a pair of coordinates in deg.mmss, map to the containing filename, e.g. q37122c2/012t0501.gif. """ latDeg = MapUtils.int_trunc(latitude) longDeg = MapUtils.int_trunc(-longitude) latMin = (latitude - latDeg) * 60. longMin = (-longitude - longDeg) * 60. # The 7.5 here is because of the 7.5 in the directory names above # (we're getting the offset of this image from the origin of # the 7.5-series map covered by the directory), # not the map series we're actually plotting now. longMinOrd = MapUtils.int_trunc(longMin / 7.5) latMinOrd = MapUtils.int_trunc(latMin / 7.5) dirname = "q" + MapUtils.ohstring(latDeg, 2) \ + MapUtils.ohstring(longDeg, 3) \ + chr(ord('a') + latMinOrd) + str(longMinOrd + 1) # Find the difference between our desired coordinates # and the origin of the map this directory represents. # The 7.5 here is because of the 7.5 in the directory names above. latMinDiff = latMin - (latMinOrd * 7.5) longMinDiff = longMin - (longMinOrd * 7.5) latOffset = MapUtils.int_trunc(latMinDiff * 10 / self.series) longOffset = MapUtils.int_trunc(longMinDiff * 10 / self.series) # Now calculate the current filename. # Note that series is either 7.5 or 15 if (self.series > 13): fileprefix = "024t" numcharts = 5 else: fileprefix = "012t" numcharts = 10 filename = fileprefix + MapUtils.ohstring(numcharts - longOffset, 2) \ + MapUtils.ohstring(numcharts - latOffset, 2) + self.img_ext return self.location + "/" + dirname + "/" + filename
def use_site(self, site, mapwin): collection = self.find_collection(site[3]) if not collection: return False mapwin.collection = collection # site[1] and site[2] are the long and lat in deg.minutes # print site[0], site[1], site[2] mapwin.center_lon = MapUtils.deg_min2dec_deg(site[1]) mapwin.center_lat = MapUtils.deg_min2dec_deg(site[2]) mapwin.pin_lon = mapwin.center_lon mapwin.pin_lat = mapwin.center_lat # print "Center in decimal degrees:", centerLon, centerLat if (self.Debug): print site[0] + ":", \ MapUtils.dec_deg2deg_min_str(mapwin.center_lon), \ MapUtils.dec_deg2deg_min_str(mapwin.center_lat) if len(site) > 4 and collection.zoom_to: collection.zoom_to(site[4]) mapwin.draw_map() return True
def get_maplet(self, longitude, latitude): """Get the maplet containing the specified coordinates. Returns pixbuf, x_offset, y_offset, filename where offsets are pixels from top left of the specified coords and pixbuf or (less often) filename may be None. """ filename = self.coords_to_filename(longitude - self.lon_correction, latitude - self.lat_correction) if (self.Debug): print "T1MC get_maplet(", MapUtils.dec_deg2deg_min_str(longitude), print ",", MapUtils.dec_deg2deg_min_str(latitude), "):", filename # Calculate offsets. # Maplets are self.series minutes wide and tall, # so any offset from that is an offset into the maplet: # the number of pixels in X and Y that have to be added # to get from the maplet's upper left corner to the # indicated coordinates. # But then we have to correct to get to WGS84 coordinates. # XXX the WGS84 part doesn't work right yet. # longitude increases rightward: x_off = int((longitude - MapUtils.truncate2frac(longitude, self.frac) - self.lon_correction) * self.xscale) if (self.Debug): print "truncated", MapUtils.dec_deg2deg_min_str(longitude), "to", print MapUtils.dec_deg2deg_min_str(MapUtils.truncate2frac(longitude, self.frac)) # Latitude decreases downward: y_off = int((MapUtils.truncate2frac(latitude, self.frac) + self.frac - latitude - self.lat_correction) * self.yscale) if (self.Debug): print "truncated", MapUtils.dec_deg2deg_min_str(latitude), "to", print MapUtils.dec_deg2deg_min_str(MapUtils.truncate2frac(latitude, self.frac)) print "y_off is", y_off if not os.access(filename, os.R_OK): return None, x_off, y_off, filename pixbuf = MapWindow.load_image_from_file(filename) return pixbuf, x_off, y_off, filename
def get_next_maplet(self, fullpathname, dX, dY): """Given a maplet's pathname, get the next or previous one. Does not currently work for jumps more than 1 in any direction. Returns pixbuf, newpath (either may be None). """ if (self.Debug): print "get_next_maplet:", fullpathname, dX, dY pathname, filename = os.path.split(fullpathname) collecdir, mapdir = os.path.split(pathname) maplat = int(mapdir[1:3]) maplon = int(mapdir[3:6]) name, ext = os.path.splitext(filename) xdir = int(mapdir[-1]) ydir = ord(mapdir[-2]) - ord('a') # convert from letter a-h if self.series == 7.5: serstr = self.ser7prefix grid = 10 else: serstr = self.ser15prefix grid = 5 x = int(name[-4:-2]) + dX y = int(name[-2:]) + dY if x < 1: x = grid xdir = xdir + 1 if xdir > 8: xdir = 1 if self.Debug: print mapdir, name, ": wrapping mapdir coordinates -x", print maplon maplon = str(int(maplon) + 1) if x > grid: x = 1 xdir = xdir - 1 if xdir < 1: xdir = 8 if self.Debug: print mapdir, name, ": wrapping mapdir coordinates +x", print maplon maplon = str(int(maplon) - 1) if y > grid: y = 1 ydir = ydir - 1 if ydir < 0: ydir = 7 if self.Debug: print mapdir, name, ": wrapping mapdir coordinates +y", print maplat maplat = str(int(maplat) - 1) if y < 1: y = grid ydir = ydir + 1 if ydir > 7: ydir = 0 if self.Debug: print mapdir, name, ": wrapping mapdir coordinates -y", print maplat maplat = str(int(maplat) + 1) # We're ready to piece the filename back together! newpath = os.path.join(collecdir, "q" + MapUtils.ohstring(maplat, 2) + MapUtils.ohstring(maplon, 3) + chr(ydir + ord('a')) + str(xdir), serstr + MapUtils.ohstring(x, 2) + MapUtils.ohstring(y, 2) + ext) if not os.access(newpath, os.R_OK): if self.Debug: print "get_next_maplet(", fullpathname, dX, dY, ")" print " Can't open", newpath return None, newpath pixbuf = MapWindow.load_image_from_file(newpath) return pixbuf, newpath
def parse_args(self, mapwin, args): """Parse runtime arguments.""" args = args[1:] while len(args) > 0: if args[0][0] == '-' and not args[0][1].isdigit(): if args[0] == "-v" or args[0] == "--version": print self.get_version() sys.exit(0) elif args[0] == "-h" or args[0] == "--help": self.Usage() # Next clause is impossible because of the prev isdigit check: # if args[0] == "-15": # series = 15 elif args[0] == "-p": self.print_sites() elif args[0] == "-c": # Specify a collection: if len(args) < 2: print "-c must specify collection" self.Usage() mapwin.collection = self.find_collection(args[1]) if mapwin.collection is None: self.error_out("Can't find a map collection called " + args[1]) # Start initially at top left, but subsequent args # may change this: mapwin.center_lon, mapwin.center_lat = \ mapwin.collection.get_top_left() if (self.Debug): print "Collection", mapwin.collection.name, print "Starting at", \ MapUtils.dec_deg2deg_min_str(mapwin.center_lon), \ ", ", \ MapUtils.dec_deg2deg_min_str(mapwin.center_lat) args = args[1:] elif args[0] == "-d": self.Debug = True elif args[0] == "-r": self.reload_tiles = time.time() elif args[0] == "-t" and len(args) > 1: if mapwin.trackpoints is None: mapwin.trackpoints = TrackPoints() # Is it a known track? for tr in self.KnownTracks: if args[1] == tr[0]: if self.Debug: print "Reading known track", tr[0], tr[1] args[1] = tr[1] break try: mapwin.trackpoints.read_track_file(args[1]) except IOError: print "Can't read track file", args[1] args = args[1:] else: self.error_out("Unknown flag " + args[0]) # Done processing this flag args = args[1:] continue # args[0] doesn't start with '-'. Is it a track file? if args[0].endswith(".gpx") \ or args[0].endswith(".kml") \ or args[0].endswith(".kmz") \ or args[0].endswith("json"): try: if mapwin.trackpoints: mapwin.trackpoints.read_track_file(args[0]) else: trackpoints = TrackPoints() trackpoints.read_track_file(args[0]) mapwin.trackpoints = trackpoints except IOError: print "Can't read track file", args[0] except xml.parsers.expat.ExpatError: print "Can't read %s: syntax error." % args[0] if args[0].lower().endswith(".kml") or \ args[0].lower().endswith(".kmz"): print """ Is this a KML made with ArcGIS? It may have an illegal xsi:schemaLocation. If so, try changing xsi:schemaLocation to just schemaLocation.""" args = args[1:] continue # Try to match a known site: for site in self.KnownSites: if args[0] == site[0]: if not self.use_site(site, mapwin): continue break if mapwin.collection and mapwin.center_lon and mapwin.center_lat: args = args[1:] continue # Doesn't match a known site. Maybe the args are coordinates? try: if len(args) >= 2 and \ len(args[0]) > 1 and args[0][1].isdigit() and \ len(args[1]) > 1 and args[1][1].isdigit(): mapwin.center_lon = MapUtils.deg_min2dec_deg(float(args[0])) mapwin.center_lat = MapUtils.deg_min2dec_deg(float(args[2])) mapwin.collection = self.find_collection(args[3]) args = args[2:] continue print "Can't make sense of argument:", args[0] self.Usage() except ValueError: print "Couldn't parse coordinates" self.Usage() # If we get here, we still have an argument but it doesn't # match anything we know: flag, collection, site or coordinate. print "Problem parsing arguments. Remaining args:", args self.Usage() # Now we've parsed all the arguments. # If we didn't get a collection, use the default, if any: if not mapwin.collection and self.default_collection: mapwin.collection = self.find_collection(self.default_collection) # If we have a collection and a track but no center point, # center it on the trackpoints, and set scale appropriately: if mapwin.trackpoints is not None and mapwin.collection is not None \ and not (mapwin.center_lat and mapwin.center_lon): minlon, minlat, maxlon, maxlat = mapwin.trackpoints.get_bounds() mapwin.center_lon = (maxlon + minlon) / 2 mapwin.center_lat = (maxlat + minlat) / 2 mapwin.collection.zoom_to_bounds(minlon, minlat, maxlon, maxlat) if self.reload_tiles and 'set_reload_tiles' in dir(mapwin.collection): mapwin.collection.set_reload_tiles(self.reload_tiles) elif self.reload_tiles: print "Collection can't re-download tiles" # By now, we hope we have the mapwin positioned with a collection # and starting coordinates: if mapwin.collection and mapwin.center_lon and mapwin.center_lat: return # Didn't match any known run mode: # start in GUI mode choosing a location: if not mapwin.selection_window(): sys.exit(0)
def draw_map(self, center_lon, center_lat, mapwin): """Draw maplets at the specified coordinates, to fill the mapwin.""" self.mapwin = mapwin # Get the current window size: win_width, win_height = mapwin.get_size() if (self.Debug): print("Window is", win_width, "x", win_height) # Now that we have a latitude, call zoom so we can finally # set the x and y scales accurately. self.zoom(0, center_lat) # Find the coordinate boundaries for the set of maps to draw. # This may (indeed, usually will) include maps partly off the screen, # so the coordinates will span a greater area than the visible window. if (self.Debug): print("Calculating boundaries: min =", \ MapUtils.dec_deg2deg_min_str(center_lon), \ center_lon, "+/-", win_width, \ "/", self.xscale, "/ 2") min_lon = center_lon - win_width / self.xscale / 2 max_lon = center_lon + win_width / self.xscale / 2 min_lat = center_lat - win_height / self.yscale / 2 max_lat = center_lat + win_height / self.yscale / 2 if (self.Debug): print("Map from", min_lon, MapUtils.dec_deg2deg_min_str(min_lon), \ MapUtils.dec_deg2deg_min_str(min_lat), \ "to", MapUtils.dec_deg2deg_min_str(max_lon), \ MapUtils.dec_deg2deg_min_str(max_lat)) # Start from the upper left: min_lon, max_lat # pdb.set_trace() curlat = max_lat cur_y = 0 y_maplet_name = None initial_x_off = None while cur_y < win_height: curlon = min_lon cur_x = 0 x_maplet_name = None while cur_x < win_width: # Reset the expected image size: w = self.img_width h = self.img_height # Is it the first maplet in this row? if x_maplet_name is None: # Is it the first maplet in the map -- # usually the one in the upper left corner? # Then we need to specify coordinates. if y_maplet_name is None: pixbuf, x_off, y_off, x_maplet_name = \ self.get_maplet(curlon, curlat) # Save the x offset: we'll need it for the # beginning of each subsequent row. initial_x_off = x_off # Not upper left corner -- # must be the beginning of a new row. # Get the maplet below the beginning of the last row. else: pixbuf, x_maplet_name = \ self.get_next_maplet(y_maplet_name, 0, 1) x_off = initial_x_off y_off = 0 # Either way, whether or not we got a pixbuf, # if we're at the beginning of a row, save the # beginning-of-row maplet name and the offset: if cur_x == 0: y_maplet_name = x_maplet_name # Continuing an existing row. # Get the maplet to the right of the last one. else: pixbuf, x_maplet_name = self.get_next_maplet( x_maplet_name, 1, 0) x_off = 0 if self.Debug: print(" ", x_maplet_name) x = cur_x y = cur_y w, h = self.draw_tile_at_position(pixbuf, mapwin, x, y, x_off, y_off) # You may ask, why not just do this subtraction before # draw_pixbuf so we don't have to subtract w and h twice? # Alas, we may not have the real w and h until we've done # pixbuf.get_width(), so we'd be subtracting the wrong thing. # XXX Not really true any more, since we're assuming fixed # XXX tile size. Revisit this! cur_x += w curlon += float(w) / self.xscale if (self.Debug): print(" ") print("New row: adding y =", h, end=' ') print("Subtracting lat", float(h) / self.yscale) cur_y += h curlat -= float(h) / self.yscale # curlat -= float(self.img_height) / self.yscale # Free all pixbuf data. Just letting pixbuf go out of scope # isn't enough; it's necessary to force garbage collection # otherwise Python will let the process grow until it # fills all of memory. # http://www.daa.com.au/pipermail/pygtk/2003-December/006499.html # (At this indentation level, we free after drawing the whole map.) gc.collect() # If we queued any downloads and aren't currently downloading, # schedule a function to take care of that: if len(self.download_tiles) > 0 and self.download_func is None: gobject.timeout_add(300, self.download_more)