33
44from typing import Any , Tuple , Dict , Optional , Union
55
6+ import os
7+
68from math import isfinite
79
810import numpy as np
1113
1214from .exceptions import *
1315
16+ from ...defaults .constants import GRID_NULL_VALUE
17+ from ...defaults .typing import Number
18+ from ...mathematics .scalars import areClose
1419from ...spatial .rasters .geotransform import GeoTransform
20+ from ...spatial .rasters .geoarray import GeoArray
1521
1622
1723def read_raster (file_ref : Any ) -> Tuple [gdal .Dataset , Optional [GeoTransform ], int , str ]:
@@ -48,7 +54,7 @@ def read_raster(file_ref: Any) -> Tuple[gdal.Dataset, Optional[GeoTransform], in
4854 return dataset , geotransform , num_bands , projection
4955
5056
51- def read_band (dataset : gdal .Dataset , bnd_ndx : int = 1 ) -> Tuple [dict , 'np.array' ]:
57+ def read_band (dataset : gdal .Dataset , bnd_ndx : int = 1 ) -> Tuple [dict , 'np.array' ]:
5258 """
5359 Read data and metadata of a rasters band based on GDAL.
5460
@@ -103,7 +109,7 @@ def read_band(dataset: gdal.Dataset, bnd_ndx: int=1) -> Tuple[dict, 'np.array']:
103109 # if nodatavalue exists, set null values to NaN in numpy array
104110
105111 if noDataVal is not None and isfinite (noDataVal ):
106- grid_values = np .where (abs (grid_values - noDataVal ) > 1e-10 , grid_values , np .NaN )
112+ grid_values = np .where (np . isclose (grid_values , noDataVal ), np .NaN , grid_values )
107113
108114 band_params = dict (
109115 dataType = data_type ,
@@ -116,6 +122,13 @@ def read_band(dataset: gdal.Dataset, bnd_ndx: int=1) -> Tuple[dict, 'np.array']:
116122
117123
118124def try_read_raster_band (raster_source : str , bnd_ndx : int = 1 ) -> Tuple [bool , Union [str , Tuple [GeoTransform , str , Dict , 'np.array' ]]]:
125+ """
126+ Deprecated. Use "read_raster_band" instead.
127+
128+ :param raster_source:
129+ :param bnd_ndx:
130+ :return:
131+ """
119132
120133 # get raster parameters and data
121134 try :
@@ -128,6 +141,113 @@ def try_read_raster_band(raster_source: str, bnd_ndx: int=1) -> Tuple[bool, Unio
128141 return True , (geotransform , projection , band_params , data )
129142
130143
144+ def read_raster_band (raster_source : str , bnd_ndx : int = 1 , epsg_cd : int = - 1 ) -> Optional [GeoArray ]:
145+ """
146+ Read parameters and values of a raster band.
147+ Since it is not immediate to get the EPSG code of the input raster,
148+ the user is advised to provide it directly in the function call.
149+
150+
151+ :param raster_source: the raster path.
152+ :param bnd_ndx: the optional band index.
153+ :param epsg_cd: the EPSG code of the raster.
154+ :return: the band as a geoarray.
155+ :rtype: Optional GeoArray.
156+ """
157+
158+ try :
159+
160+ dataset , geotransform , num_bands , projection = read_raster (raster_source )
161+ band_params , data = read_band (dataset , bnd_ndx )
162+ ga = GeoArray (
163+ inGeotransform = geotransform ,
164+ epsg_cd = epsg_cd ,
165+ inLevels = [data ]
166+ )
167+
168+ return ga
169+
170+ except :
171+
172+ return None
173+
174+
175+ def try_write_esrigrid (geoarray : GeoArray , outgrid_flpth : str , esri_nullvalue : Number = GRID_NULL_VALUE , level_ndx : int = 0 ) -> Tuple [bool , str ]:
176+ """
177+ Writes ESRI ascii grid.
178+
179+ :param geoarray:
180+ :param outgrid_flpth:
181+ :param esri_nullvalue:
182+ :param level_ndx: index of the level array to write.
183+ :type level_ndx: int.
184+ :return: success and descriptive message
185+ :rtype: tuple made up by a boolean and a string
186+ """
187+
188+ outgrid_flpth = str (outgrid_flpth )
189+
190+ out_fldr , out_flnm = os .path .split (outgrid_flpth )
191+ if not out_flnm .lower ().endswith ('.asc' ):
192+ out_flnm += '.asc'
193+
194+ outgrid_flpth = os .path .join (
195+ out_fldr ,
196+ out_flnm
197+ )
198+
199+ # checking existence of output slope grid
200+
201+ if os .path .exists (outgrid_flpth ):
202+ return False , "Output grid '{}' already exists" .format (outgrid_flpth )
203+
204+ try :
205+ outputgrid = open (outgrid_flpth , 'w' ) # create the output ascii file
206+ except Exception :
207+ return False , "Unable to create output grid '{}'" .format (outgrid_flpth )
208+
209+ if outputgrid is None :
210+ return False , "Unable to create output grid '{}'" .format (outgrid_flpth )
211+
212+ if geoarray .has_rotation :
213+ return False , "Grid has axes rotations defined"
214+
215+ cell_size_x = geoarray .src_cellsize_j
216+ cell_size_y = geoarray .src_cellsize_i
217+
218+ if not areClose (cell_size_x , cell_size_y ):
219+ return False , "Cell sizes in the x- and y- directions are not similar"
220+
221+ arr = geoarray .level (level_ndx )
222+ if arr is None :
223+ return False , "Array with index {} does not exist" .format (level_ndx )
224+
225+ num_rows , num_cols = arr .shape
226+ llc_x , llc_y = geoarray .level_llc (level_ndx )
227+
228+ # writes header of grid ascii file
229+
230+ outputgrid .write ("NCOLS %d\n " % num_cols )
231+ outputgrid .write ("NROWS %d\n " % num_rows )
232+ outputgrid .write ("XLLCORNER %.8f\n " % llc_x )
233+ outputgrid .write ("YLLCORNER %.8f\n " % llc_y )
234+ outputgrid .write ("CELLSIZE %.8f\n " % cell_size_x )
235+ outputgrid .write ("NODATA_VALUE %.8f\n " % esri_nullvalue )
236+
237+ esrigrid_outvalues = np .where (np .isnan (arr ), esri_nullvalue , arr )
238+
239+ # output of results
240+
241+ for i in range (0 , num_rows ):
242+ for j in range (0 , num_cols ):
243+ outputgrid .write ("%.8f " % (esrigrid_outvalues [i , j ]))
244+ outputgrid .write ("\n " )
245+
246+ outputgrid .close ()
247+
248+ return True , "Data saved in {}" .format (outgrid_flpth )
249+
250+
131251if __name__ == "__main__" :
132252
133253 import doctest
0 commit comments