def test_transform(): pj_utm = osr_util.get_srs(32636) utm_x = [690950.4640, 688927.6381] utm_y = [3431318.8435, 3542183.4911] for gis_order in (False, True): axis_order = osr_util.get_axis_order_from_gis_order(gis_order) pj4326 = osr_util.get_srs(4326, axis_order=axis_order) ct = osr_util.get_transform(pj4326, pj_utm) lon = [35, 35] lat = [31, 32] x, y = (lon, lat) if gis_order else (lat, lon) osr_util.transform_points(ct, x, y) d = array_util.array_dist(x, utm_x), array_util.array_dist(y, utm_y) assert max(d) < 0.01
def test_gis_order2(): pj4326_gis = osr_util.get_srs(4326, axis_order=osr.OAMS_TRADITIONAL_GIS_ORDER) pj4326_str = osr_util.get_srs_pj(4326) srs_from_epsg = osr.SpatialReference() srs_from_epsg.ImportFromEPSG(4326) assert srs_from_epsg.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT srs_from_str = osr.SpatialReference() srs_from_str.ImportFromProj4(pj4326_str) assert srs_from_str.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT assert srs_from_epsg.IsSame(srs_from_str) # testing that explicitly setting OAMS_AUTHORITY_COMPLIANT does not effect equivalence srs_from_epsg.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT) srs_from_str.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT) assert srs_from_epsg.IsSame(srs_from_str) srs_from_epsg.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER) srs_from_str.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER) srs_from_epsg2 = osr.SpatialReference() srs_from_epsg2.ImportFromEPSG(4326) srs_from_epsg2.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER) assert srs_from_epsg.IsSame(srs_from_epsg2) test_gis_order_proj_str_vs_epsg = False # explicitly setting OAMS_TRADITIONAL_GIS_ORDER triggers inequality between srs from proj-string and srs from epsg # if this issue is resolved these tests can be enabled if test_gis_order_proj_str_vs_epsg: assert srs_from_epsg.IsSame(srs_from_str) assert osr_util.are_srs_equivalent(pj4326_str, 4326) assert osr_util.are_srs_equivalent(pj4326_gis, pj4326_str)
def get_datum_and_zone_from_srs(srs: AnySRS) -> Tuple[str, Real]: srs = get_srs(srs) datum = srs.GetAttrValue('DATUM') central_meridian = srs.GetProjParm('central_meridian') if central_meridian: zone = get_utm_zone_by_lon(central_meridian) else: zone = None return datum, zone
def ogr_create_geometries_from_wkt(path: PathLikeOrStr, wkt_list: Sequence[str], of='ESRI Shapefile', srs: AnySRS = 4326): driver = ogr.GetDriverByName(of) ds = driver.CreateDataSource(os.fspath(path)) srs = get_srs(srs) layer = ds.CreateLayer('', srs, ogr.wkbUnknown) for wkt in wkt_list: feature = ogr.Feature(layer.GetLayerDefn()) geom = ogr.CreateGeometryFromWkt(wkt) feature.SetGeometry(geom) # Set the feature geometry layer.CreateFeature(feature) # Create the feature in the layer feature.Destroy() # Destroy the feature to free resources # Destroy the data source to free resources ds.Destroy()
def gdal_to_json(ds: gdal.Dataset): gt = ds.GetGeoTransform(can_return_null=True) xsize = ds.RasterXSize ysize = ds.RasterYSize srs = get_srs(ds) srs = srs.ExportToProj4() minx = gt[0] + gt[1] * 0 + gt[2] * 0 miny = gt[3] + gt[4] * 0 + gt[5] * 0 maxx = gt[0] + gt[1] * xsize + gt[2] * ysize maxy = gt[3] + gt[4] * xsize + gt[5] * ysize bbox = miny, minx, maxy, maxx band_list = range(1, ds.RasterCount + 1) data = [ ds.ReadAsArray(band_list=[bnd]).ravel().tolist() for bnd in band_list ] ndv = [ds.GetRasterBand(i).GetNoDataValue() for i in band_list] result = dict(bbox=bbox, gt=gt, srs=srs, size=(xsize, ysize), data=data, ndv=ndv) return result
def gdallocationinfo( filename_or_ds: PathOrDS, x: ArrayOrScalarLike, y: ArrayOrScalarLike, srs: CoordinateTransformationOrSRS = None, axis_order: Optional[OAMS_AXIS_ORDER] = None, open_options: Optional[dict] = None, ovr_idx: Optional[int] = None, band_nums: Optional[Sequence[int]] = None, inline_xy_replacement: bool = False, return_ovr_pixel_line: bool = False, transform_round_digits: Optional[float] = None, allow_xy_outside_extent: bool = True, pixel_offset: Real = -0.5, line_offset: Real = -0.5, resample_alg=gdalconst.GRIORA_NearestNeighbour, quiet_mode: bool = True, ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: ds = open_ds(filename_or_ds, open_options=open_options) filename = filename_or_ds if is_path_like(filename_or_ds) else '' if ds is None: raise Exception(f'Could not open {filename}.') if not isinstance(x, ArrayLike.__args__): x = [x] if not isinstance(y, ArrayLike.__args__): y = [y] if len(x) != len(y): raise Exception( f'len(x)={len(x)} should be the same as len(y)={len(y)}') point_count = len(x) dtype = np.float64 if not isinstance(x, np.ndarray) or not isinstance(y, np.ndarray): x = np.array(x, dtype=dtype) y = np.array(y, dtype=dtype) inline_xy_replacement = True if srs is None: srs = LocationInfoSRS.PixelLine # Build Spatial Reference object based on coordinate system, fetched from the opened dataset if srs != LocationInfoSRS.PixelLine: if srs != LocationInfoSRS.SameAsDS_SRS: ds_srs = ds.GetSpatialRef() ct = None if isinstance(srs, osr.CoordinateTransformation): ct = srs else: if srs == LocationInfoSRS.SameAsDS_SRS_GeogCS: points_srs = ds_srs.CloneGeogCS() else: points_srs = get_srs(srs, axis_order=axis_order) ct = get_transform(points_srs, ds_srs) if ct is not None: if not inline_xy_replacement: x = x.copy() y = y.copy() inline_xy_replacement = True transform_points(ct, x, y) if transform_round_digits is not None: x.round(transform_round_digits, out=x) y.round(transform_round_digits, out=y) # Read geotransform matrix and calculate corresponding pixel coordinates geotransform = ds.GetGeoTransform() inv_geotransform = gdal.InvGeoTransform(geotransform) if inv_geotransform is None: raise Exception("Failed InvGeoTransform()") # can we inline this transformation ? x, y = \ (inv_geotransform[0] + inv_geotransform[1] * x + inv_geotransform[2] * y), \ (inv_geotransform[3] + inv_geotransform[4] * x + inv_geotransform[5] * y) inline_xy_replacement = True xsize, ysize = ds.RasterXSize, ds.RasterYSize bands = get_bands(ds, band_nums, ovr_idx=ovr_idx) ovr_xsize, ovr_ysize = bands[0].XSize, bands[0].YSize pixel_fact, line_fact = (ovr_xsize / xsize, ovr_ysize / ysize) if ovr_idx else (1, 1) bnd_count = len(bands) shape = (bnd_count, point_count) np_dtype, np_dtype = GDALTypeCodeAndNumericTypeCodeFromDataSet(ds) results = np.empty(shape=shape, dtype=np_dtype) check_outside = not quiet_mode or not allow_xy_outside_extent if check_outside and (np.any(x < 0) or np.any(x >= xsize) or np.any(y < 0) or np.any(y >= ysize)): msg = 'Passed coordinates are not in dataset extent!' if not allow_xy_outside_extent: raise Exception(msg) elif not quiet_mode: print(msg) if pixel_fact == 1: pixels_q = x elif return_ovr_pixel_line: x *= pixel_fact pixels_q = x else: pixels_q = x * pixel_fact if line_fact == 1: lines_q = y elif return_ovr_pixel_line: y *= line_fact lines_q = y else: lines_q = y * line_fact buf_xsize = buf_ysize = 1 buf_type, typecode = GDALTypeCodeAndNumericTypeCodeFromDataSet(ds) buf_obj = np.empty([buf_ysize, buf_xsize], dtype=typecode) for idx, (pixel, line) in enumerate(zip(pixels_q, lines_q)): for bnd_idx, band in enumerate(bands): if BandRasterIONumPy(band, 0, pixel - 0.5, line - 0.5, 1, 1, buf_obj, buf_type, resample_alg, None, None) == 0: results[bnd_idx][idx] = buf_obj[0][0] is_scaled, scales, offsets = get_scales_and_offsets(bands) if is_scaled: for bnd_idx, (scale, offset) in enumerate(zip(scales, offsets)): results[bnd_idx] = results[bnd_idx] * scale + offset return x, y, results
def test_gdallocationinfo_py_7(): filename_template = 'tmp/byte{}.tif' overview_list = [2] overview_list, file_list = copy_raster_and_add_overviews( filename_src='../gcore/data/byte.tif', output_filename_template=filename_template, overview_list=overview_list) temp_files.extend(file_list) ds = open_ds(filename_template.format('')) ds_srs = ds.GetSpatialRef() gt = ds.GetGeoTransform() ovr_fact = 1 pix_offset = 0 p0 = list(i * ovr_fact + pix_offset for i in range(0, 3)) l0 = list(i * ovr_fact + pix_offset for i in range(0, 3)) p0, l0 = zip(*product(p0, l0)) x0 = list(gt[0] + pixel * gt[1] for pixel in p0) y0 = list(gt[3] + line * gt[5] for line in l0) dtype = np.float64 p0 = np.array(p0, dtype=dtype) l0 = np.array(l0, dtype=dtype) x0 = np.array(x0, dtype=dtype) y0 = np.array(y0, dtype=dtype) expected_results = [[(0.0, 0.0, 107), (0.0, 1.0, 115), (0.0, 2.0, 115), (1.0, 0.0, 123), (1.0, 1.0, 132), (1.0, 2.0, 132), (2.0, 0.0, 132), (2.0, 1.0, 107), (2.0, 2.0, 140)], [(0.0, 0.0, 120), (0.0, 0.5, 120), (0.0, 1.0, 132), (0.5, 0.0, 120), (0.5, 0.5, 120), (0.5, 1.0, 132), (1.0, 0.0, 124), (1.0, 0.5, 124), (1.0, 1.0, 129)]] expected_results = np.array(expected_results, dtype=dtype) do_print = False for ovr_idx, f in enumerate(overview_list): for srs in [ LocationInfoSRS.PixelLine, LocationInfoSRS.SameAsDS_SRS, 4326 ]: if srs == LocationInfoSRS.PixelLine: x = p0 y = l0 elif srs == LocationInfoSRS.SameAsDS_SRS: x = x0 y = y0 else: points_srs = get_srs(srs, axis_order=osr.OAMS_TRADITIONAL_GIS_ORDER) ct = get_transform(ds_srs, points_srs) x = x0.copy() y = y0.copy() transform_points(ct, x, y) pixels, lines, results = gdallocationinfo.gdallocationinfo( filename_or_ds=ds, ovr_idx=ovr_idx, x=x, y=y, transform_round_digits=2, return_ovr_pixel_line=True, srs=srs, axis_order=osr.OAMS_TRADITIONAL_GIS_ORDER) actual = list(zip(pixels, lines, *results)) actual = np.array(actual, dtype=dtype) expected = expected_results[ovr_idx] if do_print: print(actual) print(expected) outputs = list(zip(x, y, pixels, lines, *results)) print( f'ovr: {ovr_idx}, srs: {srs}, x/y/pixel/line/result: {outputs}' ) assert_allclose(expected, actual, rtol=1e-4, atol=1e-3)
def test_gis_order(): pj4326_gis2 = osr_util.get_srs(4326) # tests the correct default if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None: assert pj4326_gis2.GetAxisMappingStrategy( ) == osr.OAMS_AUTHORITY_COMPLIANT pj4326_auth = osr_util.get_srs(4326, axis_order=osr.OAMS_AUTHORITY_COMPLIANT) assert pj4326_auth.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT pj4326_gis = osr_util.get_srs(4326, axis_order=osr.OAMS_TRADITIONAL_GIS_ORDER) assert pj4326_gis.GetAxisMappingStrategy( ) == osr.OAMS_TRADITIONAL_GIS_ORDER assert not osr_util.are_srs_equivalent(pj4326_gis, pj4326_auth) if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None: assert osr_util.are_srs_equivalent(pj4326_auth, 4326) assert not osr_util.are_srs_equivalent(pj4326_gis, 4326) pj4326_str = osr_util.get_srs_pj(pj4326_auth) pj4326_str2 = osr_util.get_srs_pj(pj4326_gis) # axis order is not reflected in proj strings assert isinstance(pj4326_str, str) and pj4326_str == pj4326_str2 if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None: assert osr_util.are_srs_equivalent(pj4326_str, 4326) assert osr_util.are_srs_equivalent(pj4326_auth, pj4326_str) assert not osr_util.are_srs_equivalent(pj4326_gis, pj4326_str) osr_util.set_default_axis_order( osr.OAMS_TRADITIONAL_GIS_ORDER) # sets gis order srs = osr_util.get_srs(4326) # check the the default was changed if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None: assert srs.GetAxisMappingStrategy() == osr.OAMS_TRADITIONAL_GIS_ORDER # check that srs object is not affected by default srs = osr_util.get_srs(pj4326_auth) assert srs.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT assert osr_util.are_srs_equivalent(srs, pj4326_auth) # check that srs object is also affected if explicitly set srs = osr_util.get_srs(pj4326_auth, axis_order=osr.OAMS_TRADITIONAL_GIS_ORDER) assert srs.GetAxisMappingStrategy() == osr.OAMS_TRADITIONAL_GIS_ORDER # check that the default does not effect explicit order srs = osr_util.get_srs(4326, axis_order=osr.OAMS_TRADITIONAL_GIS_ORDER) assert srs.GetAxisMappingStrategy() == osr.OAMS_TRADITIONAL_GIS_ORDER srs = osr_util.get_srs(pj4326_str) assert srs.GetAxisMappingStrategy() == osr.OAMS_TRADITIONAL_GIS_ORDER srs = osr_util.get_srs(4326, axis_order=osr.OAMS_AUTHORITY_COMPLIANT) assert srs.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT assert not osr_util.are_srs_equivalent(pj4326_gis, pj4326_auth) assert not osr_util.are_srs_equivalent(pj4326_auth, 4326) assert osr_util.are_srs_equivalent(pj4326_gis, 4326) # restore the default and repeat some tests osr_util.set_default_axis_order() srs = osr_util.get_srs(4326) # check the the default was restored if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None: assert srs.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT srs = osr_util.get_srs(pj4326_str) if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None: assert srs.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT # check that srs object is not affected by default srs = osr_util.get_srs( pj4326_gis) # check that srs object is also affected assert srs.GetAxisMappingStrategy() == osr.OAMS_TRADITIONAL_GIS_ORDER # check that srs object is also affected if explicitly set srs = osr_util.get_srs(pj4326_gis, axis_order=osr.OAMS_AUTHORITY_COMPLIANT) assert srs.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT srs = osr_util.get_srs(4326, axis_order=osr.OAMS_TRADITIONAL_GIS_ORDER) assert srs.GetAxisMappingStrategy() == osr.OAMS_TRADITIONAL_GIS_ORDER
def gdallocationinfo( filename_or_ds: PathOrDS, x: NumpyCompatibleArrayOrReal, y: NumpyCompatibleArrayOrReal, gis_order: bool = False, open_options: Optional[dict] = None, ovr_idx: Optional[int] = None, band_nums: Optional[Sequence[int]] = None, srs: CoordinateTransformationOrSRS = None, inline_xy_replacement: bool = True, quiet_mode: bool = True, allow_xy_outside_extent: bool = True, pixel_offset: Real = -0.5, line_offset: Real = -0.5, resample_alg=gdalconst.GRIORA_NearestNeighbour ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: ds = open_ds(filename_or_ds, open_options=open_options) filename = filename_or_ds if is_path_like(filename_or_ds) else '' if ds is None: raise Exception(f'Could not open {filename}.') if not isinstance(x, NumpyCompatibleArray.__args__): x = [x] if not isinstance(y, NumpyCompatibleArray.__args__): y = [y] if len(x) != len(y): raise Exception( f'len(x)={len(x)} should be the same as len(y)={len(y)}') point_count = len(x) if not isinstance(x, np.ndarray): x = np.ndarray(x) if not isinstance(y, np.ndarray): y = np.ndarray(y) if srs is None: srs = LocationInfoSRS.PixelLine # Build Spatial Reference object based on coordinate system, fetched from the opened dataset if srs != LocationInfoSRS.PixelLine: if srs != LocationInfoSRS.SameAsDS_SRS: ds_srs = ds.GetSpatialRef() ct = None if isinstance(srs, osr.CoordinateTransformation): ct = srs else: if srs == LocationInfoSRS.SameAsDS_SRS_GeogCS: points_srs = ds_srs.CloneGeogCS() else: points_srs = get_srs(srs, gis_order=gis_order) ct = get_transform(points_srs, ds_srs) x, y, _z = transform_points(ct, x, y) # Read geotransform matrix and calculate corresponding pixel coordinates geomatrix = ds.GetGeoTransform() inv_geometrix = gdal.InvGeoTransform(geomatrix) if inv_geometrix is None: raise Exception("Failed InvGeoTransform()") x, y = \ (inv_geometrix[0] + inv_geometrix[1] * x + inv_geometrix[2] * y), \ (inv_geometrix[3] + inv_geometrix[4] * x + inv_geometrix[5] * y) xsize, ysize = ds.RasterXSize, ds.RasterYSize bands = get_bands(ds, band_nums, ovr_idx=ovr_idx) ovr_xsize, ovr_ysize = bands[0].XSize, bands[0].YSize pixel_fact, line_fact = (ovr_xsize / xsize, ovr_ysize / ysize) if ovr_idx else (1, 1) bnd_count = len(bands) shape = (bnd_count, point_count) np_dtype, np_dtype = GDALTypeCodeAndNumericTypeCodeFromDataSet(ds) results = np.empty(shape=shape, dtype=np_dtype) check_outside = not quiet_mode or not allow_xy_outside_extent if check_outside and (np.any(x < 0) or np.any(x >= xsize) or np.any(y < 0) or np.any(y >= ysize)): msg = 'Passed coordinates are not in dataset extent!' if not allow_xy_outside_extent: raise Exception(msg) elif not quiet_mode: print(msg) pixels = np.clip(x * pixel_fact + pixel_offset, 0, ovr_xsize - 1, out=x if inline_xy_replacement else None) lines = np.clip(y * line_fact + line_offset, 0, ovr_ysize - 1, out=y if inline_xy_replacement else None) for idx, (pixel, line) in enumerate(zip(pixels, lines)): for bnd_idx, band in enumerate(bands): val = band.ReadAsArray(pixel, line, 1, 1, resample_alg=resample_alg) val = val[0][0] results[bnd_idx][idx] = val is_scaled, scales, offsets = get_scales_and_offsets(bands) if is_scaled: for bnd_idx, scale, offset in enumerate(zip(scales, offsets)): results[bnd_idx] = results[bnd_idx] * scale + offset return pixels, lines, results