def test_no_clip(): """Geometry is within TilePyramid bounds.""" tp = TilePyramid("geodetic") geometry = box(177.5, 67.5, -177.5, 73.125) # no multipart out_geom = clip_geometry_to_srs_bounds(geometry, tp) assert geometry == out_geom # multipart out_geom = clip_geometry_to_srs_bounds(geometry, tp, multipart=True) assert isinstance(out_geom, list) assert len(out_geom) == 1 assert geometry == out_geom[0]
def read_vector_window( input_file, tile, pixelbuffer=0, validity_check=True ): """ Reads an input vector dataset with fiona using the tile bounding box as filter and clipping geometry. Returns a list of GeoJSON like features. """ try: assert os.path.isfile(input_file) except: raise IOError("input file does not exist: %s" % input_file) try: assert pixelbuffer >= 0 except: raise ValueError("pixelbuffer must be 0 or greater") try: assert isinstance(pixelbuffer, int) except: raise ValueError("pixelbuffer must be an integer") # Check if potentially tile boundaries exceed tile matrix boundaries on # the antimeridian, the northern or the southern boundary. tile_left, tile_bottom, tile_right, tile_top = tile.bounds(pixelbuffer) touches_left = tile_left <= tile.tile_pyramid.left touches_bottom = tile_bottom <= tile.tile_pyramid.bottom touches_right = tile_right >= tile.tile_pyramid.right touches_top = tile_top >= tile.tile_pyramid.top is_on_edge = touches_left or touches_bottom or touches_right or touches_top if pixelbuffer and is_on_edge: tile_boxes = clip_geometry_to_srs_bounds( tile.bbox(pixelbuffer), tile.tile_pyramid, multipart=True ) return chain.from_iterable( _get_reprojected_features( input_file=input_file, dst_bounds=bbox.bounds, dst_crs=tile.crs, validity_check=validity_check ) for bbox in tile_boxes ) for polygon in tile_boxes: print polygon else: return _get_reprojected_features( input_file=input_file, dst_bounds=tile.bounds(pixelbuffer), dst_crs=tile.crs, validity_check=validity_check )
def _get_warped_edge_array(tile=None, input_file=None, indexes=None, dst_shape=None, resampling=None, src_nodata=None, dst_nodata=None): tile_boxes = clip_geometry_to_srs_bounds(tile.bbox, tile.tile_pyramid, multipart=True) parts_metadata = dict(left=None, middle=None, right=None, none=None) # Split bounding box into multiple parts & request each numpy array # separately. for polygon in tile_boxes: # Check on which side the antimeridian is touched by the polygon: # "left", "middle", "right" # "none" means, the tile touches the edge just on the top and/or # bottom boundary part_metadata = {} left, bottom, right, top = polygon.bounds touches_right = left == tile.tile_pyramid.left touches_left = right == tile.tile_pyramid.right touches_both = touches_left and touches_right height = int(round((top - bottom) / tile.pixel_y_size)) width = int(round((right - left) / tile.pixel_x_size)) if indexes is None: dst_shape = (None, height, width) elif isinstance(indexes, int): dst_shape = (height, width) else: dst_shape = (dst_shape[0], height, width) part_metadata.update(bounds=polygon.bounds, shape=dst_shape) if touches_both: parts_metadata.update(middle=part_metadata) elif touches_left: parts_metadata.update(left=part_metadata) elif touches_right: parts_metadata.update(right=part_metadata) else: parts_metadata.update(none=part_metadata) # Finally, stitch numpy arrays together into one. Axis -1 is the last axis # which in case of rasterio arrays always is the width (West-East). return ma.concatenate([ _get_warped_array(input_file=input_file, indexes=indexes, dst_bounds=parts_metadata[part]["bounds"], dst_shape=parts_metadata[part]["shape"], dst_crs=tile.crs, resampling=resampling, src_nodata=src_nodata, dst_nodata=dst_nodata) for part in ["none", "left", "middle", "right"] if parts_metadata[part] ], axis=-1)
def _reproject_tile_bbox(self, out_crs=None): """ Returns tile bounding box reprojected to source file CRS. If bounding box overlaps with antimeridian, a MultiPolygon is returned. """ return reproject_geometry( clip_geometry_to_srs_bounds( self.tile.bbox(pixelbuffer=self.pixelbuffer), self.tile.tile_pyramid ), self.tile.crs, out_crs )
def _read_vector_window(input_file, tile, validity_check=True): if tile.pixelbuffer and tile.is_on_edge(): return chain.from_iterable( _get_reprojected_features(input_file=input_file, dst_bounds=bbox.bounds, dst_crs=tile.crs, validity_check=validity_check) for bbox in clip_geometry_to_srs_bounds( tile.bbox, tile.tile_pyramid, multipart=True)) else: features = _get_reprojected_features(input_file=input_file, dst_bounds=tile.bounds, dst_crs=tile.crs, validity_check=validity_check) return features
def _get_warped_edge_array( tile=None, input_file=None, band_idx=None, resampling="nearest" ): LOGGER.debug("read array at pyramid edge") tile_boxes = clip_geometry_to_srs_bounds( tile.bbox, tile.tile_pyramid, multipart=True) parts_metadata = dict(left=None, middle=None, right=None, none=None) # Split bounding box into multiple parts & request each numpy array # separately. for polygon in tile_boxes: # Check on which side the antimeridian is touched by the polygon: # "left", "middle", "right" # "none" means, the tile touches the edge just on the top and/or # bottom boundary part_metadata = {} left, bottom, right, top = polygon.bounds touches_right = left == tile.tile_pyramid.left touches_left = right == tile.tile_pyramid.right touches_both = touches_left and touches_right height = int(round((top-bottom)/tile.pixel_y_size)) width = int(round((right-left)/tile.pixel_x_size)) affine = Affine.translation( left, top) * Affine.scale( tile.pixel_x_size, -tile.pixel_y_size) part_metadata.update( bounds=polygon.bounds, shape=(height, width), affine=affine) if touches_both: parts_metadata.update(middle=part_metadata) elif touches_left: parts_metadata.update(left=part_metadata) elif touches_right: parts_metadata.update(right=part_metadata) else: parts_metadata.update(none=part_metadata) # Finally, stitch numpy arrays together into one. return ma.concatenate( [ _get_warped_array( input_file=input_file, band_idx=band_idx, dst_bounds=parts_metadata[part]["bounds"], dst_shape=parts_metadata[part]["shape"], dst_affine=parts_metadata[part]["affine"], dst_crs=tile.crs, resampling=resampling) for part in ["none", "left", "middle", "right"] if parts_metadata[part] ], axis=1)
def read_vector_window(input_file, tile, validity_check=True): """ Read a window of an input vector dataset. Also clips geometry. Parameters: ----------- input_file : string path to vector file tile : ``Tile`` tile extent to read data from validity_check : bool checks if reprojected geometry is valid and throws ``RuntimeError`` if invalid (default: True) Returns ------- features : list a list of reprojected GeoJSON-like features """ # Check if potentially tile boundaries exceed tile matrix boundaries on # the antimeridian, the northern or the southern boundary. tile_left, tile_bottom, tile_right, tile_top = tile.bounds touches_left = tile_left <= tile.tile_pyramid.left touches_bottom = tile_bottom <= tile.tile_pyramid.bottom touches_right = tile_right >= tile.tile_pyramid.right touches_top = tile_top >= tile.tile_pyramid.top is_on_edge = touches_left or touches_bottom or touches_right or touches_top if tile.pixelbuffer and is_on_edge: tile_boxes = clip_geometry_to_srs_bounds(tile.bbox, tile.tile_pyramid, multipart=True) return chain.from_iterable( _get_reprojected_features(input_file=input_file, dst_bounds=bbox.bounds, dst_crs=tile.crs, validity_check=validity_check) for bbox in tile_boxes) else: features = _get_reprojected_features(input_file=input_file, dst_bounds=tile.bounds, dst_crs=tile.crs, validity_check=validity_check) return features
def test_antimeridian_clip(invalid_geom): """Clip on antimeridian.""" tp = TilePyramid("geodetic") tp_bounds = box(tp.left, tp.bottom, tp.right, tp.top) # extends on the western side geometry = box(-183.125, 67.5, -177.5, 73.125) # get GeometryCollection out_geom = clip_geometry_to_srs_bounds(geometry, tp) assert out_geom.geom_type == "GeometryCollection" # get list out_geom = clip_geometry_to_srs_bounds(geometry, tp, multipart=True) assert isinstance(out_geom, list) for sub_geom in out_geom: assert sub_geom.within(tp_bounds) # extends on the eastern side geometry = box(177.5, 67.5, 183.125, 73.125) # get GeometryCollection out_geom = clip_geometry_to_srs_bounds(geometry, tp) assert out_geom.geom_type == "GeometryCollection" # get list out_geom = clip_geometry_to_srs_bounds(geometry, tp, multipart=True) assert isinstance(out_geom, list) for sub_geom in out_geom: assert sub_geom.within(tp_bounds) # extends on both sides geometry = box(-183.125, 67.5, 183.125, 73.125) # get GeometryCollection out_geom = clip_geometry_to_srs_bounds(geometry, tp) assert out_geom.geom_type == "GeometryCollection" # get list out_geom = clip_geometry_to_srs_bounds(geometry, tp, multipart=True) assert isinstance(out_geom, list) for sub_geom in out_geom: assert sub_geom.within(tp_bounds) assert len(out_geom) == 3 # fail on invalid geometry with pytest.raises(ValueError): clip_geometry_to_srs_bounds(invalid_geom, tp)
def read_vector_window(input_file, tile, validity_check=True): """ Read a window of an input vector dataset. Also clips geometry. Parameters: ----------- input_file : string path to vector file tile : ``Tile`` tile extent to read data from validity_check : bool checks if reprojected geometry is valid and throws ``RuntimeError`` if invalid (default: True) Returns ------- features : list a list of reprojected GeoJSON-like features """ if tile.pixelbuffer and tile.is_on_edge(): tile_boxes = clip_geometry_to_srs_bounds( tile.bbox, tile.tile_pyramid, multipart=True ) return chain.from_iterable( _get_reprojected_features( input_file=input_file, dst_bounds=bbox.bounds, dst_crs=tile.crs, validity_check=validity_check ) for bbox in tile_boxes) else: features = _get_reprojected_features( input_file=input_file, dst_bounds=tile.bounds, dst_crs=tile.crs, validity_check=validity_check ) return features