def test_from_epsg(): crs_dict = CRS.from_epsg(4326) assert crs_dict['init'].lower() == 'epsg:4326' # Test with invalid EPSG code with pytest.raises(ValueError): assert CRS.from_epsg(0)
def test_issue_1446(): """Confirm resolution of #1446""" g = transform_geom( CRS.from_epsg(4326), CRS.from_epsg(32610), {"type": "Point", "coordinates": (-122.51403808499907, 38.06106733107932)}, ) assert round(g["coordinates"][0], 1) == 542630.9 assert round(g["coordinates"][1], 1) == 4212702.1
def main(): samplefile = r'bxk1-d-ck.idf' tiffile = samplefile.replace('.idf', '.geotiff') dtype = rasterio.float64 driver = 'AAIGrid' crs = CRS.from_epsg(28992) # read data from idf file idffile = idfpy.IdfFile(filepath=samplefile, mode='rb') geotransform = idffile.geotransform height = idffile.header['nrow'] width = idffile.header['ncol'] nodata = idffile.header['nodata'] transform = Affine.from_gdal(*geotransform) # write data from idf file to geotiff with rasterio profile = { 'width': width, 'height': height, 'count': 1, 'dtype': dtype, 'driver': driver, 'crs': crs, 'transform': transform, 'nodata': nodata, } # the default profile would be sufficient for the example, however the profile dict shows how to make the export # profile idffile.to_raster(tiffile, **profile)
def test_reproject_init_dest_nodata(): """No pixels should transfer over""" crs = CRS.from_epsg(4326) transform = Affine.identity() source = np.zeros((1, 100, 100)) destination = np.ones((1, 100, 100)) reproject( source, destination, src_crs=crs, src_transform=transform, dst_crs=crs, dst_transform=transform, src_nodata=0, init_dest_nodata=False ) assert destination.all()
def test_linear_units_factor(): """CRS linear units can be had""" assert CRS.from_epsg(3857).linear_units_factor[0] == 'metre' assert CRS.from_epsg(3857).linear_units_factor[1] == 1.0 assert CRS.from_epsg(2261).linear_units_factor[0] == 'US survey foot' assert CRS.from_epsg(2261).linear_units_factor[1] == pytest.approx(0.3048006096012192) with pytest.raises(CRSError): CRS.from_epsg(4326).linear_units_factor
def feature_to_mercator(feature): '''Normalize feature and converts coords to 3857. Args: feature: geojson feature to convert to mercator geometry. ''' # Ref: https://gist.github.com/dnomadb/5cbc116aacc352c7126e779c29ab7abe src_crs = CRS.from_epsg(4326) dst_crs = CRS.from_epsg(3857) geometry = feature['geometry'] if geometry['type'] == 'Polygon': xys = (zip(*part) for part in geometry['coordinates']) xys = (list(zip(*transform(src_crs, dst_crs, *xy))) for xy in xys) yield {'coordinates': list(xys), 'type': 'Polygon'} elif geometry['type'] == 'MultiPolygon': for component in geometry['coordinates']: xys = (zip(*part) for part in component) xys = (list(zip(*transform(src_crs, dst_crs, *xy))) for xy in xys) yield {'coordinates': list(xys), 'type': 'Polygon'}
def example_reproject(): import idfpy from matplotlib import pyplot as plt from rasterio import Affine from rasterio.crs import CRS from rasterio.warp import reproject, Resampling import numpy as np with idfpy.open('bxk1-d-ck.idf') as src: a = src.read(masked=True) nr, nc = src.header['nrow'], src.header['ncol'] dx, dy = src.header['dx'], src.header['dy'] src_transform = Affine.from_gdal(*src.geotransform) # define new grid transform (same extent, 10 times resolution) dst_transform = Affine.translation(src_transform.c, src_transform.f) dst_transform *= Affine.scale(dx / 10., -dy / 10.) # define coordinate system (here RD New) src_crs = CRS.from_epsg(28992) # initialize new data array b = np.empty((10*nr, 10*nc)) # reproject using Rasterio reproject( source=a, destination=b, src_transform=src_transform, dst_transform=dst_transform, src_crs=src_crs, dst_crs=src_crs, resampling=Resampling.bilinear, ) # result as masked array b = np.ma.masked_equal(b, a.fill_value) # plot images fig, axes = plt.subplots(nrows=2, ncols=1) axes[0].imshow(a.filled(np.nan)) axes[0].set_title('bxk1 original') axes[1].imshow(b.filled(np.nan)) axes[1].set_title('bxk1 resampled') plt.show()
def __init__(self, ul, crs, res, size, desc=None): self.ul = ul if isinstance(crs, six.string_types): self.crs = CRS.from_string(crs) elif isinstance(crs, int): self.crs = CRS.from_epsg(crs) else: self.crs = crs if not self.crs.is_valid: raise ValueError('Could not parse coordinate reference system ' 'string to a valid projection ({})'.format(crs)) self.crs_str = self.crs.to_string() self.res = res self.size = size self.desc = desc or 'unnamed' self._tiles = {}
def to_raster(self, fp=None, epsg=28992, driver='AAIGrid'): """export Idf to a geotiff""" self.check_read() if fp is None: fp = self.filepath.replace('.idf', '.geotiff') logging.warning('no filepath was given, exported to {fp}'.format(fp=fp)) # set profile profile = { 'width': self.header['ncol'], 'height': self.header['nrow'], 'transform': Affine.from_gdal(*self.geotransform), 'nodata': self.header['nodata'], 'count': 1, 'dtype': rasterio.float64, 'driver': driver, 'crs': CRS.from_epsg(epsg), } logging.info('writing to {f:}'.format(f=fp)) with rasterio.open(fp, 'w', **profile) as dst: dst.write(self.masked_data.astype(profile['dtype']), 1)
def query(self, range_subset=['TMEAN'], subsets={}, bbox=[], datetime_=None, format_='json', **kwargs): """ Extract data from collection collection :param range_subset: variable :param subsets: dict of subset names with lists of ranges :param bbox: bounding box [minx,miny,maxx,maxy] :param datetime_: temporal (datestamp or extent) :param format_: data format of output :returns: coverage data as dict of CoverageJSON or native format """ args = {'indexes': None} shapes = [] if all([ self._coverage_properties['x_axis_label'] in subsets, self._coverage_properties['y_axis_label'] in subsets, len(bbox) > 0 ]): msg = 'bbox and subsetting by coordinates are exclusive' LOGGER.warning(msg) raise ProviderQueryError(msg) if len(bbox) > 0: minx, miny, maxx, maxy = bbox crs_src = CRS.from_epsg(4326) crs_dest = self._data.crs if crs_src == crs_dest: LOGGER.debug('source bbox CRS and data CRS are the same') shapes = [{ 'type': 'Polygon', 'coordinates': [[ [minx, miny], [minx, maxy], [maxx, maxy], [maxx, miny], [minx, miny], ]] }] else: LOGGER.debug('source bbox CRS and data CRS are different') LOGGER.debug('reprojecting bbox into native coordinates') temp_geom_min = {"type": "Point", "coordinates": [minx, miny]} temp_geom_max = {"type": "Point", "coordinates": [maxx, maxy]} min_coord = rasterio.warp.transform_geom( crs_src, crs_dest, temp_geom_min) minx2, miny2 = min_coord['coordinates'] max_coord = rasterio.warp.transform_geom( crs_src, crs_dest, temp_geom_max) maxx2, maxy2 = max_coord['coordinates'] LOGGER.debug('Source coordinates: {}'.format( [minx, miny, maxx, maxy])) LOGGER.debug('Destination coordinates: {}'.format( [minx2, miny2, maxx2, maxy2])) shapes = [{ 'type': 'Polygon', 'coordinates': [[ [minx2, miny2], [minx2, maxy2], [maxx2, maxy2], [maxx2, miny2], [minx2, miny2], ]] }] elif (self._coverage_properties['x_axis_label'] in subsets and self._coverage_properties['y_axis_label'] in subsets): LOGGER.debug('Creating spatial subset') x = self._coverage_properties['x_axis_label'] y = self._coverage_properties['y_axis_label'] shapes = [{ 'type': 'Polygon', 'coordinates': [[[subsets[x][0], subsets[y][0]], [subsets[x][0], subsets[y][1]], [subsets[x][1], subsets[y][1]], [subsets[x][1], subsets[y][0]], [subsets[x][0], subsets[y][0]]]] }] if range_subset[0].upper() != 'TMEAN': var = range_subset[0].upper() try: self.data = self.get_file_list(var)[-1] except IndexError as err: LOGGER.error(err) raise ProviderQueryError(err) if 'season' in subsets: seasonal = subsets['season'] try: if len(seasonal) > 1: msg = 'multiple seasons are not supported' LOGGER.error(msg) raise ProviderQueryError(msg) elif seasonal != ['DJF']: season = str(seasonal[0]) self.data = self.data.replace('DJF', season) except Exception as err: LOGGER.error(err) raise ProviderQueryError(err) if datetime_ and 'trend' in self.data: msg = 'Datetime is not supported for trend' LOGGER.error(msg) raise ProviderQueryError(msg) date_file_list = False if datetime_: if '/' not in datetime_: if 'month' in self.data: month = search('_{:d}-{:d}.tif', self.data) period = '{}-{}'.format(month[0], str(month[1]).zfill(2)) self.data = self.data.replace(str(month), str(datetime_)) else: period = search('_{:d}.tif', self.data)[0] self.data = self.data.replace(str(period), str(datetime_)) else: date_file_list = self.get_file_list(range_subset[0].upper(), datetime_) args['indexes'] = list(range(1, len(date_file_list) + 1)) if not os.path.isfile(self.data): msg = 'No such file' LOGGER.error(msg) raise ProviderQueryError(msg) with rasterio.open(self.data) as _data: LOGGER.debug('Creating output coverage metadata') out_meta = _data.meta if self.options is not None: LOGGER.debug('Adding dataset options') for key, value in self.options.items(): out_meta[key] = value if shapes: # spatial subset try: LOGGER.debug('Clipping data with bbox') out_image, out_transform = rasterio.mask.mask( _data, filled=False, shapes=shapes, crop=True, indexes=None) except ValueError as err: LOGGER.error(err) raise ProviderQueryError(err) out_meta.update({ 'driver': self.native_format, 'height': out_image.shape[1], 'width': out_image.shape[2], 'transform': out_transform }) else: # no spatial subset LOGGER.debug('Creating data in memory with band selection') out_image = _data.read(indexes=[1]) if bbox: out_meta['bbox'] = [bbox[0], bbox[1], bbox[2], bbox[3]] elif shapes: out_meta['bbox'] = [ subsets[x][0], subsets[y][0], subsets[x][1], subsets[y][1] ] else: out_meta['bbox'] = [ _data.bounds.left, _data.bounds.bottom, _data.bounds.right, _data.bounds.top ] out_meta['units'] = _data.units self.filename = self.data.split('/')[-1] if 'trend' not in self.data and datetime_: self.filename = self.filename.split('_') self.filename[-1] = '{}.tif'.format(datetime_.replace( '/', '-')) self.filename = '_'.join(self.filename) # CovJSON output does not support multiple bands yet # Only the first timestep is returned if format_ == 'json': if date_file_list: err = 'Date range not yet supported for CovJSON output' LOGGER.error(err) raise ProviderQueryError(err) else: LOGGER.debug('Creating output in CoverageJSON') out_meta['bands'] = args['indexes'] return self.gen_covjson(out_meta, out_image) else: if date_file_list: LOGGER.debug('Serializing data in memory') with MemoryFile() as memfile: out_meta.update(count=len(date_file_list)) with memfile.open(**out_meta) as dest: for id, layer in enumerate(date_file_list, start=1): with rasterio.open(layer) as src1: if shapes: # spatial subset try: LOGGER.debug('Clipping data') out_image, out_transform = \ rasterio.mask.mask( src1, filled=False, shapes=shapes, crop=True, indexes=1) except ValueError as err: LOGGER.error(err) raise ProviderQueryError(err) else: out_image = src1.read(indexes=1) dest.write_band(id, out_image) # return data in native format LOGGER.debug('Returning data in native format') return memfile.read() else: LOGGER.debug('Serializing data in memory') with MemoryFile() as memfile: with memfile.open(**out_meta) as dest: dest.write(out_image) # return data in native format LOGGER.debug('Returning data in native format') return memfile.read()
def test_linear_units(): """CRS linear units can be had""" assert CRS.from_epsg(3857).linear_units == 'metre' assert CRS.from_epsg(2261).linear_units == 'US survey foot' assert CRS.from_epsg(4326).linear_units == 'unknown'
def test_to_wkt__env_version(): with Env(OSR_WKT_FORMAT="WKT2_2018"): assert CRS.from_epsg(4326).to_wkt().startswith('GEOGCRS["WGS 84",')
def test_equality_from_epsg(epsg_code): assert CRS.from_epsg(epsg_code) == CRS.from_epsg(epsg_code)
def test_crs_hash_unequal(): """hashes of non-equivalent CRS are not equal""" assert hash(CRS.from_epsg(3857)) != hash(CRS.from_epsg(4326))
def test_crs_hash(): """hashes of equivalent CRS are equal""" assert hash(CRS.from_epsg(3857)) == hash(CRS.from_epsg(3857))
# coding=utf-8 from __future__ import absolute_import, division import re from marblecutter import render from rasterio.crs import CRS from .formats import Skadi HALF_ARC_SEC = (1 / 3600) * .5 SHAPE = (3601, 3601) SKADI_CRS = CRS.from_epsg(4326) SKADI_FORMAT = Skadi() SKADI_TILE_NAME_PATTERN = re.compile('^([NS])([0-9]{2})([EW])([0-9]{3})$') def _bbox(x, y): return ((x - 180) - HALF_ARC_SEC, (y - 90) - HALF_ARC_SEC, (x - 179) + HALF_ARC_SEC, (y - 89) + HALF_ARC_SEC) def _parse_skadi_tile(tile_name): m = SKADI_TILE_NAME_PATTERN.match(tile_name) if m: y = int(m.group(2)) x = int(m.group(4)) if m.group(1) == 'S': y = -y if m.group(3) == 'W': x = -x
def make_tarama_mask(point_list, utm_zone, buff=0, TA_dir='TA'): """Generate a mask using the gps coordinates of the captures This command follows the execution of tarama, after which a mask is normally created interactively by the user Args: point_list (list): List of (shapely.Point, str) tuples. See ``dir_to_points`` utm_zone (int): Utm zone of the project buffer (float): optional buffer to extend or reduce masked area around the convex hull of the point list TA_dir (str): tarama dir relative to current directory. Defaults to ``'TA'`` """ # Build study area polygon src_crs = CRS.from_epsg(4326) dst_crs = CRS(proj='utm', zone=utm_zone, ellps='WGS84', units='m') feature_list = [mapping(x[0]) for x in point_list] feature_list_proj = [ transform_geom(src_crs, dst_crs, x) for x in feature_list ] point_list_proj = [shape(x) for x in feature_list_proj] study_area = MultiPoint(point_list_proj).convex_hull.buffer(buff) # Retrieve Affine transform and shape from TA dir root = ET.parse(os.path.join(TA_dir, 'TA_LeChantier.xml')).getroot() x_ori, y_ori = [ float(x) for x in root.find('OriginePlani').text.split(' ') ] x_res, y_res = [ float(x) for x in root.find('ResolutionPlani').text.split(' ') ] arr_shape = tuple( reversed([int(x) for x in root.find('NombrePixels').text.split(' ')])) aff = Affine(x_res, 0, x_ori, 0, y_res, y_ori) # Rasterize study area to template raster arr = rasterize(shapes=[(study_area, 255)], out_shape=arr_shape, fill=0, transform=aff, default_value=255, dtype=rasterio.uint8) # Write mask to raster meta = { 'driver': 'GTiff', 'dtype': 'uint8', 'width': arr_shape[1], 'height': arr_shape[0], 'count': 1, 'crs': dst_crs, 'transform': aff } filename = os.path.join(TA_dir, 'TA_LeChantier_Masq.tif') with rasterio.open(filename, 'w', **meta) as dst: dst.write(arr, 1) # Create associated xml file xml_content = """<?xml version="1.0" ?> <FileOriMnt> <NameFileMnt>%s</NameFileMnt> <NombrePixels>%d %d</NombrePixels> <OriginePlani>0 0</OriginePlani> <ResolutionPlani>1 1</ResolutionPlani> <OrigineAlti>0</OrigineAlti> <ResolutionAlti>1</ResolutionAlti> <Geometrie>eGeomMNTFaisceauIm1PrCh_Px1D</Geometrie> </FileOriMnt>""" % (filename, arr_shape[0], arr_shape[1]) xml_filename = os.path.join(TA_dir, 'TA_LeChantier_Masq.xml') with open(xml_filename, 'w') as dst: dst.write(xml_content)
def uninvertable_reproject_params(): return ReprojectParams( left=-120, bottom=30, right=-80, top=70, width=80, height=80, src_crs=CRS.from_epsg(4326), dst_crs=CRS.from_epsg(26836), ) WGS84_crs = CRS.from_epsg(4326) def test_transform_src_crs_none(): with pytest.raises(CRSError): transform(None, WGS84_crs, [], []) def test_transform_dst_crs_none(): with pytest.raises(CRSError): transform(WGS84_crs, None, [], []) def test_transform_bounds_src_crs_none(): with pytest.raises(CRSError): transform_bounds(None, WGS84_crs, 0, 0, 0, 0)
def _write_quicklook( rgb: Sequence[Path], dest_path: Path, resampling: Resampling, static_range: Tuple[int, int], percentile_range: Tuple[int, int] = (2, 98), input_geobox: GridSpec = None, ) -> GridSpec: """ Write an intensity-scaled wgs84 image using the given files as bands. """ if input_geobox is None: with rasterio.open(rgb[0]) as ds: input_geobox = GridSpec.from_rio(ds) out_crs = CRS.from_epsg(4326) ( reprojected_transform, reprojected_width, reprojected_height, ) = calculate_default_transform( input_geobox.crs, out_crs, input_geobox.shape[1], input_geobox.shape[0], *input_geobox.bounds, ) reproj_grid = GridSpec((reprojected_height, reprojected_width), reprojected_transform, crs=out_crs) ql_write_args = dict( driver="GTiff", dtype="uint8", count=len(rgb), width=reproj_grid.shape[1], height=reproj_grid.shape[0], transform=reproj_grid.transform, crs=reproj_grid.crs, nodata=0, tiled="yes", ) # Only set blocksize on larger imagery; enables reduced resolution processing if reproj_grid.shape[0] > 512: ql_write_args["blockysize"] = 512 if reproj_grid.shape[1] > 512: ql_write_args["blockxsize"] = 512 with rasterio.open(dest_path, "w", **ql_write_args) as ql_ds: ql_ds: DatasetWriter # Calculate combined nodata mask valid_data_mask = numpy.ones(input_geobox.shape, dtype="bool") calculated_range = read_valid_mask_and_value_range( valid_data_mask, _iter_images(rgb), percentile_range) for band_no, (image, nodata) in enumerate(_iter_images(rgb), start=1): reprojected_data = numpy.zeros(reproj_grid.shape, dtype=numpy.uint8) reproject( rescale_intensity( image, image_null_mask=~valid_data_mask, in_range=(static_range or calculated_range), out_range=(1, 255), out_dtype=numpy.uint8, ), reprojected_data, src_crs=input_geobox.crs, src_transform=input_geobox.transform, src_nodata=0, dst_crs=reproj_grid.crs, dst_nodata=0, dst_transform=reproj_grid.transform, resampling=resampling, num_threads=2, ) ql_ds.write(reprojected_data, band_no) del reprojected_data return reproj_grid
def test_from_user_input_custom_crs_class(): """Support comparison to foreign objects that provide to_wkt()""" assert CRS.from_user_input(CustomCRS()) == CRS.from_epsg(4326)
def test_equals_different_type(other): """Comparison to non-CRS objects is False""" assert CRS.from_epsg(4326) != other
def test_environ_patch(gdalenv, monkeypatch): """PROJ_LIB is patched when rasterio._crs is imported""" monkeypatch.delenv('GDAL_DATA', raising=False) monkeypatch.delenv('PROJ_LIB', raising=False) with env_ctx_if_needed(): assert CRS.from_epsg(4326) != CRS(units='m', proj='aeqd', ellps='WGS84', datum='WGS84', lat_0=-17.0, lon_0=-44.0)
# coding=utf-8 from __future__ import absolute_import import numpy as np from rasterio import warp from rasterio.crs import CRS from .. import Bounds, PixelCollection, crop, get_extent, get_resolution WGS84_CRS = CRS.from_epsg(4326) class Transformation: buffer = 0 def __init__(self, collar=0): self.collar = int(collar) def expand(self, bounds, shape): buffer = self.buffer collar = self.collar effective_buffer = buffer + collar if effective_buffer == 0: return bounds, shape, (0, 0, 0, 0) resolution = get_resolution(bounds, shape) # apply buffer bounds_orig = bounds
meta = inds.meta.copy() rasterio.warp.transform(crs0, inds.crs, [y], [x]) a = rasterio.warp.transform(crs0, inds.crs, [y], [x]) xPixel, yPixel = pixel_location = inv_transform * (a[0][0], a[1][0]) print(pixel_location) # print(count_sliding_window(inds.read(1))) for window, transform in get_tiles(inds, tile_width, tile_height): print(window) meta['transform'] = transform meta['width'], meta['height'] = window.width, window.height outpath = os.path.join( out_folder, output_filename.format(int(window.col_off), int(window.row_off))) if ((xPixel > window.col_off) & (xPixel < window.col_off + window.width) & (yPixel > window.row_off) & (yPixel < window.row_off + window.height)): with rio.open(outpath, 'w', **meta) as outds: outds.write(inds.read(window=window)) crs0 = CRS.from_epsg(4326) for folder in os.listdir(queryDir): print(folder) imgName, xs, ys = get_info(folder) for x, y in zip(xs, ys): selectInterestArea(imgName + '.jp2', x, y) # selectInterestArea('T47PQQ_20200506T033529_TCI.jp2',12.679944,101.005028)
def test_issue1131(): """Confirm that we don't run out of memory""" transform, w, h = calculate_default_transform(CRS.from_epsg(4326), CRS.from_epsg(3857), 455880, 454450, 13.0460235139, 42.6925552354, 13.2511695428, 42.8970561511) assert (w, h) == (381595, 518398)
def test_failure_point_shp(tmp_path): """ Ensure that hedley_2005() raises an Exception if the shapefile does not contain any Polygon geometries """ g = deglint.GlintCorr(odc_meta_file, sub_product) hedley_dir = tmp_path / "HEDLEY" hedley_dir.mkdir() # ------------------------------------------- # # Test 1: create Points and save to shapefile # # ------------------------------------------- # point_shp = hedley_dir / "aus_capital_cities.shp" # Name, lon (deg. East), lat (deg. North) capital_arr = [ ["PER", 115.8605, -31.9505], ["DAR", 130.8456, -12.4634], ["ADE", 138.6007, -34.9285], ["CAN", 149.1300, -35.2809], ["SYD", 151.2093, -33.8688], ["BRI", 153.0251, -27.4698], ["HOB", 147.3272, -42.8821], ["MEL", 144.9631, -37.8136], ] schema = {"geometry": "Point", "properties": {"name": "str"}} with collection( point_shp, mode="w", driver="ESRI Shapefile", schema=schema, crs=CRS.from_epsg(4326), ) as shp: for cap in capital_arr: shp.write({ "properties": { "name": cap[0] }, "geometry": mapping(Point(cap[1], cap[2])), }) with pytest.raises(Exception) as excinfo: g.hedley_2005( vis_bands=["3"], corr_band="6", roi_shpfile=point_shp, odir=hedley_dir, water_val=5, plot=False, ) assert "input shapefile does not have any 'Polygon' geometry" in str( excinfo) # ------------------------------------------------- # # Test 2: create a LineString and save to shapefile # # ------------------------------------------------- # linestr_shp = hedley_dir / "Perth_to_Canberra_line.shp" # Name, lon (deg. East), lat (deg. North) perth = [115.8605, -31.9505] canbr = [149.1300, -35.2809] gls = LineString([Point(perth[0], perth[1]), Point(canbr[0], canbr[1])]) schema = {"geometry": "LineString", "properties": {"name": "str"}} with collection( linestr_shp, mode="w", driver="ESRI Shapefile", schema=schema, crs=CRS.from_epsg(4326), ) as shp: shp.write({ "properties": { "name": "Perth_to_Canberra" }, "geometry": mapping(gls), }) with pytest.raises(Exception) as excinfo: g.hedley_2005( vis_bands=["3"], corr_band="6", roi_shpfile=linestr_shp, odir=hedley_dir, water_val=5, plot=False, ) assert "input shapefile does not have any 'Polygon' geometry" in str( excinfo)
def test_from_epsg_overflow(): with pytest.raises(CRSError): # the argument is large enough to cause an overflow in Cython CRS.from_epsg(1111111111111111111111)
def __init__(self, array, bands, crs, transform, nodataval, driver="GTiff", rio_ds=None): import rasterio import affine from rasterio.crs import CRS self._array = array self._bands = bands meta = {"driver": driver, "nodata": nodataval} # create metadata dictionary if array.dtype in Raster.FLOAT32: dtype = "float32" elif array.dtype in Raster.FLOAT64: dtype = "float64" elif array.dtype in Raster.INT8: dtype = "int8" elif array.dtype in Raster.INT16: dtype = "int16" elif array.dtype in Raster.INT32: dtype = "int32" elif array.dtype in Raster.INT64: dtype = "int64" else: raise TypeError("dtype cannot be determined from Raster") meta['dtype'] = dtype if isinstance(crs, CRS): pass elif isinstance(crs, int): crs = CRS.from_epsg(crs) elif isinstance(crs, str): crs = CRS.from_string(crs) else: TypeError("crs type not understood, provide an epsg or proj4") meta['crs'] = crs count, height, width = array.shape meta['count'] = count meta['height'] = height meta['width'] = width if not isinstance(transform, affine.Affine): raise TypeError("Transform must be defined by an Affine object") meta['transform'] = transform self._meta = meta self._dataset = None self.__arr_dict = { self._bands[b]: arr for b, arr in enumerate(self._array) } self.__xcenters = None self.__ycenters = None if isinstance(rio_ds, rasterio.io.DatasetReader): self._dataset = rio_ds
def test_to_wkt__version(version): assert CRS.from_epsg(4326).to_wkt( version=version).startswith('GEOGCRS["WGS 84",')
def ex_crs(request): return CRS.from_epsg(request.param)
def test_to_crs_int(code): assert convert.to_crs(code) == CRS.from_epsg(code)
def test_to_crs_dict(): crs = CRS.from_epsg(4326) assert convert.to_crs(dict(crs)) == crs
def test_crs_copy(): """CRS can be copied""" assert copy.copy(CRS.from_epsg(3857)).wkt.startswith( 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84"' )
def test_to_crs_CRS(): # should just return same object crs = CRS.from_epsg(4326) assert convert.to_crs(crs) is crs
def to_wkt(self): return CRS.from_epsg(4326).to_wkt()
from haversine import haversine from rasterio import transform, warp, windows from rasterio._err import CPLE_OutOfMemoryError from rasterio.crs import CRS from rasterio.enums import ColorInterp, MaskFlags from rasterio.features import geometry_mask from rasterio.transform import Affine, from_bounds from rasterio.vrt import WarpedVRT from rasterio.warp import Resampling, transform_geom from . import mosaic from .stats import Timer from .utils import Bounds, PixelCollection EARTH_RADIUS = 6378137 WEB_MERCATOR_CRS = CRS.from_epsg(3857) WGS84_CRS = CRS.from_epsg(4326) LOG = logging.getLogger(__name__) EXTENTS = { str(WEB_MERCATOR_CRS): ( -math.pi * EARTH_RADIUS, -math.pi * EARTH_RADIUS, math.pi * EARTH_RADIUS, math.pi * EARTH_RADIUS, ), str(WGS84_CRS): ( math.degrees(-math.pi), math.degrees(-math.pi / 2), math.degrees(math.pi), math.degrees(math.pi / 2),
def _describe_file(filepath): """ Helper function to describe a geospatial data First checks if a sidecar mcf file is available, if so uses that if not, script will parse the file to retrieve some info from the file :param filepath: path to file :returns: `dict` of GeoJSON item """ content = { 'bbox': None, 'geometry': None, 'properties': {} } mcf_file = '{}.yml'.format(os.path.splitext(filepath)[0]) if os.path.isfile(mcf_file): try: from pygeometa.core import read_mcf, MCFReadError from pygeometa.schemas.stac import STACItemOutputSchema md = read_mcf(mcf_file) stacjson = STACItemOutputSchema.write(STACItemOutputSchema, md) stacdata = loads(stacjson) for k, v in stacdata.items(): content[k] = v except ImportError: LOGGER.debug('pygeometa not found') except MCFReadError as err: LOGGER.warning('MCF error: {}'.format(err)) else: LOGGER.debug('No mcf found at: {}'.format(mcf_file)) if content['geometry'] is None and content['bbox'] is None: try: import rasterio from rasterio.crs import CRS from rasterio.warp import transform_bounds except ImportError as err: LOGGER.warning('rasterio not found') LOGGER.warning(err) return content try: import fiona except ImportError as err: LOGGER.warning('fiona not found') LOGGER.warning(err) return content try: # raster LOGGER.debug('Testing raster data detection') d = rasterio.open(filepath) content['bbox'] = [ d.bounds.left, d.bounds.bottom, d.bounds.right, d.bounds.top ] content['geometry'] = { 'type': 'Polygon', 'coordinates': [[ [d.bounds.left, d.bounds.bottom], [d.bounds.left, d.bounds.top], [d.bounds.right, d.bounds.top], [d.bounds.right, d.bounds.bottom], [d.bounds.left, d.bounds.bottom] ]] } for k, v in d.tags(1).items(): content['properties'][k] = v except rasterio.errors.RasterioIOError: LOGGER.debug('Testing vector data detection') d = fiona.open(filepath) scrs = CRS(d.crs) if scrs.to_epsg() is not None and scrs.to_epsg() != 4326: tcrs = CRS.from_epsg(4326) bnds = transform_bounds(scrs, tcrs, d.bounds[0], d.bounds[1], d.bounds[2], d.bounds[3]) content['properties']['projection'] = scrs.to_epsg() else: bnds = d.bounds if d.schema['geometry'] not in [None, 'None']: content['bbox'] = [ bnds[0], bnds[1], bnds[2], bnds[3] ] content['geometry'] = { 'type': 'Polygon', 'coordinates': [[ [bnds[0], bnds[1]], [bnds[0], bnds[3]], [bnds[2], bnds[3]], [bnds[2], bnds[1]], [bnds[0], bnds[1]] ]] } for k, v in d.schema['properties'].items(): content['properties'][k] = v if d.driver == 'ESRI Shapefile': id_ = os.path.splitext(os.path.basename(filepath))[0] content['assets'] = {} for suffix in ['shx', 'dbf', 'prj', 'shp.xml']: content['assets'][suffix] = { 'href': './{}.{}'.format(id_, suffix) } return content
TILE_3_NAME = "world.tif" TILE_3_PATH = os.path.join(os.path.dirname(__file__), "fixtures", TILE_3_NAME) TILE_4_NAME = "01N_001E.tif" TILE_4_PATH = os.path.join(os.path.dirname(__file__), "fixtures", TILE_4_NAME) ########### World.tif geotransform = (-180.0, 1.0, 0.0, 90.0, 0.0, -1.0) data = np.random.randint(20, size=(180, 360)).astype("uint8") profile = { "driver": "GTiff", "height": 180, "width": 360, "count": 1, "dtype": "uint8", "crs": CRS.from_epsg(4326), "transform": Affine.from_gdal(*geotransform), } with rasterio.open(TILE_3_PATH, "w", **profile) as dst: dst.write(data, 1) ############ 01N_001E.tif geotransform = (1.0, 0.00025, 0.0, 1.0, 0.0, -0.00025) data = np.random.randint(5, size=(4000, 4000)).astype("uint8") profile = { "driver": "GTiff", "height": 4000, "width": 4000, "count": 1, "dtype": "uint8",
def test_crs_copy(): """CRS can be copied""" assert copy.copy(CRS.from_epsg(3857)).wkt.startswith('PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84"')
def clip( ctx, files, output, bounds, like, driver, nodata, projection, overwrite, creation_options, with_complement, ): """Clips a raster using projected or geographic bounds. The values of --bounds are presumed to be from the coordinate reference system of the input dataset unless the --geographic option is used, in which case the values may be longitude and latitude bounds. Either JSON, for example "[west, south, east, north]", or plain text "west south east north" representations of a bounding box are acceptable. If using --like, bounds will automatically be transformed to match the coordinate reference system of the input. Datasets with non-rectilinear geo transforms (i.e. with rotation and/or shear) may not be cropped using this command. They must be processed with rio-warp. Examples -------- $ rio clip input.tif output.tif --bounds xmin ymin xmax ymax $ rio clip input.tif output.tif --like template.tif """ from rasterio.warp import transform_bounds with ctx.obj['env']: output, files = resolve_inout(files=files, output=output, overwrite=overwrite) input = files[0] with rasterio.open(input) as src: if not src.transform.is_rectilinear: raise click.BadParameter( "Non-rectilinear rasters (i.e. with rotation or shear) cannot be clipped" ) if bounds: if projection == 'geographic': bounds = transform_bounds(CRS.from_epsg(4326), src.crs, *bounds) if disjoint_bounds(bounds, src.bounds): raise click.BadParameter('must overlap the extent of ' 'the input raster', param='--bounds', param_hint='--bounds') elif like: with rasterio.open(like) as template_ds: bounds = template_ds.bounds if template_ds.crs != src.crs: bounds = transform_bounds(template_ds.crs, src.crs, *bounds) if disjoint_bounds(bounds, src.bounds): raise click.BadParameter('must overlap the extent of ' 'the input raster', param='--like', param_hint='--like') else: raise click.UsageError('--bounds or --like required') bounds_window = src.window(*bounds) if not with_complement: bounds_window = bounds_window.intersection( Window(0, 0, src.width, src.height) ) # Get the window with integer height # and width that contains the bounds window. out_window = bounds_window.round_lengths() height = int(out_window.height) width = int(out_window.width) out_kwargs = src.profile if driver: out_kwargs["driver"] = driver if nodata is not None: out_kwargs["nodata"] = nodata out_kwargs.update({ 'height': height, 'width': width, 'transform': src.window_transform(out_window)}) out_kwargs.update(**creation_options) if "blockxsize" in out_kwargs and int(out_kwargs["blockxsize"]) > width: del out_kwargs["blockxsize"] logger.warning( "Blockxsize removed from creation options to accomodate small output width" ) if "blockysize" in out_kwargs and int(out_kwargs["blockysize"]) > height: del out_kwargs["blockysize"] logger.warning( "Blockysize removed from creation options to accomodate small output height" ) with rasterio.open(output, "w", **out_kwargs) as out: out.write( src.read( window=out_window, out_shape=(src.count, height, width), boundless=True, masked=True, ) ) if MaskFlags.per_dataset in src.mask_flag_enums[0]: out.write_mask( src.read_masks( window=out_window, out_shape=(src.count, height, width), boundless=True, )[0] )
@pytest.mark.parametrize("other", ["", 4.2, 0]) def test_equals_different_type(other): """Comparison to non-CRS objects is False""" assert CRS.from_epsg(4326) != other def test_from_user_input_custom_crs_class(): """Support comparison to foreign objects that provide to_wkt()""" assert CRS.from_user_input(CustomCRS()) == CRS.from_epsg(4326) @pytest.mark.parametrize( "crs_obj", [ CRS.from_user_input("http://www.opengis.net/def/crs/EPSG/0/4326"), CRS.from_epsg(4326), ], ) def test_epsg_treats_as_latlong(crs_obj): """EPSG treats this CRS as lat, lon (see also PR #1943).""" assert epsg_treats_as_latlong(crs_obj) @pytest.mark.parametrize("crs_obj", [ CRS.from_user_input("http://www.opengis.net/def/crs/OGC/1.3/CRS84"), CRS.from_user_input("http://www.opengis.net/def/crs/EPSG/0/2193"), CRS.from_epsg(3857), CRS.from_epsg(32618), ]) def test_epsg_treats_as_latlong_not(crs_obj): """EPSG does not treat this CRS as lat, lon (see also PR #1943)."""
def _to_crs_epsg(value): return CRS.from_epsg(value)