From 62400aa8eecea342b0197ff8c9c721be6cc2a6f7 Mon Sep 17 00:00:00 2001 From: Michael Sumner Date: Tue, 5 Sep 2023 23:53:04 +1000 Subject: [PATCH] VRT 'tr', 'r', 'srcwin', 'a_gt' for vrt:// connection (#8330) --- autotest/gcore/vrt_read.py | 41 +++++++++++++++++- doc/source/drivers/raster/vrt.rst | 13 +++++- frmts/vrt/vrtdataset.cpp | 71 +++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 2 deletions(-) diff --git a/autotest/gcore/vrt_read.py b/autotest/gcore/vrt_read.py index c2124b82af81..5e80e33817e4 100755 --- a/autotest/gcore/vrt_read.py +++ b/autotest/gcore/vrt_read.py @@ -1529,7 +1529,7 @@ def test_vrt_protocol(): ## no op, simply ignored as with gdal_translate ds = gdal.Open("vrt://data/float32.tif?projwin_srs=OGC:CRS84") - assert ds + assert ds is not None ds = gdal.Open( "vrt://data/float32.tif?projwin_srs=OGC:CRS84&projwin=-117.6407,33.90027,-117.6292,33.89181" @@ -1540,6 +1540,45 @@ def test_vrt_protocol(): assert ds.GetRasterBand(1).XSize == 18 assert ds.GetRasterBand(1).YSize == 16 + with gdal.quiet_errors(): + ds = gdal.Open("vrt://data/float32.tif?tr=120") + assert ds is None + + ds = gdal.Open("vrt://data/float32.tif?tr=120,240") + + assert ds.GetGeoTransform()[0] == 440720.0 + assert ds.GetGeoTransform()[1] == 120.0 + assert ds.GetGeoTransform()[5] == -240.0 + assert ds.GetRasterBand(1).XSize == 10 + assert ds.GetRasterBand(1).YSize == 5 + + ds = gdal.Open("vrt://data/float32.tif?r=bilinear&tr=120,240") + assert struct.unpack("f", ds.ReadRaster(0, 0, 1, 1))[0] == pytest.approx( + 128.95408630371094 + ) ## check values changed via bilinear + + with gdal.quiet_errors(): + ds = gdal.Open("vrt://data/float32.tif?srcwin=0,0,3") + assert ds is None + + ds = gdal.Open("vrt://data/float32.tif?srcwin=2,3,8,5") + assert ds.GetRasterBand(1).XSize == 8 + assert ds.GetRasterBand(1).YSize == 5 + assert struct.unpack("f", ds.ReadRaster(0, 0, 1, 1))[0] == pytest.approx( + 123.0 + ) ## check value is correct + + with gdal.quiet_errors(): + ds = gdal.Open("vrt://data/float32.tif?a_gt=1,0,0,0,1") + assert ds is None + + ds = gdal.Open("vrt://data/float32.tif?a_gt=0,1,0,0,0,1") + gdaltest.check_geotransform( + (0, 1, 0, 0, 0, 1), + ds.GetGeoTransform(), + 1e-9, + ) + @pytest.mark.require_driver("BMP") def test_vrt_protocol_expand_option(): diff --git a/doc/source/drivers/raster/vrt.rst b/doc/source/drivers/raster/vrt.rst index e32971b7f590..413055f546c2 100644 --- a/doc/source/drivers/raster/vrt.rst +++ b/doc/source/drivers/raster/vrt.rst @@ -1688,7 +1688,8 @@ For example: The supported options currently are ``bands``, ``a_srs``, ``a_ullr``, ``ovr``, ``expand``, -``a_scale``, ``a_offset``, ``ot``, ``gcp``, ``if``, ``scale``, ``exponent``, ``outsize``, and ``projwin``. +``a_scale``, ``a_offset``, ``ot``, ``gcp``, ``if``, ``scale``, ``exponent``, ``outsize``, ``projwin``, +``tr``, ``r``, ``srcwin``, and ``a_gt``. Other options may be added in the future. @@ -1748,6 +1749,16 @@ provided. The effect of the ``projwin_srs`` option (added in GDAL 3.8) is to specify the SRS in which to interpret the coordinates given with ``projwin`` in the same way as (:ref:`gdal_translate`). This option only applies if ``projwin`` is also supplied. +The effect of the ``tr`` option (added in GDAL 3.8) is to set the target resolution, two positive values in georeferenced coordinates, applied in the same way as (:ref:`gdal_translate`). The value consists of two numeric values separated by commas in the order 'xres,yres'. + +The effect of the ``r`` option (added in GDAL 3.8) is to set the resampling algorithm used, with 'nearest' as the default. This is applied in the same way as (:ref:`gdal_translate`). + +The effect of the ``srcwin`` option (added in GDAL 3.8) is to select a subwindow from the source image based on pixel/line location as with (:ref:`gdal_translate`). The value consists of four integer values separated by commas, in +the order 'xoff,yoff,xsize,ysize'. + +The effect of the ``a_gt`` option (added in GDAL 3.8) is to override/assign the geotransform of the output as with (:ref:`gdal_translate`). The value consists of six numeric values separated by commas, in +the order 'gt(0),gt(1),gt(2),gt(3),gt(4),gt(5)'. + The options may be chained together separated by '&'. (Beware the need for quoting to protect the ampersand). diff --git a/frmts/vrt/vrtdataset.cpp b/frmts/vrt/vrtdataset.cpp index 948143305e5e..8dcb69942ec4 100644 --- a/frmts/vrt/vrtdataset.cpp +++ b/frmts/vrt/vrtdataset.cpp @@ -1228,7 +1228,78 @@ GDALDataset *VRTDataset::OpenVRTProtocol(const char *pszSpec) argv.AddString("-projwin_srs"); argv.AddString(pszValue); } + else if (EQUAL(pszKey, "tr")) + { + CPLStringList aosTargetResolution( + CSLTokenizeString2(pszValue, ",", 0)); + if (aosTargetResolution.size() != 2) + { + CPLError(CE_Failure, CPLE_IllegalArg, + "Invalid tr option: %s, must be two " + "values separated by comma xres,yres", + pszValue); + poSrcDS->ReleaseRef(); + CPLFree(pszKey); + return nullptr; + } + argv.AddString("-tr"); + argv.AddString(aosTargetResolution[0]); + argv.AddString(aosTargetResolution[1]); + } + else if (EQUAL(pszKey, "r")) + { + argv.AddString("-r"); + argv.AddString(pszValue); + } + + else if (EQUAL(pszKey, "srcwin")) + { + // Parse the limits + CPLStringList aosSrcWin(CSLTokenizeString2(pszValue, ",", 0)); + // fail if not four values + if (aosSrcWin.size() != 4) + { + CPLError(CE_Failure, CPLE_IllegalArg, + "Invalid srcwin option: %s, must be four " + "values separated by comma xoff,yoff,xsize,ysize", + pszValue); + poSrcDS->ReleaseRef(); + CPLFree(pszKey); + return nullptr; + } + + argv.AddString("-srcwin"); + argv.AddString(aosSrcWin[0]); + argv.AddString(aosSrcWin[1]); + argv.AddString(aosSrcWin[2]); + argv.AddString(aosSrcWin[3]); + } + + else if (EQUAL(pszKey, "a_gt")) + { + + // Parse the limits + CPLStringList aosAGeoTransform( + CSLTokenizeString2(pszValue, ",", 0)); + // fail if not six values + if (aosAGeoTransform.size() != 6) + { + CPLError(CE_Failure, CPLE_IllegalArg, + "Invalid a_gt option: %s", pszValue); + poSrcDS->ReleaseRef(); + CPLFree(pszKey); + return nullptr; + } + + argv.AddString("-a_gt"); + argv.AddString(aosAGeoTransform[0]); + argv.AddString(aosAGeoTransform[1]); + argv.AddString(aosAGeoTransform[2]); + argv.AddString(aosAGeoTransform[3]); + argv.AddString(aosAGeoTransform[4]); + argv.AddString(aosAGeoTransform[5]); + } else { CPLError(CE_Failure, CPLE_NotSupported, "Unknown option: %s",