def test_get_kml_nw(self, app): resp = app.get("/kml/wms_cache_nw/1/0/0.kml") xml = resp.lxml assert validate_with_xsd(xml, "kml/2.2.0/ogckml22.xsd") assert bbox_equals( self._bbox(xml.xpath("/kml:kml/kml:Document", namespaces=ns)[0]), (-180, -90, 0, 0), ) assert bbox_equals( self._bbox( xml.xpath("/kml:kml/kml:Document/kml:GroundOverlay", namespaces=ns)[0]), (-180, -66.51326, -90, 0), ) assert xml.xpath( "/kml:kml/kml:Document/kml:GroundOverlay/kml:Icon/kml:href/text()", namespaces=ns, ) == [ "http://localhost/kml/wms_cache_nw/EPSG900913/2/0/1.jpeg", "http://localhost/kml/wms_cache_nw/EPSG900913/2/1/1.jpeg", "http://localhost/kml/wms_cache_nw/EPSG900913/2/0/0.jpeg", "http://localhost/kml/wms_cache_nw/EPSG900913/2/1/0.jpeg", ] assert xml.xpath( "/kml:kml/kml:Document/kml:NetworkLink/kml:Link/kml:href/text()", namespaces=ns, ) == [ "http://localhost/kml/wms_cache_nw/EPSG900913/2/0/1.kml", "http://localhost/kml/wms_cache_nw/EPSG900913/2/1/1.kml", "http://localhost/kml/wms_cache_nw/EPSG900913/2/0/0.kml", "http://localhost/kml/wms_cache_nw/EPSG900913/2/1/0.kml", ]
def test_get_kml_nw(self): resp = self.app.get('/kml/wms_cache_nw/1/0/0.kml') xml = resp.lxml assert validate_with_xsd(xml, 'kml/2.2.0/ogckml22.xsd') assert bbox_equals( self._bbox(xml.xpath('/kml:kml/kml:Document', namespaces=ns)[0]), (-180, -90, 0, 0) ) assert bbox_equals( self._bbox(xml.xpath('/kml:kml/kml:Document/kml:GroundOverlay', namespaces=ns)[0]), (-180, -66.51326, -90, 0) ) eq_(xml.xpath('/kml:kml/kml:Document/kml:GroundOverlay/kml:Icon/kml:href/text()', namespaces=ns), ['http://localhost/kml/wms_cache_nw/EPSG900913/2/0/1.jpeg', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/1/1.jpeg', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/0/0.jpeg', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/1/0.jpeg'] ) eq_(xml.xpath('/kml:kml/kml:Document/kml:NetworkLink/kml:Link/kml:href/text()', namespaces=ns), ['http://localhost/kml/wms_cache_nw/EPSG900913/2/0/1.kml', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/1/1.kml', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/0/0.kml', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/1/0.kml'] )
def test_get_kml(self): resp = self.app.get('/kml/wms_cache/0/0/0.kml') xml = resp.lxml assert validate_with_xsd(xml, 'kml/2.2.0/ogckml22.xsd') assert bbox_equals( self._bbox(xml.xpath('/kml:kml/kml:Document', namespaces=ns)[0]), (-180, -90, 180, 90) ) assert bbox_equals( self._bbox(xml.xpath('/kml:kml/kml:Document/kml:GroundOverlay', namespaces=ns)[0]), (-180, 0, 0, 90) ) eq_(xml.xpath('/kml:kml/kml:Document/kml:GroundOverlay/kml:Icon/kml:href/text()', namespaces=ns), ['http://localhost/kml/wms_cache/EPSG900913/1/0/1.jpeg', 'http://localhost/kml/wms_cache/EPSG900913/1/1/1.jpeg', 'http://localhost/kml/wms_cache/EPSG900913/1/0/0.jpeg', 'http://localhost/kml/wms_cache/EPSG900913/1/1/0.jpeg'] ) eq_(xml.xpath('/kml:kml/kml:Document/kml:NetworkLink/kml:Link/kml:href/text()', namespaces=ns), ['http://localhost/kml/wms_cache/EPSG900913/1/0/1.kml', 'http://localhost/kml/wms_cache/EPSG900913/1/1/1.kml', 'http://localhost/kml/wms_cache/EPSG900913/1/0/0.kml', 'http://localhost/kml/wms_cache/EPSG900913/1/1/0.kml'] ) etag = hashlib.md5(resp.body).hexdigest() max_age = base_config().tiles.expires_hours * 60 * 60 self._check_cache_control_headers(resp, etag, max_age, None) resp = self.app.get('/kml/wms_cache/0/0/0.kml', headers={'If-None-Match': etag}) eq_(resp.status, '304 Not Modified')
def test_get_kml_nw(self): resp = self.app.get('/kml/wms_cache_nw/1/0/0.kml') xml = resp.lxml assert validate_with_xsd(xml, 'kml/2.2.0/ogckml22.xsd') assert bbox_equals( self._bbox(xml.xpath('/kml:kml/kml:Document', namespaces=ns)[0]), (-180, -90, 0, 0)) assert bbox_equals( self._bbox( xml.xpath('/kml:kml/kml:Document/kml:GroundOverlay', namespaces=ns)[0]), (-180, -66.51326, -90, 0)) eq_( xml.xpath( '/kml:kml/kml:Document/kml:GroundOverlay/kml:Icon/kml:href/text()', namespaces=ns), [ 'http://localhost/kml/wms_cache_nw/EPSG900913/2/0/1.jpeg', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/1/1.jpeg', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/0/0.jpeg', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/1/0.jpeg' ]) eq_( xml.xpath( '/kml:kml/kml:Document/kml:NetworkLink/kml:Link/kml:href/text()', namespaces=ns), [ 'http://localhost/kml/wms_cache_nw/EPSG900913/2/0/1.kml', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/1/1.kml', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/0/0.kml', 'http://localhost/kml/wms_cache_nw/EPSG900913/2/1/0.kml' ])
def wms_query_eq(expected, actual): """ >>> wms_query_eq('bAR=baz&foo=bizz&bbOX=0,0,100000,100000', 'foO=bizz&BBOx=-.0001,0.01,99999.99,100000.09&bar=baz') True >>> wms_query_eq('bAR=baz&foo=bizz&bbOX=0,0,100000,100000', 'foO=bizz&BBOx=-.0001,0.01,99999.99,100000.11&bar=baz') False >>> wms_query_eq('/service?bar=baz&fOO=bizz', 'foo=bizz&bar=baz') False >>> wms_query_eq('/1/2/3.png', '/1/2/3.png') True >>> wms_query_eq('/1/2/3.png', '/1/2/0.png') False """ from mapproxy.srs import bbox_equals if path_from_query(expected) != path_from_query(actual): return False expected = query_to_dict(expected) actual = query_to_dict(actual) if 'bbox' in expected and 'bbox' in actual: expected = expected.copy() expected_bbox = [float(x) for x in expected.pop('bbox').split(',')] actual = actual.copy() actual_bbox = [float(x) for x in actual.pop('bbox').split(',')] if expected != actual: return False if not bbox_equals(expected_bbox, actual_bbox): return False else: if expected != actual: return False return True
def auth(service, layers, environ, query_extent, **kw): eq_(environ['PATH_INFO'], '/kml/layer3_EPSG900913/1/0/0.jpeg') eq_(service, 'kml') eq_(len(layers), 1) eq_(query_extent[0], 'EPSG:900913') assert bbox_equals(query_extent[1], (-20037508.342789244, -20037508.342789244, 0, 0)) return auth_dict
def auth(service, layers, environ, query_extent, **kw): eq_(environ['PATH_INFO'], '/wmts/layer3/GLOBAL_MERCATOR/1/0/0.jpeg') eq_(service, 'wmts') eq_(len(layers), 1) eq_(query_extent[0], 'EPSG:900913') assert bbox_equals(query_extent[1], (-20037508.342789244, 0, 0, 20037508.342789244)) return auth_dict
def is_subset_of(self, other): """ Returns ``True`` if every tile in `self` is present in `other`. Tile coordinates might differ and `other` may contain more tiles (more levels, larger bbox). """ if self.srs != other.srs: return False if self.tile_size != other.tile_size: return False # check if all level tiles from self align with (affected) # tiles from other for self_level, self_level_res in self.resolutions.iteritems(): level_size = ( self.grid_sizes[self_level][0] * self.tile_size[0], self.grid_sizes[self_level][1] * self.tile_size[1] ) level_bbox = self._tiles_bbox([ (0, 0, self_level), (self.grid_sizes[self_level][0] - 1, self.grid_sizes[self_level][1] - 1, self_level) ]) bbox, level = other.get_affected_bbox_and_level(level_bbox, level_size) bbox, grid_size, tiles = other.get_affected_level_tiles(level_bbox, level) if other.resolution(level) != self_level_res: return False if not bbox_equals(bbox, level_bbox): return False return True
def test_intersection(self): assert (DefaultMapExtent().intersection(MapExtent((0, 0, 10, 10), SRS(4326))) == MapExtent((0, 0, 10, 10), SRS(4326))) assert (MapExtent((0, 0, 10, 10), SRS(4326)).intersection(MapExtent((20, 20, 30, 30), SRS(4326))) == None) sub = MapExtent((0, 0, 10, 10), SRS(4326)).intersection(MapExtent((-1000, -1000, 100000, 100000), SRS(3857))) bbox = SRS(3857).transform_bbox_to(SRS(4326), (0, 0, 100000, 100000), 0) assert bbox_equals(bbox, sub.bbox)
def test_intersection(self): eq_(self.coverage.intersection((15, 15, 20, 20), SRS(4326)), BBOXCoverage((15, 15, 20, 20), SRS(4326))) eq_(self.coverage.intersection((15, 15, 80, 20), SRS(4326)), BBOXCoverage((15, 15, 80, 20), SRS(4326))) eq_(self.coverage.intersection((9, 10, 20, 20), SRS(4326)), BBOXCoverage((9, 10, 20, 20), SRS(4326))) eq_(self.coverage.intersection((-30, 10, -8, 70), SRS(4326)), BBOXCoverage((-10, 10, -8, 70), SRS(4326))) eq_(self.coverage.intersection((-30, 10, -11, 70), SRS(4326)), None) eq_(self.coverage.intersection((0, 0, 1000, 1000), SRS(900913)), None) assert bbox_equals( self.coverage.intersection((0, 0, 1500000, 1500000), SRS(900913)).bbox, (0.0, 10, 13.47472926179282, 13.352207626707813), )
def auth(service, layers, environ, query_extent, **kw): eq_(environ['PATH_INFO'], '/tms/1.0.0/layer1_EPSG900913/0/0/0.png') eq_(service, 'tms') eq_(query_extent[0], 'EPSG:900913') assert bbox_equals(query_extent[1], (-20037508.342789244, -20037508.342789244, 0, 0)) eq_(len(layers), 1) return { 'authorized': 'partial', 'layers': { 'layer1': {'tile': True}, } }
def _image(self, query): try: src_bbox, tile_grid, affected_tile_coords = \ self.grid.get_affected_tiles(query.bbox, query.size, req_srs=query.srs) except NoTiles: raise BlankImage() except GridError as ex: raise MapBBOXError(ex.args[0]) num_tiles = tile_grid[0] * tile_grid[1] if self.max_tile_limit and num_tiles >= self.max_tile_limit: raise MapBBOXError( "too many tiles, max_tile_limit: %s, num_tiles: %s" % (self.max_tile_limit, num_tiles)) if query.tiled_only: if num_tiles > 1: raise MapBBOXError("not a single tile") bbox = query.bbox if not bbox_equals(bbox, src_bbox, abs((bbox[2] - bbox[0]) / query.size[0] / 10), abs((bbox[3] - bbox[1]) / query.size[1] / 10)): raise MapBBOXError("query does not align to tile boundaries") with self.tile_manager.session(): tile_collection = self.tile_manager.load_tile_coords( affected_tile_coords, with_metadata=query.tiled_only) if tile_collection.empty: raise BlankImage() if query.tiled_only: tile = tile_collection[0].source tile.image_opts = self.tile_manager.image_opts tile.cacheable = tile_collection[0].cacheable return tile tile_sources = [tile.source for tile in tile_collection] tiled_image = TiledImage(tile_sources, src_bbox=src_bbox, src_srs=self.grid.srs, tile_grid=tile_grid, tile_size=self.grid.tile_size) try: return tiled_image.transform(query.bbox, query.srs, query.size, self.tile_manager.image_opts) except ProjError: raise MapBBOXError("could not transform query BBOX") except IOError as ex: from mapproxy.source import SourceError raise SourceError("unable to transform image: %s" % ex)
def auth(service, layers, query_extent, **kw): eq_(service, 'kml') eq_(len(layers), 1) eq_(query_extent[0], 'EPSG:900913') assert bbox_equals(query_extent[1], (-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244)) return { 'authorized': 'partial', 'layers': { 'layer1': {'tile': True}, } }
def auth(service, layers, environ, query_extent, **kw): eq_(environ['PATH_INFO'], '/wmts/layer1/GLOBAL_MERCATOR/0/0/0.png') eq_(service, 'wmts') eq_(len(layers), 1) eq_(query_extent[0], 'EPSG:900913') assert bbox_equals(query_extent[1], (-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244)) return { 'authorized': 'partial', 'layers': { 'layer1': {'tile': True}, } }
def auth(service, layers, environ, query_extent, **kw): eq_(environ['PATH_INFO'], '/tms/1.0.0/layer1/0/0/0.png') eq_(service, 'tms') eq_(query_extent[0], 'EPSG:900913') assert bbox_equals(query_extent[1], (-20037508.342789244, -20037508.342789244, 0, 0)) eq_(len(layers), 1) return { 'authorized': 'partial', 'layers': { 'layer1': {'tile': True}, } }
def test_get_kml(self, app, base_config): resp = app.get("/kml/wms_cache/0/0/0.kml") xml = resp.lxml assert validate_with_xsd(xml, "kml/2.2.0/ogckml22.xsd") assert bbox_equals( self._bbox(xml.xpath("/kml:kml/kml:Document", namespaces=ns)[0]), (-180, -90, 180, 90), ) assert bbox_equals( self._bbox( xml.xpath("/kml:kml/kml:Document/kml:GroundOverlay", namespaces=ns)[0]), (-180, 0, 0, 90), ) assert xml.xpath( "/kml:kml/kml:Document/kml:GroundOverlay/kml:Icon/kml:href/text()", namespaces=ns, ) == [ "http://localhost/kml/wms_cache/EPSG900913/1/0/1.jpeg", "http://localhost/kml/wms_cache/EPSG900913/1/1/1.jpeg", "http://localhost/kml/wms_cache/EPSG900913/1/0/0.jpeg", "http://localhost/kml/wms_cache/EPSG900913/1/1/0.jpeg", ] assert xml.xpath( "/kml:kml/kml:Document/kml:NetworkLink/kml:Link/kml:href/text()", namespaces=ns, ) == [ "http://localhost/kml/wms_cache/EPSG900913/1/0/1.kml", "http://localhost/kml/wms_cache/EPSG900913/1/1/1.kml", "http://localhost/kml/wms_cache/EPSG900913/1/0/0.kml", "http://localhost/kml/wms_cache/EPSG900913/1/1/0.kml", ] etag = hashlib.md5(resp.body).hexdigest() max_age = base_config.tiles.expires_hours * 60 * 60 self._check_cache_control_headers(resp, etag, max_age, None) resp = app.get("/kml/wms_cache/0/0/0.kml", headers={"If-None-Match": etag}) assert resp.status == "304 Not Modified"
def test_intersection(self): eq_(self.coverage.intersection((15, 15, 20, 20), SRS(4326)), BBOXCoverage((15, 15, 20, 20), SRS(4326))) eq_(self.coverage.intersection((15, 15, 80, 20), SRS(4326)), BBOXCoverage((15, 15, 80, 20), SRS(4326))) eq_(self.coverage.intersection((9, 10, 20, 20), SRS(4326)), BBOXCoverage((9, 10, 20, 20), SRS(4326))) eq_(self.coverage.intersection((-30, 10, -8, 70), SRS(4326)), BBOXCoverage((-10, 10, -8, 70), SRS(4326))) eq_(self.coverage.intersection((-30, 10, -11, 70), SRS(4326)), None) eq_(self.coverage.intersection((0, 0, 1000, 1000), SRS(900913)), None) assert bbox_equals( self.coverage.intersection((0, 0, 1500000, 1500000), SRS(900913)).bbox, (0.0, 10, 13.47472926179282, 13.352207626707813))
def _no_transformation_needed(self, src_size, src_bbox, dst_size, dst_bbox): """ >>> src_bbox = (-2504688.5428486541, 1252344.271424327, ... -1252344.271424327, 2504688.5428486541) >>> dst_bbox = (-2504688.5431999983, 1252344.2704, ... -1252344.2719999983, 2504688.5416000001) >>> from mapproxy.srs import SRS >>> t = ImageTransformer(SRS(900913), SRS(900913)) >>> t._no_transformation_needed((256, 256), src_bbox, (256, 256), dst_bbox) True """ xres = (dst_bbox[2]-dst_bbox[0])/dst_size[0] yres = (dst_bbox[3]-dst_bbox[1])/dst_size[1] return (src_size == dst_size and self.src_srs == self.dst_srs and bbox_equals(src_bbox, dst_bbox, xres/10, yres/10))
def auth(service, layers, environ, query_extent, **kw): eq_(environ['PATH_INFO'], '/wmts/layer3/GLOBAL_MERCATOR/1/0/0.jpeg') eq_(service, 'wmts') eq_(len(layers), 1) eq_(query_extent[0], 'EPSG:900913') assert bbox_equals(query_extent[1], (-20037508.342789244, 0, 0, 20037508.342789244)) return { 'authorized': 'partial', 'limited_to': { 'geometry': [-180, -89, -90, 89], 'srs': 'EPSG:4326', }, 'layers': { 'layer3': {'tile': True}, } }
def _image(self, query): try: src_bbox, tile_grid, affected_tile_coords = \ self.grid.get_affected_tiles(query.bbox, query.size, req_srs=query.srs) except NoTiles: raise BlankImage() except GridError as ex: raise MapBBOXError(ex.args[0]) num_tiles = tile_grid[0] * tile_grid[1] if self.max_tile_limit and num_tiles >= self.max_tile_limit: raise MapBBOXError("too many tiles") if query.tiled_only: if num_tiles > 1: raise MapBBOXError("not a single tile") bbox = query.bbox if not bbox_equals(bbox, src_bbox, abs((bbox[2]-bbox[0])/query.size[0]/10), abs((bbox[3]-bbox[1])/query.size[1]/10)): raise MapBBOXError("query does not align to tile boundaries") with self.tile_manager.session(): tile_collection = self.tile_manager.load_tile_coords(affected_tile_coords, with_metadata=query.tiled_only) if tile_collection.empty: raise BlankImage() if query.tiled_only: tile = tile_collection[0].source tile.image_opts = self.tile_manager.image_opts tile.cacheable = tile_collection[0].cacheable return tile tile_sources = [tile.source for tile in tile_collection] tiled_image = TiledImage(tile_sources, src_bbox=src_bbox, src_srs=self.grid.srs, tile_grid=tile_grid, tile_size=self.grid.tile_size) try: return tiled_image.transform(query.bbox, query.srs, query.size, self.tile_manager.image_opts) except ProjError: raise MapBBOXError("could not transform query BBOX") except IOError as ex: from mapproxy.source import SourceError raise SourceError("unable to transform image: %s" % ex)
def is_subset_of(self, other): """ Returns ``True`` if every tile in `self` is present in `other`. Tile coordinates might differ and `other` may contain more tiles (more levels, larger bbox). """ if self.srs != other.srs: return False if self.tile_size != other.tile_size: return False # check if all level tiles from self align with (affected) # tiles from other for self_level, self_level_res in self.resolutions.iteritems(): level_size = (self.grid_sizes[self_level][0] * self.tile_size[0], self.grid_sizes[self_level][1] * self.tile_size[1]) level_bbox = self._tiles_bbox([ (0, 0, self_level), (self.grid_sizes[self_level][0] - 1, self.grid_sizes[self_level][1] - 1, self_level) ]) try: bbox, level = other.get_affected_bbox_and_level( level_bbox, level_size) except NoTiles: return False try: bbox, grid_size, tiles = other.get_affected_level_tiles( level_bbox, level) except GridError: return False if other.resolution(level) != self_level_res: return False if not bbox_equals(bbox, level_bbox): return False return True
def test_bbox(self): assert bbox_equals(self.coverage.bbox, [-8.98315284, 0.0, 20.0, 10.0], 0.0001), self.coverage.bbox
def test_bbox(self): assert bbox_equals(self.coverage.bbox, [5.0, 5.0, 10.0, 10.0], 0.0001), self.coverage.bbox
def test_bbox(self): assert bbox_equals(self.coverage.bbox, [-10, 0, 120, 80], 0.0001)
def test_bbox(self): assert bbox_equals(self.extent.bbox, [-10, 10, 80, 80], 0.0001)
class CacheMapLayer(MapLayer): def __init__(self, tile_manager, extent=None, image_opts=None, max_tile_limit=None): MapLayer.__init__(self, image_opts=image_opts) self.tile_manager = tile_manager self.grid = tile_manager.grid self.extent = extent or map_extent_from_grid(self.grid) self.res_range = merge_layer_res_ranges(self.tile_manager.sources) self.transparent = tile_manager.transparent self.max_tile_limit = max_tile_limit def get_map(self, query): self.check_res_range(query) if query.tiled_only: self._check_tiled(query) query_extent = MapExtent(query.bbox, query.srs) if not query.tiled_only and self.extent and not self.extent.contains( query_extent): if not self.extent.intersects(query_extent): raise BlankImage() size, offset, bbox = bbox_position_in_image( query.bbox, query.size, self.extent.bbox_for(query.srs)) if size[0] == 0 or size[1] == 0: raise BlankImage() src_query = MapQuery(bbox, size, query.srs, query.format) resp = self._image(src_query) result = SubImageSource(resp, size=query.size, offset=offset, image_opts=self.image_opts, cacheable=resp.cacheable) else: result = self._image(query) return result def _check_tiled(self, query): if query.format != self.tile_manager.format: raise MapError("invalid tile format, use %s" % self.tile_manager.format) if query.size != self.grid.tile_size: raise MapError("invalid tile size (use %dx%d)" % self.grid.tile_size) def _image(self, query): try: src_bbox, tile_grid, affected_tile_coords = \ self.grid.get_affected_tiles(query.bbox, query.size, req_srs=query.srs) except NoTiles: raise BlankImage() except GridError, ex: raise MapBBOXError(ex.args[0]) num_tiles = tile_grid[0] * tile_grid[1] if self.max_tile_limit and num_tiles >= self.max_tile_limit: raise MapBBOXError("to many tiles") if query.tiled_only: if num_tiles > 1: raise MapBBOXError("not a single tile") bbox = query.bbox if not bbox_equals(bbox, src_bbox, (bbox[2] - bbox[0] / query.size[0] / 10), (bbox[3] - bbox[1] / query.size[1] / 10)): raise MapBBOXError("query does not align to tile boundaries") with self.tile_manager.session(): tile_collection = self.tile_manager.load_tile_coords( affected_tile_coords, with_metadata=query.tiled_only) if tile_collection.empty: raise BlankImage() if query.tiled_only: tile = tile_collection[0].source tile.image_opts = self.tile_manager.image_opts tile.cacheable = tile_collection[0].cacheable return tile tile_sources = [tile.source for tile in tile_collection] tiled_image = TiledImage(tile_sources, src_bbox=src_bbox, src_srs=self.grid.srs, tile_grid=tile_grid, tile_size=self.grid.tile_size) try: return tiled_image.transform(query.bbox, query.srs, query.size, self.tile_manager.image_opts) except ProjError: raise MapBBOXError("could not transform query BBOX")