Skip to content

Commit ac95cad

Browse files
authored
Merge pull request OSGeo#12814 from dbaston/raster-clip-fix-bbox-check
gdal raster clip: fix bbox check
2 parents 1c27109 + 9fe5fe3 commit ac95cad

File tree

4 files changed

+115
-30
lines changed

4 files changed

+115
-30
lines changed

apps/gdalalg_raster_clip.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,9 @@ bool GDALRasterClipAlgorithm::RunStep(GDALPipelineStepRunContext &)
252252
poClipGeomInSrcSRS->getEnvelope(&env);
253253
}
254254

255-
if (!m_allowExtentOutsideSource &&
256-
!(env.MinX >= gt[0] &&
257-
env.MaxX <= gt[0] + gt[1] * poSrcDS->GetRasterXSize() &&
258-
env.MaxY >= gt[3] &&
259-
env.MinY <= gt[3] + gt[5] * poSrcDS->GetRasterYSize()))
255+
OGREnvelope rasterEnv;
256+
poSrcDS->GetExtent(&rasterEnv, nullptr);
257+
if (!m_allowExtentOutsideSource && !rasterEnv.Contains(env))
260258
{
261259
ReportError(CE_Failure, CPLE_AppDefined,
262260
"Clipping geometry is partially or totally outside the "

autotest/gcore/basic_test.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import gdaltest
2020
import pytest
2121

22-
from osgeo import gdal
22+
from osgeo import gdal, osr
2323

2424

2525
###############################################################################
@@ -1108,3 +1108,56 @@ def test_basic_block_windows(tmp_vsimem):
11081108
assert windows[8].yoff == 512
11091109
assert windows[8].xsize == 1050 - 1024
11101110
assert windows[8].ysize == 600 - 512
1111+
1112+
1113+
###############################################################################
1114+
# Test GetExtent()
1115+
1116+
1117+
def test_basic_get_extent():
1118+
1119+
with gdal.Open("data/byte.tif") as ds:
1120+
assert ds.GetExtent() == (440720.0, 441920.0, 3750120.0, 3751320.0)
1121+
1122+
1123+
def test_basic_get_extent_reprojected():
1124+
1125+
wgs84 = osr.SpatialReference(epsg=4326)
1126+
wgs84.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
1127+
1128+
with gdal.Open("data/byte.tif") as ds:
1129+
assert ds.GetExtent(wgs84) == pytest.approx(
1130+
(-117.642, -117.629, 33.892, 33.902), abs=1e-3
1131+
)
1132+
1133+
1134+
def test_basic_get_extent_no_crs():
1135+
1136+
with gdal.GetDriverByName("MEM").Create("", 5, 5) as ds:
1137+
ds.SetGeoTransform((3, 0.5, 0, 7, 0, -1))
1138+
assert ds.GetExtent() == (3, 5.5, 2, 7)
1139+
1140+
1141+
def test_basic_get_extent_no_crs_reprojected():
1142+
1143+
wgs84 = osr.SpatialReference(epsg=4326)
1144+
wgs84.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
1145+
1146+
with gdal.GetDriverByName("MEM").Create("", 5, 5) as ds:
1147+
ds.SetGeoTransform((3, 0.5, 0, 7, 0, -1))
1148+
assert ds.GetExtent(wgs84) is None
1149+
1150+
1151+
def test_basic_get_extent_bottom_up():
1152+
1153+
with gdal.GetDriverByName("MEM").Create("", 5, 5) as ds:
1154+
ds.SetGeoTransform((3, 0.5, 0, 7, 0, 1))
1155+
assert ds.GetExtent() == (3, 5.5, 7, 12)
1156+
1157+
1158+
def test_basic_get_extent_rotated():
1159+
1160+
with gdal.Open("data/geomatrix.tif") as ds:
1161+
assert ds.GetExtent() == pytest.approx(
1162+
(1840900, 1841030, 1143870, 1144000), abs=4
1163+
)

autotest/utilities/test_gdalalg_raster_clip.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,28 @@ def test_gdalalg_raster_clip_bbox_crs():
169169
)
170170

171171

172+
def test_gdalgalg_raster_clip_geometry(tmp_vsimem):
173+
174+
alg = get_alg()
175+
176+
alg["input"] = "../gcore/data/byte.tif"
177+
alg["output"] = ""
178+
alg["output-format"] = "MEM"
179+
alg[
180+
"geometry"
181+
] = "POLYGON ((440885 3750741, 441344 3750294, 441612 3750501, 441773 3751203, 441545 3751254, 441576 3750847, 441576 3750847, 440885 3750741))"
182+
183+
assert alg.Run()
184+
185+
ds = alg["output"].GetDataset()
186+
assert ds.RasterXSize == 16
187+
assert ds.RasterYSize == 17
188+
assert ds.GetSpatialRef().GetAuthorityCode(None) == "26711"
189+
assert ds.GetGeoTransform() == pytest.approx(
190+
(440840, 60.0, 0.0, 3751260, 0.0, -60.0), rel=1e-8
191+
)
192+
193+
172194
def test_gdalalg_raster_clip_geometry_add_alpha():
173195

174196
src_ds = gdal.Open("../gcore/data/byte.tif")

gcore/gdaldataset.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10621,7 +10621,7 @@ CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
1062110621
if (auto poLayer = poThisDS->GetLayer(0))
1062210622
poThisCRS = poLayer->GetSpatialRef();
1062310623
}
10624-
if (!poThisCRS)
10624+
if (poCRS && !poThisCRS)
1062510625
return CE_Failure;
1062610626
}
1062710627
if (!poCRS)
@@ -10633,34 +10633,46 @@ CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
1063310633
const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
1063410634
if (bHasGT)
1063510635
{
10636-
auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
10637-
OGRCreateCoordinateTransformation(poThisCRS, poCRS));
10636+
std::unique_ptr<OGRCoordinateTransformation> poCT;
10637+
if (poCRS)
10638+
{
10639+
poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
10640+
}
10641+
10642+
constexpr int DENSIFY_POINT_COUNT = 21;
10643+
double dfULX = gt[0];
10644+
double dfULY = gt[3];
10645+
double dfURX = 0, dfURY = 0;
10646+
gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
10647+
double dfLLX = 0, dfLLY = 0;
10648+
gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
10649+
double dfLRX = 0, dfLRY = 0;
10650+
gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
10651+
const double xmin =
10652+
std::min(std::min(dfULX, dfURX), std::min(dfLLX, dfLRX));
10653+
const double ymin =
10654+
std::min(std::min(dfULY, dfURY), std::min(dfLLY, dfLRY));
10655+
const double xmax =
10656+
std::max(std::max(dfULX, dfURX), std::max(dfLLX, dfLRX));
10657+
const double ymax =
10658+
std::max(std::max(dfULY, dfURY), std::max(dfLLY, dfLRY));
1063810659
if (poCT)
1063910660
{
10640-
constexpr int DENSIFY_POINT_COUNT = 21;
1064110661
OGREnvelope sEnvTmp;
10642-
double dfULX = gt[0];
10643-
double dfULY = gt[3];
10644-
double dfURX = 0, dfURY = 0;
10645-
gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
10646-
double dfLLX = 0, dfLLY = 0;
10647-
gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
10648-
double dfLRX = 0, dfLRY = 0;
10649-
gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
10650-
const double xmin =
10651-
std::min(std::min(dfULX, dfURX), std::min(dfLLX, dfLRX));
10652-
const double ymin =
10653-
std::min(std::min(dfULY, dfURY), std::min(dfLLY, dfLRY));
10654-
const double xmax =
10655-
std::max(std::max(dfULX, dfURX), std::max(dfLLX, dfLRX));
10656-
const double ymax =
10657-
std::max(std::max(dfULY, dfURY), std::max(dfLLY, dfLRY));
10658-
if (poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
10659-
&(sEnvTmp.MinY), &(sEnvTmp.MaxX),
10660-
&(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
10662+
if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
10663+
&(sEnvTmp.MinY), &(sEnvTmp.MaxX),
10664+
&(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
1066110665
{
10662-
*psExtent = std::move(sEnvTmp);
10666+
return CE_Failure;
1066310667
}
10668+
*psExtent = sEnvTmp;
10669+
}
10670+
else
10671+
{
10672+
psExtent->MinX = xmin;
10673+
psExtent->MinY = ymin;
10674+
psExtent->MaxX = xmax;
10675+
psExtent->MaxY = ymax;
1066410676
}
1066510677
}
1066610678

0 commit comments

Comments
 (0)