def renderArea(self, width, height, srs, xmin, ymin, xmax, ymax, zoom): """ Return an image for an area. Each argument (width, height, etc.) is substituted into the template. """ if self.source_projection is not None: ne_location = self.layer.projection.projLocation(Point(xmax, ymax)) ne_point = self.source_projection.locationProj(ne_location) ymax = ne_point.y xmax = ne_point.x sw_location = self.layer.projection.projLocation(Point(xmin, ymin)) sw_point = self.source_projection.locationProj(sw_location) ymin = sw_point.y xmin = sw_point.x srs = self.source_projection.srs mapping = {'width': width, 'height': height, 'srs': srs, 'zoom': zoom} mapping.update({ 'xmin': xmin, 'ymin': ymin, 'xmax': xmax, 'ymax': ymax }) href = self.template.safe_substitute(mapping) req = urllib2.Request(href) if self.referer: req.add_header('Referer', self.referer) body = urllib2.urlopen(req, timeout=self.timeout).read() tile = Verbatim(body) return tile
def preview_url(ul, ur, lr, ll): ''' ''' merc = MercatorProjection(0) ul = merc.rawUnproject(Point(*ul)) ur = merc.rawUnproject(Point(*ur)) lr = merc.rawUnproject(Point(*lr)) ll = merc.rawUnproject(Point(*ll)) q = dict(width='512', height='384', module='map') ulx, uly, urx, ury, lrx, lry, llx, lly \ = [rad2deg(v) for v in (ul.x, ul.y, ur.x, ur.y, lr.x, lr.y, ll.x, ll.y)] xmin, ymin = min(ulx, urx, lrx, llx), min(uly, ury, lry, lly) xmax, ymax = max(uly, ury, lry, lly), max(ulx, urx, lrx, llx) perimeter = (ulx, uly, urx, ury, lrx, lry, llx, lly, ulx, uly) q.update(dict(polygons=','.join(['%.4f' % v for v in perimeter]))) q.update( dict(bbox=','.join(('%.4f' % xmin, '%.4f' % ymax, '%.4f' % xmax, '%.4f' % ymin)))) return 'http://pafciu17.dev.openstreetmap.org/?' + urlencode(q)
def calculate_corners(aspect, x, y, size, theta): ''' Return latitude, longitude corners for a geometric placement. ''' merc = MercatorProjection(0) # # Get the natural angle of the hypotenuse from map aspect ratio, # measured from the lower-right to the upper-left corner and expressed # in CCW radians from due east. # base_theta = atan2(1, -float(aspect)) # # Derive center-to-corners offset from natural angle and placement theta. # place_theta = base_theta + theta dx = sin(place_theta - pi/2) * size/2 dy = cos(place_theta - pi/2) * size/2 ul = Point(x - dx, y + dy) lr = Point(x + dx, y - dy) # # Convert back to degree latitude and longitude # ul = merc.rawUnproject(ul) lr = merc.rawUnproject(lr) ul_lat, ul_lon = rad2deg(ul.y), rad2deg(ul.x) lr_lat, lr_lon = rad2deg(lr.y), rad2deg(lr.x) return ul_lat, ul_lon, lr_lat, lr_lon
def build_rough_placement_polygon(aspect, ul_lat, ul_lon, lr_lat, lr_lon): ''' Return rough placement geometry. Length of map hypotenuse in mercator units, angle of hypotenuse in radians counter-clockwise from due east, and footprint polygon. ''' merc = MercatorProjection(0) # # Get the natural angle of the hypotenuse from map aspect ratio, # measured from the lower-right to the upper-left corner and expressed # in CCW radians from due east. # base_theta = atan2(1, -float(aspect)) # # Convert corner lat, lons to conformal mercator projection # ul = merc.rawProject(Point(deg2rad(ul_lon), deg2rad(ul_lat))) lr = merc.rawProject(Point(deg2rad(lr_lon), deg2rad(lr_lat))) # # Derive dimensions of map in mercator units. # map_hypotenuse = hypot(ul.x - lr.x, ul.y - lr.y) map_width = map_hypotenuse * sin(base_theta - pi / 2) map_height = map_hypotenuse * cos(base_theta - pi / 2) # # Get the placed angle of the hypotenuse from the two placed corners, # again measured from the lower-right to the upper-left corner and # expressed in CCW radians from due east. # place_theta = atan2(ul.y - lr.y, ul.x - lr.x) diff_theta = place_theta - base_theta # # Derive the other two corners of the roughly-placed map, # and make a polygon in mercator units. # dx = map_height * sin(diff_theta) dy = map_height * cos(diff_theta) ur = Point(lr.x - dx, lr.y + dy) dx = map_width * cos(diff_theta) dy = map_width * sin(diff_theta) ll = Point(lr.x - dx, lr.y - dy) poly = [(ul.x, ul.y), (ur.x, ur.y), (lr.x, lr.y), (ll.x, ll.y)] return map_hypotenuse, diff_theta, poly
def coordinateProj(self, coord): """ Convert from Coordinate object to a Point object in EPSG:3857 """ # the zoom at which we're dealing with meters on the ground diameter = 2 * _pi * 6378137 zoom = _log(diameter) / _log(2) coord = coord.zoomTo(zoom) # global offsets point = Point(coord.column, coord.row) point.x = point.x - diameter/2 point.y = diameter/2 - point.y return point
def coordinateProj(self, coord): """ Convert from Coordinate object to a Point object in EPSG:900913 """ # the zoom at which we're dealing with meters on the ground diameter = 2 * _pi * 6378137 zoom = _log(diameter) / _log(2) coord = coord.zoomTo(zoom) # global offsets point = Point(coord.column, coord.row) point.x = point.x - diameter/2 point.y = diameter/2 - point.y return point
def get_map_scale(mmap, map_height_pt): """ """ north = mmap.pointLocation(Point(0, 0)).lat south = mmap.pointLocation(mmap.dimensions).lat vertical_degrees = north - south vertical_meters = 6378137 * pi * 2 * vertical_degrees / 360 pts_per_meter = map_height_pt / vertical_meters # a selection of reasonable scale values to show meterses = range(50, 300, 50) + range(300, 1000, 100) + range(1000, 10000, 1000) + range(10000, 100000, 10000) + range(100000, 1000000, 100000) + range(1000000, 10000000, 1000000) for meters in meterses: points = meters * pts_per_meter if points > 100: # stop at an inch and a half or so break if meters > 1000: distance = '%d' % (meters / 1000.0) units = 'kilometers' elif meters == 1000: distance = '%d' % (meters / 1000.0) units = 'kilometer' else: distance = '%d' % meters units = 'meters' return points, distance, units
def save(self, out, format): ''' ''' if format == 'MVT': mvt.encode(out, []) elif format == 'JSON': geojson.encode(out, [], 0, False) elif format == 'TopoJSON': ll = SphericalMercator().projLocation(Point(*self.bounds[0:2])) ur = SphericalMercator().projLocation(Point(*self.bounds[2:4])) topojson.encode(out, [], (ll.lon, ll.lat, ur.lon, ur.lat), False) else: raise ValueError(format)
def location_point(self, lat, lon): """ Return a location and point object for the lat, lon pair. """ location = Location(float(lat), float(lon)) x, y = self.proj(location.lon, location.lat) point = Point(x / self.scale, y / self.scale) return location, point
def coordinateProj(self, coord): """Convert from Coordinate object to a Point object in the defined projection""" if coord.zoom >= len(self.tile_dimensions): raise TileStache.Core.KnownUnknown( 'Requested zoom level %d outside defined resolutions.' % coord.zoom) p = self.unproject(Point(coord.column, coord.row), 1.0 / self.tile_dimensions[coord.zoom]) return p
def location_point(self, lat, lon): """ Return a location and point object for the lat, lon pair. """ try: location = Location(float(lat), float(lon)) coord = _osm.locationCoordinate(location).zoomTo(self.zoom + 8) point = Point(coord.column - self.radius, self.radius - coord.row) return location, point except ValueError: raise Exception((lat, lon, zoom))
def location_point(lat, lon, zoom): """ Return a point that maps to pixels at the requested zoom level for 2^8 tile size. """ try: location = Location(float(lat), float(lon)) coord = _osm.locationCoordinate(location).zoomTo(zoom + 8) point = Point(coord.column, coord.row) return location, point except ValueError: raise Exception((lat, lon, zoom))
def save(self, out, format): ''' ''' with Connection(self.dbinfo) as db: db.execute(self.query[format]) features = [] for row in db.fetchall(): if row['__geometry__'] is None: continue wkb = bytes(row['__geometry__']) prop = dict([(k, v) for (k, v) in row.items() if k not in ('__geometry__', '__id__')]) if '__id__' in row: features.append((wkb, prop, row['__id__'])) else: features.append((wkb, prop)) if format == 'MVT': mvt.encode(out, features) elif format == 'JSON': geojson.encode(out, features, self.zoom, self.clip) elif format == 'TopoJSON': ll = SphericalMercator().projLocation(Point(*self.bounds[0:2])) ur = SphericalMercator().projLocation(Point(*self.bounds[2:4])) topojson.encode(out, features, (ll.lon, ll.lat, ur.lon, ur.lat), self.clip) elif format == 'PBF': pbf.encode(out, features, self.coord, layer_name=self.layer_name) else: raise ValueError(format)
def get_texture_offsets(self, texture, xmin, ymax, zoom): texture_width, texture_height = texture.size # exact coordinate of upper-left corner of the selected area ul_coord = self.layer.projection.projCoordinate(Point(xmin, ymax)) # pixel position, in the current render area, of the top-left # corner of a 1024x1024 texture image assuming 256x256 tiles. texture_x_offset = int(round(ul_coord.zoomTo(zoom + 8).column) % texture_width) texture_y_offset = int(round(ul_coord.zoomTo(zoom + 8).row) % texture_height) # pixel positions adjusted to cover full image by going negative texture_x_offset = texture_x_offset and (texture_x_offset - texture_width) texture_y_offset = texture_y_offset and (texture_y_offset - texture_height) return texture_x_offset, texture_y_offset
def renderArea(self, width, height, srs, xmin, ymin, xmax, ymax, zoom): """ Return a PIL Image for a given area. For more info: http://tilestache.org/doc/#custom-providers. """ driver = gdal.GetDriverByName('GTiff') try: # Figure out bbox and contained images ----------------------------- sw = self.layer.projection.projLocation(Point(xmin, ymin)) ne = self.layer.projection.projLocation(Point(xmax, ymax)) bbox = sw.lon, sw.lat, ne.lon, ne.lat images = self.client.images_by_bbox(bbox, output='full') images = map(localize_image_path, images) if not images: # once you go black return Image.new('RGB', (width, height), (0, 0, 0)) # Set up a target oam.Image ---------------------------------------- target = oam.Image("unused", bbox, width, height, crs=images[0].crs) # Build input gdal datasource -------------------------------------- vrtdoc = build_vrt(target, images) vrt = vrtdoc.toxml('utf-8') source_ds = gdal.Open(vrt) assert source_ds, \ "oam.tiles.Provider couldn't open the VRT: %s" % vrt # Prepare output gdal datasource ----------------------------------- destination_ds = driver.Create('/vsimem/output', width, height, 3) assert destination_ds is not None, \ "oam.tiles.Provider couldn't make the file: /vsimem/output" merc = osr.SpatialReference() merc.ImportFromProj4(srs) destination_ds.SetProjection(merc.ExportToWkt()) # note that 900913 points north and east x, y = xmin, ymax w, h = xmax - xmin, ymin - ymax gtx = [x, w / width, 0, y, 0, h / height] destination_ds.SetGeoTransform(gtx) # Create rendered area --------------------------------------------- gdal.ReprojectImage(source_ds, destination_ds) r, g, b = [ destination_ds.GetRasterBand(i).ReadRaster( 0, 0, width, height) for i in (1, 2, 3) ] data = ''.join([''.join(pixel) for pixel in zip(r, g, b)]) area = Image.fromstring('RGB', (width, height), data) finally: driver.Delete("/vsimem/output") return area
def _coordinateProj(self, coord): tile_meters = self.tilesize * self.resolutions[coord.zoom] row = (2**coord.zoom - coord.row) if self.xyz else coord.row px = coord.column * tile_meters py = row * tile_meters return Point(px, py)
def locationProj(self, location): """Convert from Location object to a Point object in the defined projection""" x,y = self.proj(location.lon, location.lat) return Point(x, y)
def generate_map_tiles(mysql, bucket, map_id): ''' ''' mysql.execute('''SELECT * FROM maps WHERE id = %s''', (map_id, )) map = mysql.fetchdict() # # Retrieve the original uploaded image from storage. # img = bucket.get_key(map['image']) if not img: # started using unqoute_plus to name the keys, to handle double encoding of file names on S3 img = bucket.get_key(unquote_plus(map['image'])) # ok give up if not img: logging.error("No image found for map: %s" % (map['id'])) return tmpdir = mkdtemp(prefix='gen-map-tiles-') imgname = join(tmpdir, basename(img.name)) img.get_contents_to_filename(imgname) img = Image.open(imgname) w, h = img.size # # Calculate a geo transformation based on three corner points. # size, theta, (ul, ur, lr, ll) \ = build_rough_placement_polygon(map['aspect'], map['ul_lat'], map['ul_lon'], map['lr_lat'], map['lr_lon']) logging.info(preview_url(ul, ur, lr, ll)) ul = terra.transform(Point(*ul)) ur = terra.transform(Point(*ur)) ll = terra.transform(Point(*ll)) lr = terra.transform(Point(*lr)) args = (0, 0, ul.x, ul.y, 0, h, ll.x, ll.y, w, h, lr.x, lr.y) xform = deriveTransformation(*args) # # Build a VRT file in spherical mercator projection. # vrtname = join(tmpdir, 'image.vrt') vrt = build_vrt(basename(imgname), img.size[0], img.size[1], xform) vrt.write(open(vrtname, 'w')) key = bucket.new_key(join(dirname(map['image']), 'image.vrt')) key.set_contents_from_filename( vrtname, {'Content-Type': 'application/gdal-vrt+xml'}, policy='public-read') # # Generate image tiles and upload them. # queue = JoinableQueue() tiles = join(dirname(map['image']), 'tiles') uploader1 = Process(target=upload_map_tiles, args=(queue, bucket, tiles)) uploader2 = Process(target=upload_map_tiles, args=(queue, bucket, tiles)) uploader1.start() uploader2.start() max_zoom = round(1 + native_zoom(w, h, ul, lr)) logging.info("max_zoom from native_zoom: %s" % (max_zoom)) # cap zoom at 18 max_zoom = min(max_zoom, 18.0) cut_map_tiles(vrtname, queue, ul, ur, lr, ll, max_zoom) uploader1.join() uploader2.join() # # Clean up. # rmtree(tmpdir) logging.info('Set %s on %s' % (repr(dict(tiles=basename(tiles))), map['id'])) mysql.execute('UPDATE maps SET tiles = %s WHERE id = %s', (tiles, map['id']))
label_geometry = bbox_polygon(place.label_bbox(), osm, zoom).__geo_interface__ label_features.append({'type': 'Feature', 'geometry': label_geometry, 'properties': properties }) dumpjson({'type': 'FeatureCollection', 'features': point_features}, open(pointsfile, 'w')) dumpjson({'type': 'FeatureCollection', 'features': label_features}, open(labelsfile, 'w')) print 'Wrote %d points to %s and %s.' % (len(point_features), pointsfile, labelsfile) print '-' * 80 map = mapByCenterZoom(osm, Location(0, 0), zoom, Point(2 ** (zoom + 8), 2 ** (zoom + 8))) if zoom > 5: map = mapByCenterZoom(osm, Location(40.078, -96.987), zoom, Point(1400, 800)) map = mapByCenterZoom(osm, Location(38.889, -77.050), zoom, Point(1200, 900)) img = map.draw(False) # newimg('RGB', (map.dimensions.x, map.dimensions.y), (0xFF, 0xFF, 0xFF)) draw = drawimg(img) print '-' * 80 sw = map.pointLocation(Point(-100, map.dimensions.y + 100)) ne = map.pointLocation(Point(map.dimensions.x + 100, -100)) previewed_places = [place for place in visible_places if (sw.lat < place.location.lat and place.location.lat < ne.lat
from csv import DictReader from sys import argv, stderr from math import cos, pi import json from dateutil import parser from ModestMaps import mapByExtent from ModestMaps.Core import Point from ModestMaps.Geo import Location from ModestMaps.OpenStreetMap import Provider import lib provider = Provider() dimensions = Point(960, 600) base_url = 'http://osm-extracted-metros.s3.amazonaws.com/log.txt' extract_pat = compile(r'^((\S+)\.osm\.(bz2|pbf))\s+(\d+)$') coastshape_pat = compile(r'^((\S+)\.coastline\.zip)\s+(\d+)$') shp_imposm_pat = compile(r'^((\S+)\.imposm-shapefiles\.zip)\s+(\d+)$') shp_osm2pgsql_pat = compile(r'^((\S+)\..*\bshapefiles\.zip)\s+(\d+)$') coastline_pat = compile(r'^((\w+)-(latlon|merc)\.tar\.bz2)\s+(\d+)$') months = '- Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split() def nice_size(size): KB = 1024. MB = 1024. * KB GB = 1024. * MB TB = 1024. * GB
from csv import DictReader try: from PIL import Image from PIL.ImageDraw import ImageDraw except ImportError: import Image from ImageDraw import ImageDraw from ModestMaps import mapByExtent from ModestMaps.OpenStreetMap import Provider from ModestMaps.Geo import Location from ModestMaps.Core import Point provider = Provider() dimensions = Point(310, 200) cities = list(DictReader(open('cities.txt'), dialect='excel-tab')) try: (previews, ) = argv[1:] except ValueError: print >> stderr, 'Usage: compose-city-previews.py <previews directory>' exit(1) for city in cities: if not city['name']: raise Exception('Need a name for ' + str(city)) print >> stderr, city['name'], '...',
def main(apibase, password, print_id, pages, paper_size, orientation, layout): """ """ print_path = 'atlas.php?' + urlencode({'id': print_id}) print_href = print_id and urljoin(apibase.rstrip('/')+'/', print_path) or None print_info = {} # # Prepare a shorthands for pushing data. # _append_file = lambda name, body: print_id and append_print_file(print_id, name, body, apibase, password) or None _finish_print = lambda print_info: print_id and finish_print(apibase, password, print_id, print_info) or None _update_print = lambda progress: print_id and update_print(apibase, password, print_id, progress) or None print 'Print:', print_id print 'Paper:', orientation, paper_size, layout # # Prepare output context. # handle, print_filename = mkstemp(suffix='.pdf') close(handle) page_width_pt, page_height_pt, points_FG, hm2pt_ratio = paper_info(paper_size, orientation) print_context, finish_drawing = get_drawing_context(print_filename, page_width_pt, page_height_pt) try: map_xmin_pt = .5 * ptpin map_ymin_pt = 1 * ptpin map_xmax_pt = page_width_pt - .5 * ptpin map_ymax_pt = page_height_pt - .5 * ptpin map_bounds_pt = map_xmin_pt, map_ymin_pt, map_xmax_pt, map_ymax_pt # # Add pages to the PDF one by one. # for (index, page) in enumerate(pages): _update_print(0.1 + 0.9 * float(index) / len(pages)) page_href = print_href and (print_href + '/%(number)s' % page) or None provider = TemplatedMercatorProvider(page['provider']) zoom = page['zoom'] mark = page.get('mark', None) or None fuzzy = page.get('fuzzy', None) or None text = unicode(page.get('text', None) or '').encode('utf8') role = page.get('role', None) or None north, west, south, east = page['bounds'] northwest = Location(north, west) southeast = Location(south, east) page_mmap = mapByExtentZoom(provider, northwest, southeast, zoom) if role == 'index': indexees = [pages[other] for other in range(len(pages)) if other != index] else: indexees = [] add_print_page(print_context, page_mmap, page_href, map_bounds_pt, points_FG, hm2pt_ratio, layout, text, mark, fuzzy, indexees) # # Now make a smaller preview map for the page, # 600px looking like a reasonable upper bound. # preview_mmap = copy(page_mmap) while preview_mmap.dimensions.x > 600: preview_zoom = preview_mmap.coordinate.zoom - 1 preview_mmap = mapByExtentZoom(provider, northwest, southeast, preview_zoom) out = StringIO() preview_mmap.draw(fatbits_ok=True).save(out, format='JPEG', quality=85) preview_url = _append_file('preview-p%(number)s.jpg' % page, out.getvalue()) print_info['pages[%(number)s][preview_url]' % page] = preview_url # # Complete the PDF and upload it. # finish_drawing() pdf_name = 'field-paper-%s.pdf' % print_id pdf_url = _append_file(pdf_name, open(print_filename, 'r').read()) print_info['pdf_url'] = pdf_url except: raise finally: unlink(print_filename) # # Make a small preview map of the whole print coverage area. # provider = TemplatedMercatorProvider(pages[0]['provider']) norths, wests, souths, easts = zip(*[page['bounds'] for page in pages]) northwest = Location(max(norths), min(wests)) southeast = Location(min(souths), max(easts)) dimensions = Point(*get_preview_map_size(orientation, paper_size)) preview_mmap = mapByExtent(provider, northwest, southeast, dimensions) out = StringIO() preview_mmap.draw(fatbits_ok=True).save(out, format='JPEG', quality=85) preview_url = _append_file('preview.jpg' % page, out.getvalue()) print_info['preview_url'] = preview_url # # All done, wrap it up. # _finish_print(print_info)
from urllib import urlopen from urlparse import urljoin, urlparse from httplib import HTTPConnection from re import compile from csv import DictReader from sys import argv, stderr from dateutil import parser from ModestMaps import mapByExtent from ModestMaps.Core import Point from ModestMaps.Geo import Location from ModestMaps.OpenStreetMap import Provider provider = Provider() dimensions = Point(960, 600) base_url = 'http://osm-metro-extracts.s3.amazonaws.com/log.txt' extract_pat = compile(r'^((\S+)\.osm\.(bz2|pbf))\s+(\d+)$') coastshape_pat = compile(r'^((\S+)\.coastline\.zip)\s+(\d+)$') shp_imposm_pat = compile(r'^((\S+)\.imposm-shapefiles\.zip)\s+(\d+)$') shp_osm2pgsql_pat = compile(r'^((\S+)\..*\bshapefiles\.zip)\s+(\d+)$') coastline_pat = compile(r'^((\w+)-(latlon|merc)\.tar\.bz2)\s+(\d+)$') months = '- Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split() def nice_size(size): KB = 1024. MB = 1024. * KB GB = 1024. * MB TB = 1024. * GB
def locationProj(self, location): """ Convert from Location object to a Point object in EPSG:4326 """ return Point(location.lon, location.lat)