def test_proj_antimeridian_bbox(): # this is logic from feature_style_processor::prepare_layer() PROJ_ENVELOPE_POINTS = 20 # include/mapnik/config.hpp prjGeog = mapnik.Projection('+init=epsg:4326') prjProj = mapnik.Projection('+init=epsg:2193') prj_trans_fwd = mapnik.ProjTransform(prjProj, prjGeog) prj_trans_rev = mapnik.ProjTransform(prjGeog, prjProj) # bad = mapnik.Box2d(-177.31453250437079, -62.33374815225163, 178.02778363316355, -24.584597490955804) better = mapnik.Box2d(-180.0, -62.33374815225163, 180.0, -24.584597490955804) buffered_query_ext = mapnik.Box2d(274000, 3087000, 3327000, 7173000) fwd_ext = prj_trans_fwd.forward(buffered_query_ext, PROJ_ENVELOPE_POINTS) assert_box2d_almost_equal(fwd_ext, better) # check the same logic works for .backward() ext = mapnik.Box2d(274000, 3087000, 3327000, 7173000) rev_ext = prj_trans_rev.backward(ext, PROJ_ENVELOPE_POINTS) assert_box2d_almost_equal(rev_ext, better) # checks for not being snapped (ie. not antimeridian) normal = mapnik.Box2d(148.766759749,-60.1222810238,159.95484893,-24.9771195151) buffered_query_ext = mapnik.Box2d(274000, 3087000, 276000, 7173000) fwd_ext = prj_trans_fwd.forward(buffered_query_ext, PROJ_ENVELOPE_POINTS) assert_box2d_almost_equal(fwd_ext, normal) # check the same logic works for .backward() ext = mapnik.Box2d(274000, 3087000, 276000, 7173000) rev_ext = prj_trans_rev.backward(ext, PROJ_ENVELOPE_POINTS) assert_box2d_almost_equal(rev_ext, normal)
def __init__(self): print 'CREATE MAP: %s' % (settings.MAPNIK_MAPFILE, ) self.mutex = Lock() self.mapfile = settings.MAPNIK_MAPFILE self.map = mapnik.Map(settings.MAPNIK_TILE_SIZE, settings.MAPNIK_TILE_SIZE) mapnik.load_map(self.map, self.mapfile) self.map.zoom_to_box(self.map.maximum_extent) self.proj = mapnik.Projection(self.map.srs) self.transform = mapnik.ProjTransform(LONGLAT_PROJ, self.proj) self.inverse_transform = mapnik.ProjTransform(self.proj, LONGLAT_PROJ)
def test_raster_warping(): lyrSrs = "+init=epsg:32630" mapSrs = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' lyr = mapnik.Layer('dataraster', lyrSrs) if 'gdal' in mapnik.DatasourceCache.plugin_names(): lyr.datasource = mapnik.Gdal( file='../data/raster/dataraster.tif', band=1, ) sym = mapnik.RasterSymbolizer() sym.colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_DISCRETE, mapnik.Color(255, 255, 0)) rule = mapnik.Rule() rule.symbols.append(sym) style = mapnik.Style() style.rules.append(rule) _map = mapnik.Map(256, 256, mapSrs) _map.append_style('foo', style) lyr.styles.append('foo') _map.layers.append(lyr) map_proj = mapnik.Projection(mapSrs) layer_proj = mapnik.Projection(lyrSrs) prj_trans = mapnik.ProjTransform(map_proj, layer_proj) _map.zoom_to_box(prj_trans.backward(lyr.envelope())) im = mapnik.Image(_map.width, _map.height) mapnik.render(_map, im) imdata = im.tostring() assert contains_word('\xff\xff\x00\xff', imdata)
def __std_render(self, parameters, filename): merc = mapnik.Projection( '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over' ) longlat = mapnik.Projection( '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') imgwidth = math.trunc(parameters.pagewidth / inch * parameters.dpi) imgheight = math.trunc(parameters.pageheight / inch * parameters.dpi) m = mapnik.Map(imgwidth, imgheight) mapnik.load_map(m, parameters.mapstyle) m.srs = merc.params() if hasattr(mapnik, 'Box2d'): bbox = mapnik.Box2d(self.minlon, self.minlat, self.maxlon, self.maxlat) else: bbox = mapnik.Envelope(self.minlon, self.minlat, self.maxlon, self.maxlat) transform = mapnik.ProjTransform(longlat, merc) merc_bbox = transform.forward(bbox) m.zoom_to_box(merc_bbox) #pdfprint = mapnik.printing.PDFPrinter(pagesize=[ (pagewidthcm+2) / 100, (pageheightcm+2) / 100], resolution=dpi) #pdfprint.render_map(m, filename) #context = pdfprint.get_context() #pdfprint.render_scale(m, ctx=context) #pdfprint.render_legend(m, ctx=context, attribution="(c) OpenStreetMap contributors") mapnik.render_to_file(m, filename, parameters.output_format)
def test_render_points(): if not mapnik.has_cairo(): return # create and populate point datasource (WGS84 lat-lon coordinates) ds = mapnik.MemoryDatasource() context = mapnik.Context() context.push('Name') f = mapnik.Feature(context, 1) f['Name'] = 'Westernmost Point' f.geometry = mapnik.Geometry.from_wkt('POINT (142.48 -38.38)') ds.add_feature(f) f = mapnik.Feature(context, 2) f['Name'] = 'Southernmost Point' f.geometry = mapnik.Geometry.from_wkt('POINT (143.10 -38.60)') ds.add_feature(f) # create layer/rule/style s = mapnik.Style() r = mapnik.Rule() symb = mapnik.PointSymbolizer() symb.allow_overlap = True r.symbols.append(symb) s.rules.append(r) lyr = mapnik.Layer('Places', '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') lyr.datasource = ds lyr.styles.append('places_labels') # latlon bounding box corners ul_lonlat = mapnik.Coord(142.30, -38.20) lr_lonlat = mapnik.Coord(143.40, -38.80) # render for different projections projs = { 'google': '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over', 'latlon': '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs', 'merc': '+proj=merc +datum=WGS84 +k=1.0 +units=m +over +no_defs', 'utm': '+proj=utm +zone=54 +datum=WGS84' } for projdescr in projs: m = mapnik.Map(1000, 500, projs[projdescr]) m.append_style('places_labels', s) m.layers.append(lyr) dest_proj = mapnik.Projection(projs[projdescr]) src_proj = mapnik.Projection('+init=epsg:4326') tr = mapnik.ProjTransform(src_proj, dest_proj) m.zoom_to_box(tr.forward(mapnik.Box2d(ul_lonlat, lr_lonlat))) # Render to SVG so that it can be checked how many points are there # with string comparison svg_file = os.path.join(tempfile.gettempdir(), 'mapnik-render-points-%s.svg' % projdescr) mapnik.render_to_file(m, svg_file) num_points_present = len(list(ds.all_features())) with open(svg_file, 'r') as f: svg = f.read() num_points_rendered = svg.count('<image ') eq_( num_points_present, num_points_rendered, "Not all points were rendered (%d instead of %d) at projection %s" % (num_points_rendered, num_points_present, projdescr))
def test_raster_warping(): lyrSrs = "+init=epsg:32630" mapSrs = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' lyr = mapnik.Layer('dataraster', lyrSrs) if 'gdal' in mapnik.DatasourceCache.plugin_names(): lyr.datasource = mapnik.Gdal( file = '../data/raster/dataraster.tif', band = 1, ) sym = mapnik.RasterSymbolizer() sym.colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_DISCRETE, mapnik.Color(255,255,0)) rule = mapnik.Rule() rule.symbols.append(sym) style = mapnik.Style() style.rules.append(rule) _map = mapnik.Map(256,256, mapSrs) _map.append_style('foo', style) lyr.styles.append('foo') _map.layers.append(lyr) map_proj = mapnik.Projection(mapSrs) layer_proj = mapnik.Projection(lyrSrs) prj_trans = mapnik.ProjTransform(map_proj, layer_proj) _map.zoom_to_box(prj_trans.backward(lyr.envelope())) im = mapnik.Image(_map.width,_map.height) mapnik.render(_map, im) expected_file = './images/support/raster_warping.png' actual_file = '/tmp/' + os.path.basename(expected_file) im.save(actual_file,'png32') if not os.path.exists(expected_file) or os.environ.get('UPDATE'): im.save(expected_file,'png32') actual = mapnik.Image.open(actual_file) expected = mapnik.Image.open(expected_file) eq_(actual.tostring('png32'),expected.tostring('png32'), 'failed comparing actual (%s) and expected (%s)' % (actual_file,expected_file))
def render_map(_map, mimetype='application/pdf'): merc = mapnik.Projection( '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over' ) longlat = mapnik.Projection( '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') transform = mapnik.ProjTransform(longlat, merc) bbox = mapnik.Box2d(*_map.bbox) merc_bbox = transform.forward(bbox) mapnik_map = mapnik.Map(int(merc_bbox.width()), int(merc_bbox.height())) mapnik_map.zoom_to_box(merc_bbox) mapnik_map.buffer_size = 5 # add osm data mapnik.load_map(mapnik_map, current_app.config['MAPNIK_OSM_XML']) # add grid data = _map.grid path = os.path.join(SRC_PATH, "maps-xml/grid.xml") xml_str = get_xml(path).format(json.dumps(data)).encode() mapnik.load_map_from_string(mapnik_map, xml_str) # add all features features = FeatureCollection([f.to_dict() for f in _map.features]) path = os.path.join(SRC_PATH, "maps-xml/features.xml") xml_str = get_xml(path).format(json.dumps(features)).encode() mapnik.load_map_from_string(mapnik_map, xml_str) # add legend add_legend(mapnik_map, _map.legend) # export as in-memory file f = io.BytesIO() if mimetype == 'image/svg+xml': surface = cairo.SVGSurface(f, mapnik_map.width, mapnik_map.height) elif mimetype == 'image/png': ratio = float(mapnik_map.height) / mapnik_map.width mapnik.height = 800 mapnik.width = int(600 * ratio) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, mapnik_map.width, mapnik_map.height) else: surface = cairo.PDFSurface(f, mapnik_map.width, mapnik_map.height) mapnik.render(mapnik_map, surface) if mimetype == 'image/png': surface.write_to_png(f) surface.finish() f.seek(0) return f
def zoom_to_box(m, west, south, east, north): # the box is defined in degrees when passed in to us, but now that # the projection is Mercator, the bounding box must be specified # in metres (no, I don't know why). we solve this by explicitly # converting degrees to metres source = mapnik.Projection( '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') target = mapnik.Projection(m.srs) trans = mapnik.ProjTransform(source, target) thebox = mapnik.Box2d(west, south, east, north) m.zoom_to_box(trans.forward(thebox))
def layer_bbox(m, names, proj_target, bbox=None): """Calculate extent of given layers and bbox""" for layer in (l for l in m.layers if l.name in names): # it may as well be a GPX layer in WGS84 layer_proj = mapnik.Projection(layer.srs) box_trans = mapnik.ProjTransform(layer_proj, proj_target) lbbox = box_trans.forward(layer.envelope()) if bbox: bbox.expand_to_include(lbbox) else: bbox = lbbox return bbox
def render(parameters): if not parameters.verbose: mapnik.logger.set_severity(getattr(mapnik.severity_type, 'None')) merc = mapnik.Projection( '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over' ) longlat = mapnik.Projection( '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') imgwidth = math.trunc(parameters.pagewidth / inch * parameters.dpi) imgheight = math.trunc(parameters.pageheight / inch * parameters.dpi) m = mapnik.Map(imgwidth, imgheight) mapnik.load_map(m, parameters.mapstyle) mapnik.load_map(m, parameters.hikingmapstyle) m.srs = merc.params() if hasattr(mapnik, 'Box2d'): bbox = mapnik.Box2d(parameters.minlon, parameters.minlat, parameters.maxlon, parameters.maxlat) else: bbox = mapnik.Envelope(parameters.minlon, parameters.minlat, parameters.maxlon, parameters.maxlat) transform = mapnik.ProjTransform(longlat, merc) merc_bbox = transform.forward(bbox) m.zoom_to_box(merc_bbox) for gpxfile in parameters.gpxfiles: gpxlayer = mapnik.Layer('GPXLayer') gpxlayer.datasource = mapnik.Ogr(file=gpxfile, layer='tracks') gpxlayer.styles.append('GPXStyle') m.layers.append(gpxlayer) if parameters.temptrackfile: overviewlayer = mapnik.Layer('OverviewLayer') overviewlayer.datasource = mapnik.Ogr(file=parameters.temptrackfile, layer='tracks') overviewlayer.styles.append('GPXStyle') m.layers.append(overviewlayer) if parameters.tempwaypointfile: waypointlayer = mapnik.Layer('WaypointLayer') waypointlayer.datasource = mapnik.Ogr(file=parameters.tempwaypointfile, layer='waypoints') waypointlayer.styles.append('WaypointStyle') m.layers.append(waypointlayer) mapnik.render_to_file( m, parameters.basefilename + "." + parameters.output_format, parameters.output_format, parameters.scale_factor)
def __std_render(self, parameters, tempwaypointfile, filename): merc = mapnik.Projection( '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over' ) longlat = mapnik.Projection( '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') imgwidth = math.trunc(self.get_page_width() / inch * parameters.dpi) imgheight = math.trunc(self.get_page_height() / inch * parameters.dpi) m = mapnik.Map(imgwidth, imgheight) mapnik.load_map(m, parameters.mapstyle) mapnik.load_map(m, parameters.hikingmapstyle) m.srs = merc.params() if hasattr(mapnik, 'Box2d'): bbox = mapnik.Box2d(self.minlon, self.minlat, self.maxlon, self.maxlat) else: bbox = mapnik.Envelope(self.minlon, self.minlat, self.maxlon, self.maxlat) transform = mapnik.ProjTransform(longlat, merc) merc_bbox = transform.forward(bbox) m.zoom_to_box(merc_bbox) for gpxfile in parameters.gpxfiles: gpxlayer = mapnik.Layer('GPXLayer') gpxlayer.datasource = mapnik.Ogr(file=gpxfile, layer='tracks') gpxlayer.styles.append('GPXStyle') m.layers.append(gpxlayer) if parameters.waypt_distance > 0: waypointlayer = mapnik.Layer('WaypointLayer') waypointlayer.datasource = mapnik.Ogr(file=tempwaypointfile, layer='waypoints') waypointlayer.styles.append('WaypointStyle') m.layers.append(waypointlayer) #pdfprint = mapnik.printing.PDFPrinter(pagesize = [ 0.21, 0.297 ], \ # margin = 0.005, resolution = parameters.dpi) #context = pdfprint.get_cairo_context() #pdfprint.render_scale(m, ctx=context) #pdfprint.render_legend(m, ctx=context, attribution="(c) OpenStreetMap contributors") #pdfprint.render_map(m, filename) #im = mapnik.Image(m.width, m.height) #mapnik.render(m, im) #im.save(filename, parameters.output_format) mapnik.render_to_file(m, filename, parameters.output_format)
def test_proj_transform_between_init_and_literal(): one = mapnik.Projection('+init=epsg:4326') two = mapnik.Projection('+init=epsg:3857') tr1 = mapnik.ProjTransform(one,two) tr1b = mapnik.ProjTransform(two,one) wgs84 = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' merc = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over' src = mapnik.Projection(wgs84) dest = mapnik.Projection(merc) tr2 = mapnik.ProjTransform(src,dest) tr2b = mapnik.ProjTransform(dest,src) for x in xrange(-180,180,10): for y in xrange(-60,60,10): coord = mapnik.Coord(x,y) merc_coord1 = tr1.forward(coord) merc_coord2 = tr1b.backward(coord) merc_coord3 = tr2.forward(coord) merc_coord4 = tr2b.backward(coord) eq_(math.fabs(merc_coord1.x - merc_coord1.x) < 1,True) eq_(math.fabs(merc_coord1.x - merc_coord2.x) < 1,True) eq_(math.fabs(merc_coord1.x - merc_coord3.x) < 1,True) eq_(math.fabs(merc_coord1.x - merc_coord4.x) < 1,True) eq_(math.fabs(merc_coord1.y - merc_coord1.y) < 1,True) eq_(math.fabs(merc_coord1.y - merc_coord2.y) < 1,True) eq_(math.fabs(merc_coord1.y - merc_coord3.y) < 1,True) eq_(math.fabs(merc_coord1.y - merc_coord4.y) < 1,True) lon_lat_coord1 = tr1.backward(merc_coord1) lon_lat_coord2 = tr1b.forward(merc_coord2) lon_lat_coord3 = tr2.backward(merc_coord3) lon_lat_coord4 = tr2b.forward(merc_coord4) eq_(math.fabs(coord.x - lon_lat_coord1.x) < 1,True) eq_(math.fabs(coord.x - lon_lat_coord2.x) < 1,True) eq_(math.fabs(coord.x - lon_lat_coord3.x) < 1,True) eq_(math.fabs(coord.x - lon_lat_coord4.x) < 1,True) eq_(math.fabs(coord.y - lon_lat_coord1.y) < 1,True) eq_(math.fabs(coord.y - lon_lat_coord2.y) < 1,True) eq_(math.fabs(coord.y - lon_lat_coord3.y) < 1,True) eq_(math.fabs(coord.y - lon_lat_coord4.y) < 1,True)
def __init__(self, q, map_file, map_prj, max_zoom, tile_size, tile_fmt): self.q = q self.m = mapnik.Map(tile_size, tile_size) self.m.aspect_fix_mode = mapnik.aspect_fix_mode.RESPECT # Load style XML mapnik.load_map(self.m, map_file, True) # Obtain <Map> projection self.prj = mapnik.Projection(self.m.srs) self.tr = mapnik.ProjTransform(map_prj, self.prj) # Projects between tile pixel co-ordinates and LatLong (EPSG:4326) self.tile_proj = GoogleProjection(max_zoom + 1, tile_size) self.tile_size = tile_size self.tile_fmt = tile_fmt
def tile(self, x, y, z): nw = self.deg(x, y, z) se = self.deg(x + 1, y + 1, z) xmin = nw[0] ymin = se[1] xmax = se[0] ymax = nw[1] m = mapnik.Map(256, 256) m.srs = "+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +a=6378137 +b=6378137 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs" m.append_style("pointstyle", self.style) layer = mapnik.Layer("pointlayer") layer.datasource = self.datasource layer.styles.append("pointstyle") m.layers.append(layer) bbox = mapnik.Box2d(xmin, ymin, xmax, ymax) merc = mapnik.Projection(m.srs) longlat = mapnik.Projection( "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") transform = mapnik.ProjTransform(longlat, merc) merc_bbox = transform.forward(bbox) m.zoom_to_box(merc_bbox) m.buffer_size = 10 im = mapnik.Image(256, 256) mapnik.render(m, im) ims = im.tostring() pim = PIL.Image.frombuffer("RGBA", (256, 256), ims, "raw", "RGBA", 0, 1) buf = BytesIO() pim.save(buf, "png") self.db.tiles.remove({"id": self.id, "xyz": "%s_%s_%s" % (x, y, z)}) if buf.__sizeof__() == self.blanksize: self.db.tiles.insert_one({ "id": self.id, "xyz": "%s_%s_%s" % (x, y, z), "blank": True }) else: self.db.tiles.insert_one({ "id": self.id, "xyz": "%s_%s_%s" % (x, y, z), "tile": Binary(buf.getvalue()) })
def renderandSave(m, output, metadata, zoom=19, size=224): " Faster than getTile" # Define size of tile if type(size) == tuple: width = size[0] height = size[1] else: width, height = size, size # target projection projection = '+proj=aeqd +ellps=WGS84 +lat_0={} +lon_0={}'.format( 90, -metadata['yaw'] + metadata['lon']) merc = mapnik.Projection(projection) # WGS lat/long source projection of centrel longlat = mapnik.Projection( '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') # ensure the target map projection is mercator m.srs = merc.params() # transform the centre point into the target coord sys centre = mapnik.Coord(metadata['lon'], metadata['lat']) transform = mapnik.ProjTransform(longlat, merc) merc_centre = transform.forward(centre) # 360/(2**zoom) degrees = 256 px # so in merc 1px = (20037508.34*2) / (256 * 2**zoom) # hence to find the bounds of our rectangle in projected coordinates + and - half the image width worth of projected coord units dx = ((20037508.34 * 2 * (width / 2))) / (width * (2**(zoom))) minx = merc_centre.x - dx maxx = merc_centre.x + dx # grow the height bbox, as we only accurately set the width bbox m.aspect_fix_mode = mapnik.aspect_fix_mode.ADJUST_BBOX_HEIGHT bounds = mapnik.Box2d( minx, merc_centre.y - 10, maxx, merc_centre.y + 10) # the y bounds will be fixed by mapnik due to ADJUST_BBOX_HEIGHT m.zoom_to_box(bounds) # render the map image to a file mapnik.render_to_file(m, output)
except ImportError: HAS_CAIRO = False # ----- BEGIN PRINTMAPS ----- VERSION = '1.7 (Printmpas)' # ----- END PRINTMAPS ----- TILE_BUFFER = 128 IM_MONTAGE = 'montage' EPSG_4326 = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' EPSG_3857 = ( '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 ' + '+k=1.0 +units=m +nadgrids=@null +no_defs +over') proj_lonlat = mapnik.Projection(EPSG_4326) proj_web_merc = mapnik.Projection(EPSG_3857) transform_lonlat_webmerc = mapnik.ProjTransform(proj_lonlat, proj_web_merc) def layer_bbox(m, names, proj_target, bbox=None): """Calculate extent of given layers and bbox""" for layer in (l for l in m.layers if l.name in names): # it may as well be a GPX layer in WGS84 layer_proj = mapnik.Projection(layer.srs) box_trans = mapnik.ProjTransform(layer_proj, proj_target) lbbox = box_trans.forward(layer.envelope()) if bbox: bbox.expand_to_include(lbbox) else: bbox = lbbox return bbox
def run(options): dim_mm = None scale = None size = None bbox = None rotate = not options.norotate if (options.ozi and options.projection.lower() != 'epsg:3857' and options.projection != EPSG_3857): raise Exception( 'Ozi map file output is only supported for Web Mercator (EPSG:3857). ' + 'Please remove --projection.') if options.url: parse_url(options.url, options) # format should not be empty if options.fmt: fmt = options.fmt.lower() elif '.' in options.output: fmt = options.output.split('.')[-1].lower() else: fmt = 'png256' need_cairo = fmt in ['svg', 'pdf'] # output projection if options.projection.isdigit(): proj_target = mapnik.Projection('+init=epsg:{}'.format( options.projection)) else: proj_target = mapnik.Projection(options.projection) transform = mapnik.ProjTransform(proj_lonlat, proj_target) # get image size in millimeters if options.paper: portrait = False if options.paper[0] == '-': portrait = True rotate = False options.paper = options.paper[1:] elif options.paper[0] == '+': rotate = False options.paper = options.paper[1:] else: rotate = True dim_mm = get_paper_size(options.paper.lower()) if not dim_mm: raise Exception('Incorrect paper format: ' + options.paper) if portrait: dim_mm = [dim_mm[1], dim_mm[0]] elif options.size: dim_mm = options.size if dim_mm and options.margin: dim_mm[0] = max(0, dim_mm[0] - options.margin * 2) dim_mm[1] = max(0, dim_mm[1] - options.margin * 2) # ppi and scale factor are the same thing if options.ppi: ppmm = options.ppi / 25.4 scale_factor = options.ppi / 90.7 else: scale_factor = options.factor ppmm = 90.7 / 25.4 * scale_factor # svg / pdf can be scaled only in cairo mode if scale_factor != 1 and need_cairo and not HAS_CAIRO: logging.error('Warning: install pycairo for using --factor or --ppi') scale_factor = 1 ppmm = 90.7 / 25.4 # convert physical size to pixels if options.size_px: size = options.size_px elif dim_mm: size = [int(round(dim_mm[0] * ppmm)), int(round(dim_mm[1] * ppmm))] if size and size[0] + size[1] <= 0: raise Exception('Both dimensions are less or equal to zero') if options.bbox: bbox = options.bbox # scale can be specified with zoom or with 1:NNN scale fix_scale = False if options.zoom: scale = 2 * 3.14159 * 6378137 / 2**(options.zoom + 8) / scale_factor elif options.scale: scale = options.scale * 0.00028 / scale_factor # Now we have to divide by cos(lat), but we might not know latitude at this point # TODO: division should only happen for EPSG:3857 or not at all if options.center: scale = scale / math.cos(math.radians(options.center[1])) elif options.bbox: scale = scale / math.cos( math.radians((options.bbox[3] + options.bbox[1]) / 2)) else: fix_scale = True # all calculations are in EPSG:3857 projection (it's easier) if bbox: bbox = transform.forward(mapnik.Box2d(*bbox)) bbox_web_merc = transform_lonlat_webmerc.forward( mapnik.Box2d(*(options.bbox))) if scale: scale = correct_scale(bbox, scale, bbox_web_merc, bbox) # calculate bbox through center, zoom and target size if not bbox and options.center and size and size[0] > 0 and size[ 1] > 0 and scale: # We don't know over which latitude range the bounding box spans, so we # first do everything in Web Mercator. center = transform_lonlat_webmerc.forward( mapnik.Coord(*options.center)) w = size[0] * scale / 2 h = size[1] * scale / 2 bbox_web_merc = mapnik.Box2d(center.x - w, center.y - h, center.x + w, center.y + h) bbox = transform_lonlat_webmerc.backward(bbox_web_merc) bbox = transform.forward(bbox) # now correct the scale scale = correct_scale(bbox, scale, bbox_web_merc, bbox) center = transform.forward(mapnik.Coord(*options.center)) w = size[0] * scale / 2 h = size[1] * scale / 2 bbox = mapnik.Box2d(center.x - w, center.y - h, center.x + w, center.y + h) # reading style xml into memory for preprocessing if options.style == '-': style_xml = sys.stdin.read() style_path = '' else: with codecs.open(options.style, 'r', 'utf-8') as style_file: style_xml = style_file.read() style_path = os.path.dirname(options.style) if options.base: style_path = options.base if options.vars: style_xml = xml_vars(style_xml, options.vars) if options.layers or options.add_layers: style_xml = reenable_layers( style_xml, parse_layers_string(options.layers) + parse_layers_string(options.add_layers)) # for layer processing we need to create the Map object # ----- BEGIN PRINTMAPS ----- # m = mapnik.Map(100, 100) # temporary size, will be changed before output m = mapnik.Map(size[0], size[1]) # ----- END PRINTMAPS ----- mapnik.load_map_from_string(m, style_xml.encode("utf-8"), False, style_path) m.srs = proj_target.params() # register non-standard fonts if options.fonts: for f in options.fonts: add_fonts(f) # get bbox from layer extents if options.fit: bbox = layer_bbox(m, options.fit.split(','), proj_target, bbox) # here's where we can fix scale, no new bboxes below if bbox and fix_scale: scale = scale / math.cos( math.radians(transform.backward(bbox.center()).y)) bbox_web_merc = transform_lonlat_webmerc.forward( transform.backward(bbox)) if scale: scale = correct_scale(bbox, scale, bbox_web_merc, bbox) # expand bbox with padding in mm if bbox and options.padding and (scale or size): if scale: tscale = scale else: tscale = min((bbox.maxx - bbox.minx) / max(size[0], 0.01), (bbox.maxy - bbox.miny) / max(size[1], 0.01)) bbox.pad(options.padding * ppmm * tscale) # bbox should be specified by this point if not bbox: raise Exception('Bounding box was not specified in any way') # rotate image to fit bbox better if rotate and size: portrait = bbox.maxy - bbox.miny > bbox.maxx - bbox.minx # take into consideration zero values, which mean they should be calculated from bbox if (size[0] == 0 or size[0] > size[1]) and portrait: size = [size[1], size[0]] # calculate pixel size from bbox and scale if not size: if scale: size = [ int(round(abs(bbox.maxx - bbox.minx) / scale)), int(round(abs(bbox.maxy - bbox.miny) / scale)) ] else: raise Exception( 'Image dimensions or scale were not specified in any way') elif size[0] == 0: size[0] = int( round(size[1] * (bbox.maxx - bbox.minx) / (bbox.maxy - bbox.miny))) elif size[1] == 0: size[1] = int( round(size[0] / (bbox.maxx - bbox.minx) * (bbox.maxy - bbox.miny))) if options.output == '-' or (need_cairo and options.tiles > 1): options.tiles = 1 # ----- BEGIN PRINTMAPS ----- # if max(size[0], size[1]) / options.tiles > 16384: # raise Exception('Image size exceeds mapnik limit ({} > {}), use --tiles'.format( # max(size[0], size[1]) / options.tiles, 16384)) # ----- END PRINTMAPS ----- # add / remove some layers if options.layers: filter_layers(m, parse_layers_string(options.layers)) if options.add_layers or options.hide_layers: select_layers(m, parse_layers_string(options.add_layers), parse_layers_string(options.hide_layers)) # ----- BEGIN PRINTMAPS ----- # logging.debug('scale=%s', scale) # logging.debug('scale_factor=%s', scale_factor) # logging.debug('size=%s,%s', size[0], size[1]) # logging.debug('bbox=%s', bbox) # logging.debug('bbox_wgs84=%s', transform.backward(bbox) if bbox else None) # logging.debug('layers=%s', ','.join([l.name for l in m.layers if l.active])) print('scale={}'.format(scale)) print('scale_factor={}'.format(scale_factor)) print('size={},{}'.format(size[0], size[1])) print('bbox={}'.format(bbox)) print('bbox_wgs84={}'.format(transform.backward(bbox) if bbox else None)) print('layers=' + ','.join([l.name for l in m.layers if l.active])) # ----- END PRINTMAPS ----- # ----- BEGIN PRINTMAPS ----- if options.info: quit() # ----- END PRINTMAPS ----- # generate metadata if options.ozi: options.ozi.write( prepare_ozi(bbox, size[0], size[1], options.output, transform)) if options.wld: options.wld.write(prepare_wld(bbox, size[0], size[1])) # export image m.aspect_fix_mode = mapnik.aspect_fix_mode.GROW_BBOX # ----- BEGIN PRINTMAPS ----- # m.resize(size[0], size[1]) # ----- END PRINTMAPS ----- m.zoom_to_box(bbox) outfile = options.output if options.output == '-': outfile = tempfile.TemporaryFile(mode='w+b') if need_cairo: if HAS_CAIRO: if fmt == 'svg': surface = cairo.SVGSurface(outfile, size[0], size[1]) else: surface = cairo.PDFSurface(outfile, size[0], size[1]) mapnik.render(m, surface, scale_factor, 0, 0) surface.finish() else: mapnik.render_to_file(m, outfile, fmt) else: if options.tiles == 1: im = mapnik.Image(size[0], size[1]) mapnik.render(m, im, scale_factor) im.save(outfile, fmt) else: # we cannot make mapnik calculate scale for us, so fixing aspect ratio outselves rdiff = (bbox.maxx - bbox.minx) / (bbox.maxy - bbox.miny) - size[0] / size[1] if rdiff > 0: bbox.height((bbox.maxx - bbox.minx) * size[1] / size[0]) elif rdiff < 0: bbox.width((bbox.maxy - bbox.miny) * size[0] / size[1]) scale = (bbox.maxx - bbox.minx) / size[0] width = max(32, int(math.ceil(1.0 * size[0] / options.tiles))) height = max(32, int(math.ceil(1.0 * size[1] / options.tiles))) m.resize(width, height) m.buffer_size = TILE_BUFFER tile_cnt = [ int(math.ceil(1.0 * size[0] / width)), int(math.ceil(1.0 * size[1] / height)) ] logging.debug('tile_count=%s %s', tile_cnt[0], tile_cnt[1]) logging.debug('tile_size=%s,%s', width, height) # ----- BEGIN PRINTMAPS ----- # tmp_tile = '{:02d}_{:02d}_{}' tmp_tile = '{}_{:02d}_{:02d}' # ----- END PRINTMAPS ----- tile_files = [] for row in range(0, tile_cnt[1]): for column in range(0, tile_cnt[0]): logging.debug('tile=%s,%s', row, column) tile_bbox = mapnik.Box2d( bbox.minx + 1.0 * width * scale * column, bbox.maxy - 1.0 * height * scale * row, bbox.minx + 1.0 * width * scale * (column + 1), bbox.maxy - 1.0 * height * scale * (row + 1)) tile_size = [ width if column < tile_cnt[0] - 1 else size[0] - width * (tile_cnt[0] - 1), height if row < tile_cnt[1] - 1 else size[1] - height * (tile_cnt[1] - 1) ] m.zoom_to_box(tile_bbox) im = mapnik.Image(tile_size[0], tile_size[1]) mapnik.render(m, im, scale_factor) # ----- BEGIN PRINTMAPS ----- # tile_name = tmp_tile.format(row, column, options.output) tile_name = tmp_tile.format(options.output, row, column) # ----- END PRINTMAPS ----- im.save(tile_name, fmt) if options.just_tiles: # write ozi/wld for a tile if needed if '.' not in tile_name: tile_basename = tile_name + '.' else: tile_basename = tile_name[0:tile_name.rindex('.') + 1] if options.ozi: with open(tile_basename + 'ozi', 'w') as f: f.write( prepare_ozi(tile_bbox, tile_size[0], tile_size[1], tile_basename + '.ozi', transform)) if options.wld: with open(tile_basename + 'wld', 'w') as f: f.write( prepare_wld(tile_bbox, tile_size[0], tile_size[1])) else: tile_files.append(tile_name) if not options.just_tiles: # join tiles and remove them if joining succeeded import subprocess result = subprocess.call([ IM_MONTAGE, '-geometry', '+0+0', '-tile', '{}x{}'.format( tile_cnt[0], tile_cnt[1]) ] + tile_files + [options.output]) if result == 0: for tile in tile_files: os.remove(tile) if options.output == '-': if sys.platform == "win32": # fix binary output on windows import msvcrt msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) outfile.seek(0) sys.stdout.write(outfile.read()) outfile.close()
attribution="population per square kilometre in Germany - Andreas Binder ©OpenStreetMap contributors ODbL (State 14.05.2019)" merc = mapnik.Projection('+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over') longlat = mapnik.Projection('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') width=450 * scale height=600 * scale m = mapnik.Map(width, height) mapnik.load_map(m, 'population-density.xml') m.srs = merc.params() centre = mapnik.Coord(centrex, centrey) transform = mapnik.ProjTransform(longlat, merc) merc_centre = transform.forward(centre) dx = ((20037508.34*2*(width/2)))/(256*(2 ** (zoom))) minx = merc_centre.x - dx maxx = merc_centre.x + dx m.aspect_fix_mode = mapnik.aspect_fix_mode.ADJUST_BBOX_HEIGHT bounds = mapnik.Box2d(minx, merc_centre.y-10, maxx, merc_centre.y+10) m.zoom_to_box(bounds) bbox_latlon = merc.inverse(m.envelope()) R = 6373.0 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,m.width,m.height)
'yaw': 0, 'lat': 40.734852, 'lon': -73.990707, } # ------ Source projection ----------------------- # WGS latlong (epsg 4326) source_proj = mapnik.Projection( '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') # ------ Temporal merc projection ---------------------- string = '+proj=merc +datum=WGS84 +k=1.0 +units=m +over +no_defs' merc_proj = mapnik.Projection(string) source_centre = mapnik.Coord(metadata['lon'], metadata['lat']) transform = mapnik.ProjTransform(source_proj, merc_proj) merc_centre = transform.forward(source_centre) tile_size_m = 40075016.68 / ( 2**zoom ) # This is the distance covered by a map tile in the equator given the zoom #----- target projection ---------------------- # Two point equidistant projection: https://proj.org/operations/projections/tpeqd.html # Also useful https://gist.github.com/eyeNsky/9853026 # https://desktop.arcgis.com/en/arcmap/latest/map/projections/two-point-equidistant.htm # It is a generalization of the azimuthal equidistant projection. # Neither conformal nor equal-area (Shapes, areas, distances, directions and angles are generally distorted) # Distances from any of the two reference points are correct. # Only supported with spheres
import mapnik try: spherical_merc = mapnik.Projection('+init=epsg:900913') except: # you don't have 900913 in /usr/share/proj/epsg spherical_merc = mapnik.Projection( '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over' ) try: longlat = mapnik.Projection('+init=epsg:4326') except: # your proj4 files are broken longlat = mapnik.Projection( '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') from_srs, to_srs = longlat, spherical_merc ct = mapnik.ProjTransform(from_srs, to_srs) longlat_coords = mapnik.Coord(-180, 45) merc_coords = ct.forward(longlat_coords) print 'merc_coords:', merc_coords longlat_coords = ct.backward(merc_coords) print 'longlat_coords:', longlat_coords
def render(parameters): if not parameters.verbose: mapnik.logger.set_severity(getattr(mapnik.severity_type, 'None')) merc = mapnik.Projection('+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over') longlat = mapnik.Projection('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') imgwidth = math.trunc(parameters.pagewidth / inch * parameters.dpi) imgheight = math.trunc(parameters.pageheight / inch * parameters.dpi) m = mapnik.Map(imgwidth, imgheight) #mapnik.load_map(m, parameters.mapstyle) mapnik.load_map(m, parameters.hikingmapstyle) m.srs = merc.params() if hasattr(mapnik, 'Box2d'): bbox = mapnik.Box2d(parameters.minlon, parameters.minlat, parameters.maxlon, parameters.maxlat) else: bbox = mapnik.Envelope(parameters.minlon, parameters.minlat, parameters.maxlon, parameters.maxlat) transform = mapnik.ProjTransform(longlat, merc) merc_bbox = transform.forward(bbox) m.zoom_to_box(merc_bbox) # create raster symbolizer / rule / style rastersymbolizer = mapnik.RasterSymbolizer() rastersymbolizer.opacity = 1.0 rasterrule = mapnik.Rule() rasterrule.symbols.append(rastersymbolizer) rasterstyle = mapnik.Style() rasterstyle.rules.append(rasterrule) m.append_style('RasterStyle', rasterstyle) # fetch tiles using the landez TileManager tm = create_tiles_manager(parameters) zoomlevel = calc_zoomlevel(parameters.pagewidth, parameters.pageheight, parameters.dpi, \ parameters.scale_factor, parameters.tile_size, \ parameters.minlon, parameters.minlat, \ parameters.maxlon, parameters.maxlat) if parameters.verbose: print("Calculated zoomlevel = %d" % zoomlevel[0]) for tile in tm.tileslist(bbox = (parameters.minlon, parameters.minlat, \ parameters.maxlon, parameters.maxlat), \ zoomlevels = zoomlevel): # calc tile metadata tile_path = tm.cache.tile_fullpath(tile) proj = GoogleProjection(tm.tile_size, zoomlevel, tm.tile_scheme) (tile_lox, tile_loy, tile_hix, tile_hiy) = proj.tile_bbox(tile) try: # make sure the tile is on disk; tiledata is not needed tiledata = tm.tile(tile) # add to mapnik layer rasterlayer = mapnik.Layer("RasterLayer-%d-%d-%d" % tile) rasterlayer.datasource = mapnik.Raster(file = tile_path, \ lox = tile_lox, loy = tile_loy, \ hix = tile_hix, hiy = tile_hiy) rasterlayer.styles.append('RasterStyle') m.layers.append(rasterlayer) except ExtractionError: print("warning: missing tile zoom=%d x=%d y=%d" % tile) for gpxfile in parameters.gpxfiles: gpxlayer = mapnik.Layer('GPXLayer') gpxlayer.datasource = mapnik.Ogr(file = gpxfile, layer = 'tracks') gpxlayer.styles.append('GPXStyle') m.layers.append(gpxlayer) if parameters.temptrackfile: overviewlayer = mapnik.Layer('OverviewLayer') overviewlayer.datasource = mapnik.Ogr(file = parameters.temptrackfile, layer = 'tracks') overviewlayer.styles.append('GPXStyle') m.layers.append(overviewlayer) if parameters.tempwaypointfile: waypointlayer = mapnik.Layer('WaypointLayer') waypointlayer.datasource = mapnik.Ogr(file = parameters.tempwaypointfile, layer = 'waypoints') waypointlayer.styles.append('WaypointStyle') m.layers.append(waypointlayer) mapnik.render_to_file(m, parameters.basefilename + "." + parameters.output_format, parameters.output_format, parameters.scale_factor)
def forward(self, from_prj, to_prj): trans = mapnik.ProjTransform(from_prj, to_prj) return trans.forward(self)
def _make_transform(source, target): source = mapnik.Projection(source) target = mapnik.Projection(target) trans = mapnik.ProjTransform(source, target) return trans
#!/usr/bin/env python # -*- coding: utf-8 -*- import math import re import mapnik import environment EPSG_4326 = mapnik.Projection('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') EPSG_3857 = mapnik.Projection('+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over') latitudeLongitudeToWebMercator = mapnik.ProjTransform(EPSG_4326, EPSG_3857) ORIENTATION_LANDSCAPE = 'landscape' ORIENTATION_PORTRAIT = 'portrait' def determinePaperDimensions(paperSize): # Paper sizes in meter paperSizes = { 'A5': {'width': 0.149, 'height': 0.210}, 'A4': {'width': 0.210, 'height': 0.297}, 'A3': {'width': 0.297, 'height': 0.420}, 'A2': {'width': 0.420, 'height': 0.594}, 'A1': {'width': 0.594, 'height': 0.841}, 'A0': {'width': 0.841, 'height': 1.189}, } millimeters = re.match(r'^(\d+\.?\d*) mm [x×] (\d+\.?\d*) mm$', paperSize) meters = re.match(r'^(\d+\.?\d*) m [x×] (\d+\.?\d*) m$', paperSize) inches = re.match(r'^(\d+\.?\d*) in [x×] (\d+\.?\d*) in$', paperSize)
try: import cairo HAS_CAIRO = True except ImportError: HAS_CAIRO = False VERSION = '1.6' TILE_BUFFER = 128 IM_MONTAGE = 'montage' p3857 = mapnik.Projection( '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over' ) p4326 = mapnik.Projection('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') transform = mapnik.ProjTransform(p4326, p3857) def layer_bbox(m, names, bbox=None): """Calculate extent of given layers and bbox""" for layer in (l for l in m.layers if l.name in names): # it may as well be a GPX layer in WGS84 p = mapnik.Projection(layer.srs) lbbox = layer.envelope().inverse(p).forward(p3857) if bbox: bbox.expand_to_include(lbbox) else: bbox = lbbox return bbox