def check_crs(crs): """ Checks a CRS instance Args: crs (``CRS`` | int | dict | str): The CRS instance. Returns: ``rasterio.crs.CRS`` """ if isinstance(crs, pyproj.crs.crs.CRS): dst_crs = CRS.from_proj4(crs.to_proj4()) elif isinstance(crs, CRS): dst_crs = crs elif isinstance(crs, int): dst_crs = CRS.from_epsg(crs) elif isinstance(crs, dict): dst_crs = CRS.from_dict(crs) elif isinstance(crs, str): if crs.startswith('+proj'): dst_crs = CRS.from_proj4(crs) else: dst_crs = CRS.from_string(crs) else: logger.exception(' The CRS was not understood.') raise TypeError return dst_crs
def test_schema(): """Translate Model to Schema.""" tms = morecantile.tms.get("WebMercatorQuad") assert tms.schema() assert tms.schema_json() assert tms.json(exclude_none=True) assert tms.dict(exclude_none=True) crs = CRS.from_proj4( "+proj=stere +lat_0=90 +lon_0=0 +k=2 +x_0=0 +y_0=0 +R=3396190 +units=m +no_defs" ) extent = [-13584760.000, -13585240.000, 13585240.000, 13584760.000] tms = morecantile.TileMatrixSet.custom(extent, crs, identifier="MarsNPolek2MOLA5k") assert tms.schema() assert tms.schema_json() assert tms.dict(exclude_none=True) json_doc = json.loads(tms.json(exclude_none=True)) # We cannot translate PROJ4 to epsg so it's set to None assert json_doc[ "supportedCRS"] == "http://www.opengis.net/def/crs/EPSG/0/None" crs = CRS.from_epsg(3031) extent = [-948.75, -543592.47, 5817.41, -3333128.95] # From https:///epsg.io/3031 tms = morecantile.TileMatrixSet.custom(extent, crs, identifier="MyCustomTmsEPSG3031") assert tms.schema() assert tms.schema_json() assert tms.json(exclude_none=True) json_doc = json.loads(tms.json(exclude_none=True)) assert json_doc[ "supportedCRS"] == "http://www.opengis.net/def/crs/EPSG/0/3031"
def check_crs(crs): """ Checks a CRS instance Args: crs (``CRS`` | int | dict | str): The CRS instance. Returns: ``rasterio.crs.CRS`` """ import warnings with rio.Env(): with warnings.catch_warnings(): warnings.simplefilter('ignore', UserWarning) if isinstance(crs, pyproj.crs.crs.CRS): dst_crs = CRS.from_proj4(crs.to_proj4()) elif isinstance(crs, CRS): dst_crs = crs elif isinstance(crs, int): dst_crs = CRS.from_epsg(crs) elif isinstance(crs, dict): dst_crs = CRS.from_dict(crs) elif isinstance(crs, str): if crs.startswith('+proj'): dst_crs = CRS.from_proj4(crs) else: dst_crs = CRS.from_string(crs.replace('+init=', '')) else: logger.exception(' The CRS was not understood.') raise TypeError return dst_crs
def _parse_crs(crs): """Parse a coordinate reference system from a variety of representations. Parameters ---------- crs : {str, dict, int, CRS} Must be either a rasterio CRS object, a proj-string, rasterio supported dictionary, WKT string, or EPSG integer. Returns ------- rasterio.crs.CRS The parsed CRS. Raises ------ CRSError Raises an error if the input cannot be parsed. """ # # NOTE: This doesn't currently throw an error if the EPSG code is invalid. # parsed = None if isinstance(crs, CRS): parsed = crs elif isinstance(crs, str): try: # proj-string or wkt parsed = CRS.from_string(crs) except CRSError: # wkt parsed = CRS.from_wkt(crs) elif isinstance(crs, dict): parsed = CRS(crs) elif isinstance(crs, int): parsed = CRS.from_epsg(crs) elif isinstance(crs, pyproj.Proj): parsed = CRS.from_proj4(crs.proj4_init) if parsed is None or not parsed.is_valid: raise CRSError('Could not parse CRS: {}'.format(crs)) return parsed
def create_grs_schema(cls, name, description, projection, meridian, degreesx, degreesy, bbox, srid=100001): """Create a Brazil Data Cube Grid Schema.""" grid_mapping, proj4 = create_grids(names=[name], projection=projection, meridian=meridian, degreesx=[degreesx], degreesy=[degreesy], bbox=bbox, srid=srid) grid = grid_mapping[name] with db.session.begin_nested(): crs = CRS.from_proj4(proj4) data = dict(auth_name='Albers Equal Area', auth_srid=srid, srid=srid, srtext=crs.to_wkt(), proj4text=proj4) spatial_index, _ = get_or_create_model(SpatialRefSys, defaults=data, srid=srid) grs = GridRefSys.create_geometry_table(table_name=name, features=grid['features'], srid=srid) grs.description = description db.session.add(grs) for tile_obj in grid['tiles']: tile = Tile(**tile_obj, grs=grs) db.session.add(tile) db.session.commit() return 'Grid {} created with successfully'.format(name), 201
def _get_utm_crs(self, datum='WGS84', ellps='WGS84'): """Get coordinate system from zone number associated with the longitude of the northwest corner Parameters ========== datum : str, optional Origin of destination coordinate system, used to describe PROJ.4 string; default is WGS84. ellps : str, optional Ellipsoid defining the shape of the earth in the destination coordinate system, used to describe PROJ.4 string; default is WGS84. """ #west, south, east, north = self.bounds self.zone_number = int((self.bounds[0] + 180) / 6) + 1 proj = '+proj=utm +zone={:d} '.format(self.zone_number) \ + '+datum={:s} +units=m +no_defs '.format(datum) \ + '+ellps={:s} +towgs84=0,0,0'.format(ellps) self.utm_crs = CRS.from_proj4(proj)
def create_grs_schema(cls, name, description, projection, meridian, degreesx, degreesy, bbox, srid=100001): """Create a Brazil Data Cube Grid Schema.""" bbox = bbox.split(',') bbox_obj = { "w": float(bbox[0]), "n": float(bbox[1]), "e": float(bbox[2]), "s": float(bbox[3]) } tile_srs_p4 = "+proj=longlat +ellps=GRS80 +datum=GRS80 +no_defs" if projection == 'aea': tile_srs_p4 = "+proj=aea +lat_0=-12 +lon_0={} +lat_1=-2 +lat_2=-22 +x_0=5000000 +y_0=10000000 +ellps=GRS80 +units=m +no_defs".format( meridian) elif projection == 'sinu': tile_srs_p4 = "+proj=sinu +lon_0={} +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m +no_defs".format( meridian) # Number of tiles and base tile num_tiles_x = int(360. / degreesx) num_tiles_y = int(180. / degreesy) h_base = num_tiles_x / 2 v_base = num_tiles_y / 2 # Tile size in meters (dx,dy) at center of system (argsmeridian,0.) src_crs = '+proj=longlat +ellps=GRS80 +datum=GRS80 +no_defs' dst_crs = tile_srs_p4 xs = [(meridian - degreesx / 2), (meridian + degreesx / 2), meridian, meridian, 0.] ys = [0., 0., -degreesy / 2, degreesy / 2, 0.] out = transform(src_crs, dst_crs, xs, ys, zs=None) x1 = out[0][0] x2 = out[0][1] y1 = out[1][2] y2 = out[1][3] dx = x2 - x1 dy = y2 - y1 # Coordinates of WRS center (0.,0.) - top left coordinate of (h_base,v_base) x_center = out[0][4] y_center = out[1][4] # Border coordinates of WRS grid x_min = x_center - dx * h_base y_max = y_center + dy * v_base # Upper Left is (xl,yu) Bottom Right is (xr,yb) xs = [bbox_obj['w'], bbox_obj['e'], meridian, meridian] ys = [0., 0., bbox_obj['n'], bbox_obj['s']] out = transform(src_crs, dst_crs, xs, ys, zs=None) xl = out[0][0] xr = out[0][1] yu = out[1][2] yb = out[1][3] h_min = int((xl - x_min) / dx) h_max = int((xr - x_min) / dx) v_min = int((y_max - yu) / dy) v_max = int((y_max - yb) / dy) tiles = [] features = [] dst_crs = '+proj=longlat +ellps=GRS80 +datum=GRS80 +no_defs' src_crs = tile_srs_p4 for ix in range(h_min, h_max + 1): x1 = x_min + ix * dx x2 = x1 + dx for iy in range(v_min, v_max + 1): y1 = y_max - iy * dy y2 = y1 - dy # Evaluate the bounding box of tile in longlat xs = [x1, x2, x2, x1] ys = [y1, y1, y2, y2] out = rasterio.warp.transform(src_crs, dst_crs, xs, ys, zs=None) polygon = from_shape(Polygon([(x1, y2), (x2, y2), (x2, y1), (x1, y1), (x1, y2)]), srid=SRID_ALBERS_EQUAL_AREA) # Insert tile tile_name = '{0:03d}{1:03d}'.format(ix, iy) tiles.append(dict(name=tile_name)) features.append(dict(tile=tile_name, geom=polygon)) with db.session.begin_nested(): crs = CRS.from_proj4(tile_srs_p4) data = dict(auth_name='Albers Equal Area', auth_srid=srid, srid=srid, srtext=crs.to_wkt(), proj4text=tile_srs_p4) spatial_index, _ = get_or_create_model(SpatialRefSys, defaults=data, srid=srid) grs = GridRefSys.create_geometry_table(table_name=name, features=features, srid=SRID_ALBERS_EQUAL_AREA) grs.description = description db.session.add(grs) [db.session.add(Tile(**tile, grs=grs)) for tile in tiles] db.session.commit() return 'Grid {} created with successfully'.format(name), 201
def test_exception_proj4(): """Get the exception message we expect""" with pytest.raises(CRSError): CRS.from_proj4("+proj=bogus")
def mask(data, df, query=None, keep='in'): """ Masks a DataArray by vector polygon geometry Args: data (DataArray): The ``xarray.DataArray`` to mask. df (GeoDataFrame or str): The ``geopandas.GeoDataFrame`` or filename to use for masking. query (Optional[str]): A query to apply to ``df``. keep (Optional[str]): If ``keep`` = 'in', mask values outside of the geometry (keep inside). Otherwise, if ``keep`` = 'out', mask values inside (keep outside). Returns: ``xarray.DataArray`` Examples: >>> import geowombat as gw >>> >>> with gw.open('image.tif') as ds: >>> ds = ds.gw.mask(df) """ if isinstance(df, str) and os.path.isfile(df): df = gpd.read_file(df) if query: df = df.query(query) try: if data.crs.strip() != CRS.from_dict(df.crs).to_proj4().strip(): # Re-project the DataFrame to match the image CRS df = df.to_crs(data.crs) except: if data.crs.strip() != CRS.from_proj4(df.crs).to_proj4().strip(): df = df.to_crs(data.crs) # Rasterize the geometry and store as a DataArray mask = xr.DataArray(data=da.from_array( features.rasterize(list(df.geometry.values), out_shape=(data.gw.nrows, data.gw.ncols), transform=data.transform, fill=0, out=None, all_touched=True, default_value=1, dtype='int32'), chunks=(data.gw.row_chunks, data.gw.col_chunks)), dims=['y', 'x'], coords={ 'y': data.y.values, 'x': data.x.values }) # Return the masked array if keep == 'out': return data.where(mask != 1) else: return data.where(mask == 1)
def clip(self, data, df, query=None, mask_data=False, expand_by=0): """ Clips a DataArray by vector polygon geometry Args: data (DataArray): The ``xarray.DataArray`` to subset. df (GeoDataFrame or str): The ``geopandas.GeoDataFrame`` or filename to clip to. query (Optional[str]): A query to apply to ``df``. mask_data (Optional[bool]): Whether to mask values outside of the ``df`` geometry envelope. expand_by (Optional[int]): Expand the clip array bounds by ``expand_by`` pixels on each side. Returns: ``xarray.DataArray`` Examples: >>> import geowombat as gw >>> >>> with gw.open('image.tif') as ds: >>> ds = gw.clip(ds, df, query="Id == 1") >>> >>> # or >>> >>> with gw.open('image.tif') as ds: >>> ds = ds.gw.clip(df, query="Id == 1") """ if isinstance(df, str) and os.path.isfile(df): df = gpd.read_file(df) if query: df = df.query(query) try: if data.crs.strip() != CRS.from_dict(df.crs).to_proj4().strip(): # Re-project the DataFrame to match the image CRS df = df.to_crs(data.crs) except: if data.crs.strip() != CRS.from_proj4(df.crs).to_proj4().strip(): df = df.to_crs(data.crs) row_chunks = data.gw.row_chunks col_chunks = data.gw.col_chunks left, bottom, right, top = df.total_bounds # Align the geometry array grid align_transform, align_width, align_height = align_bounds( left, bottom, right, top, data.res) # Get the new bounds new_left, new_bottom, new_right, new_top = array_bounds( align_height, align_width, align_transform) if expand_by > 0: new_left -= data.gw.cellx * expand_by new_bottom -= data.gw.celly * expand_by new_right += data.gw.cellx * expand_by new_top += data.gw.celly * expand_by # Subset the array data = self.subset(data, left=new_left, bottom=new_bottom, right=new_right, top=new_top) if mask_data: # Rasterize the geometry and store as a DataArray mask = xr.DataArray(data=da.from_array( features.rasterize(list(df.geometry.values), out_shape=(align_height, align_width), transform=align_transform, fill=0, out=None, all_touched=True, default_value=1, dtype='int32'), chunks=(row_chunks, col_chunks)), dims=['y', 'x'], coords={ 'y': data.y.values, 'x': data.x.values }) # Return the clipped array return data.where(mask == 1) else: return data
def warp(filename, resampling='nearest', bounds=None, crs=None, res=None, nodata=0, warp_mem_limit=512, num_threads=1, tap=False): """ Warps an image to a VRT object Args: filename (str): The input file name. resampling (Optional[str]): The resampling method. Choices are ['average', 'bilinear', 'cubic', 'cubic_spline', 'gauss', 'lanczos', 'max', 'med', 'min', 'mode', 'nearest']. bounds (Optional[tuple]): The extent bounds to warp to. crs (Optional[object]): The CRS to warp to. res (Optional[tuple]): The cell resolution to warp to. nodata (Optional[int or float]): The 'no data' value. warp_mem_limit (Optional[int]): The memory limit (in MB) for the ``rasterio.vrt.WarpedVRT`` function. num_threads (Optional[int]): The number of warp worker threads. tap (Optional[bool]): Whether to target align pixels. Returns: ``rasterio.vrt.WarpedVRT`` """ with rio.open(filename) as src: if res: dst_res = res else: dst_res = src.res if crs: if isinstance(crs, CRS): dst_crs = crs elif isinstance(crs, int): dst_crs = CRS.from_epsg(crs) elif isinstance(crs, dict): dst_crs = CRS.from_dict(crs) elif isinstance(crs, str): if crs.startswith('+proj'): dst_crs = CRS.from_proj4(crs) else: dst_crs = CRS.from_string(crs) else: logger.exception(' The CRS was not understood.') else: dst_crs = src.crs dst_transform, dst_width, dst_height = calculate_default_transform( src.crs, dst_crs, src.width, src.height, left=src.bounds.left, bottom=src.bounds.bottom, right=src.bounds.right, top=src.bounds.top, resolution=dst_res) # Check if the data need to be subset if bounds and (bounds != src.bounds): if isinstance(bounds, str): if bounds.startswith('BoundingBox'): bounds_str = bounds.replace('BoundingBox(', '').split(',') for str_ in bounds_str: if str_.strip().startswith('left='): left_coord = float( str_.strip().split('=')[1].replace(')', '')) elif str_.strip().startswith('bottom='): bottom_coord = float( str_.strip().split('=')[1].replace(')', '')) elif str_.strip().startswith('right='): right_coord = float( str_.strip().split('=')[1].replace(')', '')) elif str_.strip().startswith('top='): top_coord = float( str_.strip().split('=')[1].replace(')', '')) bounds = BoundingBox(left=left_coord, bottom=bottom_coord, right=right_coord, top=top_coord) else: logger.exception(' The bounds were not accepted.') left, bottom, right, top = bounds # Keep the CRS but subset the data dst_transform, dst_width, dst_height = calculate_default_transform( dst_crs, dst_crs, dst_width, dst_height, left=left, bottom=bottom, right=right, top=top, resolution=dst_res) dst_width = int((right - left) / dst_res[0]) dst_height = int((top - bottom) / dst_res[1]) else: bounds = src.bounds # Do not warp if all the key metadata match the reference information if (src.bounds == bounds) and (src.res == dst_res) and ( src.crs == dst_crs) and (src.width == dst_width) and (src.height == dst_height): output = filename else: if tap: # Align the cells dst_transform, dst_width, dst_height = aligned_target( dst_transform, dst_width, dst_height, dst_res) vrt_options = { 'resampling': getattr(Resampling, resampling), 'crs': dst_crs, 'transform': dst_transform, 'height': dst_height, 'width': dst_width, 'nodata': nodata, 'warp_mem_limit': warp_mem_limit, 'warp_extras': { 'multi': True, 'warp_option': 'NUM_THREADS={:d}'.format(num_threads) } } with WarpedVRT(src, **vrt_options) as vrt: output = vrt return output
def create_grids(names: List[str], projection, meridian, degreesx: List[float], degreesy: List[float], bbox, srid=100001): """Create a list of hierarchically grids for Brazil Data Cube. With a meridian, bounding box and list of degrees, this function creates a list of grids based in the lowest degree. After that, the other grids are generated inherit the lowest to be hierarchical. For example, the grids BDC_SM_V2, BDC_MD_V2 and BDC_LG_V2 are hierarchically identical. - BDC_SM_V2 consists in tiles of 1.5 by 1.0 degrees. - BDC_MD_V2 represents 4 tiles of BDC_SM_V2 (2x2). - BDC_LG_V2 represents 16 tiles of BDC_SM_V2 (4x4) or 4 tiles of BDC_MD_V2 (2x2) Note: Keep the order of names according degree's Args: names (List[str]): List of grid names projection (str): The Grid projection kind - "sinu" for sinusoidal grids and "aea" for Albers Equal Area. meridian (float): The center pixel for grid as reference. degreesx (List[float]): List the degree in X degreesy (List[float]): List the degree in Y bbox (Tuple[float, float, float, float]): The bounding box limits (minx, miny, maxx, maxy). srid (int): The projection SRID to create. """ bbox_obj = { "w": float(bbox[0]), "n": float(bbox[1]), "e": float(bbox[2]), "s": float(bbox[3]) } tile_srs_p4 = "+proj=longlat +ellps=GRS80 +no_defs" if projection == 'aea': tile_srs_p4 = "+proj=aea +lat_0=-12 +lon_0={} +lat_1=-2 +lat_2=-22 +x_0=5000000 +y_0=10000000 +ellps=GRS80 +units=m +no_defs".format( meridian) elif projection == 'sinu': tile_srs_p4 = "+proj=sinu +lon_0={} +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m +no_defs".format( meridian) ref_degree_x = degreesx[0] ref_degree_y = degreesy[0] # Tile size in meters (dx,dy) at center of system (argsmeridian,0.) src_crs = '+proj=longlat +ellps=GRS80 +no_defs' dst_crs = tile_srs_p4 xs = [(meridian - ref_degree_x / 2.), (meridian + ref_degree_x / 2.), meridian, meridian, 0.] ys = [0., 0., -ref_degree_y / 2., ref_degree_y / 2., 0.] out = transform(CRS.from_proj4(src_crs), CRS.from_proj4(dst_crs), xs, ys, zs=None) xmin_center_tile = out[0][0] xmax_center_tile = out[0][1] ymin_center_tile = out[1][2] ymax_center_tile = out[1][3] tile_size_x = xmax_center_tile - xmin_center_tile tile_size_y = ymax_center_tile - ymin_center_tile bbox_alber_envelope_xs = [bbox_obj['w'], bbox_obj['e'], meridian, meridian] bbox_alber_envelope_ys = [0., 0., bbox_obj['n'], bbox_obj['s']] bbox_alber_envelope = transform(src_crs, dst_crs, bbox_alber_envelope_xs, bbox_alber_envelope_ys, zs=None) total_tiles_left = math.ceil(abs((xmin_center_tile - bbox_alber_envelope[0][0])) / tile_size_x) total_tiles_upper = math.ceil(abs((ymax_center_tile - bbox_alber_envelope[1][2])) / tile_size_y) # Border coordinates of WRS grid x_min = xmin_center_tile - (tile_size_x * total_tiles_left) y_max = ymax_center_tile + (tile_size_y * total_tiles_upper) # Upper Left is (xl,yu) Bottom Right is (xr,yb) xs = [bbox_obj['w'], bbox_obj['e'], meridian, meridian] ys = [0., 0., bbox_obj['n'], bbox_obj['s']] out = transform(src_crs, dst_crs, xs, ys, zs=None) xl = out[0][0] xr = out[0][1] yu = out[1][2] yb = out[1][3] grids = {} for grid_name, res_x, res_y in zip(names, degreesx, degreesy): factor_x = res_x / ref_degree_x factor_y = res_y / ref_degree_y grid_tile_size_x = tile_size_x * factor_x grid_tile_size_y = tile_size_y * factor_y tiles, features = _create_tiles(tile_size=(grid_tile_size_x, grid_tile_size_y), grid_x_min=x_min, grid_y_max=y_max, bbox=(xl, xr, yb, yu), srid=srid) grids[grid_name] = dict( tiles=tiles, features=features ) return grids, tile_srs_p4