Skip to content

Commit 0855511

Browse files
authored
Merge pull request #13442 from elpaso/bugfix-gh13424-vector-rasterize-autocalc-px-dim
[rasterize] Calculate one size from the other and the input extent if one of the size values is 0 This allows to specify only one of the sizes (-ts) arguments. Fixes #13424
1 parent 3eb76a7 commit 0855511

File tree

4 files changed

+280
-60
lines changed

4 files changed

+280
-60
lines changed

apps/gdal_rasterize_lib.cpp

Lines changed: 187 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -991,18 +991,15 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
991991

992992
std::unique_ptr<GDALRasterizeOptions, decltype(&GDALRasterizeOptionsFree)>
993993
psOptionsToFree(nullptr, GDALRasterizeOptionsFree);
994-
const GDALRasterizeOptions *psOptions = psOptionsIn;
995-
if (psOptions == nullptr)
996-
{
997-
psOptionsToFree.reset(GDALRasterizeOptionsNew(nullptr, nullptr));
998-
psOptions = psOptionsToFree.get();
999-
}
994+
GDALRasterizeOptions sOptions;
995+
if (psOptionsIn)
996+
sOptions = *psOptionsIn;
1000997

1001998
const bool bCloseOutDSOnError = hDstDS == nullptr;
1002999
if (pszDest == nullptr)
10031000
pszDest = GDALGetDescription(hDstDS);
10041001

1005-
if (psOptions->osSQL.empty() && psOptions->aosLayers.empty() &&
1002+
if (sOptions.osSQL.empty() && sOptions.aosLayers.empty() &&
10061003
GDALDatasetGetLayerCount(hSrcDataset) != 1)
10071004
{
10081005
CPLError(CE_Failure, CPLE_NotSupported,
@@ -1017,13 +1014,13 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
10171014
/* Open target raster file. Eventually we will add optional */
10181015
/* creation. */
10191016
/* -------------------------------------------------------------------- */
1020-
const bool bCreateOutput = psOptions->bCreateOutput || hDstDS == nullptr;
1017+
const bool bCreateOutput = sOptions.bCreateOutput || hDstDS == nullptr;
10211018

10221019
GDALDriverH hDriver = nullptr;
10231020
if (bCreateOutput)
10241021
{
10251022
CPLString osFormat;
1026-
if (psOptions->osFormat.empty())
1023+
if (sOptions.osFormat.empty())
10271024
{
10281025
osFormat = GetOutputDriverForRaster(pszDest);
10291026
if (osFormat.empty())
@@ -1033,7 +1030,7 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
10331030
}
10341031
else
10351032
{
1036-
osFormat = psOptions->osFormat;
1033+
osFormat = sOptions.osFormat;
10371034
}
10381035

10391036
/* --------------------------------------------------------------------
@@ -1072,16 +1069,131 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
10721069
}
10731070
}
10741071

1072+
auto calculateSize = [&](const OGREnvelope &sEnvelope) -> bool
1073+
{
1074+
const double width{sEnvelope.MaxX - sEnvelope.MinX};
1075+
if (std::isnan(width))
1076+
{
1077+
return false;
1078+
}
1079+
1080+
const double height{sEnvelope.MaxY - sEnvelope.MinY};
1081+
if (std::isnan(height))
1082+
{
1083+
return false;
1084+
}
1085+
1086+
if (height == 0 || width == 0)
1087+
{
1088+
return false;
1089+
}
1090+
1091+
if (sOptions.nXSize == 0)
1092+
{
1093+
const double xSize{
1094+
(sEnvelope.MaxX - sEnvelope.MinX) /
1095+
((sEnvelope.MaxY - sEnvelope.MinY) / sOptions.nYSize)};
1096+
if (std::isnan(xSize) || xSize > std::numeric_limits<int>::max() ||
1097+
xSize < std::numeric_limits<int>::min())
1098+
{
1099+
return false;
1100+
}
1101+
sOptions.nXSize = static_cast<int>(xSize);
1102+
}
1103+
else
1104+
{
1105+
const double ySize{
1106+
(sEnvelope.MaxY - sEnvelope.MinY) /
1107+
((sEnvelope.MaxX - sEnvelope.MinX) / sOptions.nXSize)};
1108+
if (std::isnan(ySize) || ySize > std::numeric_limits<int>::max() ||
1109+
ySize < std::numeric_limits<int>::min())
1110+
{
1111+
return false;
1112+
}
1113+
sOptions.nYSize = static_cast<int>(ySize);
1114+
}
1115+
return sOptions.nXSize > 0 && sOptions.nYSize > 0;
1116+
};
1117+
1118+
const int nLayerCount =
1119+
(sOptions.osSQL.empty() && sOptions.aosLayers.empty())
1120+
? 1
1121+
: static_cast<int>(sOptions.aosLayers.size());
1122+
1123+
const bool bOneSizeNeedsCalculation{
1124+
static_cast<bool>((sOptions.nXSize == 0) ^ (sOptions.nYSize == 0))};
1125+
1126+
// Calculate the size if either nXSize or nYSize is 0
1127+
if (sOptions.osSQL.empty() && bOneSizeNeedsCalculation)
1128+
{
1129+
CPLErr eErr = CE_None;
1130+
// Get the extent of the source dataset
1131+
OGREnvelope sEnvelope;
1132+
bool bFirstLayer = true;
1133+
for (int i = 0; i < nLayerCount; i++)
1134+
{
1135+
OGRLayerH hLayer;
1136+
if (sOptions.aosLayers.size() > static_cast<size_t>(i))
1137+
hLayer = GDALDatasetGetLayerByName(
1138+
hSrcDataset, sOptions.aosLayers[i].c_str());
1139+
else
1140+
hLayer = GDALDatasetGetLayer(hSrcDataset, 0);
1141+
if (hLayer == nullptr)
1142+
{
1143+
CPLError(CE_Failure, CPLE_AppDefined,
1144+
"Unable to find layer \"%s\".",
1145+
sOptions.aosLayers.size() > static_cast<size_t>(i)
1146+
? sOptions.aosLayers[i].c_str()
1147+
: "0");
1148+
eErr = CE_Failure;
1149+
break;
1150+
}
1151+
OGREnvelope sLayerEnvelop;
1152+
if (OGR_L_GetExtent(hLayer, &sLayerEnvelop, TRUE) != OGRERR_NONE)
1153+
{
1154+
CPLError(CE_Failure, CPLE_AppDefined,
1155+
"Cannot get layer extent");
1156+
eErr = CE_Failure;
1157+
break;
1158+
}
1159+
if (bFirstLayer)
1160+
{
1161+
sEnvelope = sLayerEnvelop;
1162+
bFirstLayer = false;
1163+
}
1164+
else
1165+
{
1166+
sEnvelope.Merge(sLayerEnvelop);
1167+
}
1168+
}
1169+
1170+
if (!calculateSize(sEnvelope))
1171+
{
1172+
CPLError(CE_Failure, CPLE_AppDefined,
1173+
"Cannot calculate size from layer extent");
1174+
eErr = CE_Failure;
1175+
}
1176+
1177+
if (eErr == CE_Failure)
1178+
{
1179+
if (bCloseOutDSOnError && hDstDS)
1180+
{
1181+
GDALClose(hDstDS);
1182+
}
1183+
return nullptr;
1184+
}
1185+
}
1186+
10751187
const auto GetOutputDataType = [&](OGRLayerH hLayer)
10761188
{
10771189
CPLAssert(bCreateOutput);
10781190
CPLAssert(hDriver);
1079-
GDALDataType eOutputType = psOptions->eOutputType;
1080-
if (eOutputType == GDT_Unknown && !psOptions->osBurnAttribute.empty())
1191+
GDALDataType eOutputType = sOptions.eOutputType;
1192+
if (eOutputType == GDT_Unknown && !sOptions.osBurnAttribute.empty())
10811193
{
10821194
OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn(hLayer);
10831195
const int iBurnField = OGR_FD_GetFieldIndex(
1084-
hLayerDefn, psOptions->osBurnAttribute.c_str());
1196+
hLayerDefn, sOptions.osBurnAttribute.c_str());
10851197
if (iBurnField >= 0 && OGR_Fld_GetType(OGR_FD_GetFieldDefn(
10861198
hLayerDefn, iBurnField)) == OFTInteger64)
10871199
{
@@ -1103,36 +1215,56 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
11031215

11041216
// Store SRS handle
11051217
OGRSpatialReferenceH hSRS =
1106-
psOptions->oOutputSRS.IsEmpty()
1218+
sOptions.oOutputSRS.IsEmpty()
11071219
? nullptr
11081220
: OGRSpatialReference::ToHandle(
1109-
const_cast<OGRSpatialReference *>(&psOptions->oOutputSRS));
1221+
const_cast<OGRSpatialReference *>(&sOptions.oOutputSRS));
11101222

11111223
/* -------------------------------------------------------------------- */
11121224
/* Process SQL request. */
11131225
/* -------------------------------------------------------------------- */
11141226
CPLErr eErr = CE_Failure;
11151227

1116-
if (!psOptions->osSQL.empty())
1228+
if (!sOptions.osSQL.empty())
11171229
{
11181230
OGRLayerH hLayer =
1119-
GDALDatasetExecuteSQL(hSrcDataset, psOptions->osSQL.c_str(),
1120-
nullptr, psOptions->osDialect.c_str());
1231+
GDALDatasetExecuteSQL(hSrcDataset, sOptions.osSQL.c_str(), nullptr,
1232+
sOptions.osDialect.c_str());
11211233
if (hLayer != nullptr)
11221234
{
1235+
1236+
if (bOneSizeNeedsCalculation)
1237+
{
1238+
OGREnvelope sEnvelope;
1239+
bool bSizeCalculationError{
1240+
OGR_L_GetExtent(hLayer, &sEnvelope, TRUE) != OGRERR_NONE};
1241+
if (!bSizeCalculationError)
1242+
{
1243+
bSizeCalculationError = !calculateSize(sEnvelope);
1244+
}
1245+
1246+
if (bSizeCalculationError)
1247+
{
1248+
CPLError(CE_Failure, CPLE_AppDefined,
1249+
"Cannot get layer extent");
1250+
GDALDatasetReleaseResultSet(hSrcDataset, hLayer);
1251+
return nullptr;
1252+
}
1253+
}
1254+
11231255
if (bCreateOutput)
11241256
{
11251257
std::vector<OGRLayerH> ahLayers;
11261258
ahLayers.push_back(hLayer);
11271259

11281260
const GDALDataType eOutputType = GetOutputDataType(hLayer);
11291261
hDstDS = CreateOutputDataset(
1130-
ahLayers, hSRS, psOptions->sEnvelop, hDriver, pszDest,
1131-
psOptions->nXSize, psOptions->nYSize, psOptions->dfXRes,
1132-
psOptions->dfYRes, psOptions->bTargetAlignedPixels,
1133-
static_cast<int>(psOptions->anBandList.size()), eOutputType,
1134-
psOptions->aosCreationOptions, psOptions->adfInitVals,
1135-
psOptions->osNoData.c_str());
1262+
ahLayers, hSRS, sOptions.sEnvelop, hDriver, pszDest,
1263+
sOptions.nXSize, sOptions.nYSize, sOptions.dfXRes,
1264+
sOptions.dfYRes, sOptions.bTargetAlignedPixels,
1265+
static_cast<int>(sOptions.anBandList.size()), eOutputType,
1266+
sOptions.aosCreationOptions, sOptions.adfInitVals,
1267+
sOptions.osNoData.c_str());
11361268
if (hDstDS == nullptr)
11371269
{
11381270
GDALDatasetReleaseResultSet(hSrcDataset, hLayer);
@@ -1141,11 +1273,10 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
11411273
}
11421274

11431275
eErr = ProcessLayer(
1144-
hLayer, hSRS != nullptr, hDstDS, psOptions->anBandList,
1145-
psOptions->adfBurnValues, psOptions->b3D, psOptions->bInverse,
1146-
psOptions->osBurnAttribute.c_str(),
1147-
psOptions->aosRasterizeOptions, psOptions->aosTO,
1148-
psOptions->pfnProgress, psOptions->pProgressData);
1276+
hLayer, hSRS != nullptr, hDstDS, sOptions.anBandList,
1277+
sOptions.adfBurnValues, sOptions.b3D, sOptions.bInverse,
1278+
sOptions.osBurnAttribute.c_str(), sOptions.aosRasterizeOptions,
1279+
sOptions.aosTO, sOptions.pfnProgress, sOptions.pProgressData);
11491280

11501281
GDALDatasetReleaseResultSet(hSrcDataset, hLayer);
11511282
}
@@ -1154,31 +1285,27 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
11541285
/* -------------------------------------------------------------------- */
11551286
/* Create output file if necessary. */
11561287
/* -------------------------------------------------------------------- */
1157-
const int nLayerCount =
1158-
(psOptions->osSQL.empty() && psOptions->aosLayers.empty())
1159-
? 1
1160-
: static_cast<int>(psOptions->aosLayers.size());
11611288

11621289
if (bCreateOutput && hDstDS == nullptr)
11631290
{
11641291
std::vector<OGRLayerH> ahLayers;
11651292

1166-
GDALDataType eOutputType = psOptions->eOutputType;
1293+
GDALDataType eOutputType = sOptions.eOutputType;
11671294

11681295
for (int i = 0; i < nLayerCount; i++)
11691296
{
11701297
OGRLayerH hLayer;
1171-
if (psOptions->aosLayers.size() > static_cast<size_t>(i))
1298+
if (sOptions.aosLayers.size() > static_cast<size_t>(i))
11721299
hLayer = GDALDatasetGetLayerByName(
1173-
hSrcDataset, psOptions->aosLayers[i].c_str());
1300+
hSrcDataset, sOptions.aosLayers[i].c_str());
11741301
else
11751302
hLayer = GDALDatasetGetLayer(hSrcDataset, 0);
11761303
if (hLayer == nullptr)
11771304
{
11781305
CPLError(CE_Failure, CPLE_AppDefined,
11791306
"Unable to find layer \"%s\".",
1180-
psOptions->aosLayers.size() > static_cast<size_t>(i)
1181-
? psOptions->aosLayers[i].c_str()
1307+
sOptions.aosLayers.size() > static_cast<size_t>(i)
1308+
? sOptions.aosLayers[i].c_str()
11821309
: "0");
11831310
return nullptr;
11841311
}
@@ -1197,12 +1324,12 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
11971324
}
11981325

11991326
hDstDS = CreateOutputDataset(
1200-
ahLayers, hSRS, psOptions->sEnvelop, hDriver, pszDest,
1201-
psOptions->nXSize, psOptions->nYSize, psOptions->dfXRes,
1202-
psOptions->dfYRes, psOptions->bTargetAlignedPixels,
1203-
static_cast<int>(psOptions->anBandList.size()), eOutputType,
1204-
psOptions->aosCreationOptions, psOptions->adfInitVals,
1205-
psOptions->osNoData.c_str());
1327+
ahLayers, hSRS, sOptions.sEnvelop, hDriver, pszDest,
1328+
sOptions.nXSize, sOptions.nYSize, sOptions.dfXRes, sOptions.dfYRes,
1329+
sOptions.bTargetAlignedPixels,
1330+
static_cast<int>(sOptions.anBandList.size()), eOutputType,
1331+
sOptions.aosCreationOptions, sOptions.adfInitVals,
1332+
sOptions.osNoData.c_str());
12061333
if (hDstDS == nullptr)
12071334
{
12081335
return nullptr;
@@ -1216,25 +1343,25 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
12161343
for (int i = 0; i < nLayerCount; i++)
12171344
{
12181345
OGRLayerH hLayer;
1219-
if (psOptions->aosLayers.size() > static_cast<size_t>(i))
1346+
if (sOptions.aosLayers.size() > static_cast<size_t>(i))
12201347
hLayer = GDALDatasetGetLayerByName(hSrcDataset,
1221-
psOptions->aosLayers[i].c_str());
1348+
sOptions.aosLayers[i].c_str());
12221349
else
12231350
hLayer = GDALDatasetGetLayer(hSrcDataset, 0);
12241351
if (hLayer == nullptr)
12251352
{
12261353
CPLError(CE_Failure, CPLE_AppDefined,
12271354
"Unable to find layer \"%s\".",
1228-
psOptions->aosLayers.size() > static_cast<size_t>(i)
1229-
? psOptions->aosLayers[i].c_str()
1355+
sOptions.aosLayers.size() > static_cast<size_t>(i)
1356+
? sOptions.aosLayers[i].c_str()
12301357
: "0");
12311358
eErr = CE_Failure;
12321359
break;
12331360
}
12341361

1235-
if (!psOptions->osWHERE.empty())
1362+
if (!sOptions.osWHERE.empty())
12361363
{
1237-
if (OGR_L_SetAttributeFilter(hLayer, psOptions->osWHERE.c_str()) !=
1364+
if (OGR_L_SetAttributeFilter(hLayer, sOptions.osWHERE.c_str()) !=
12381365
OGRERR_NONE)
12391366
{
12401367
eErr = CE_Failure;
@@ -1243,15 +1370,14 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
12431370
}
12441371

12451372
void *pScaledProgress = GDALCreateScaledProgress(
1246-
0.0, 1.0 * (i + 1) / nLayerCount, psOptions->pfnProgress,
1247-
psOptions->pProgressData);
1373+
0.0, 1.0 * (i + 1) / nLayerCount, sOptions.pfnProgress,
1374+
sOptions.pProgressData);
12481375

1249-
eErr = ProcessLayer(hLayer, !psOptions->oOutputSRS.IsEmpty(), hDstDS,
1250-
psOptions->anBandList, psOptions->adfBurnValues,
1251-
psOptions->b3D, psOptions->bInverse,
1252-
psOptions->osBurnAttribute.c_str(),
1253-
psOptions->aosRasterizeOptions, psOptions->aosTO,
1254-
GDALScaledProgress, pScaledProgress);
1376+
eErr = ProcessLayer(
1377+
hLayer, !sOptions.oOutputSRS.IsEmpty(), hDstDS, sOptions.anBandList,
1378+
sOptions.adfBurnValues, sOptions.b3D, sOptions.bInverse,
1379+
sOptions.osBurnAttribute.c_str(), sOptions.aosRasterizeOptions,
1380+
sOptions.aosTO, GDALScaledProgress, pScaledProgress);
12551381

12561382
GDALDestroyScaledProgress(pScaledProgress);
12571383
if (eErr != CE_None)
@@ -1454,10 +1580,11 @@ GDALRasterizeOptionsNew(char **papszArgv,
14541580
psOptions->nXSize = nXSize;
14551581
psOptions->nYSize = nYSize;
14561582

1457-
if (psOptions->nXSize <= 0 || psOptions->nYSize <= 0)
1583+
if (!(psOptions->nXSize > 0 || psOptions->nYSize > 0))
14581584
{
14591585
CPLError(CE_Failure, CPLE_AppDefined,
1460-
"Wrong value for -ts parameter.");
1586+
"Wrong value for -ts parameter: at least one of the "
1587+
"arguments must be greater than zero.");
14611588
return nullptr;
14621589
}
14631590

0 commit comments

Comments
 (0)