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

Generated by: LCOV version 1.14