LCOV - code coverage report
Current view: top level - apps - gdal_grid_lib.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 485 644 75.3 %
Date: 2024-11-21 22:18:42 Functions: 14 16 87.5 %

          Line data    Source code
       1             : /* ****************************************************************************
       2             :  *
       3             :  * Project:  GDAL Utilities
       4             :  * Purpose:  GDAL scattered data gridding (interpolation) tool
       5             :  * Author:   Andrey Kiselev, dron@ak4719.spb.edu
       6             :  *
       7             :  * ****************************************************************************
       8             :  * Copyright (c) 2007, Andrey Kiselev <dron@ak4719.spb.edu>
       9             :  * Copyright (c) 2015, Even Rouault <even dot rouault at spatialys dot com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "gdal_utils.h"
      16             : #include "gdal_utils_priv.h"
      17             : #include "commonutils.h"
      18             : #include "gdalargumentparser.h"
      19             : 
      20             : #include <cmath>
      21             : #include <cstdint>
      22             : #include <cstdio>
      23             : #include <cstdlib>
      24             : #include <algorithm>
      25             : #include <vector>
      26             : 
      27             : #include "cpl_conv.h"
      28             : #include "cpl_error.h"
      29             : #include "cpl_progress.h"
      30             : #include "cpl_string.h"
      31             : #include "cpl_vsi.h"
      32             : #include "gdal.h"
      33             : #include "gdal_alg.h"
      34             : #include "gdal_priv.h"
      35             : #include "gdalgrid.h"
      36             : #include "ogr_api.h"
      37             : #include "ogr_core.h"
      38             : #include "ogr_feature.h"
      39             : #include "ogr_geometry.h"
      40             : #include "ogr_spatialref.h"
      41             : #include "ogr_srs_api.h"
      42             : #include "ogrsf_frmts.h"
      43             : 
      44             : /************************************************************************/
      45             : /*                          GDALGridOptions                             */
      46             : /************************************************************************/
      47             : 
      48             : /** Options for use with GDALGrid(). GDALGridOptions* must be allocated
      49             :  * and freed with GDALGridOptionsNew() and GDALGridOptionsFree() respectively.
      50             :  */
      51             : struct GDALGridOptions
      52             : {
      53             :     /*! output format. Use the short format name. */
      54             :     std::string osFormat{};
      55             : 
      56             :     /*! allow or suppress progress monitor and other non-error output */
      57             :     bool bQuiet = true;
      58             : 
      59             :     /*! the progress function to use */
      60             :     GDALProgressFunc pfnProgress = GDALDummyProgress;
      61             : 
      62             :     /*! pointer to the progress data variable */
      63             :     void *pProgressData = nullptr;
      64             : 
      65             :     CPLStringList aosLayers{};
      66             :     std::string osBurnAttribute{};
      67             :     double dfIncreaseBurnValue = 0.0;
      68             :     double dfMultiplyBurnValue = 1.0;
      69             :     std::string osWHERE{};
      70             :     std::string osSQL{};
      71             :     GDALDataType eOutputType = GDT_Float64;
      72             :     CPLStringList aosCreateOptions{};
      73             :     int nXSize = 0;
      74             :     int nYSize = 0;
      75             :     double dfXRes = 0;
      76             :     double dfYRes = 0;
      77             :     double dfXMin = 0;
      78             :     double dfXMax = 0;
      79             :     double dfYMin = 0;
      80             :     double dfYMax = 0;
      81             :     bool bIsXExtentSet = false;
      82             :     bool bIsYExtentSet = false;
      83             :     GDALGridAlgorithm eAlgorithm = GGA_InverseDistanceToAPower;
      84             :     std::unique_ptr<void, VSIFreeReleaser> pOptions{};
      85             :     std::string osOutputSRS{};
      86             :     std::unique_ptr<OGRGeometry> poSpatialFilter{};
      87             :     bool bClipSrc = false;
      88             :     std::unique_ptr<OGRGeometry> poClipSrc{};
      89             :     std::string osClipSrcDS{};
      90             :     std::string osClipSrcSQL{};
      91             :     std::string osClipSrcLayer{};
      92             :     std::string osClipSrcWhere{};
      93             :     bool bNoDataSet = false;
      94             :     double dfNoDataValue = 0;
      95             : 
      96         107 :     GDALGridOptions()
      97         107 :     {
      98         107 :         void *l_pOptions = nullptr;
      99         107 :         GDALGridParseAlgorithmAndOptions(szAlgNameInvDist, &eAlgorithm,
     100             :                                          &l_pOptions);
     101         107 :         pOptions.reset(l_pOptions);
     102         107 :     }
     103             : 
     104             :     CPL_DISALLOW_COPY_ASSIGN(GDALGridOptions)
     105             : };
     106             : 
     107             : /************************************************************************/
     108             : /*                          GetAlgorithmName()                          */
     109             : /*                                                                      */
     110             : /*      Grids algorithm code into mnemonic name.                        */
     111             : /************************************************************************/
     112             : 
     113          54 : static void PrintAlgorithmAndOptions(GDALGridAlgorithm eAlgorithm,
     114             :                                      void *pOptions)
     115             : {
     116          54 :     switch (eAlgorithm)
     117             :     {
     118           6 :         case GGA_InverseDistanceToAPower:
     119             :         {
     120           6 :             printf("Algorithm name: \"%s\".\n", szAlgNameInvDist);
     121           6 :             GDALGridInverseDistanceToAPowerOptions *pOptions2 =
     122             :                 static_cast<GDALGridInverseDistanceToAPowerOptions *>(pOptions);
     123           6 :             CPLprintf("Options are "
     124             :                       "\"power=%f:smoothing=%f:radius1=%f:radius2=%f:angle=%f"
     125             :                       ":max_points=%u:min_points=%u:nodata=%f\"\n",
     126             :                       pOptions2->dfPower, pOptions2->dfSmoothing,
     127             :                       pOptions2->dfRadius1, pOptions2->dfRadius2,
     128             :                       pOptions2->dfAngle, pOptions2->nMaxPoints,
     129             :                       pOptions2->nMinPoints, pOptions2->dfNoDataValue);
     130           6 :             break;
     131             :         }
     132           3 :         case GGA_InverseDistanceToAPowerNearestNeighbor:
     133             :         {
     134           3 :             printf("Algorithm name: \"%s\".\n",
     135             :                    szAlgNameInvDistNearestNeighbor);
     136           3 :             GDALGridInverseDistanceToAPowerNearestNeighborOptions *pOptions2 =
     137             :                 static_cast<
     138             :                     GDALGridInverseDistanceToAPowerNearestNeighborOptions *>(
     139             :                     pOptions);
     140           6 :             CPLString osStr;
     141             :             osStr.Printf("power=%f:smoothing=%f:radius=%f"
     142             :                          ":max_points=%u:min_points=%u:nodata=%f",
     143             :                          pOptions2->dfPower, pOptions2->dfSmoothing,
     144             :                          pOptions2->dfRadius, pOptions2->nMaxPoints,
     145           3 :                          pOptions2->nMinPoints, pOptions2->dfNoDataValue);
     146           3 :             if (pOptions2->nMinPointsPerQuadrant > 0)
     147             :                 osStr += CPLSPrintf(":min_points_per_quadrant=%u",
     148           0 :                                     pOptions2->nMinPointsPerQuadrant);
     149           3 :             if (pOptions2->nMaxPointsPerQuadrant > 0)
     150             :                 osStr += CPLSPrintf(":max_points_per_quadrant=%u",
     151           0 :                                     pOptions2->nMaxPointsPerQuadrant);
     152           3 :             printf("Options are: \"%s\n", osStr.c_str()); /* ok */
     153           3 :             break;
     154             :         }
     155           6 :         case GGA_MovingAverage:
     156             :         {
     157           6 :             printf("Algorithm name: \"%s\".\n", szAlgNameAverage);
     158           6 :             GDALGridMovingAverageOptions *pOptions2 =
     159             :                 static_cast<GDALGridMovingAverageOptions *>(pOptions);
     160          12 :             CPLString osStr;
     161             :             osStr.Printf("radius1=%f:radius2=%f:angle=%f:min_points=%u"
     162             :                          ":nodata=%f",
     163             :                          pOptions2->dfRadius1, pOptions2->dfRadius2,
     164             :                          pOptions2->dfAngle, pOptions2->nMinPoints,
     165           6 :                          pOptions2->dfNoDataValue);
     166           6 :             if (pOptions2->nMinPointsPerQuadrant > 0)
     167             :                 osStr += CPLSPrintf(":min_points_per_quadrant=%u",
     168           0 :                                     pOptions2->nMinPointsPerQuadrant);
     169           6 :             if (pOptions2->nMaxPointsPerQuadrant > 0)
     170             :                 osStr += CPLSPrintf(":max_points_per_quadrant=%u",
     171           0 :                                     pOptions2->nMaxPointsPerQuadrant);
     172           6 :             if (pOptions2->nMaxPoints > 0)
     173           0 :                 osStr += CPLSPrintf(":max_points=%u", pOptions2->nMaxPoints);
     174           6 :             printf("Options are: \"%s\n", osStr.c_str()); /* ok */
     175           6 :             break;
     176             :         }
     177          12 :         case GGA_NearestNeighbor:
     178             :         {
     179          12 :             printf("Algorithm name: \"%s\".\n", szAlgNameNearest);
     180          12 :             GDALGridNearestNeighborOptions *pOptions2 =
     181             :                 static_cast<GDALGridNearestNeighborOptions *>(pOptions);
     182          12 :             CPLprintf("Options are "
     183             :                       "\"radius1=%f:radius2=%f:angle=%f:nodata=%f\"\n",
     184             :                       pOptions2->dfRadius1, pOptions2->dfRadius2,
     185             :                       pOptions2->dfAngle, pOptions2->dfNoDataValue);
     186          12 :             break;
     187             :         }
     188          26 :         case GGA_MetricMinimum:
     189             :         case GGA_MetricMaximum:
     190             :         case GGA_MetricRange:
     191             :         case GGA_MetricCount:
     192             :         case GGA_MetricAverageDistance:
     193             :         case GGA_MetricAverageDistancePts:
     194             :         {
     195          26 :             const char *pszAlgName = "";
     196          26 :             switch (eAlgorithm)
     197             :             {
     198           6 :                 case GGA_MetricMinimum:
     199           6 :                     pszAlgName = szAlgNameMinimum;
     200           6 :                     break;
     201           6 :                 case GGA_MetricMaximum:
     202           6 :                     pszAlgName = szAlgNameMaximum;
     203           6 :                     break;
     204           3 :                 case GGA_MetricRange:
     205           3 :                     pszAlgName = szAlgNameRange;
     206           3 :                     break;
     207           5 :                 case GGA_MetricCount:
     208           5 :                     pszAlgName = szAlgNameCount;
     209           5 :                     break;
     210           3 :                 case GGA_MetricAverageDistance:
     211           3 :                     pszAlgName = szAlgNameAverageDistance;
     212           3 :                     break;
     213           3 :                 case GGA_MetricAverageDistancePts:
     214           3 :                     pszAlgName = szAlgNameAverageDistancePts;
     215           3 :                     break;
     216           0 :                 default:
     217           0 :                     CPLAssert(false);
     218             :                     break;
     219             :             }
     220          26 :             printf("Algorithm name: \"%s\".\n", pszAlgName);
     221          26 :             GDALGridDataMetricsOptions *pOptions2 =
     222             :                 static_cast<GDALGridDataMetricsOptions *>(pOptions);
     223          52 :             CPLString osStr;
     224             :             osStr.Printf("radius1=%f:radius2=%f:angle=%f:min_points=%u"
     225             :                          ":nodata=%f",
     226             :                          pOptions2->dfRadius1, pOptions2->dfRadius2,
     227             :                          pOptions2->dfAngle, pOptions2->nMinPoints,
     228          26 :                          pOptions2->dfNoDataValue);
     229          26 :             if (pOptions2->nMinPointsPerQuadrant > 0)
     230             :                 osStr += CPLSPrintf(":min_points_per_quadrant=%u",
     231           0 :                                     pOptions2->nMinPointsPerQuadrant);
     232          26 :             if (pOptions2->nMaxPointsPerQuadrant > 0)
     233             :                 osStr += CPLSPrintf(":max_points_per_quadrant=%u",
     234           0 :                                     pOptions2->nMaxPointsPerQuadrant);
     235          26 :             printf("Options are: \"%s\n", osStr.c_str()); /* ok */
     236          26 :             break;
     237             :         }
     238           1 :         case GGA_Linear:
     239             :         {
     240           1 :             printf("Algorithm name: \"%s\".\n", szAlgNameLinear);
     241           1 :             GDALGridLinearOptions *pOptions2 =
     242             :                 static_cast<GDALGridLinearOptions *>(pOptions);
     243           1 :             CPLprintf("Options are "
     244             :                       "\"radius=%f:nodata=%f\"\n",
     245             :                       pOptions2->dfRadius, pOptions2->dfNoDataValue);
     246           1 :             break;
     247             :         }
     248           0 :         default:
     249             :         {
     250           0 :             printf("Algorithm is unknown.\n");
     251           0 :             break;
     252             :         }
     253             :     }
     254          54 : }
     255             : 
     256             : /************************************************************************/
     257             : /*  Extract point coordinates from the geometry reference and set the   */
     258             : /*  Z value as requested. Test whether we are in the clipped region     */
     259             : /*  before processing.                                                  */
     260             : /************************************************************************/
     261             : 
     262             : class GDALGridGeometryVisitor final : public OGRDefaultConstGeometryVisitor
     263             : {
     264             :   public:
     265             :     const OGRGeometry *poClipSrc = nullptr;
     266             :     int iBurnField = 0;
     267             :     double dfBurnValue = 0;
     268             :     double dfIncreaseBurnValue = 0;
     269             :     double dfMultiplyBurnValue = 1;
     270             :     std::vector<double> adfX{};
     271             :     std::vector<double> adfY{};
     272             :     std::vector<double> adfZ{};
     273             : 
     274             :     using OGRDefaultConstGeometryVisitor::visit;
     275             : 
     276       64928 :     void visit(const OGRPoint *p) override
     277             :     {
     278       64928 :         if (poClipSrc && !p->Within(poClipSrc))
     279          20 :             return;
     280             : 
     281       64908 :         if (iBurnField < 0 && std::isnan(p->getZ()))
     282           1 :             return;
     283             : 
     284       64907 :         adfX.push_back(p->getX());
     285       64907 :         adfY.push_back(p->getY());
     286       64907 :         if (iBurnField < 0)
     287      129806 :             adfZ.push_back((p->getZ() + dfIncreaseBurnValue) *
     288       64903 :                            dfMultiplyBurnValue);
     289             :         else
     290           4 :             adfZ.push_back((dfBurnValue + dfIncreaseBurnValue) *
     291           4 :                            dfMultiplyBurnValue);
     292             :     }
     293             : };
     294             : 
     295             : /************************************************************************/
     296             : /*                            ProcessLayer()                            */
     297             : /*                                                                      */
     298             : /*      Process all the features in a layer selection, collecting       */
     299             : /*      geometries and burn values.                                     */
     300             : /************************************************************************/
     301             : 
     302         103 : static CPLErr ProcessLayer(OGRLayer *poSrcLayer, GDALDataset *poDstDS,
     303             :                            const OGRGeometry *poClipSrc, int nXSize, int nYSize,
     304             :                            int nBand, bool &bIsXExtentSet, bool &bIsYExtentSet,
     305             :                            double &dfXMin, double &dfXMax, double &dfYMin,
     306             :                            double &dfYMax, const std::string &osBurnAttribute,
     307             :                            const double dfIncreaseBurnValue,
     308             :                            const double dfMultiplyBurnValue, GDALDataType eType,
     309             :                            GDALGridAlgorithm eAlgorithm, void *pOptions,
     310             :                            bool bQuiet, GDALProgressFunc pfnProgress,
     311             :                            void *pProgressData)
     312             : 
     313             : {
     314             :     /* -------------------------------------------------------------------- */
     315             :     /*      Get field index, and check.                                     */
     316             :     /* -------------------------------------------------------------------- */
     317         103 :     int iBurnField = -1;
     318             : 
     319         103 :     if (!osBurnAttribute.empty())
     320             :     {
     321             :         iBurnField =
     322           1 :             poSrcLayer->GetLayerDefn()->GetFieldIndex(osBurnAttribute.c_str());
     323           1 :         if (iBurnField == -1)
     324             :         {
     325           0 :             printf("Failed to find field %s on layer %s, skipping.\n",
     326           0 :                    osBurnAttribute.c_str(), poSrcLayer->GetName());
     327           0 :             return CE_Failure;
     328             :         }
     329             :     }
     330             : 
     331             :     /* -------------------------------------------------------------------- */
     332             :     /*      Collect the geometries from this layer, and build list of       */
     333             :     /*      values to be interpolated.                                      */
     334             :     /* -------------------------------------------------------------------- */
     335         206 :     GDALGridGeometryVisitor oVisitor;
     336         103 :     oVisitor.poClipSrc = poClipSrc;
     337         103 :     oVisitor.iBurnField = iBurnField;
     338         103 :     oVisitor.dfIncreaseBurnValue = dfIncreaseBurnValue;
     339         103 :     oVisitor.dfMultiplyBurnValue = dfMultiplyBurnValue;
     340             : 
     341       64882 :     for (auto &&poFeat : poSrcLayer)
     342             :     {
     343       64779 :         const OGRGeometry *poGeom = poFeat->GetGeometryRef();
     344       64779 :         if (poGeom)
     345             :         {
     346       64779 :             if (iBurnField >= 0)
     347             :             {
     348           5 :                 if (!poFeat->IsFieldSetAndNotNull(iBurnField))
     349             :                 {
     350           1 :                     continue;
     351             :                 }
     352           4 :                 oVisitor.dfBurnValue = poFeat->GetFieldAsDouble(iBurnField);
     353             :             }
     354             : 
     355       64778 :             poGeom->accept(&oVisitor);
     356             :         }
     357             :     }
     358             : 
     359         103 :     if (oVisitor.adfX.empty())
     360             :     {
     361           0 :         printf("No point geometry found on layer %s, skipping.\n",
     362           0 :                poSrcLayer->GetName());
     363           0 :         return CE_None;
     364             :     }
     365             : 
     366             :     /* -------------------------------------------------------------------- */
     367             :     /*      Compute grid geometry.                                          */
     368             :     /* -------------------------------------------------------------------- */
     369         103 :     if (!bIsXExtentSet || !bIsYExtentSet)
     370             :     {
     371           0 :         OGREnvelope sEnvelope;
     372           0 :         if (poSrcLayer->GetExtent(&sEnvelope, TRUE) == OGRERR_FAILURE)
     373             :         {
     374           0 :             return CE_Failure;
     375             :         }
     376             : 
     377           0 :         if (!bIsXExtentSet)
     378             :         {
     379           0 :             dfXMin = sEnvelope.MinX;
     380           0 :             dfXMax = sEnvelope.MaxX;
     381           0 :             bIsXExtentSet = true;
     382             :         }
     383             : 
     384           0 :         if (!bIsYExtentSet)
     385             :         {
     386           0 :             dfYMin = sEnvelope.MinY;
     387           0 :             dfYMax = sEnvelope.MaxY;
     388           0 :             bIsYExtentSet = true;
     389             :         }
     390             :     }
     391             : 
     392             :     // Produce north-up images
     393         103 :     if (dfYMin < dfYMax)
     394          51 :         std::swap(dfYMin, dfYMax);
     395             : 
     396             :     /* -------------------------------------------------------------------- */
     397             :     /*      Perform gridding.                                               */
     398             :     /* -------------------------------------------------------------------- */
     399             : 
     400         103 :     const double dfDeltaX = (dfXMax - dfXMin) / nXSize;
     401         103 :     const double dfDeltaY = (dfYMax - dfYMin) / nYSize;
     402             : 
     403         103 :     if (!bQuiet)
     404             :     {
     405          54 :         printf("Grid data type is \"%s\"\n", GDALGetDataTypeName(eType));
     406          54 :         printf("Grid size = (%d %d).\n", nXSize, nYSize);
     407          54 :         CPLprintf("Corner coordinates = (%f %f)-(%f %f).\n", dfXMin, dfYMin,
     408             :                   dfXMax, dfYMax);
     409          54 :         CPLprintf("Grid cell size = (%f %f).\n", dfDeltaX, dfDeltaY);
     410          54 :         printf("Source point count = %lu.\n",
     411          54 :                static_cast<unsigned long>(oVisitor.adfX.size()));
     412          54 :         PrintAlgorithmAndOptions(eAlgorithm, pOptions);
     413          54 :         printf("\n");
     414             :     }
     415             : 
     416         103 :     GDALRasterBand *poBand = poDstDS->GetRasterBand(nBand);
     417             : 
     418         103 :     int nBlockXSize = 0;
     419         103 :     int nBlockYSize = 0;
     420         103 :     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eType);
     421             : 
     422             :     // Try to grow the work buffer up to 16 MB if it is smaller
     423         103 :     poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     424         103 :     if (nXSize == 0 || nYSize == 0 || nBlockXSize == 0 || nBlockYSize == 0)
     425           0 :         return CE_Failure;
     426             : 
     427         103 :     const int nDesiredBufferSize = 16 * 1024 * 1024;
     428         103 :     if (nBlockXSize < nXSize && nBlockYSize < nYSize &&
     429           0 :         nBlockXSize < nDesiredBufferSize / (nBlockYSize * nDataTypeSize))
     430             :     {
     431           0 :         const int nNewBlockXSize =
     432           0 :             nDesiredBufferSize / (nBlockYSize * nDataTypeSize);
     433           0 :         nBlockXSize = (nNewBlockXSize / nBlockXSize) * nBlockXSize;
     434           0 :         if (nBlockXSize > nXSize)
     435           0 :             nBlockXSize = nXSize;
     436             :     }
     437         103 :     else if (nBlockXSize == nXSize && nBlockYSize < nYSize &&
     438           7 :              nBlockYSize < nDesiredBufferSize / (nXSize * nDataTypeSize))
     439             :     {
     440           7 :         const int nNewBlockYSize =
     441           7 :             nDesiredBufferSize / (nXSize * nDataTypeSize);
     442           7 :         nBlockYSize = (nNewBlockYSize / nBlockYSize) * nBlockYSize;
     443           7 :         if (nBlockYSize > nYSize)
     444           7 :             nBlockYSize = nYSize;
     445             :     }
     446         103 :     CPLDebug("GDAL_GRID", "Work buffer: %d * %d", nBlockXSize, nBlockYSize);
     447             : 
     448             :     std::unique_ptr<void, VSIFreeReleaser> pData(
     449         206 :         VSIMalloc3(nBlockXSize, nBlockYSize, nDataTypeSize));
     450         103 :     if (!pData)
     451             :     {
     452           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate work buffer");
     453           0 :         return CE_Failure;
     454             :     }
     455             : 
     456         103 :     GIntBig nBlock = 0;
     457         103 :     const double dfBlockCount =
     458         103 :         static_cast<double>(DIV_ROUND_UP(nXSize, nBlockXSize)) *
     459         103 :         DIV_ROUND_UP(nYSize, nBlockYSize);
     460             : 
     461             :     struct GDALGridContextReleaser
     462             :     {
     463         103 :         void operator()(GDALGridContext *psContext)
     464             :         {
     465         103 :             GDALGridContextFree(psContext);
     466         103 :         }
     467             :     };
     468             : 
     469             :     std::unique_ptr<GDALGridContext, GDALGridContextReleaser> psContext(
     470             :         GDALGridContextCreate(eAlgorithm, pOptions,
     471         103 :                               static_cast<int>(oVisitor.adfX.size()),
     472         103 :                               &(oVisitor.adfX[0]), &(oVisitor.adfY[0]),
     473         309 :                               &(oVisitor.adfZ[0]), TRUE));
     474         103 :     if (!psContext)
     475             :     {
     476           0 :         return CE_Failure;
     477             :     }
     478             : 
     479         103 :     CPLErr eErr = CE_None;
     480         206 :     for (int nYOffset = 0; nYOffset < nYSize && eErr == CE_None;
     481         103 :          nYOffset += nBlockYSize)
     482             :     {
     483         206 :         for (int nXOffset = 0; nXOffset < nXSize && eErr == CE_None;
     484         103 :              nXOffset += nBlockXSize)
     485             :         {
     486             :             std::unique_ptr<void, GDALScaledProgressReleaser> pScaledProgress(
     487             :                 GDALCreateScaledProgress(
     488         103 :                     static_cast<double>(nBlock) / dfBlockCount,
     489         103 :                     static_cast<double>(nBlock + 1) / dfBlockCount, pfnProgress,
     490         206 :                     pProgressData));
     491         103 :             nBlock++;
     492             : 
     493         103 :             int nXRequest = nBlockXSize;
     494         103 :             if (nXOffset > nXSize - nXRequest)
     495           2 :                 nXRequest = nXSize - nXOffset;
     496             : 
     497         103 :             int nYRequest = nBlockYSize;
     498         103 :             if (nYOffset > nYSize - nYRequest)
     499           2 :                 nYRequest = nYSize - nYOffset;
     500             : 
     501         206 :             eErr = GDALGridContextProcess(
     502         103 :                 psContext.get(), dfXMin + dfDeltaX * nXOffset,
     503         103 :                 dfXMin + dfDeltaX * (nXOffset + nXRequest),
     504         103 :                 dfYMin + dfDeltaY * nYOffset,
     505         103 :                 dfYMin + dfDeltaY * (nYOffset + nYRequest), nXRequest,
     506             :                 nYRequest, eType, pData.get(), GDALScaledProgress,
     507             :                 pScaledProgress.get());
     508             : 
     509         103 :             if (eErr == CE_None)
     510         103 :                 eErr = poBand->RasterIO(GF_Write, nXOffset, nYOffset, nXRequest,
     511             :                                         nYRequest, pData.get(), nXRequest,
     512             :                                         nYRequest, eType, 0, 0, nullptr);
     513             :         }
     514             :     }
     515         103 :     if (eErr == CE_None && pfnProgress)
     516         103 :         pfnProgress(1.0, "", pProgressData);
     517             : 
     518         103 :     return eErr;
     519             : }
     520             : 
     521             : /************************************************************************/
     522             : /*                            LoadGeometry()                            */
     523             : /*                                                                      */
     524             : /*  Read geometries from the given dataset using specified filters and  */
     525             : /*  returns a collection of read geometries.                            */
     526             : /************************************************************************/
     527             : 
     528           1 : static std::unique_ptr<OGRGeometry> LoadGeometry(const std::string &osDS,
     529             :                                                  const std::string &osSQL,
     530             :                                                  const std::string &osLyr,
     531             :                                                  const std::string &osWhere)
     532             : {
     533             :     auto poDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
     534           2 :         osDS.c_str(), GDAL_OF_VECTOR, nullptr, nullptr, nullptr));
     535           1 :     if (!poDS)
     536           0 :         return nullptr;
     537             : 
     538           1 :     OGRLayer *poLyr = nullptr;
     539           1 :     if (!osSQL.empty())
     540           0 :         poLyr = poDS->ExecuteSQL(osSQL.c_str(), nullptr, nullptr);
     541           1 :     else if (!osLyr.empty())
     542           0 :         poLyr = poDS->GetLayerByName(osLyr.c_str());
     543             :     else
     544           1 :         poLyr = poDS->GetLayer(0);
     545             : 
     546           1 :     if (poLyr == nullptr)
     547             :     {
     548           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     549             :                  "Failed to identify source layer from datasource.");
     550           0 :         return nullptr;
     551             :     }
     552             : 
     553           1 :     if (!osWhere.empty())
     554           0 :         poLyr->SetAttributeFilter(osWhere.c_str());
     555             : 
     556           1 :     std::unique_ptr<OGRGeometryCollection> poGeom;
     557           2 :     for (auto &poFeat : poLyr)
     558             :     {
     559           1 :         const OGRGeometry *poSrcGeom = poFeat->GetGeometryRef();
     560           1 :         if (poSrcGeom)
     561             :         {
     562             :             const OGRwkbGeometryType eType =
     563           1 :                 wkbFlatten(poSrcGeom->getGeometryType());
     564             : 
     565           1 :             if (!poGeom)
     566           1 :                 poGeom = std::make_unique<OGRMultiPolygon>();
     567             : 
     568           1 :             if (eType == wkbPolygon)
     569             :             {
     570           1 :                 poGeom->addGeometry(poSrcGeom);
     571             :             }
     572           0 :             else if (eType == wkbMultiPolygon)
     573             :             {
     574             :                 const int nGeomCount =
     575           0 :                     poSrcGeom->toMultiPolygon()->getNumGeometries();
     576             : 
     577           0 :                 for (int iGeom = 0; iGeom < nGeomCount; iGeom++)
     578             :                 {
     579           0 :                     poGeom->addGeometry(
     580           0 :                         poSrcGeom->toMultiPolygon()->getGeometryRef(iGeom));
     581             :                 }
     582             :             }
     583             :             else
     584             :             {
     585           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     586             :                          "Geometry not of polygon type.");
     587           0 :                 if (!osSQL.empty())
     588           0 :                     poDS->ReleaseResultSet(poLyr);
     589           0 :                 return nullptr;
     590             :             }
     591             :         }
     592             :     }
     593             : 
     594           1 :     if (!osSQL.empty())
     595           0 :         poDS->ReleaseResultSet(poLyr);
     596             : 
     597           1 :     return poGeom;
     598             : }
     599             : 
     600             : /************************************************************************/
     601             : /*                               GDALGrid()                             */
     602             : /************************************************************************/
     603             : 
     604             : /* clang-format off */
     605             : /**
     606             :  * Create raster from the scattered data.
     607             :  *
     608             :  * This is the equivalent of the
     609             :  * <a href="/programs/gdal_grid.html">gdal_grid</a> utility.
     610             :  *
     611             :  * GDALGridOptions* must be allocated and freed with GDALGridOptionsNew()
     612             :  * and GDALGridOptionsFree() respectively.
     613             :  *
     614             :  * @param pszDest the destination dataset path.
     615             :  * @param hSrcDataset the source dataset handle.
     616             :  * @param psOptionsIn the options struct returned by GDALGridOptionsNew() or
     617             :  * NULL.
     618             :  * @param pbUsageError pointer to a integer output variable to store if any
     619             :  * usage error has occurred or NULL.
     620             :  * @return the output dataset (new dataset that must be closed using
     621             :  * GDALClose()) or NULL in case of error.
     622             :  *
     623             :  * @since GDAL 2.1
     624             :  */
     625             : /* clang-format on */
     626             : 
     627         106 : GDALDatasetH GDALGrid(const char *pszDest, GDALDatasetH hSrcDataset,
     628             :                       const GDALGridOptions *psOptionsIn, int *pbUsageError)
     629             : 
     630             : {
     631         106 :     if (hSrcDataset == nullptr)
     632             :     {
     633           0 :         CPLError(CE_Failure, CPLE_AppDefined, "No source dataset specified.");
     634             : 
     635           0 :         if (pbUsageError)
     636           0 :             *pbUsageError = TRUE;
     637           0 :         return nullptr;
     638             :     }
     639         106 :     if (pszDest == nullptr)
     640             :     {
     641           0 :         CPLError(CE_Failure, CPLE_AppDefined, "No target dataset specified.");
     642             : 
     643           0 :         if (pbUsageError)
     644           0 :             *pbUsageError = TRUE;
     645           0 :         return nullptr;
     646             :     }
     647             : 
     648         106 :     std::unique_ptr<GDALGridOptions> psOptionsToFree;
     649         106 :     const GDALGridOptions *psOptions = psOptionsIn;
     650         106 :     if (psOptions == nullptr)
     651             :     {
     652           0 :         psOptionsToFree = std::make_unique<GDALGridOptions>();
     653           0 :         psOptions = psOptionsToFree.get();
     654             :     }
     655             : 
     656         106 :     GDALDataset *poSrcDS = GDALDataset::FromHandle(hSrcDataset);
     657             : 
     658         153 :     if (psOptions->osSQL.empty() && psOptions->aosLayers.empty() &&
     659          47 :         poSrcDS->GetLayerCount() != 1)
     660             :     {
     661           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     662             :                  "Neither -sql nor -l are specified, but the source dataset "
     663             :                  "has not one single layer.");
     664           0 :         if (pbUsageError)
     665           0 :             *pbUsageError = TRUE;
     666           0 :         return nullptr;
     667             :     }
     668             : 
     669         106 :     if ((psOptions->nXSize != 0 || psOptions->nYSize != 0) &&
     670         105 :         (psOptions->dfXRes != 0 || psOptions->dfYRes != 0))
     671             :     {
     672           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     673             :                  "-outsize and -tr options cannot be used at the same time.");
     674           0 :         return nullptr;
     675             :     }
     676             : 
     677             :     /* -------------------------------------------------------------------- */
     678             :     /*      Find the output driver.                                         */
     679             :     /* -------------------------------------------------------------------- */
     680         212 :     std::string osFormat;
     681         106 :     if (psOptions->osFormat.empty())
     682             :     {
     683          54 :         osFormat = GetOutputDriverForRaster(pszDest);
     684          54 :         if (osFormat.empty())
     685             :         {
     686           0 :             return nullptr;
     687             :         }
     688             :     }
     689             :     else
     690             :     {
     691          52 :         osFormat = psOptions->osFormat;
     692             :     }
     693             : 
     694         106 :     GDALDriverH hDriver = GDALGetDriverByName(osFormat.c_str());
     695         106 :     if (hDriver == nullptr)
     696             :     {
     697           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     698             :                  "Output driver `%s' not recognised.", osFormat.c_str());
     699           0 :         fprintf(stderr, "The following format drivers are configured and "
     700             :                         "support output:\n");
     701           0 :         for (int iDr = 0; iDr < GDALGetDriverCount(); iDr++)
     702             :         {
     703           0 :             hDriver = GDALGetDriver(iDr);
     704             : 
     705           0 :             if (GDALGetMetadataItem(hDriver, GDAL_DCAP_RASTER, nullptr) !=
     706           0 :                     nullptr &&
     707           0 :                 (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) !=
     708           0 :                      nullptr ||
     709           0 :                  GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY, nullptr) !=
     710             :                      nullptr))
     711             :             {
     712           0 :                 fprintf(stderr, "  %s: %s\n", GDALGetDriverShortName(hDriver),
     713             :                         GDALGetDriverLongName(hDriver));
     714             :             }
     715             :         }
     716           0 :         printf("\n");
     717           0 :         return nullptr;
     718             :     }
     719             : 
     720             :     /* -------------------------------------------------------------------- */
     721             :     /*      Create target raster file.                                      */
     722             :     /* -------------------------------------------------------------------- */
     723         106 :     int nLayerCount = psOptions->aosLayers.size();
     724         106 :     if (nLayerCount == 0 && psOptions->osSQL.empty())
     725          47 :         nLayerCount = 1; /* due to above check */
     726             : 
     727         106 :     int nBands = nLayerCount;
     728             : 
     729         106 :     if (!psOptions->osSQL.empty())
     730           4 :         nBands++;
     731             : 
     732             :     int nXSize;
     733             :     int nYSize;
     734         106 :     if (psOptions->dfXRes != 0 && psOptions->dfYRes != 0)
     735             :     {
     736           1 :         if ((psOptions->dfXMax == psOptions->dfXMin) ||
     737           1 :             (psOptions->dfYMax == psOptions->dfYMin))
     738             :         {
     739           0 :             CPLError(CE_Failure, CPLE_IllegalArg,
     740             :                      "Invalid txe or tye parameters detected. Please check "
     741             :                      "your -txe or -tye argument.");
     742             : 
     743           0 :             if (pbUsageError)
     744           0 :                 *pbUsageError = TRUE;
     745           0 :             return nullptr;
     746             :         }
     747             : 
     748           1 :         double dfXSize = (std::fabs(psOptions->dfXMax - psOptions->dfXMin) +
     749           1 :                           (psOptions->dfXRes / 2.0)) /
     750           1 :                          psOptions->dfXRes;
     751           1 :         double dfYSize = (std::fabs(psOptions->dfYMax - psOptions->dfYMin) +
     752           1 :                           (psOptions->dfYRes / 2.0)) /
     753           1 :                          psOptions->dfYRes;
     754             : 
     755           1 :         if (dfXSize >= 1 && dfXSize <= INT_MAX && dfYSize >= 1 &&
     756             :             dfYSize <= INT_MAX)
     757             :         {
     758           1 :             nXSize = static_cast<int>(dfXSize);
     759           1 :             nYSize = static_cast<int>(dfYSize);
     760             :         }
     761             :         else
     762             :         {
     763           0 :             CPLError(
     764             :                 CE_Failure, CPLE_IllegalArg,
     765             :                 "Invalid output size detected. Please check your -tr argument");
     766             : 
     767           0 :             if (pbUsageError)
     768           0 :                 *pbUsageError = TRUE;
     769           0 :             return nullptr;
     770           1 :         }
     771             :     }
     772             :     else
     773             :     {
     774             :         // FIXME
     775         105 :         nXSize = psOptions->nXSize;
     776         105 :         if (nXSize == 0)
     777           0 :             nXSize = 256;
     778         105 :         nYSize = psOptions->nYSize;
     779         105 :         if (nYSize == 0)
     780           0 :             nYSize = 256;
     781             :     }
     782             : 
     783             :     std::unique_ptr<GDALDataset> poDstDS(GDALDataset::FromHandle(GDALCreate(
     784         106 :         hDriver, pszDest, nXSize, nYSize, nBands, psOptions->eOutputType,
     785         212 :         psOptions->aosCreateOptions.List())));
     786         106 :     if (!poDstDS)
     787             :     {
     788           0 :         return nullptr;
     789             :     }
     790             : 
     791         106 :     if (psOptions->bNoDataSet)
     792             :     {
     793         104 :         for (int i = 1; i <= nBands; i++)
     794             :         {
     795          52 :             poDstDS->GetRasterBand(i)->SetNoDataValue(psOptions->dfNoDataValue);
     796             :         }
     797             :     }
     798             : 
     799         106 :     double dfXMin = psOptions->dfXMin;
     800         106 :     double dfYMin = psOptions->dfYMin;
     801         106 :     double dfXMax = psOptions->dfXMax;
     802         106 :     double dfYMax = psOptions->dfYMax;
     803         106 :     bool bIsXExtentSet = psOptions->bIsXExtentSet;
     804         106 :     bool bIsYExtentSet = psOptions->bIsYExtentSet;
     805         106 :     CPLErr eErr = CE_None;
     806             : 
     807             :     /* -------------------------------------------------------------------- */
     808             :     /*      Process SQL request.                                            */
     809             :     /* -------------------------------------------------------------------- */
     810             : 
     811         106 :     if (!psOptions->osSQL.empty())
     812             :     {
     813             :         OGRLayer *poLayer =
     814           4 :             poSrcDS->ExecuteSQL(psOptions->osSQL.c_str(),
     815           4 :                                 psOptions->poSpatialFilter.get(), nullptr);
     816           4 :         if (poLayer == nullptr)
     817             :         {
     818           1 :             return nullptr;
     819             :         }
     820             : 
     821             :         // Custom layer will be rasterized in the first band.
     822           3 :         eErr = ProcessLayer(
     823           3 :             poLayer, poDstDS.get(), psOptions->poSpatialFilter.get(), nXSize,
     824             :             nYSize, 1, bIsXExtentSet, bIsYExtentSet, dfXMin, dfXMax, dfYMin,
     825           3 :             dfYMax, psOptions->osBurnAttribute, psOptions->dfIncreaseBurnValue,
     826           3 :             psOptions->dfMultiplyBurnValue, psOptions->eOutputType,
     827           3 :             psOptions->eAlgorithm, psOptions->pOptions.get(), psOptions->bQuiet,
     828           3 :             psOptions->pfnProgress, psOptions->pProgressData);
     829             : 
     830           3 :         poSrcDS->ReleaseResultSet(poLayer);
     831             :     }
     832             : 
     833             :     /* -------------------------------------------------------------------- */
     834             :     /*      Process each layer.                                             */
     835             :     /* -------------------------------------------------------------------- */
     836         210 :     std::string osOutputSRS(psOptions->osOutputSRS);
     837         205 :     for (int i = 0; i < nLayerCount; i++)
     838             :     {
     839         102 :         auto poLayer = psOptions->aosLayers.empty()
     840         102 :                            ? poSrcDS->GetLayer(0)
     841          55 :                            : poSrcDS->GetLayerByName(psOptions->aosLayers[i]);
     842         102 :         if (!poLayer)
     843             :         {
     844           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     845             :                      "Unable to find layer \"%s\".",
     846           1 :                      !psOptions->aosLayers.empty() && psOptions->aosLayers[i]
     847           1 :                          ? psOptions->aosLayers[i]
     848             :                          : "null");
     849           1 :             eErr = CE_Failure;
     850           1 :             break;
     851             :         }
     852             : 
     853         101 :         if (!psOptions->osWHERE.empty())
     854             :         {
     855           2 :             if (poLayer->SetAttributeFilter(psOptions->osWHERE.c_str()) !=
     856             :                 OGRERR_NONE)
     857             :             {
     858           1 :                 eErr = CE_Failure;
     859           1 :                 break;
     860             :             }
     861             :         }
     862             : 
     863         100 :         if (psOptions->poSpatialFilter)
     864           2 :             poLayer->SetSpatialFilter(psOptions->poSpatialFilter.get());
     865             : 
     866             :         // Fetch the first meaningful SRS definition
     867         100 :         if (osOutputSRS.empty())
     868             :         {
     869         100 :             auto poSRS = poLayer->GetSpatialRef();
     870         100 :             if (poSRS)
     871          91 :                 osOutputSRS = poSRS->exportToWkt();
     872             :         }
     873             : 
     874         100 :         eErr = ProcessLayer(
     875         100 :             poLayer, poDstDS.get(), psOptions->poSpatialFilter.get(), nXSize,
     876         100 :             nYSize, i + 1 + nBands - nLayerCount, bIsXExtentSet, bIsYExtentSet,
     877         100 :             dfXMin, dfXMax, dfYMin, dfYMax, psOptions->osBurnAttribute,
     878         100 :             psOptions->dfIncreaseBurnValue, psOptions->dfMultiplyBurnValue,
     879         100 :             psOptions->eOutputType, psOptions->eAlgorithm,
     880         100 :             psOptions->pOptions.get(), psOptions->bQuiet,
     881         100 :             psOptions->pfnProgress, psOptions->pProgressData);
     882         100 :         if (eErr != CE_None)
     883           0 :             break;
     884             :     }
     885             : 
     886             :     /* -------------------------------------------------------------------- */
     887             :     /*      Apply geotransformation matrix.                                 */
     888             :     /* -------------------------------------------------------------------- */
     889         105 :     double adfGeoTransform[6] = {dfXMin, (dfXMax - dfXMin) / nXSize,
     890             :                                  0.0,    dfYMin,
     891         105 :                                  0.0,    (dfYMax - dfYMin) / nYSize};
     892         105 :     poDstDS->SetGeoTransform(adfGeoTransform);
     893             : 
     894             :     /* -------------------------------------------------------------------- */
     895             :     /*      Apply SRS definition if set.                                    */
     896             :     /* -------------------------------------------------------------------- */
     897         105 :     if (!osOutputSRS.empty())
     898             :     {
     899          91 :         poDstDS->SetProjection(osOutputSRS.c_str());
     900             :     }
     901             : 
     902             :     /* -------------------------------------------------------------------- */
     903             :     /*      End                                                             */
     904             :     /* -------------------------------------------------------------------- */
     905             : 
     906         105 :     if (eErr != CE_None)
     907             :     {
     908           2 :         return nullptr;
     909             :     }
     910             : 
     911         103 :     return GDALDataset::ToHandle(poDstDS.release());
     912             : }
     913             : 
     914             : /************************************************************************/
     915             : /*                       GDALGridOptionsGetParser()                     */
     916             : /************************************************************************/
     917             : 
     918             : /*! @cond Doxygen_Suppress */
     919             : 
     920             : static std::unique_ptr<GDALArgumentParser>
     921         107 : GDALGridOptionsGetParser(GDALGridOptions *psOptions,
     922             :                          GDALGridOptionsForBinary *psOptionsForBinary,
     923             :                          int nCountClipSrc)
     924             : {
     925             :     auto argParser = std::make_unique<GDALArgumentParser>(
     926         107 :         "gdal_grid", /* bForBinary=*/psOptionsForBinary != nullptr);
     927             : 
     928         107 :     argParser->add_description(
     929             :         _("Creates a regular grid (raster) from the scattered data read from a "
     930         107 :           "vector datasource."));
     931             : 
     932         107 :     argParser->add_epilog(_(
     933             :         "Available algorithms and parameters with their defaults:\n"
     934             :         "    Inverse distance to a power (default)\n"
     935             :         "        "
     936             :         "invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_"
     937             :         "points=0:min_points=0:nodata=0.0\n"
     938             :         "    Inverse distance to a power with nearest neighbor search\n"
     939             :         "        "
     940             :         "invdistnn:power=2.0:radius=1.0:max_points=12:min_points=0:nodata=0\n"
     941             :         "    Moving average\n"
     942             :         "        "
     943             :         "average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0\n"
     944             :         "    Nearest neighbor\n"
     945             :         "        nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0\n"
     946             :         "    Various data metrics\n"
     947             :         "        <metric "
     948             :         "name>:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0\n"
     949             :         "        possible metrics are:\n"
     950             :         "            minimum\n"
     951             :         "            maximum\n"
     952             :         "            range\n"
     953             :         "            count\n"
     954             :         "            average_distance\n"
     955             :         "            average_distance_pts\n"
     956             :         "    Linear\n"
     957             :         "        linear:radius=-1.0:nodata=0.0\n"
     958             :         "\n"
     959         107 :         "For more details, consult https://gdal.org/programs/gdal_grid.html"));
     960             : 
     961             :     argParser->add_quiet_argument(
     962         107 :         psOptionsForBinary ? &psOptionsForBinary->bQuiet : nullptr);
     963             : 
     964         107 :     argParser->add_output_format_argument(psOptions->osFormat);
     965             : 
     966         107 :     argParser->add_output_type_argument(psOptions->eOutputType);
     967             : 
     968         107 :     argParser->add_argument("-txe")
     969         214 :         .metavar("<xmin> <xmax>")
     970         107 :         .nargs(2)
     971         107 :         .scan<'g', double>()
     972         107 :         .help(_("Set georeferenced X extents of output file to be created."));
     973             : 
     974         107 :     argParser->add_argument("-tye")
     975         214 :         .metavar("<ymin> <ymax>")
     976         107 :         .nargs(2)
     977         107 :         .scan<'g', double>()
     978         107 :         .help(_("Set georeferenced Y extents of output file to be created."));
     979             : 
     980         107 :     argParser->add_argument("-outsize")
     981         214 :         .metavar("<xsize> <ysize>")
     982         107 :         .nargs(2)
     983         107 :         .scan<'i', int>()
     984         107 :         .help(_("Set the size of the output file."));
     985             : 
     986         107 :     argParser->add_argument("-tr")
     987         214 :         .metavar("<xres> <yes>")
     988         107 :         .nargs(2)
     989         107 :         .scan<'g', double>()
     990         107 :         .help(_("Set target resolution."));
     991             : 
     992         107 :     argParser->add_creation_options_argument(psOptions->aosCreateOptions);
     993             : 
     994         107 :     argParser->add_argument("-zfield")
     995         214 :         .metavar("<field_name>")
     996         107 :         .store_into(psOptions->osBurnAttribute)
     997         107 :         .help(_("Field name from which to get Z values."));
     998             : 
     999         107 :     argParser->add_argument("-z_increase")
    1000         214 :         .metavar("<increase_value>")
    1001         107 :         .store_into(psOptions->dfIncreaseBurnValue)
    1002             :         .help(_("Addition to the attribute field on the features to be used to "
    1003         107 :                 "get a Z value from."));
    1004             : 
    1005         107 :     argParser->add_argument("-z_multiply")
    1006         214 :         .metavar("<multiply_value>")
    1007         107 :         .store_into(psOptions->dfMultiplyBurnValue)
    1008         107 :         .help(_("Multiplication ratio for the Z field.."));
    1009             : 
    1010         107 :     argParser->add_argument("-where")
    1011         214 :         .metavar("<expression>")
    1012         107 :         .store_into(psOptions->osWHERE)
    1013             :         .help(_("Query expression to be applied to select features to process "
    1014         107 :                 "from the input layer(s)."));
    1015             : 
    1016         107 :     argParser->add_argument("-l")
    1017         214 :         .metavar("<layer_name>")
    1018         107 :         .append()
    1019          55 :         .action([psOptions](const std::string &s)
    1020         162 :                 { psOptions->aosLayers.AddString(s.c_str()); })
    1021             :         .help(_("Layer(s) from the datasource that will be used for input "
    1022         107 :                 "features."));
    1023             : 
    1024         107 :     argParser->add_argument("-sql")
    1025         214 :         .metavar("<select_statement>")
    1026         107 :         .store_into(psOptions->osSQL)
    1027             :         .help(_("SQL statement to be evaluated to produce a layer of features "
    1028         107 :                 "to be processed."));
    1029             : 
    1030         107 :     argParser->add_argument("-spat")
    1031         214 :         .metavar("<xmin> <ymin> <xmax> <ymax>")
    1032         107 :         .nargs(4)
    1033         107 :         .scan<'g', double>()
    1034             :         .help(_("The area of interest. Only features within the rectangle will "
    1035         107 :                 "be reported."));
    1036             : 
    1037         107 :     argParser->add_argument("-clipsrc")
    1038         107 :         .nargs(nCountClipSrc)
    1039         214 :         .metavar("[<xmin> <ymin> <xmax> <ymax>]|<WKT>|<datasource>|spat_extent")
    1040         107 :         .help(_("Clip geometries (in source SRS)."));
    1041             : 
    1042         107 :     argParser->add_argument("-clipsrcsql")
    1043         214 :         .metavar("<sql_statement>")
    1044         107 :         .store_into(psOptions->osClipSrcSQL)
    1045             :         .help(_("Select desired geometries from the source clip datasource "
    1046         107 :                 "using an SQL query."));
    1047             : 
    1048         107 :     argParser->add_argument("-clipsrclayer")
    1049         214 :         .metavar("<layername>")
    1050         107 :         .store_into(psOptions->osClipSrcLayer)
    1051         107 :         .help(_("Select the named layer from the source clip datasource."));
    1052             : 
    1053         107 :     argParser->add_argument("-clipsrcwhere")
    1054         214 :         .metavar("<expression>")
    1055         107 :         .store_into(psOptions->osClipSrcWhere)
    1056             :         .help(_("Restrict desired geometries from the source clip layer based "
    1057         107 :                 "on an attribute query."));
    1058             : 
    1059         107 :     argParser->add_argument("-a_srs")
    1060         214 :         .metavar("<srs_def>")
    1061             :         .action(
    1062           0 :             [psOptions](const std::string &osOutputSRSDef)
    1063             :             {
    1064           0 :                 OGRSpatialReference oOutputSRS;
    1065             : 
    1066           0 :                 if (oOutputSRS.SetFromUserInput(osOutputSRSDef.c_str()) !=
    1067             :                     OGRERR_NONE)
    1068             :                 {
    1069             :                     throw std::invalid_argument(
    1070           0 :                         std::string("Failed to process SRS definition: ")
    1071           0 :                             .append(osOutputSRSDef));
    1072             :                 }
    1073             : 
    1074           0 :                 char *pszWKT = nullptr;
    1075           0 :                 oOutputSRS.exportToWkt(&pszWKT);
    1076           0 :                 if (pszWKT)
    1077           0 :                     psOptions->osOutputSRS = pszWKT;
    1078           0 :                 CPLFree(pszWKT);
    1079         107 :             })
    1080         107 :         .help(_("Assign an output SRS, but without reprojecting."));
    1081             : 
    1082         107 :     argParser->add_argument("-a")
    1083         214 :         .metavar("<algorithm>[[:<parameter1>=<value1>]...]")
    1084             :         .action(
    1085         352 :             [psOptions](const std::string &s)
    1086             :             {
    1087         100 :                 const char *pszAlgorithm = s.c_str();
    1088         100 :                 void *pOptions = nullptr;
    1089         100 :                 if (GDALGridParseAlgorithmAndOptions(pszAlgorithm,
    1090             :                                                      &psOptions->eAlgorithm,
    1091         100 :                                                      &pOptions) != CE_None)
    1092             :                 {
    1093             :                     throw std::invalid_argument(
    1094           0 :                         "Failed to process algorithm name and parameters");
    1095             :                 }
    1096         100 :                 psOptions->pOptions.reset(pOptions);
    1097             : 
    1098             :                 const CPLStringList aosParams(
    1099         200 :                     CSLTokenizeString2(pszAlgorithm, ":", FALSE));
    1100         100 :                 const char *pszNoDataValue = aosParams.FetchNameValue("nodata");
    1101         100 :                 if (pszNoDataValue != nullptr)
    1102             :                 {
    1103          52 :                     psOptions->bNoDataSet = true;
    1104          52 :                     psOptions->dfNoDataValue = CPLAtofM(pszNoDataValue);
    1105             :                 }
    1106         207 :             })
    1107             :         .help(_("Set the interpolation algorithm or data metric name and "
    1108         107 :                 "(optionally) its parameters."));
    1109             : 
    1110         107 :     if (psOptionsForBinary)
    1111             :     {
    1112             :         argParser->add_open_options_argument(
    1113          55 :             &(psOptionsForBinary->aosOpenOptions));
    1114             :     }
    1115             : 
    1116         107 :     if (psOptionsForBinary)
    1117             :     {
    1118          55 :         argParser->add_argument("src_dataset_name")
    1119         110 :             .metavar("<src_dataset_name>")
    1120          55 :             .store_into(psOptionsForBinary->osSource)
    1121          55 :             .help(_("Input dataset."));
    1122             : 
    1123          55 :         argParser->add_argument("dst_dataset_name")
    1124         110 :             .metavar("<dst_dataset_name>")
    1125          55 :             .store_into(psOptionsForBinary->osDest)
    1126          55 :             .help(_("Output dataset."));
    1127             :     }
    1128             : 
    1129         107 :     return argParser;
    1130             : }
    1131             : 
    1132             : /*! @endcond */
    1133             : 
    1134             : /************************************************************************/
    1135             : /*                         GDALGridGetParserUsage()                     */
    1136             : /************************************************************************/
    1137             : 
    1138           0 : std::string GDALGridGetParserUsage()
    1139             : {
    1140             :     try
    1141             :     {
    1142           0 :         GDALGridOptions sOptions;
    1143           0 :         GDALGridOptionsForBinary sOptionsForBinary;
    1144             :         auto argParser =
    1145           0 :             GDALGridOptionsGetParser(&sOptions, &sOptionsForBinary, 1);
    1146           0 :         return argParser->usage();
    1147             :     }
    1148           0 :     catch (const std::exception &err)
    1149             :     {
    1150           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
    1151           0 :                  err.what());
    1152           0 :         return std::string();
    1153             :     }
    1154             : }
    1155             : 
    1156             : /************************************************************************/
    1157             : /*                   CHECK_HAS_ENOUGH_ADDITIONAL_ARGS()                 */
    1158             : /************************************************************************/
    1159             : 
    1160             : #ifndef CheckHasEnoughAdditionalArgs_defined
    1161             : #define CheckHasEnoughAdditionalArgs_defined
    1162             : 
    1163           1 : static bool CheckHasEnoughAdditionalArgs(CSLConstList papszArgv, int i,
    1164             :                                          int nExtraArg, int nArgc)
    1165             : {
    1166           1 :     if (i + nExtraArg >= nArgc)
    1167             :     {
    1168           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
    1169           0 :                  "%s option requires %d argument%s", papszArgv[i], nExtraArg,
    1170             :                  nExtraArg == 1 ? "" : "s");
    1171           0 :         return false;
    1172             :     }
    1173           1 :     return true;
    1174             : }
    1175             : #endif
    1176             : 
    1177             : #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg)                            \
    1178             :     if (!CheckHasEnoughAdditionalArgs(papszArgv, i, nExtraArg, nArgc))         \
    1179             :     {                                                                          \
    1180             :         return nullptr;                                                        \
    1181             :     }
    1182             : 
    1183             : /************************************************************************/
    1184             : /*                             GDALGridOptionsNew()                     */
    1185             : /************************************************************************/
    1186             : 
    1187             : /**
    1188             :  * Allocates a GDALGridOptions struct.
    1189             :  *
    1190             :  * @param papszArgv NULL terminated list of options (potentially including
    1191             :  * filename and open options too), or NULL. The accepted options are the ones of
    1192             :  * the <a href="/programs/gdal_translate.html">gdal_translate</a> utility.
    1193             :  * @param psOptionsForBinary (output) may be NULL (and should generally be
    1194             :  * NULL), otherwise (gdal_translate_bin.cpp use case) must be allocated with
    1195             :  *                           GDALGridOptionsForBinaryNew() prior to this
    1196             :  * function. Will be filled with potentially present filename, open options,...
    1197             :  * @return pointer to the allocated GDALGridOptions struct. Must be freed with
    1198             :  * GDALGridOptionsFree().
    1199             :  *
    1200             :  * @since GDAL 2.1
    1201             :  */
    1202             : 
    1203             : GDALGridOptions *
    1204         107 : GDALGridOptionsNew(char **papszArgv,
    1205             :                    GDALGridOptionsForBinary *psOptionsForBinary)
    1206             : {
    1207         213 :     auto psOptions = std::make_unique<GDALGridOptions>();
    1208             : 
    1209             :     /* -------------------------------------------------------------------- */
    1210             :     /*      Pre-processing for custom syntax that ArgumentParser does not   */
    1211             :     /*      support.                                                        */
    1212             :     /* -------------------------------------------------------------------- */
    1213             : 
    1214         213 :     CPLStringList aosArgv;
    1215         107 :     const int nArgc = CSLCount(papszArgv);
    1216         107 :     int nCountClipSrc = 0;
    1217        1744 :     for (int i = 0;
    1218        1744 :          i < nArgc && papszArgv != nullptr && papszArgv[i] != nullptr; i++)
    1219             :     {
    1220        1637 :         if (EQUAL(papszArgv[i], "-clipsrc"))
    1221             :         {
    1222           1 :             if (nCountClipSrc)
    1223             :             {
    1224           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Duplicate argument %s",
    1225           0 :                          papszArgv[i]);
    1226           0 :                 return nullptr;
    1227             :             }
    1228             :             // argparse doesn't handle well variable number of values
    1229             :             // just before the positional arguments, so we have to detect
    1230             :             // it manually and set the correct number.
    1231           1 :             nCountClipSrc = 1;
    1232           1 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
    1233           1 :             if (CPLGetValueType(papszArgv[i + 1]) != CPL_VALUE_STRING &&
    1234           0 :                 i + 4 < nArgc)
    1235             :             {
    1236           0 :                 nCountClipSrc = 4;
    1237             :             }
    1238             : 
    1239           3 :             for (int j = 0; j < 1 + nCountClipSrc; ++j)
    1240             :             {
    1241           2 :                 aosArgv.AddString(papszArgv[i]);
    1242           2 :                 ++i;
    1243             :             }
    1244           1 :             --i;
    1245             :         }
    1246             : 
    1247             :         else
    1248             :         {
    1249        1636 :             aosArgv.AddString(papszArgv[i]);
    1250             :         }
    1251             :     }
    1252             : 
    1253             :     try
    1254             :     {
    1255             :         auto argParser = GDALGridOptionsGetParser(
    1256         213 :             psOptions.get(), psOptionsForBinary, nCountClipSrc);
    1257             : 
    1258         107 :         argParser->parse_args_without_binary_name(aosArgv.List());
    1259             : 
    1260         212 :         if (auto oTXE = argParser->present<std::vector<double>>("-txe"))
    1261             :         {
    1262         106 :             psOptions->dfXMin = (*oTXE)[0];
    1263         106 :             psOptions->dfXMax = (*oTXE)[1];
    1264         106 :             psOptions->bIsXExtentSet = true;
    1265             :         }
    1266             : 
    1267         212 :         if (auto oTYE = argParser->present<std::vector<double>>("-tye"))
    1268             :         {
    1269         106 :             psOptions->dfYMin = (*oTYE)[0];
    1270         106 :             psOptions->dfYMax = (*oTYE)[1];
    1271         106 :             psOptions->bIsYExtentSet = true;
    1272             :         }
    1273             : 
    1274         211 :         if (auto oOutsize = argParser->present<std::vector<int>>("-outsize"))
    1275             :         {
    1276         105 :             psOptions->nXSize = (*oOutsize)[0];
    1277         105 :             psOptions->nYSize = (*oOutsize)[1];
    1278             :         }
    1279             : 
    1280         106 :         if (auto adfTargetRes = argParser->present<std::vector<double>>("-tr"))
    1281             :         {
    1282           1 :             psOptions->dfXRes = (*adfTargetRes)[0];
    1283           1 :             psOptions->dfYRes = (*adfTargetRes)[1];
    1284           1 :             if (psOptions->dfXRes <= 0 || psOptions->dfYRes <= 0)
    1285             :             {
    1286           0 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1287             :                          "Wrong value for -tr parameters.");
    1288           0 :                 return nullptr;
    1289             :             }
    1290             :         }
    1291             : 
    1292         107 :         if (auto oSpat = argParser->present<std::vector<double>>("-spat"))
    1293             :         {
    1294           2 :             OGRLinearRing oRing;
    1295           1 :             const double dfMinX = (*oSpat)[0];
    1296           1 :             const double dfMinY = (*oSpat)[1];
    1297           1 :             const double dfMaxX = (*oSpat)[2];
    1298           1 :             const double dfMaxY = (*oSpat)[3];
    1299             : 
    1300           1 :             oRing.addPoint(dfMinX, dfMinY);
    1301           1 :             oRing.addPoint(dfMinX, dfMaxY);
    1302           1 :             oRing.addPoint(dfMaxX, dfMaxY);
    1303           1 :             oRing.addPoint(dfMaxX, dfMinY);
    1304           1 :             oRing.addPoint(dfMinX, dfMinY);
    1305             : 
    1306           2 :             auto poPolygon = std::make_unique<OGRPolygon>();
    1307           1 :             poPolygon->addRing(&oRing);
    1308           1 :             psOptions->poSpatialFilter = std::move(poPolygon);
    1309             :         }
    1310             : 
    1311         106 :         if (auto oClipSrc =
    1312         106 :                 argParser->present<std::vector<std::string>>("-clipsrc"))
    1313             :         {
    1314           1 :             const std::string &osVal = (*oClipSrc)[0];
    1315             : 
    1316           1 :             psOptions->poClipSrc.reset();
    1317           1 :             psOptions->osClipSrcDS.clear();
    1318             : 
    1319             :             VSIStatBufL sStat;
    1320           1 :             psOptions->bClipSrc = true;
    1321           1 :             if (oClipSrc->size() == 4)
    1322             :             {
    1323           0 :                 const double dfMinX = CPLAtofM((*oClipSrc)[0].c_str());
    1324           0 :                 const double dfMinY = CPLAtofM((*oClipSrc)[1].c_str());
    1325           0 :                 const double dfMaxX = CPLAtofM((*oClipSrc)[2].c_str());
    1326           0 :                 const double dfMaxY = CPLAtofM((*oClipSrc)[3].c_str());
    1327             : 
    1328           0 :                 OGRLinearRing oRing;
    1329             : 
    1330           0 :                 oRing.addPoint(dfMinX, dfMinY);
    1331           0 :                 oRing.addPoint(dfMinX, dfMaxY);
    1332           0 :                 oRing.addPoint(dfMaxX, dfMaxY);
    1333           0 :                 oRing.addPoint(dfMaxX, dfMinY);
    1334           0 :                 oRing.addPoint(dfMinX, dfMinY);
    1335             : 
    1336           0 :                 auto poPoly = std::make_unique<OGRPolygon>();
    1337           0 :                 poPoly->addRing(&oRing);
    1338           0 :                 psOptions->poClipSrc = std::move(poPoly);
    1339             :             }
    1340           1 :             else if ((STARTS_WITH_CI(osVal.c_str(), "POLYGON") ||
    1341           1 :                       STARTS_WITH_CI(osVal.c_str(), "MULTIPOLYGON")) &&
    1342           0 :                      VSIStatL(osVal.c_str(), &sStat) != 0)
    1343             :             {
    1344           0 :                 OGRGeometry *poGeom = nullptr;
    1345           0 :                 OGRGeometryFactory::createFromWkt(osVal.c_str(), nullptr,
    1346             :                                                   &poGeom);
    1347           0 :                 psOptions->poClipSrc.reset(poGeom);
    1348           0 :                 if (psOptions->poClipSrc == nullptr)
    1349             :                 {
    1350           0 :                     CPLError(CE_Failure, CPLE_IllegalArg,
    1351             :                              "Invalid geometry. Must be a valid POLYGON or "
    1352             :                              "MULTIPOLYGON WKT");
    1353           0 :                     return nullptr;
    1354             :                 }
    1355             :             }
    1356           1 :             else if (EQUAL(osVal.c_str(), "spat_extent"))
    1357             :             {
    1358             :                 // Nothing to do
    1359             :             }
    1360             :             else
    1361             :             {
    1362           1 :                 psOptions->osClipSrcDS = osVal;
    1363             :             }
    1364             :         }
    1365             : 
    1366         106 :         if (psOptions->bClipSrc && !psOptions->osClipSrcDS.empty())
    1367             :         {
    1368           2 :             psOptions->poClipSrc = LoadGeometry(
    1369           1 :                 psOptions->osClipSrcDS, psOptions->osClipSrcSQL,
    1370           2 :                 psOptions->osClipSrcLayer, psOptions->osClipSrcWhere);
    1371           1 :             if (!psOptions->poClipSrc)
    1372             :             {
    1373           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1374             :                          "Cannot load source clip geometry.");
    1375           0 :                 return nullptr;
    1376             :             }
    1377             :         }
    1378         105 :         else if (psOptions->bClipSrc && !psOptions->poClipSrc &&
    1379           0 :                  !psOptions->poSpatialFilter)
    1380             :         {
    1381           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1382             :                      "-clipsrc must be used with -spat option or \n"
    1383             :                      "a bounding box, WKT string or datasource must be "
    1384             :                      "specified.");
    1385           0 :             return nullptr;
    1386             :         }
    1387             : 
    1388         106 :         if (psOptions->poSpatialFilter)
    1389             :         {
    1390           1 :             if (psOptions->poClipSrc)
    1391             :             {
    1392             :                 auto poTemp = std::unique_ptr<OGRGeometry>(
    1393           0 :                     psOptions->poSpatialFilter->Intersection(
    1394           0 :                         psOptions->poClipSrc.get()));
    1395           0 :                 if (poTemp)
    1396             :                 {
    1397           0 :                     psOptions->poSpatialFilter = std::move(poTemp);
    1398             :                 }
    1399             : 
    1400           0 :                 psOptions->poClipSrc.reset();
    1401             :             }
    1402             :         }
    1403             :         else
    1404             :         {
    1405         105 :             if (psOptions->poClipSrc)
    1406             :             {
    1407           1 :                 psOptions->poSpatialFilter = std::move(psOptions->poClipSrc);
    1408             :             }
    1409             :         }
    1410             : 
    1411         106 :         return psOptions.release();
    1412             :     }
    1413           0 :     catch (const std::exception &err)
    1414             :     {
    1415           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", err.what());
    1416           0 :         return nullptr;
    1417             :     }
    1418             : }
    1419             : 
    1420             : /************************************************************************/
    1421             : /*                          GDALGridOptionsFree()                       */
    1422             : /************************************************************************/
    1423             : 
    1424             : /**
    1425             :  * Frees the GDALGridOptions struct.
    1426             :  *
    1427             :  * @param psOptions the options struct for GDALGrid().
    1428             :  *
    1429             :  * @since GDAL 2.1
    1430             :  */
    1431             : 
    1432         106 : void GDALGridOptionsFree(GDALGridOptions *psOptions)
    1433             : {
    1434         106 :     delete psOptions;
    1435         106 : }
    1436             : 
    1437             : /************************************************************************/
    1438             : /*                     GDALGridOptionsSetProgress()                     */
    1439             : /************************************************************************/
    1440             : 
    1441             : /**
    1442             :  * Set a progress function.
    1443             :  *
    1444             :  * @param psOptions the options struct for GDALGrid().
    1445             :  * @param pfnProgress the progress callback.
    1446             :  * @param pProgressData the user data for the progress callback.
    1447             :  *
    1448             :  * @since GDAL 2.1
    1449             :  */
    1450             : 
    1451          54 : void GDALGridOptionsSetProgress(GDALGridOptions *psOptions,
    1452             :                                 GDALProgressFunc pfnProgress,
    1453             :                                 void *pProgressData)
    1454             : {
    1455          54 :     psOptions->pfnProgress = pfnProgress;
    1456          54 :     psOptions->pProgressData = pProgressData;
    1457          54 :     if (pfnProgress == GDALTermProgress)
    1458          54 :         psOptions->bQuiet = false;
    1459          54 : }
    1460             : 
    1461             : #undef CHECK_HAS_ENOUGH_ADDITIONAL_ARGS

Generated by: LCOV version 1.14