Beispiel #1
0
 def register_layer(self, layer, defaultstyle, extrastyles=()):
     layername = layer.name
     if not layername:
         raise ServerConfigurationError('Attempted to register an unnamed layer.')
     if not layer.wms_srs and not re.match('^\+init=epsg:\d+$', layer.srs) and not re.match('^\+proj=.*$', layer.srs):
         raise ServerConfigurationError('Attempted to register a layer without an epsg projection defined.')
     if defaultstyle not in self.styles.keys() + self.aggregatestyles.keys():
         raise ServerConfigurationError('Attempted to register a layer with an non-existent default style.')
     layer.wmsdefaultstyle = defaultstyle
     if isinstance(extrastyles, tuple):
         for stylename in extrastyles:
             if type(stylename) == type(''):
                 if stylename not in self.styles.keys() + self.aggregatestyles.keys():
                     raise ServerConfigurationError('Attempted to register a layer with an non-existent extra style.')
             else:
                 ServerConfigurationError('Attempted to register a layer with an invalid extra style name.')
         layer.wmsextrastyles = extrastyles
     else:
         raise ServerConfigurationError('Layer "%s" was passed an invalid list of extra styles.  List must be a tuple of strings.' % layername)
     layerproj = common.Projection(layer.srs)
     env = getattr(layer, 'maximum_extent', layer.envelope())
     llp = layerproj.inverse(Coord(env.minx, env.miny))
     urp = layerproj.inverse(Coord(env.maxx, env.maxy))
     if self.latlonbb is None:
         self.latlonbb = Box2d(llp, urp)
     else:
         self.latlonbb.expand_to_include(Box2d(llp, urp))
     self.ordered_layers.append(layer)
     self.layers[layername] = layer
Beispiel #2
0
    def loadXML(self, xmlfile=None, strict=False, xmlstring='', basepath=''):
        """Loads and stores a complete map definition in leiu of a set of layers.
        Stores an empty style of the same name, which is the only option for rendering.
        The map will be rendered as prescribed in the XML."""
        config = ConfigParser.SafeConfigParser()
        map_wms_srs = None
        if self.configpath:
            config.readfp(open(self.configpath))

            if config.has_option('map', 'wms_srs'):
                map_wms_srs = config.get('map', 'wms_srs')

        tmp_map = Map(0,0)
        if xmlfile:
            load_map(tmp_map, xmlfile, strict)
        elif xmlstring:
            load_map_from_string(tmp_map, xmlstring, strict, basepath)
        else:
            raise ServerConfigurationError("Mapnik configuration XML is not specified - 'xmlfile' and 'xmlstring' variables are empty.\
Please set one of this variables to load mapnik map object.")
        # parse map level attributes
        if tmp_map.background:
            self.map_attributes['bgcolor'] = tmp_map.background
        if tmp_map.buffer_size:
            self.map_attributes['buffer_size'] = tmp_map.buffer_size

        if xmlfile is None : 
            # Map objects have no name, so just call it default.
            layer_name = 'default'
        else : 
            # The layer name is the basename of the xml file or the 
            # whole file name
            layer_name = xmlfile
            fname_match = re.match('([A-Za-z0-9_\-\.]+).xml', xmlfile)
            if fname_match is not None : 
                layer_name = fname_match.group(1)
            else : 
                layer_name = xmlfile

        style_name = layer_name
        style_obj = Style()

        # Make the map have attributes expected of layers
        tmp_map.name = layer_name
        map_p = common.Projection(tmp_map.srs)
        if map_wms_srs is None : 
            tmp_map.wms_srs = map_p.epsgstring()
        else : 
            tmp_map.wms_srs = map_wms_srs
        tmp_map.queryable = False

        # set map extent from config file.
        geog_coords = config.get('map','wms_extent').split(',')
        geog_box = Box2d(float(geog_coords[0]), float(geog_coords[1]), float(geog_coords[2]), float(geog_coords[3]))
        proj_box = geog_box.forward(map_p)
        tmp_map.zoom_to_box(proj_box)
        tmp_map.maximum_extent = proj_box

        self.register_style(style_name, style_obj)
        self.register_layer(tmp_map, style_name) 
Beispiel #3
0
def tile_generator(zoom_lvl, tile_width, tile_height, style_sheet,
                   target_storage_path):
    print('\n\t[+]Generating tiles in zoom level -- {}\n'.format(zoom_lvl))
    tiles = get_tile_extent(zoom_lvl, (-180, +90), tile_width, tile_height,
                            360, 180)
    if (not tiles):
        return False
    for key, value in tiles.items():
        map_obj = Map(tile_width, tile_height,
                      '+proj=longlat +datum=WGS84 +no_defs ')
        if (not format_style_sheet(style_sheet, [
                'layer1', 'layer2', 'layer3', 'layer4', 'layer5', 'layer6'
        ], 'Parameter', ['name', 'extent'], '{}, {}, {}, {}'.format(*value),
                                   'tmp.xml')):
            return False
        print('\t\t[+]Rendering tile {} - {} - {} ...'.format(
            zoom_lvl, *key.split(',')))
        load_map(map_obj, 'tmp.xml')  # loads generated XML style sheet
        map_obj.zoom_to_box(Box2d(*value))
        render_to_file(
            map_obj,
            join(target_storage_path,
                 '{}_{}_{}.png'.format(zoom_lvl, *key.split(','))), 'png256')
    # removes temporary XML file, which was generated from template XML
    unlink('tmp.xml')
    return True
Beispiel #4
0
def getPixelTileEnv(x, y, ntiles=1, includeBorder=True):
    """Returns the OSM Pixel coordinate Box2d for the tile(s) for
    the specified tile(s)."""
    border = 0
    size = TILE_SIZE * ntiles
    if includeBorder:
        border = BORDER_WIDTH
    return Box2d(x * size - border, y * size - border, (x + 1) * size + border,
                 (y + 1) * size + border)
Beispiel #5
0
def getTiles(envLL):
    """Gets the (basename, Box2d) of all (existing) 1/3 NED tiles
    to cover the specified Box2d"""
    fromx = int(floor(envLL.minx))
    tox = int(floor(envLL.maxx))
    fromy = int(ceil(envLL.miny))
    toy = int(ceil(envLL.maxy))
    tiles = []
    for y in range(fromy, toy + 1):
        for x in range(fromx, tox + 1):
            basename = 'n%02dw%03d' % (y, -x)
            tilepath = getTilepath(basename)
            print tilepath
            if path.isfile(tilepath):
                tiles.append((basename, Box2d(x, y - 1, x + 1, y)))
    return tiles
Beispiel #6
0
    def __init__(self, content):
        """ With MapRenderer you can render an aktionskarten map in different
            file formats like pdf, svg or png.

            Internally it uses mapnik and cairo to archieve this. A valid style
            has to be defined through `MAPNIK_OSM_XML`. Normally this a carto
            derived `style.xml`. In this file your datasource is specified. This
            can be for instance a postgres+postgis database with imported osm
            data.

            :param content: dict of map content
        """
        # Mapnik uses mercator as internal projection. Our data is encoded in
        # latlon. Therefor we need a transformer for coordindates from longlat
        # to mercator
        proj_merc = 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')
        proj_longlat = Projection('+proj=longlat +ellps=WGS84 +datum=WGS84  \
                                   +no_defs')
        transformer = ProjTransform(proj_longlat, proj_merc)

        # our maps should be printable on a DIN A4 page with 150dpi
        self._map = Map(1754, 1240)
        bbox = transformer.forward(Box2d(*content['bbox']))
        self._map.zoom_to_box(bbox)
        self._map.buffer_size = 5

        start = timer()

        # add osm data (background)
        load_map(self._map, current_app.config['MAPNIK_OSM_XML'])

        mid = timer()

        self._add_grid(content['grid'])
        self._add_features(content['features'])
        self._add_legend(content['name'], content['place'], content['datetime'],
                        content['attributes'])

        end = timer()
        print("Map.init - OSM: ", mid - start)
        print("Map.init - Map: ", end - mid)
        print("Map.init - Total: ", end - start)
Beispiel #7
0
    def __call__(self, layers, system):
        request = system['request']

        # get image width and height
        width = 256
        height = 256

        # get image bbox
        z = int(request.matchdict['z'])
        x = int(request.matchdict['x'])
        y = int(request.matchdict['y'])
        step = max / (2**(int(z) - 1))

        xmin = x * step - max
        ymin = max - y * step
        xmax = (x + 1) * step - max
        ymax = max - (y + 1) * step

        bbox = Box2d(xmin, ymax, xmax, ymin)

        m = Map(width, height)
        load_map(m, abspath_from_asset_spec('osmtm:views/map.xml'))

        for l in layers:
            m.layers.append(l)

        m.zoom_to_box(bbox)

        format = request.matchdict['format']
        if format == 'png':
            im = Image(width, height)
            render(m, im, 1, 1)

            request.response_content_type = 'image/png'
            return im.tostring('png')

        elif format == 'json':
            grid = Grid(width, height)
            render_layer(m, grid, layer=0, fields=['id'])
            utfgrid = grid.encode('utf', resolution=4)
            return json.dumps(utfgrid)
Beispiel #8
0
#!/usr/bin/python

from mapnik import Box2d
    
# Misc test areas
WA = Box2d(-125.3, 45.4, -116.8, 49.1)
WAdetail = Box2d(-123.4, 46.2, -120.0, 48.1)
Seattle = Box2d(-122.4, 47.5, -122.2, 47.7)
WAnw = Box2d(-125.3, 47.7, -121, 49.1)
WAne = Box2d(-121, 47.7, -116.8, 49.1)
WAsw = Box2d(-125.3, 45.4, -121, 47.7)
WAse = Box2d(-121, 45.4, -116.8, 47.7)
NEdetail = Box2d(-71.5, 42, -70.5, 43)
Stow = Box2d(-71.55, 42.40, -71.46, 42.47)
BostonSS = Box2d(-71.2, 42.0, -70.6, 42.4)
BostonDetail = Box2d(-71.11, 42.30, -70.99, 42.41)
COdetail = Box2d(-105.1, 38.7, -104.7, 39.0)
COminor = Box2d(-105.0, 38.8, -104.8, 38.95)

NEdetail1 = Box2d(-71.0, 42.0, -70.5, 42.5)
NEdetail2 = Box2d(-71.0, 42.5, -70.5, 43.0)
NEdetail3 = Box2d(-71.5, 42.0, -71.0, 42.5)
NEdetail4 = Box2d(-71.5, 42.5, -71.0, 43.0)

ca = Box2d(-124.9, 32.3, -113.9, 42.1)
cadetail = Box2d(-123, 37, -119.0, 38.0)
sfo = Box2d(-122.6, 37.6, -122.2, 37.9)
oakland = Box2d(-122.34, 37.75, -122.12, 37.89)
yosdetail = Box2d(-119.67, 37.70, -119.52, 37.76)

AbandonedRailwayRelation = Box2d(-76.660, 39.196, -76.652, 39.207)
Beispiel #9
0
    def __init__(self,
                 template,
                 sort_key=None,
                 clipped='true',
                 zoom_data='single'):
        ''' Make a new Datasource.
        
            Parameters:
        
              template:
                Required URL template with placeholders for tile zoom, x and y,
                e.g. "http://example.com/layer/{z}/{x}/{y}.json".
        
              sort_key:
                Optional field name to use when sorting features for rendering.
                E.g. "name" or "name ascending" to sort ascending by name,
                "name descending" to sort descending by name.
              
              clipped:
                Optional boolean flag to determine correct behavior for
                duplicate geometries. When tile data is not clipped, features()
                will check geometry uniqueness and throw out duplicates.

                Setting clipped to false for actually-clipped geometries has no
                effect but wastes time. Setting clipped to false for unclipped
                geometries will result in possibly wrong-looking output.

                Default is "true".
              
              zoom_data:
                Optional keyword specifying single or double zoom data tiles.
                Works especially well with relatively sparse label layers.
                
                When set to "double", tiles will be requested at one zoom level
                out from the map view, e.g. double-sized z13 tiles will be used
                to render a normal z14 map.

                Default is "single".
        '''
        scheme, host, path, p, query, f = urlparse(template)

        self.host = host
        self.port = 443 if scheme == 'https' else 80

        if ':' in host:
            self.host = host.split(':', 1)[0]
            self.port = int(host.split(':', 1)[1])

        self.path = path + ('?' if query else '') + query
        self.path = self.path.replace('%', '%%')
        self.path = self.path.replace('{Z}', '{z}').replace('{z}', '%(z)d')
        self.path = self.path.replace('{X}', '{x}').replace('{x}', '%(x)d')
        self.path = self.path.replace('{Y}', '{y}').replace('{y}', '%(y)d')

        if sort_key is None:
            self.sort, self.reverse = None, None

        elif sort_key.lower().endswith(' descending'):
            logging.debug('Will sort by %s descending' % sort_key)
            self.sort, self.reverse = sort_key.split()[0], True

        else:
            logging.debug('Will sort by %s ascending' % sort_key)
            self.sort, self.reverse = sort_key.split()[0], False

        self.clipped = clipped.lower() not in ('false', 'no', '0')
        self.zoom_adjust = {'double': 1}.get(zoom_data.lower(), 0)

        bbox = Box2d(-diameter / 2, -diameter / 2, diameter / 2, diameter / 2)
        PythonDatasource.__init__(self, envelope=bbox)
Beispiel #10
0
        def _render(value, system):
            request = system['request']

            if not isinstance(value, tuple):
                value = (None, value)

            layer_name, collection = value

            if not hasattr(collection, 'features'):
                raise ValueError('renderer is not passed a feature collection')

            # get image width and height
            try:
                img_width = int(request.params.get('img_width', 256))
            except:
                request.response_status = 400
                return 'incorrect img_width'
            try:
                img_height = int(request.params.get('img_height', 256))
            except:
                request.response_status = 400
                return 'incorrect img_height'

            # get image format
            try:
                img_format = request.params.get(
                    'img_format', request.matchdict.get('format', 'png'))
                img_format = str(img_format)
            except:
                request.response_status = 400
                return 'incorrect img_format'

            # get image bbox
            img_bbox = request.params.get('img_bbox',
                                          request.params.get('bbox'))
            if img_bbox:
                try:
                    img_bbox = map(float, img_bbox.split(','))
                except ValueError:
                    request.response_status = 400
                    return 'incorrect img_bbox'
                img_bbox = Box2d(*img_bbox)

            m = Map(img_width, img_height)
            load_map(m, mapfile)

            if len(m.layers) == 0:
                raise ValueError('no layer in the mapnik map')

            # if no layer_name is provided then, by convention, use
            # the first layer in the mapnik map
            if layer_name is None:
                layer_name = m.layers[0].name

            layer = self._set_layer_in_map(m, layer_name)
            layer.datasource = self._create_datasource(collection)

            m.zoom_to_box(img_bbox or layer.envelope())

            im = Image(img_width, img_height)
            render(m, im, 1, 1)

            # get the image format from the request

            request.response.content_type = 'image/%s' % img_format
            return im.tostring(img_format)
Beispiel #11
0

if __name__ == "__main__":
    mapfile = "my_styles/mapnik2normal.xml"

    map_uri = "map.png"

    lat = 49.25
    lon = 7.0
    if len(sys.argv) == 2:
        zoom = int(sys.argv[1])
    else:
        zoom = 13
    imgx = 500
    imgy = 400

    ll = center_to_bbox(lat, lon, zoom, imgx, imgy)
    m = Map(imgx, imgy)
    load_map(m, mapfile)
    prj = 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")
    c0 = prj.forward(Coord(ll[0], ll[1]))
    c1 = prj.forward(Coord(ll[2], ll[3]))
    bbox = Box2d(c0.x, c0.y, c1.x, c1.y)
    m.zoom_to_box(bbox)
    im = Image(imgx, imgy)
    render(m, im)
    view = im.view(0, 0, imgx, imgy)  # x,y,width,height
    view.save(map_uri, 'png')
Beispiel #12
0
transform = ProjTransform(latlon, merc)

if len(sys.argv) == 3:
    ll = transform.forward(Coord(float(sys.argv[1]), float(sys.argv[2])))
    if (ll.y > max_3785):
        print(' '.join([str(ll.x), str(max_3785)]))
    elif (ll.y < -max_3785):
        print(' '.join([str(ll.x), str(-max_3785)]))
    else:
        print(' '.join([str(ll.x), str(ll.y)]))

elif len(sys.argv) == 5:
    minx, miny, maxx, maxy = (float(sys.argv[1]), float(sys.argv[2]),
                              float(sys.argv[3]), float(sys.argv[4]))

    if (miny < -max_4326):
        miny = -max_4326

    if (maxy > max_4326):
        maxy = max_4326

    bbox = transform.forward(Box2d(minx, miny, maxx, maxy))
    print(' '.join(
        [str(bbox.minx),
         str(bbox.miny),
         str(bbox.maxx),
         str(bbox.maxy)]))

else:
    print("Error: Incorrect number of arguments")
Beispiel #13
0
    def _buildMap(self, params):
        """This variant of buildmap just serves up the map as defined in the
        xml file, plus some customizations from the params. Style and SRS are
        ignored."""
        if str(params['crs']) not in self.allowedepsgcodes:
            raise OGCException(
                'Unsupported CRS "%s" requested.' % str(params['crs']).upper(),
                'InvalidCRS')
        if params['bbox'][0] >= params['bbox'][2]:
            raise OGCException(
                "BBOX values don't make sense.  minx is greater than maxx.")
        if params['bbox'][1] >= params['bbox'][3]:
            raise OGCException(
                "BBOX values don't make sense.  miny is greater than maxy.")

        # There should be only one layer requested.
        if len(params['layers']) <> 1:
            raise OGCException(
                "When specifying a pre-rendered map, only one layer is allowed."
            )

        # retrieve the map object and set width and height.
        # leave srs alone.
        m = self.mapfactory.layers[params['layers'][0]]
        m.width = params['width']
        m.height = params['height']

        transparent = params.get('transparent', '').lower() == 'true'

        # disable transparent on incompatible formats
        if transparent and params.get('format', '') == 'image/jpeg':
            transparent = False

        if transparent:
            # transparent has highest priority
            pass
        elif params.has_key('bgcolor'):
            # if not transparent use bgcolor in url
            m.background = params['bgcolor']
        else:
            # if not bgcolor in url use map background
            if mapnik_version() >= 200000:
                bgcolor = self.mapfactory.map_attributes.get('bgcolor', None)
            else:
                bgcolor = self.mapfactory.map_attributes.get(
                    'background-color', None)

            if bgcolor:
                m.background = bgcolor
            else:
                # if not map background defined use white color
                m.background = Color(255, 255, 255, 255)

        if params.has_key('buffer_size'):
            if params['buffer_size']:
                m.buffer_size = params['buffer_size']
        else:
            buffer_ = self.mapfactory.map_attributes.get('buffer_size')
            if buffer_:
                m.buffer_size = self.mapfactory.map_attributes['buffer_size']

        m.zoom_to_box(
            Box2d(params['bbox'][0], params['bbox'][1], params['bbox'][2],
                  params['bbox'][3]))
        return m
Beispiel #14
0
    def _buildMap(self, params):
        if str(params['crs']) not in self.allowedepsgcodes:
            raise OGCException(
                'Unsupported CRS "%s" requested.' % str(params['crs']).upper(),
                'InvalidCRS')
        if params['bbox'][0] >= params['bbox'][2]:
            raise OGCException(
                "BBOX values don't make sense.  minx is greater than maxx.")
        if params['bbox'][1] >= params['bbox'][3]:
            raise OGCException(
                "BBOX values don't make sense.  miny is greater than maxy.")

        # relax this for now to allow for a set of specific layers (meta layers even)
        # to be used without known their styles or putting the right # of commas...

        #if params.has_key('styles') and len(params['styles']) != len(params['layers']):
        #    raise OGCException('STYLES length does not match LAYERS length.')
        m = Map(params['width'], params['height'], '+init=%s' % params['crs'])

        transparent = params.get('transparent', '').lower() == 'true'

        # disable transparent on incompatible formats
        if transparent and params.get('format', '') == 'image/jpeg':
            transparent = False

        if transparent:
            # transparent has highest priority
            pass
        elif params.has_key('bgcolor'):
            # if not transparent use bgcolor in url
            m.background = params['bgcolor']
        else:
            # if not bgcolor in url use map background
            if mapnik_version() >= 200000:
                bgcolor = self.mapfactory.map_attributes.get('bgcolor', None)
            else:
                bgcolor = self.mapfactory.map_attributes.get(
                    'background-color', None)

            if bgcolor:
                m.background = bgcolor
            else:
                # if not map background defined use white color
                m.background = Color(255, 255, 255, 255)

        if params.has_key('buffer_size'):
            if params['buffer_size']:
                m.buffer_size = params['buffer_size']
        else:
            buffer_ = self.mapfactory.map_attributes.get('buffer_size')
            if buffer_:
                m.buffer_size = self.mapfactory.map_attributes['buffer_size']

        # haiti spec tmp hack! show meta layers without having
        # to request huge string to avoid some client truncating it!
        if params['layers'] and params['layers'][0] in (
                'osm_haiti_overlay', 'osm_haiti_overlay_900913'):
            for layer_obj in self.mapfactory.ordered_layers:
                layer = copy_layer(layer_obj)
                if not hasattr(layer, 'meta_style'):
                    pass
                else:
                    layer.styles.append(layer.meta_style)
                    m.append_style(
                        layer.meta_style,
                        self.mapfactory.meta_styles[layer.meta_style])
                    m.layers.append(layer)
        # a non WMS spec way of requesting all layers
        # uses orderedlayers that preserves original ordering in XML mapfile
        elif params['layers'] and params['layers'][0] == '__all__':
            for layer_obj in self.mapfactory.ordered_layers:
                # if we don't copy the layer here we get
                # duplicate layers added to the map because the
                # layer is kept around and the styles "pile up"...
                layer = copy_layer(layer_obj)
                if hasattr(layer, 'meta_style'):
                    continue
                reqstyle = layer.wmsdefaultstyle
                if reqstyle in self.mapfactory.aggregatestyles.keys():
                    for stylename in self.mapfactory.aggregatestyles[reqstyle]:
                        layer.styles.append(stylename)
                else:
                    layer.styles.append(reqstyle)
                for stylename in layer.styles:
                    if stylename in self.mapfactory.styles.keys():
                        m.append_style(stylename,
                                       self.mapfactory.styles[stylename])
                m.layers.append(layer)
        else:
            for layerindex, layername in enumerate(params['layers']):
                if layername in self.mapfactory.meta_layers:
                    layer = copy_layer(self.mapfactory.meta_layers[layername])
                    layer.styles.append(layername)
                    m.append_style(layername,
                                   self.mapfactory.meta_styles[layername])
                else:
                    try:
                        # uses unordered dict of layers
                        # order based on params['layers'] request which
                        # should be originally informed by order of GetCaps response
                        layer = copy_layer(self.mapfactory.layers[layername])
                    except KeyError:
                        raise OGCException(
                            'Layer "%s" not defined.' % layername,
                            'LayerNotDefined')
                    try:
                        reqstyle = params['styles'][layerindex]
                    except IndexError:
                        reqstyle = ''
                    if len(layer.wmsextrastyles) > 1 and reqstyle == 'default':
                        reqstyle = ''
                    if reqstyle and reqstyle not in layer.wmsextrastyles:
                        raise OGCException(
                            'Invalid style "%s" requested for layer "%s".' %
                            (reqstyle, layername), 'StyleNotDefined')
                    if not reqstyle:
                        reqstyle = layer.wmsdefaultstyle
                    if reqstyle in self.mapfactory.aggregatestyles.keys():
                        for stylename in self.mapfactory.aggregatestyles[
                                reqstyle]:
                            layer.styles.append(stylename)
                    else:
                        layer.styles.append(reqstyle)

                    for stylename in layer.styles:
                        if stylename in self.mapfactory.styles.keys():
                            m.append_style(stylename,
                                           self.mapfactory.styles[stylename])
                        else:
                            raise ServerConfigurationError(
                                'Layer "%s" refers to non-existent style "%s".'
                                % (layername, stylename))

                m.layers.append(layer)
        m.zoom_to_box(
            Box2d(params['bbox'][0], params['bbox'][1], params['bbox'][2],
                  params['bbox'][3]))
        return m
Beispiel #15
0
 def envPixelToLL(self, env, zoom):
     lb = self.pixelToLL(Coord(env.minx, env.miny), zoom)
     rt = self.pixelToLL(Coord(env.maxx, env.maxy), zoom)
     return Box2d(lb.x, lb.y, rt.x, rt.y)
Beispiel #16
0
 def envLLToPixel(self, env, zoom):
     lb = self.LLToPixel(Coord(env.minx, env.miny), zoom)
     rt = self.LLToPixel(Coord(env.maxx, env.maxy), zoom)
     return Box2d(lb.x, lb.y, rt.x, rt.y)